/** * Retrieve the terms in a given taxonomy or list of taxonomies. * * You can fully inject any customizations to the query before it is sent, as * well as control the output with a filter. * * The {@see 'get_terms'} filter will be called when the cache has the term and will * pass the found term along with the array of $taxonomies and array of $args. * This filter is also called before the array of terms is passed and will pass * the array of terms, along with the $taxonomies and $args. * * The {@see 'list_terms_exclusions'} filter passes the compiled exclusions along with * the $args. * * The {@see 'get_terms_orderby'} filter passes the `ORDER BY` clause for the query * along with the $args array. * * @since 2.3.0 * @since 4.2.0 Introduced 'name' and 'childless' parameters. * @since 4.4.0 Introduced the ability to pass 'term_id' as an alias of 'id' for the `orderby` parameter. * Introduced the 'meta_query' and 'update_term_meta_cache' parameters. Converted to return * a list of WP_Term objects. * * @global wpdb $wpdb WordPress database abstraction object. * @global array $wp_filter * * @param string|array $taxonomies Taxonomy name or list of Taxonomy names. * @param array|string $args { * Optional. Array or string of arguments to get terms. * * @type string $orderby Field(s) to order terms by. Accepts term fields ('name', 'slug', * 'term_group', 'term_id', 'id', 'description'), 'count' for term * taxonomy count, 'include' to match the 'order' of the $include param, * or 'none' to skip ORDER BY. Defaults to 'name'. * @type string $order Whether to order terms in ascending or descending order. * Accepts 'ASC' (ascending) or 'DESC' (descending). * Default 'ASC'. * @type bool|int $hide_empty Whether to hide terms not assigned to any posts. Accepts * 1|true or 0|false. Default 1|true. * @type array|string $include Array or comma/space-separated string of term ids to include. * Default empty array. * @type array|string $exclude Array or comma/space-separated string of term ids to exclude. * If $include is non-empty, $exclude is ignored. * Default empty array. * @type array|string $exclude_tree Array or comma/space-separated string of term ids to exclude * along with all of their descendant terms. If $include is * non-empty, $exclude_tree is ignored. Default empty array. * @type int|string $number Maximum number of terms to return. Accepts ''|0 (all) or any * positive number. Default ''|0 (all). * @type int $offset The number by which to offset the terms query. Default empty. * @type string $fields Term fields to query for. Accepts 'all' (returns an array of complete * term objects), 'ids' (returns an array of ids), 'id=>parent' (returns * an associative array with ids as keys, parent term IDs as values), * 'names' (returns an array of term names), 'count' (returns the number * of matching terms), 'id=>name' (returns an associative array with ids * as keys, term names as values), or 'id=>slug' (returns an associative * array with ids as keys, term slugs as values). Default 'all'. * @type string|array $name Optional. Name or array of names to return term(s) for. Default empty. * @type string|array $slug Optional. Slug or array of slugs to return term(s) for. Default empty. * @type bool $hierarchical Whether to include terms that have non-empty descendants (even * if $hide_empty is set to true). Default true. * @type string $search Search criteria to match terms. Will be SQL-formatted with * wildcards before and after. Default empty. * @type string $name__like Retrieve terms with criteria by which a term is LIKE $name__like. * Default empty. * @type string $description__like Retrieve terms where the description is LIKE $description__like. * Default empty. * @type bool $pad_counts Whether to pad the quantity of a term's children in the quantity * of each term's "count" object variable. Default false. * @type string $get Whether to return terms regardless of ancestry or whether the terms * are empty. Accepts 'all' or empty (disabled). Default empty. * @type int $child_of Term ID to retrieve child terms of. If multiple taxonomies * are passed, $child_of is ignored. Default 0. * @type int|string $parent Parent term ID to retrieve direct-child terms of. Default empty. * @type bool $childless True to limit results to terms that have no children. This parameter * has no effect on non-hierarchical taxonomies. Default false. * @type string $cache_domain Unique cache key to be produced when this query is stored in an * object cache. Default is 'core'. * @type bool $update_term_meta_cache Whether to prime meta caches for matched terms. Default true. * @type array $meta_query Meta query clauses to limit retrieved terms by. * See `WP_Meta_Query`. Default empty. * } * @return array|int|WP_Error List of WP_Term instances and their children. Will return WP_Error, if any of $taxonomies * do not exist. */ function get_terms($taxonomies, $args = '') { global $wpdb; $empty_array = array(); $single_taxonomy = !is_array($taxonomies) || 1 === count($taxonomies); if (!is_array($taxonomies)) { $taxonomies = array($taxonomies); } foreach ($taxonomies as $taxonomy) { if (!taxonomy_exists($taxonomy)) { return new WP_Error('invalid_taxonomy', __('Invalid taxonomy')); } } $defaults = array('orderby' => 'name', 'order' => 'ASC', 'hide_empty' => true, 'exclude' => array(), 'exclude_tree' => array(), 'include' => array(), 'number' => '', 'fields' => 'all', 'name' => '', 'slug' => '', 'parent' => '', 'childless' => false, 'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'description__like' => '', 'pad_counts' => false, 'offset' => '', 'search' => '', 'cache_domain' => 'core', 'update_term_meta_cache' => true, 'meta_query' => ''); $args = wp_parse_args($args, $defaults); $args['number'] = absint($args['number']); $args['offset'] = absint($args['offset']); // Save queries by not crawling the tree in the case of multiple taxes or a flat tax. $has_hierarchical_tax = false; foreach ($taxonomies as $_tax) { if (is_taxonomy_hierarchical($_tax)) { $has_hierarchical_tax = true; } } if (!$has_hierarchical_tax) { $args['hierarchical'] = false; $args['pad_counts'] = false; } // 'parent' overrides 'child_of'. if (0 < intval($args['parent'])) { $args['child_of'] = false; } if ('all' == $args['get']) { $args['childless'] = false; $args['child_of'] = 0; $args['hide_empty'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } /** * Filter the terms query arguments. * * @since 3.1.0 * * @param array $args An array of get_term() arguments. * @param array $taxonomies An array of taxonomies. */ $args = apply_filters('get_terms_args', $args, $taxonomies); // Avoid the query if the queried parent/child_of term has no descendants. $child_of = $args['child_of']; $parent = $args['parent']; if ($child_of) { $_parent = $child_of; } elseif ($parent) { $_parent = $parent; } else { $_parent = false; } if ($_parent) { $in_hierarchy = false; foreach ($taxonomies as $_tax) { $hierarchy = _get_term_hierarchy($_tax); if (isset($hierarchy[$_parent])) { $in_hierarchy = true; } } if (!$in_hierarchy) { return $empty_array; } } $_orderby = strtolower($args['orderby']); if ('count' == $_orderby) { $orderby = 'tt.count'; } elseif ('name' == $_orderby) { $orderby = 't.name'; } elseif ('slug' == $_orderby) { $orderby = 't.slug'; } elseif ('include' == $_orderby && !empty($args['include'])) { $include = implode(',', array_map('absint', $args['include'])); $orderby = "FIELD( t.term_id, {$include} )"; } elseif ('term_group' == $_orderby) { $orderby = 't.term_group'; } elseif ('description' == $_orderby) { $orderby = 'tt.description'; } elseif ('none' == $_orderby) { $orderby = ''; } elseif (empty($_orderby) || 'id' == $_orderby || 'term_id' === $_orderby) { $orderby = 't.term_id'; } else { $orderby = 't.name'; } /** * Filter the ORDERBY clause of the terms query. * * @since 2.8.0 * * @param string $orderby `ORDERBY` clause of the terms query. * @param array $args An array of terms query arguments. * @param array $taxonomies An array of taxonomies. */ $orderby = apply_filters('get_terms_orderby', $orderby, $args, $taxonomies); $order = strtoupper($args['order']); if (!empty($orderby)) { $orderby = "ORDER BY {$orderby}"; } else { $order = ''; } if ('' !== $order && !in_array($order, array('ASC', 'DESC'))) { $order = 'ASC'; } $where = "tt.taxonomy IN ('" . implode("', '", $taxonomies) . "')"; $exclude = $args['exclude']; $exclude_tree = $args['exclude_tree']; $include = $args['include']; $inclusions = ''; if (!empty($include)) { $exclude = ''; $exclude_tree = ''; $inclusions = implode(',', wp_parse_id_list($include)); } if (!empty($inclusions)) { $inclusions = ' AND t.term_id IN ( ' . $inclusions . ' )'; $where .= $inclusions; } $exclusions = array(); if (!empty($exclude_tree)) { $exclude_tree = wp_parse_id_list($exclude_tree); $excluded_children = $exclude_tree; foreach ($exclude_tree as $extrunk) { $excluded_children = array_merge($excluded_children, (array) get_terms($taxonomies[0], array('child_of' => intval($extrunk), 'fields' => 'ids', 'hide_empty' => 0))); } $exclusions = array_merge($excluded_children, $exclusions); } if (!empty($exclude)) { $exclusions = array_merge(wp_parse_id_list($exclude), $exclusions); } // 'childless' terms are those without an entry in the flattened term hierarchy. $childless = (bool) $args['childless']; if ($childless) { foreach ($taxonomies as $_tax) { $term_hierarchy = _get_term_hierarchy($_tax); $exclusions = array_merge(array_keys($term_hierarchy), $exclusions); } } if (!empty($exclusions)) { $exclusions = ' AND t.term_id NOT IN (' . implode(',', array_map('intval', $exclusions)) . ')'; } else { $exclusions = ''; } /** * Filter the terms to exclude from the terms query. * * @since 2.3.0 * * @param string $exclusions `NOT IN` clause of the terms query. * @param array $args An array of terms query arguments. * @param array $taxonomies An array of taxonomies. */ $exclusions = apply_filters('list_terms_exclusions', $exclusions, $args, $taxonomies); if (!empty($exclusions)) { $where .= $exclusions; } if (!empty($args['name'])) { $names = (array) $args['name']; foreach ($names as &$_name) { $_name = sanitize_term_field('name', $_name, 0, reset($taxonomies), 'db'); } $where .= " AND t.name IN ('" . implode("', '", array_map('esc_sql', $names)) . "')"; } if (!empty($args['slug'])) { if (is_array($args['slug'])) { $slug = array_map('sanitize_title', $args['slug']); $where .= " AND t.slug IN ('" . implode("', '", $slug) . "')"; } else { $slug = sanitize_title($args['slug']); $where .= " AND t.slug = '{$slug}'"; } } if (!empty($args['name__like'])) { $where .= $wpdb->prepare(" AND t.name LIKE %s", '%' . $wpdb->esc_like($args['name__like']) . '%'); } if (!empty($args['description__like'])) { $where .= $wpdb->prepare(" AND tt.description LIKE %s", '%' . $wpdb->esc_like($args['description__like']) . '%'); } if ('' !== $parent) { $parent = (int) $parent; $where .= " AND tt.parent = '{$parent}'"; } $hierarchical = $args['hierarchical']; if ('count' == $args['fields']) { $hierarchical = false; } if ($args['hide_empty'] && !$hierarchical) { $where .= ' AND tt.count > 0'; } $number = $args['number']; $offset = $args['offset']; // Don't limit the query results when we have to descend the family tree. if ($number && !$hierarchical && !$child_of && '' === $parent) { if ($offset) { $limits = 'LIMIT ' . $offset . ',' . $number; } else { $limits = 'LIMIT ' . $number; } } else { $limits = ''; } if (!empty($args['search'])) { $like = '%' . $wpdb->esc_like($args['search']) . '%'; $where .= $wpdb->prepare(' AND ((t.name LIKE %s) OR (t.slug LIKE %s))', $like, $like); } // Meta query support. $join = ''; if (!empty($args['meta_query'])) { $mquery = new WP_Meta_Query($args['meta_query']); $mq_sql = $mquery->get_sql('term', 't', 'term_id'); $join .= $mq_sql['join']; $where .= $mq_sql['where']; } $selects = array(); switch ($args['fields']) { case 'all': $selects = array('t.*', 'tt.*'); break; case 'ids': case 'id=>parent': $selects = array('t.term_id', 'tt.parent', 'tt.count', 'tt.taxonomy'); break; case 'names': $selects = array('t.term_id', 'tt.parent', 'tt.count', 't.name', 'tt.taxonomy'); break; case 'count': $orderby = ''; $order = ''; $selects = array('COUNT(*)'); break; case 'id=>name': $selects = array('t.term_id', 't.name', 'tt.count', 'tt.taxonomy'); break; case 'id=>slug': $selects = array('t.term_id', 't.slug', 'tt.count', 'tt.taxonomy'); break; } $_fields = $args['fields']; /** * Filter the fields to select in the terms query. * * Field lists modified using this filter will only modify the term fields returned * by the function when the `$fields` parameter set to 'count' or 'all'. In all other * cases, the term fields in the results array will be determined by the `$fields` * parameter alone. * * Use of this filter can result in unpredictable behavior, and is not recommended. * * @since 2.8.0 * * @param array $selects An array of fields to select for the terms query. * @param array $args An array of term query arguments. * @param array $taxonomies An array of taxonomies. */ $fields = implode(', ', apply_filters('get_terms_fields', $selects, $args, $taxonomies)); $join .= " INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id"; $pieces = array('fields', 'join', 'where', 'orderby', 'order', 'limits'); /** * Filter the terms query SQL clauses. * * @since 3.1.0 * * @param array $pieces Terms query SQL clauses. * @param array $taxonomies An array of taxonomies. * @param array $args An array of terms query arguments. */ $clauses = apply_filters('terms_clauses', compact($pieces), $taxonomies, $args); $fields = isset($clauses['fields']) ? $clauses['fields'] : ''; $join = isset($clauses['join']) ? $clauses['join'] : ''; $where = isset($clauses['where']) ? $clauses['where'] : ''; $orderby = isset($clauses['orderby']) ? $clauses['orderby'] : ''; $order = isset($clauses['order']) ? $clauses['order'] : ''; $limits = isset($clauses['limits']) ? $clauses['limits'] : ''; $query = "SELECT {$fields} FROM {$wpdb->terms} AS t {$join} WHERE {$where} {$orderby} {$order} {$limits}"; // $args can be anything. Only use the args defined in defaults to compute the key. $key = md5(serialize(wp_array_slice_assoc($args, array_keys($defaults))) . serialize($taxonomies) . $query); $last_changed = wp_cache_get('last_changed', 'terms'); if (!$last_changed) { $last_changed = microtime(); wp_cache_set('last_changed', $last_changed, 'terms'); } $cache_key = "get_terms:{$key}:{$last_changed}"; $cache = wp_cache_get($cache_key, 'terms'); if (false !== $cache) { if ('all' === $_fields) { $cache = array_map('get_term', $cache); } /** * Filter the given taxonomy's terms cache. * * @since 2.3.0 * * @param array $cache Cached array of terms for the given taxonomy. * @param array $taxonomies An array of taxonomies. * @param array $args An array of get_terms() arguments. */ return apply_filters('get_terms', $cache, $taxonomies, $args); } if ('count' == $_fields) { return $wpdb->get_var($query); } $terms = $wpdb->get_results($query); if ('all' == $_fields) { update_term_cache($terms); } // Prime termmeta cache. if ($args['update_term_meta_cache']) { $term_ids = wp_list_pluck($terms, 'term_id'); update_termmeta_cache($term_ids); } if (empty($terms)) { wp_cache_add($cache_key, array(), 'terms', DAY_IN_SECONDS); /** This filter is documented in wp-includes/taxonomy-functions.php */ return apply_filters('get_terms', array(), $taxonomies, $args); } if ($child_of) { foreach ($taxonomies as $_tax) { $children = _get_term_hierarchy($_tax); if (!empty($children)) { $terms = _get_term_children($child_of, $terms, $_tax); } } } // Update term counts to include children. if ($args['pad_counts'] && 'all' == $_fields) { foreach ($taxonomies as $_tax) { _pad_term_counts($terms, $_tax); } } // Make sure we show empty categories that have children. if ($hierarchical && $args['hide_empty'] && is_array($terms)) { foreach ($terms as $k => $term) { if (!$term->count) { $children = get_term_children($term->term_id, $term->taxonomy); if (is_array($children)) { foreach ($children as $child_id) { $child = get_term($child_id, $term->taxonomy); if ($child->count) { continue 2; } } } // It really is empty. unset($terms[$k]); } } } $_terms = array(); if ('id=>parent' == $_fields) { foreach ($terms as $term) { $_terms[$term->term_id] = $term->parent; } } elseif ('ids' == $_fields) { foreach ($terms as $term) { $_terms[] = $term->term_id; } } elseif ('names' == $_fields) { foreach ($terms as $term) { $_terms[] = $term->name; } } elseif ('id=>name' == $_fields) { foreach ($terms as $term) { $_terms[$term->term_id] = $term->name; } } elseif ('id=>slug' == $_fields) { foreach ($terms as $term) { $_terms[$term->term_id] = $term->slug; } } if (!empty($_terms)) { $terms = $_terms; } if ($number && is_array($terms) && count($terms) > $number) { $terms = array_slice($terms, $offset, $number); } wp_cache_add($cache_key, $terms, 'terms', DAY_IN_SECONDS); if ('all' === $_fields) { $terms = array_map('get_term', $terms); } /** This filter is documented in wp-includes/taxonomy */ return apply_filters('get_terms', $terms, $taxonomies, $args); }
/** * Extended get_terms public static function support * - Limit category * - Limit days * - Selection restrict * - Min usage * * @param string|array $taxonomies * @param string $args * @return array */ public static function getTerms($taxonomies, $args = '') { global $wpdb; $empty_array = array(); $join_relation = false; $single_taxonomy = false; if (!is_array($taxonomies)) { $single_taxonomy = true; $taxonomies = array($taxonomies); } foreach ((array) $taxonomies as $taxonomy) { if (!taxonomy_exists($taxonomy)) { $error = new WP_Error('invalid_taxonomy', __('Invalid Taxonomy')); return $error; } } $in_taxonomies = "'" . implode("', '", $taxonomies) . "'"; $defaults = array('orderby' => 'name', 'order' => 'ASC', 'hide_empty' => true, 'exclude' => array(), 'exclude_tree' => array(), 'include' => array(), 'number' => '', 'fields' => 'all', 'slug' => '', 'parent' => '', 'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'pad_counts' => false, 'offset' => '', 'search' => '', 'limit_days' => 0, 'category' => 0, 'min_usage' => 0, 'st_name__like' => ''); $args = wp_parse_args($args, $defaults); // Translate selection order $args['orderby'] = self::compatOldOrder($args['selectionby'], 'orderby'); $args['order'] = self::compatOldOrder($args['selection'], 'order'); $args['number'] = absint($args['number']); $args['offset'] = absint($args['offset']); $args['limit_days'] = absint($args['limit_days']); $args['min_usage'] = absint($args['min_usage']); if (!$single_taxonomy || !is_taxonomy_hierarchical($taxonomies[0]) || '' !== $args['parent']) { $args['child_of'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } if ('all' == $args['get']) { $args['child_of'] = 0; $args['hide_empty'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } extract($args, EXTR_SKIP); if ($child_of) { $hierarchy = _get_term_hierarchy($taxonomies[0]); if (!isset($hierarchy[$child_of])) { return $empty_array; } } if ($parent) { $hierarchy = _get_term_hierarchy($taxonomies[0]); if (!isset($hierarchy[$parent])) { return $empty_array; } } // $args can be whatever, only use the args defined in defaults to compute the key $filter_key = has_filter('list_terms_exclusions') ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : ''; $key = md5(serialize(compact(array_keys($defaults))) . serialize($taxonomies) . $filter_key); $last_changed = wp_cache_get('last_changed', 's-terms'); if (!$last_changed) { $last_changed = time(); wp_cache_set('last_changed', $last_changed, 's-terms'); } $cache_key = "get_terms:{$key}:{$last_changed}"; $cache = wp_cache_get($cache_key, 's-terms'); if (false !== $cache) { $cache = apply_filters('get_terms', $cache, $taxonomies, $args); return $cache; } $_orderby = strtolower($orderby); if ('count' == $_orderby) { $orderby = 'tt.count'; } if ('random' == $_orderby) { $orderby = 'RAND()'; } else { if ('name' == $_orderby) { $orderby = 't.name'; } else { if ('slug' == $_orderby) { $orderby = 't.slug'; } else { if ('term_group' == $_orderby) { $orderby = 't.term_group'; } elseif (empty($_orderby) || 'id' == $_orderby) { $orderby = 't.term_id'; } } } } $orderby = apply_filters('get_terms_orderby', $orderby, $args); if (!empty($orderby)) { $orderby = "ORDER BY {$orderby}"; } else { $order = ''; } $where = ''; $inclusions = ''; if (!empty($include)) { $exclude = ''; $exclude_tree = ''; $interms = wp_parse_id_list($include); foreach ($interms as $interm) { if (empty($inclusions)) { $inclusions = ' AND ( t.term_id = ' . intval($interm) . ' '; } else { $inclusions .= ' OR t.term_id = ' . intval($interm) . ' '; } } } if (!empty($inclusions)) { $inclusions .= ')'; } $where .= $inclusions; $exclusions = ''; if (!empty($exclude_tree)) { $excluded_trunks = wp_parse_id_list($exclude_tree); foreach ($excluded_trunks as $extrunk) { $excluded_children = (array) get_terms($taxonomies[0], array('child_of' => intval($extrunk), 'fields' => 'ids')); $excluded_children[] = $extrunk; foreach ($excluded_children as $exterm) { if (empty($exclusions)) { $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' '; } else { $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' '; } } } } if (!empty($exclude)) { $exterms = wp_parse_id_list($exclude); foreach ($exterms as $exterm) { if (empty($exclusions)) { $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' '; } else { $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' '; } } } if (!empty($exclusions)) { $exclusions .= ')'; } $exclusions = apply_filters('list_terms_exclusions', $exclusions, $args); $where .= $exclusions; // ST Features : Restrict category if ($category != 0) { if (!is_array($taxonomies)) { $taxonomies = array($taxonomies); } $incategories = wp_parse_id_list($category); $taxonomies = "'" . implode("', '", $taxonomies) . "'"; $incategories = "'" . implode("', '", $incategories) . "'"; $where .= " AND tr.object_id IN ( "; $where .= "SELECT tr.object_id FROM {$wpdb->term_relationships} AS tr INNER JOIN {$wpdb->term_taxonomy} AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id INNER JOIN {$wpdb->posts} as p ON tr.object_id=p.ID WHERE tt.term_id IN ({$incategories}) AND p.post_status='publish'"; $where .= " ) "; $join_relation = true; unset($incategories, $category); } // ST Features : Limit posts date if ($limit_days != 0) { $where .= " AND tr.object_id IN ( "; $where .= "SELECT DISTINCT ID FROM {$wpdb->posts} AS p WHERE p.post_status='publish' AND " . (is_page_have_tags() ? "p.post_type IN('page', 'post')" : "post_type = 'post'") . " AND p.post_date_gmt > '" . date('Y-m-d H:i:s', time() - $limit_days * 86400) . "'"; $where .= " ) "; $join_relation = true; unset($limit_days); } if (!empty($slug)) { $slug = sanitize_title($slug); $where .= " AND t.slug = '{$slug}'"; } if (!empty($name__like)) { $where .= " AND t.name LIKE '{$name__like}%'"; } if ('' !== $parent) { $parent = (int) $parent; $where .= " AND tt.parent = '{$parent}'"; } // ST Features : Another way to search if (strpos($st_name__like, ' ') !== false) { $st_terms_formatted = array(); $st_terms = preg_split('/[\\s,]+/', $st_name_like); foreach ((array) $st_terms as $st_term) { if (empty($st_term)) { continue; } $st_terms_formatted[] = "t.name LIKE '%" . like_escape($st_term) . "%'"; } $where .= " AND ( " . explode(' OR ', $st_terms_formatted) . " ) "; unset($st_term, $st_terms_formatted, $st_terms); } elseif (!empty($st_name__like)) { $where .= " AND t.name LIKE '%{$st_name__like}%'"; } // ST Features : Add min usage if ($hide_empty && !$hierarchical) { if ($min_usage == 0) { $where .= ' AND tt.count > 0'; } else { $where .= $wpdb->prepare(' AND tt.count >= %d', $min_usage); } } // don't limit the query results when we have to descend the family tree if (!empty($number) && !$hierarchical && empty($child_of) && '' === $parent) { if ($offset) { $limit = 'LIMIT ' . $offset . ',' . $number; } else { $limit = 'LIMIT ' . $number; } } else { $limit = ''; } if (!empty($search)) { $search = like_escape($search); $where .= " AND (t.name LIKE '%{$search}%')"; } $selects = array(); switch ($fields) { case 'all': $selects = array('t.*', 'tt.*'); break; case 'ids': case 'id=>parent': $selects = array('t.term_id', 'tt.parent', 'tt.count'); break; case 'names': $selects = array('t.term_id', 'tt.parent', 'tt.count', 't.name'); break; case 'count': $orderby = ''; $order = ''; $selects = array('COUNT(*)'); } $select_this = implode(', ', apply_filters('get_terms_fields', $selects, $args)); // Add inner to relation table ? $join_relation = $join_relation == false ? '' : "INNER JOIN {$wpdb->term_relationships} AS tr ON tt.term_taxonomy_id = tr.term_taxonomy_id"; $query = "SELECT {$select_this}\r\n\t\t\tFROM {$wpdb->terms} AS t\r\n\t\t\tINNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id\r\n\t\t\t{$join_relation}\r\n\t\t\tWHERE tt.taxonomy IN ({$in_taxonomies})\r\n\t\t\t{$where}\r\n\t\t\t{$orderby} {$order}\r\n\t\t\t{$limit}"; // GROUP BY t.term_id if ('count' == $fields) { $term_count = $wpdb->get_var($query); return $term_count; } $terms = $wpdb->get_results($query); if ('all' == $fields) { update_term_cache($terms); } if (empty($terms)) { wp_cache_add($cache_key, array(), 's-terms'); $terms = apply_filters('get_terms', array(), $taxonomies, $args); return $terms; } if ($child_of) { $children = _get_term_hierarchy($taxonomies[0]); if (!empty($children)) { $terms =& _get_term_children($child_of, $terms, $taxonomies[0]); } } // Update term counts to include children. if ($pad_counts && 'all' == $fields) { _pad_term_counts($terms, $taxonomies[0]); } // Make sure we show empty categories that have children. if ($hierarchical && $hide_empty && is_array($terms)) { foreach ($terms as $k => $term) { if (!$term->count) { $children = _get_term_children($term->term_id, $terms, $taxonomies[0]); if (is_array($children)) { foreach ($children as $child) { if ($child->count) { continue 2; } } } // It really is empty unset($terms[$k]); } } } reset($terms); $_terms = array(); if ('id=>parent' == $fields) { while ($term = array_shift($terms)) { $_terms[$term->term_id] = $term->parent; } $terms = $_terms; } elseif ('ids' == $fields) { while ($term = array_shift($terms)) { $_terms[] = $term->term_id; } $terms = $_terms; } elseif ('names' == $fields) { while ($term = array_shift($terms)) { $_terms[] = $term->name; } $terms = $_terms; } if (0 < $number && intval(@count($terms)) > $number) { $terms = array_slice($terms, $offset, $number); } wp_cache_add($cache_key, $terms, 's-terms'); $terms = apply_filters('get_terms', $terms, $taxonomies, $args); return $terms; }
/** * get_terms() - Retrieve the terms in taxonomy or list of taxonomies. * * You can fully inject any customizations to the query before it is sent, as well as control * the output with a filter. * * The 'get_terms' filter will be called when the cache has the term and will pass the found * term along with the array of $taxonomies and array of $args. This filter is also called * before the array of terms is passed and will pass the array of terms, along with the $taxonomies * and $args. * * The 'list_terms_exclusions' filter passes the compiled exclusions along with the $args. * * The list that $args can contain, which will overwrite the defaults. * orderby - Default is 'name'. Can be name, count, or nothing (will use term_id). * order - Default is ASC. Can use DESC. * hide_empty - Default is true. Will not return empty $terms. * fields - Default is all. * slug - Any terms that has this value. Default is empty string. * hierarchical - Whether to return hierarchical taxonomy. Default is true. * name__like - Default is empty string. * * The argument 'pad_counts' will count all of the children along with the $terms. * * The 'get' argument allows for overwriting 'hide_empty' and 'child_of', which can be done by * setting the value to 'all', instead of its default empty string value. * * The 'child_of' argument will be used if you use multiple taxonomy or the first $taxonomy * isn't hierarchical or 'parent' isn't used. The default is 0, which will be translated to * a false value. If 'child_of' is set, then 'child_of' value will be tested against * $taxonomy to see if 'child_of' is contained within. Will return an empty array if test * fails. * * If 'parent' is set, then it will be used to test against the first taxonomy. Much like * 'child_of'. Will return an empty array if the test fails. * * @package WordPress * @subpackage Taxonomy * @since 2.3 * * @uses $wpdb * @uses wp_parse_args() Merges the defaults with those defined by $args and allows for strings. * * * @param string|array Taxonomy name or list of Taxonomy names * @param string|array $args The values of what to search for when returning terms * @return array|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies do not exist. */ function &get_terms($taxonomies, $args = '') { global $wpdb; $empty_array = array(); $single_taxonomy = false; if ( !is_array($taxonomies) ) { $single_taxonomy = true; $taxonomies = array($taxonomies); } foreach ( $taxonomies as $taxonomy ) { if ( ! is_taxonomy($taxonomy) ) return new WP_Error('invalid_taxonomy', __('Invalid Taxonomy')); } $in_taxonomies = "'" . implode("', '", $taxonomies) . "'"; $defaults = array('orderby' => 'name', 'order' => 'ASC', 'hide_empty' => true, 'exclude' => '', 'include' => '', 'number' => '', 'fields' => 'all', 'slug' => '', 'parent' => '', 'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'pad_counts' => false, 'offset' => '', 'search' => ''); $args = wp_parse_args( $args, $defaults ); $args['number'] = absint( $args['number'] ); $args['offset'] = absint( $args['offset'] ); if ( !$single_taxonomy || !is_taxonomy_hierarchical($taxonomies[0]) || '' != $args['parent'] ) { $args['child_of'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } if ( 'all' == $args['get'] ) { $args['child_of'] = 0; $args['hide_empty'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } extract($args, EXTR_SKIP); if ( $child_of ) { $hierarchy = _get_term_hierarchy($taxonomies[0]); if ( !isset($hierarchy[$child_of]) ) return $empty_array; } if ( $parent ) { $hierarchy = _get_term_hierarchy($taxonomies[0]); if ( !isset($hierarchy[$parent]) ) return $empty_array; } $key = md5( serialize( $args ) . serialize( $taxonomies ) ); if ( $cache = wp_cache_get( 'get_terms', 'terms' ) ) { if ( isset( $cache[ $key ] ) ) return apply_filters('get_terms', $cache[$key], $taxonomies, $args); } if ( 'count' == $orderby ) $orderby = 'tt.count'; else if ( 'name' == $orderby ) $orderby = 't.name'; else if ( 'slug' == $orderby ) $orderby = 't.slug'; else if ( 'term_group' == $orderby ) $orderby = 't.term_group'; else $orderby = 't.term_id'; $where = ''; $inclusions = ''; if ( !empty($include) ) { $exclude = ''; $interms = preg_split('/[\s,]+/',$include); if ( count($interms) ) { foreach ( $interms as $interm ) { if (empty($inclusions)) $inclusions = ' AND ( t.term_id = ' . intval($interm) . ' '; else $inclusions .= ' OR t.term_id = ' . intval($interm) . ' '; } } } if ( !empty($inclusions) ) $inclusions .= ')'; $where .= $inclusions; $exclusions = ''; if ( !empty($exclude) ) { $exterms = preg_split('/[\s,]+/',$exclude); if ( count($exterms) ) { foreach ( $exterms as $exterm ) { if (empty($exclusions)) $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' '; else $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' '; } } } if ( !empty($exclusions) ) $exclusions .= ')'; $exclusions = apply_filters('list_terms_exclusions', $exclusions, $args ); $where .= $exclusions; if ( !empty($slug) ) { $slug = sanitize_title($slug); $where .= " AND t.slug = '$slug'"; } if ( !empty($name__like) ) $where .= " AND t.name LIKE '{$name__like}%'"; if ( '' != $parent ) { $parent = (int) $parent; $where .= " AND tt.parent = '$parent'"; } if ( $hide_empty && !$hierarchical ) $where .= ' AND tt.count > 0'; if ( !empty($number) ) { if( $offset ) $number = 'LIMIT ' . $offset . ',' . $number; else $number = 'LIMIT ' . $number; } else $number = ''; if ( !empty($search) ) { $search = like_escape($search); $where .= " AND (t.name LIKE '%$search%')"; } $select_this = ''; if ( 'all' == $fields ) $select_this = 't.*, tt.*'; else if ( 'ids' == $fields ) $select_this = 't.term_id'; else if ( 'names' == $fields ) $select_this = 't.name'; $query = "SELECT $select_this FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy IN ($in_taxonomies) $where ORDER BY $orderby $order $number"; if ( 'all' == $fields ) { $terms = $wpdb->get_results($query); update_term_cache($terms); } else if ( ('ids' == $fields) || ('names' == $fields) ) { $terms = $wpdb->get_col($query); } if ( empty($terms) ) { $cache[ $key ] = array(); wp_cache_set( 'get_terms', $cache, 'terms' ); return apply_filters('get_terms', array(), $taxonomies, $args); } if ( $child_of || $hierarchical ) { $children = _get_term_hierarchy($taxonomies[0]); if ( ! empty($children) ) $terms = & _get_term_children($child_of, $terms, $taxonomies[0]); } // Update term counts to include children. if ( $pad_counts ) _pad_term_counts($terms, $taxonomies[0]); // Make sure we show empty categories that have children. if ( $hierarchical && $hide_empty ) { foreach ( $terms as $k => $term ) { if ( ! $term->count ) { $children = _get_term_children($term->term_id, $terms, $taxonomies[0]); foreach ( $children as $child ) if ( $child->count ) continue 2; // It really is empty unset($terms[$k]); } } } reset ( $terms ); $cache[ $key ] = $terms; wp_cache_set( 'get_terms', $cache, 'terms' ); $terms = apply_filters('get_terms', $terms, $taxonomies, $args); return $terms; }
/** * Retrieve the terms in a given taxonomy or list of taxonomies. * * You can fully inject any customizations to the query before it is sent, as * well as control the output with a filter. * * The 'get_terms' filter will be called when the cache has the term and will * pass the found term along with the array of $taxonomies and array of $args. * This filter is also called before the array of terms is passed and will pass * the array of terms, along with the $taxonomies and $args. * * The 'list_terms_exclusions' filter passes the compiled exclusions along with * the $args. * * The 'get_terms_orderby' filter passes the ORDER BY clause for the query * along with the $args array. * The 'get_terms_fields' filter passes the fields for the SELECT query * along with the $args array. * * The list of arguments that $args can contain, which will overwrite the defaults: * * orderby - Default is 'name'. Can be name, count, term_group, slug or nothing * (will use term_id), Passing a custom value other than these will cause it to * order based on the custom value. * * order - Default is ASC. Can use DESC. * * hide_empty - Default is true. Will not return empty terms, which means * terms whose count is 0 according to the given taxonomy. * * exclude - Default is an empty string. A comma- or space-delimited string * of term ids to exclude from the return array. If 'include' is non-empty, * 'exclude' is ignored. * * exclude_tree - A comma- or space-delimited string of term ids to exclude * from the return array, along with all of their descendant terms according to * the primary taxonomy. If 'include' is non-empty, 'exclude_tree' is ignored. * * include - Default is an empty string. A comma- or space-delimited string * of term ids to include in the return array. * * number - The maximum number of terms to return. Default is empty. * * offset - The number by which to offset the terms query. * * fields - Default is 'all', which returns an array of term objects. * If 'fields' is 'ids' or 'names', returns an array of * integers or strings, respectively. * * slug - Returns terms whose "slug" matches this value. Default is empty string. * * hierarchical - Whether to include terms that have non-empty descendants * (even if 'hide_empty' is set to true). * * search - Returned terms' names will contain the value of 'search', * case-insensitive. Default is an empty string. * * name__like - Returned terms' names will begin with the value of 'name__like', * case-insensitive. Default is empty string. * * The argument 'pad_counts', if set to true will include the quantity of a term's * children in the quantity of each term's "count" object variable. * * The 'get' argument, if set to 'all' instead of its default empty string, * returns terms regardless of ancestry or whether the terms are empty. * * The 'child_of' argument, when used, should be set to the integer of a term ID. Its default * is 0. If set to a non-zero value, all returned terms will be descendants * of that term according to the given taxonomy. Hence 'child_of' is set to 0 * if more than one taxonomy is passed in $taxonomies, because multiple taxonomies * make term ancestry ambiguous. * * The 'parent' argument, when used, should be set to the integer of a term ID. Its default is * the empty string '', which has a different meaning from the integer 0. * If set to an integer value, all returned terms will have as an immediate * ancestor the term whose ID is specified by that integer according to the given taxonomy. * The 'parent' argument is different from 'child_of' in that a term X is considered a 'parent' * of term Y only if term X is the father of term Y, not its grandfather or great-grandfather, etc. * * @package WordPress * @subpackage Taxonomy * @since 2.3.0 * * @uses $wpdb * @uses wp_parse_args() Merges the defaults with those defined by $args and allows for strings. * * @param string|array Taxonomy name or list of Taxonomy names * @param string|array $args The values of what to search for when returning terms * @return array|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies do not exist. */ function &get_terms($taxonomies, $args = '') { global $wpdb; $empty_array = array(); $single_taxonomy = false; if (!is_array($taxonomies)) { $single_taxonomy = true; $taxonomies = array($taxonomies); } foreach ((array) $taxonomies as $taxonomy) { if (!is_taxonomy($taxonomy)) { $error =& new WP_Error('invalid_taxonomy', __('Invalid Taxonomy')); return $error; } } $in_taxonomies = "'" . implode("', '", $taxonomies) . "'"; $defaults = array('orderby' => 'name', 'order' => 'ASC', 'hide_empty' => true, 'exclude' => '', 'exclude_tree' => '', 'include' => '', 'number' => '', 'fields' => 'all', 'slug' => '', 'parent' => '', 'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'pad_counts' => false, 'offset' => '', 'search' => ''); $args = wp_parse_args($args, $defaults); $args['number'] = absint($args['number']); $args['offset'] = absint($args['offset']); if (!$single_taxonomy || !is_taxonomy_hierarchical($taxonomies[0]) || '' !== $args['parent']) { $args['child_of'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } if ('all' == $args['get']) { $args['child_of'] = 0; $args['hide_empty'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } extract($args, EXTR_SKIP); if ($child_of) { $hierarchy = _get_term_hierarchy($taxonomies[0]); if (!isset($hierarchy[$child_of])) { return $empty_array; } } if ($parent) { $hierarchy = _get_term_hierarchy($taxonomies[0]); if (!isset($hierarchy[$parent])) { return $empty_array; } } // $args can be whatever, only use the args defined in defaults to compute the key $filter_key = has_filter('list_terms_exclusions') ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : ''; $key = md5(serialize(compact(array_keys($defaults))) . serialize($taxonomies) . $filter_key); $last_changed = wp_cache_get('last_changed', 'terms'); if (!$last_changed) { $last_changed = time(); wp_cache_set('last_changed', $last_changed, 'terms'); } $cache_key = "get_terms:{$key}:{$last_changed}"; $cache = wp_cache_get($cache_key, 'terms'); if (false !== $cache) { $cache = apply_filters('get_terms', $cache, $taxonomies, $args); return $cache; } $_orderby = strtolower($orderby); if ('count' == $_orderby) { $orderby = 'tt.count'; } else { if ('name' == $_orderby) { $orderby = 't.name'; } else { if ('slug' == $_orderby) { $orderby = 't.slug'; } else { if ('term_group' == $_orderby) { $orderby = 't.term_group'; } elseif (empty($_orderby) || 'id' == $_orderby) { $orderby = 't.term_id'; } } } } $orderby = apply_filters('get_terms_orderby', $orderby, $args); $where = ''; $inclusions = ''; if (!empty($include)) { $exclude = ''; $exclude_tree = ''; $interms = preg_split('/[\\s,]+/', $include); if (count($interms)) { foreach ((array) $interms as $interm) { if (empty($inclusions)) { $inclusions = ' AND ( t.term_id = ' . intval($interm) . ' '; } else { $inclusions .= ' OR t.term_id = ' . intval($interm) . ' '; } } } } if (!empty($inclusions)) { $inclusions .= ')'; } $where .= $inclusions; $exclusions = ''; if (!empty($exclude_tree)) { $excluded_trunks = preg_split('/[\\s,]+/', $exclude_tree); foreach ((array) $excluded_trunks as $extrunk) { $excluded_children = (array) get_terms($taxonomies[0], array('child_of' => intval($extrunk), 'fields' => 'ids')); $excluded_children[] = $extrunk; foreach ((array) $excluded_children as $exterm) { if (empty($exclusions)) { $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' '; } else { $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' '; } } } } if (!empty($exclude)) { $exterms = preg_split('/[\\s,]+/', $exclude); if (count($exterms)) { foreach ((array) $exterms as $exterm) { if (empty($exclusions)) { $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' '; } else { $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' '; } } } } if (!empty($exclusions)) { $exclusions .= ')'; } $exclusions = apply_filters('list_terms_exclusions', $exclusions, $args); $where .= $exclusions; if (!empty($slug)) { $slug = sanitize_title($slug); $where .= " AND t.slug = '{$slug}'"; } if (!empty($name__like)) { $where .= " AND t.name LIKE '{$name__like}%'"; } if ('' !== $parent) { $parent = (int) $parent; $where .= " AND tt.parent = '{$parent}'"; } if ($hide_empty && !$hierarchical) { $where .= ' AND tt.count > 0'; } // don't limit the query results when we have to descend the family tree if (!empty($number) && !$hierarchical && empty($child_of) && '' === $parent) { if ($offset) { $limit = 'LIMIT ' . $offset . ',' . $number; } else { $limit = 'LIMIT ' . $number; } } else { $limit = ''; } if (!empty($search)) { $search = like_escape($search); $where .= " AND (t.name LIKE '%{$search}%')"; } $selects = array(); if ('all' == $fields) { $selects = array('t.*', 'tt.*'); } else { if ('ids' == $fields) { $selects = array('t.term_id', 'tt.parent', 'tt.count'); } else { if ('names' == $fields) { $selects = array('t.term_id', 'tt.parent', 'tt.count', 't.name'); } } } $select_this = implode(', ', apply_filters('get_terms_fields', $selects, $args)); $query = "SELECT {$select_this} FROM {$wpdb->terms} AS t INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy IN ({$in_taxonomies}) {$where} ORDER BY {$orderby} {$order} {$limit}"; $terms = $wpdb->get_results($query); if ('all' == $fields) { update_term_cache($terms); } if (empty($terms)) { wp_cache_add($cache_key, array(), 'terms'); $terms = apply_filters('get_terms', array(), $taxonomies, $args); return $terms; } if ($child_of) { $children = _get_term_hierarchy($taxonomies[0]); if (!empty($children)) { $terms =& _get_term_children($child_of, $terms, $taxonomies[0]); } } // Update term counts to include children. if ($pad_counts && 'all' == $fields) { _pad_term_counts($terms, $taxonomies[0]); } // Make sure we show empty categories that have children. if ($hierarchical && $hide_empty && is_array($terms)) { foreach ($terms as $k => $term) { if (!$term->count) { $children = _get_term_children($term->term_id, $terms, $taxonomies[0]); if (is_array($children)) { foreach ($children as $child) { if ($child->count) { continue 2; } } } // It really is empty unset($terms[$k]); } } } reset($terms); $_terms = array(); if ('ids' == $fields) { while ($term = array_shift($terms)) { $_terms[] = $term->term_id; } $terms = $_terms; } elseif ('names' == $fields) { while ($term = array_shift($terms)) { $_terms[] = $term->name; } $terms = $_terms; } if (0 < $number && intval(@count($terms)) > $number) { $terms = array_slice($terms, $offset, $number); } wp_cache_add($cache_key, $terms, 'terms'); $terms = apply_filters('get_terms', $terms, $taxonomies, $args); return $terms; }
/** * Extended get_terms function support * - Limit category * - Limit days * - Selection restrict * - Min usage * * @param string|array $taxonomies * @param string $args * @return array */ function getTerms( $taxonomies, $args = '', $skip_cache = false, $internal_st = false ) { global $wpdb; $empty_array = array(); $single_taxonomy = false; if ( !is_array($taxonomies) ) { $single_taxonomy = true; $taxonomies = array($taxonomies); } foreach ( $taxonomies as $taxonomy ) { if ( ! is_taxonomy($taxonomy) ) { return new WP_Error('invalid_taxonomy', __('Invalid Taxonomy')); } } $in_taxonomies = "'" . implode("', '", $taxonomies) . "'"; $defaults = array( 'orderby' => 'name', 'order' => 'ASC', 'cloud_selection' => 'count-desc', 'hide_empty' => true, 'exclude' => '', 'include' => '', 'number' => '', 'fields' => 'all', 'slug' => '', 'parent' => '', 'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'st_name_like' => '', 'pad_counts' => false, 'offset' => '', 'search' => '', 'limit_days' => 0, 'category' => 0, 'min_usage' => 0 ); $args = wp_parse_args( $args, $defaults ); if ( $internal_st != true ) { // Allow limit :) $args['number'] = absint( $args['number'] ); } $args['offset'] = absint( $args['offset'] ); if ( !$single_taxonomy || !is_taxonomy_hierarchical($taxonomies[0]) || '' != $args['parent'] ) { $args['child_of'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } if ( 'all' == $args['get'] ) { $args['child_of'] = 0; $args['hide_empty'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } extract($args, EXTR_SKIP); if ( $child_of ) { $hierarchy = _get_term_hierarchy($taxonomies[0]); if ( !isset($hierarchy[$child_of]) ) return $empty_array; } if ( $parent ) { $hierarchy = _get_term_hierarchy($taxonomies[0]); if ( !isset($hierarchy[$parent]) ) return $empty_array; } if ( $skip_cache != true ) { // $args can be whatever, only use the args defined in defaults to compute the key $filter_key = ( has_filter('list_terms_exclusions') ) ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : ''; $key = md5( serialize( compact(array_keys($defaults)) ) . serialize( $taxonomies ) . $filter_key ); $last_changed = wp_cache_get('last_changed', 'terms'); if ( !$last_changed ) { $last_changed = time(); wp_cache_set('last_changed', $last_changed, 'terms'); } $cache_key = "get_terms:$key:$last_changed"; if ( $cache = wp_cache_get( $cache_key, 'terms' ) ) { $terms = apply_filters('get_terms', $cache, $taxonomies, $args); return $terms; } } // Restrict category $category_sql = ''; if ( !empty($category) && $category != '0' ) { $incategories = preg_split('/[\s,]+/', $category); $objects_id = get_objects_in_term( $incategories, 'category' ); $objects_id = array_unique ($objects_id); // to be sure haven't duplicates if ( empty($objects_id) ) { // No posts for this category = no tags for this category return array(); } foreach ( (array) $objects_id as $object_id ) { $category_sql .= "'". $object_id . "', "; } $category_sql = substr($category_sql, 0, strlen($category_sql) - 2); // Remove latest ", " $category_sql = 'AND p.ID IN ('.$category_sql.')'; } // count-asc/count-desc/name-asc/name-desc/random $cloud_selection = strtolower($cloud_selection); switch ( $cloud_selection ) { case 'count-asc': $order_by = 'tt.count ASC'; break; case 'random': $order_by = 'RAND()'; break; case 'name-asc': $order_by = 't.name ASC'; break; case 'name-desc': $order_by = 't.name DESC'; break; default: // count-desc $order_by = 'tt.count DESC'; break; } // Min usage $restict_usage = ''; $min_usage = (int) $min_usage; if ( $min_usage != 0 ) { $restict_usage = ' AND tt.count >= '. $min_usage; } $where = ''; $inclusions = ''; if ( !empty($include) ) { $exclude = ''; $interms = preg_split('/[\s,]+/',$include); foreach ( (array) $interms as $interm ) { if (empty($inclusions)) { $inclusions = ' AND ( t.term_id = ' . intval($interm) . ' '; } else { $inclusions .= ' OR t.term_id = ' . intval($interm) . ' '; } } } if ( !empty($inclusions) ) { $inclusions .= ')'; } $where .= $inclusions; $exclusions = ''; if ( !empty($exclude) ) { $exterms = preg_split('/[\s,]+/',$exclude); foreach ( (array) $exterms as $exterm ) { if (empty($exclusions)) { $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' '; } else { $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' '; } } } if ( !empty($exclusions) ) { $exclusions .= ')'; } $exclusions = apply_filters('list_terms_exclusions', $exclusions, $args ); $where .= $exclusions; if ( !empty($slug) ) { $slug = sanitize_title($slug); $where .= " AND t.slug = '$slug'"; } if ( !empty($name__like) ) { $where .= " AND t.name LIKE '{$name__like}%'"; } if ( strpos($st_name_like, ' ') != false || strpos($st_name_like, ' ') != null ) { $tmp = ''; $sts = explode(' ', $st_name_like); foreach ( (array) $sts as $st ) { if ( empty($st) ) continue; $st = addslashes_gpc($st); $tmp .= " t.name LIKE '%{$st}%' OR "; } // Remove latest OR $tmp = substr( $tmp, 0, strlen($tmp) - 4); $where .= " AND ( $tmp ) "; unset($tmp) ; } elseif ( !empty($st_name_like) ) { $where .= " AND t.name LIKE '%{$st_name_like}%'"; } if ( '' != $parent ) { $parent = (int) $parent; $where .= " AND tt.parent = '$parent'"; } if ( $hide_empty && !$hierarchical ) { $where .= ' AND tt.count > 0'; } $number_sql = ''; if ( strpos($number, ',') != false || strpos($number, ',') != null ) { $number_sql = $number; } else { $number = (int) $number; if ( $number != 0 ) { $number_sql = 'LIMIT ' . $number; } } if ( !empty($search) ) { $search = like_escape($search); $where .= " AND (t.name LIKE '%$search%')"; } $select_this = ''; if ( 'all' == $fields ) { $select_this = 't.*, tt.*'; } else if ( 'ids' == $fields ) { $select_this = 't.term_id, tt.parent, tt.count'; } else if ( 'names' == $fields ) { $select_this = 't.term_id, tt.parent, tt.count, t.name'; } // Limit posts date $limitdays_sql = ''; $limit_days = (int) $limit_days; if ( $limit_days != 0 ) { $limitdays_sql = 'AND p.post_date_gmt > "' .date( 'Y-m-d H:i:s', time() - $limit_days * 86400 ). '"'; } $query = "SELECT {$select_this} FROM {$wpdb->terms} AS t INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id INNER JOIN {$wpdb->term_relationships} AS tr ON tt.term_taxonomy_id = tr.term_taxonomy_id INNER JOIN {$wpdb->posts} AS p ON tr.object_id = p.ID WHERE tt.taxonomy IN ( {$in_taxonomies} ) AND p.post_date_gmt < '".current_time('mysql')."' {$limitdays_sql} {$category_sql} {$where} {$restict_usage} GROUP BY t.term_id ORDER BY {$order_by} {$number_sql}"; if ( 'all' == $fields ) { $terms = $wpdb->get_results($query); if ( $skip_cache != true ) { update_term_cache($terms); } } else if ( ('ids' == $fields) || ('names' == $fields) ) { $terms = $wpdb->get_results($query); } if ( empty($terms) ) { $cache[ $key ] = array(); wp_cache_set( 'get_terms', $cache, 'terms' ); $terms = apply_filters('get_terms', array(), $taxonomies, $args); return $terms; } if ( $child_of ) { $children = _get_term_hierarchy($taxonomies[0]); if ( ! empty($children) ) $terms = & _get_term_children($child_of, $terms, $taxonomies[0]); } // Update term counts to include children. if ( $pad_counts && 'all' == $fields ) _pad_term_counts($terms, $taxonomies[0]); // Make sure we show empty categories that have children. if ( $hierarchical && $hide_empty && is_array($terms) ) { foreach ( $terms as $k => $term ) { if ( ! $term->count ) { $children = _get_term_children($term->term_id, $terms, $taxonomies[0]); if( is_array($children) ) foreach ( $children as $child ) if ( $child->count ) continue 2; // It really is empty unset($terms[$k]); } } } reset ( $terms ); $_terms = array(); if ( 'ids' == $fields ) { while ( $term = array_shift($terms) ) $_terms[] = $term->term_id; $terms = $_terms; } elseif ( 'names' == $fields ) { while ( $term = array_shift($terms) ) $_terms[] = $term->name; $terms = $_terms; } if ( $skip_cache != true ) { wp_cache_add( $cache_key, $terms, 'terms' ); } $terms = apply_filters('get_terms', $terms, $taxonomies, $args); return $terms; }
/** * Retrieve the terms in a given taxonomy or list of taxonomies. * * You can fully inject any customizations to the query before it is sent, as * well as control the output with a filter. * * The 'get_terms' filter will be called when the cache has the term and will * pass the found term along with the array of $taxonomies and array of $args. * This filter is also called before the array of terms is passed and will pass * the array of terms, along with the $taxonomies and $args. * * The 'list_terms_exclusions' filter passes the compiled exclusions along with * the $args. * * The 'get_terms_orderby' filter passes the ORDER BY clause for the query * along with the $args array. * * The 'get_terms_fields' filter passes the fields for the SELECT query * along with the $args array. * * The list of arguments that $args can contain, which will overwrite the defaults: * * orderby - Default is 'name'. Can be name, count, term_group, slug or nothing * (will use term_id), Passing a custom value other than these will cause it to * order based on the custom value. * * order - Default is ASC. Can use DESC. * * hide_empty - Default is true. Will not return empty terms, which means * terms whose count is 0 according to the given taxonomy. * * exclude - Default is an empty array. An array, comma- or space-delimited string * of term ids to exclude from the return array. If 'include' is non-empty, * 'exclude' is ignored. * * exclude_tree - Default is an empty array. An array, comma- or space-delimited * string of term ids to exclude from the return array, along with all of their * descendant terms according to the primary taxonomy. If 'include' is non-empty, * 'exclude_tree' is ignored. * * include - Default is an empty array. An array, comma- or space-delimited string * of term ids to include in the return array. * * number - The maximum number of terms to return. Default is to return them all. * * offset - The number by which to offset the terms query. * * fields - Default is 'all', which returns an array of term objects. * If 'fields' is 'ids' or 'names', returns an array of * integers or strings, respectively. * * slug - Returns terms whose "slug" matches this value. Default is empty string. * * hierarchical - Whether to include terms that have non-empty descendants * (even if 'hide_empty' is set to true). * * search - Returned terms' names will contain the value of 'search', * case-insensitive. Default is an empty string. * * name__like - Returned terms' names will begin with the value of 'name__like', * case-insensitive. Default is empty string. * * The argument 'pad_counts', if set to true will include the quantity of a term's * children in the quantity of each term's "count" object variable. * * The 'get' argument, if set to 'all' instead of its default empty string, * returns terms regardless of ancestry or whether the terms are empty. * * The 'child_of' argument, when used, should be set to the integer of a term ID. Its default * is 0. If set to a non-zero value, all returned terms will be descendants * of that term according to the given taxonomy. Hence 'child_of' is set to 0 * if more than one taxonomy is passed in $taxonomies, because multiple taxonomies * make term ancestry ambiguous. * * The 'parent' argument, when used, should be set to the integer of a term ID. Its default is * the empty string '', which has a different meaning from the integer 0. * If set to an integer value, all returned terms will have as an immediate * ancestor the term whose ID is specified by that integer according to the given taxonomy. * The 'parent' argument is different from 'child_of' in that a term X is considered a 'parent' * of term Y only if term X is the father of term Y, not its grandfather or great-grandfather, etc. * * The 'cache_domain' argument enables a unique cache key to be produced when this query is stored * in object cache. For instance, if you are using one of this function's filters to modify the * query (such as 'terms_clauses'), setting 'cache_domain' to a unique value will not overwrite * the cache for similar queries. Default value is 'core'. * * @package WordPress * @subpackage Taxonomy * @since 2.3.0 * * @uses $wpdb * @uses wp_parse_args() Merges the defaults with those defined by $args and allows for strings. * * @param string|array $taxonomies Taxonomy name or list of Taxonomy names * @param string|array $args The values of what to search for when returning terms * @return array|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies do not exist. */ function get_terms($taxonomies, $args = '') { global $wpdb; $empty_array = array(); $single_taxonomy = ! is_array( $taxonomies ) || 1 === count( $taxonomies ); if ( ! is_array( $taxonomies ) ) $taxonomies = array( $taxonomies ); foreach ( $taxonomies as $taxonomy ) { if ( ! taxonomy_exists($taxonomy) ) { $error = new WP_Error('invalid_taxonomy', __('Invalid taxonomy')); return $error; } } $defaults = array('orderby' => 'name', 'order' => 'ASC', 'hide_empty' => true, 'exclude' => array(), 'exclude_tree' => array(), 'include' => array(), 'number' => '', 'fields' => 'all', 'slug' => '', 'parent' => '', 'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'pad_counts' => false, 'offset' => '', 'search' => '', 'cache_domain' => 'core' ); $args = wp_parse_args( $args, $defaults ); $args['number'] = absint( $args['number'] ); $args['offset'] = absint( $args['offset'] ); if ( !$single_taxonomy || !is_taxonomy_hierarchical($taxonomies[0]) || '' !== $args['parent'] ) { $args['child_of'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } if ( 'all' == $args['get'] ) { $args['child_of'] = 0; $args['hide_empty'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } $args = apply_filters( 'get_terms_args', $args, $taxonomies ); extract($args, EXTR_SKIP); if ( $child_of ) { $hierarchy = _get_term_hierarchy($taxonomies[0]); if ( !isset($hierarchy[$child_of]) ) return $empty_array; } if ( $parent ) { $hierarchy = _get_term_hierarchy($taxonomies[0]); if ( !isset($hierarchy[$parent]) ) return $empty_array; } // $args can be whatever, only use the args defined in defaults to compute the key $filter_key = ( has_filter('list_terms_exclusions') ) ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : ''; $key = md5( serialize( compact(array_keys($defaults)) ) . serialize( $taxonomies ) . $filter_key ); $last_changed = wp_cache_get('last_changed', 'terms'); if ( !$last_changed ) { $last_changed = time(); wp_cache_set('last_changed', $last_changed, 'terms'); } $cache_key = "get_terms:$key:$last_changed"; $cache = wp_cache_get( $cache_key, 'terms' ); if ( false !== $cache ) { $cache = apply_filters('get_terms', $cache, $taxonomies, $args); return $cache; } $_orderby = strtolower($orderby); if ( 'count' == $_orderby ) $orderby = 'tt.count'; else if ( 'name' == $_orderby ) $orderby = 't.name'; else if ( 'slug' == $_orderby ) $orderby = 't.slug'; else if ( 'term_group' == $_orderby ) $orderby = 't.term_group'; else if ( 'none' == $_orderby ) $orderby = ''; elseif ( empty($_orderby) || 'id' == $_orderby ) $orderby = 't.term_id'; else $orderby = 't.name'; $orderby = apply_filters( 'get_terms_orderby', $orderby, $args ); if ( !empty($orderby) ) $orderby = "ORDER BY $orderby"; else $order = ''; $order = strtoupper( $order ); if ( '' !== $order && !in_array( $order, array( 'ASC', 'DESC' ) ) ) $order = 'ASC'; $where = "tt.taxonomy IN ('" . implode("', '", $taxonomies) . "')"; $inclusions = ''; if ( !empty($include) ) { $exclude = ''; $exclude_tree = ''; $interms = wp_parse_id_list($include); foreach ( $interms as $interm ) { if ( empty($inclusions) ) $inclusions = ' AND ( t.term_id = ' . intval($interm) . ' '; else $inclusions .= ' OR t.term_id = ' . intval($interm) . ' '; } } if ( !empty($inclusions) ) $inclusions .= ')'; $where .= $inclusions; $exclusions = ''; if ( !empty( $exclude_tree ) ) { $excluded_trunks = wp_parse_id_list($exclude_tree); foreach ( $excluded_trunks as $extrunk ) { $excluded_children = (array) get_terms($taxonomies[0], array('child_of' => intval($extrunk), 'fields' => 'ids', 'hide_empty' => 0)); $excluded_children[] = $extrunk; foreach( $excluded_children as $exterm ) { if ( empty($exclusions) ) $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' '; else $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' '; } } } if ( !empty($exclude) ) { $exterms = wp_parse_id_list($exclude); foreach ( $exterms as $exterm ) { if ( empty($exclusions) ) $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' '; else $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' '; } } if ( !empty($exclusions) ) $exclusions .= ')'; $exclusions = apply_filters('list_terms_exclusions', $exclusions, $args ); $where .= $exclusions; if ( !empty($slug) ) { $slug = sanitize_title($slug); $where .= " AND t.slug = '$slug'"; } if ( !empty($name__like) ) { $name__like = like_escape( $name__like ); $where .= $wpdb->prepare( " AND t.name LIKE %s", $name__like . '%' ); } if ( '' !== $parent ) { $parent = (int) $parent; $where .= " AND tt.parent = '$parent'"; } if ( $hide_empty && !$hierarchical ) $where .= ' AND tt.count > 0'; // don't limit the query results when we have to descend the family tree if ( ! empty($number) && ! $hierarchical && empty( $child_of ) && '' === $parent ) { if ( $offset ) $limits = 'LIMIT ' . $offset . ',' . $number; else $limits = 'LIMIT ' . $number; } else { $limits = ''; } if ( !empty($search) ) { $search = like_escape($search); $where .= $wpdb->prepare( " AND (t.name LIKE %s)", '%' . $search . '%'); } $selects = array(); switch ( $fields ) { case 'all': $selects = array('t.*', 'tt.*'); break; case 'ids': case 'id=>parent': $selects = array('t.term_id', 'tt.parent', 'tt.count'); break; case 'names': $selects = array('t.term_id', 'tt.parent', 'tt.count', 't.name'); break; case 'count': $orderby = ''; $order = ''; $selects = array('COUNT(*)'); } $_fields = $fields; $fields = implode(', ', apply_filters( 'get_terms_fields', $selects, $args )); $join = "INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id"; $pieces = array( 'fields', 'join', 'where', 'orderby', 'order', 'limits' ); $clauses = apply_filters( 'terms_clauses', compact( $pieces ), $taxonomies, $args ); foreach ( $pieces as $piece ) $$piece = isset( $clauses[ $piece ] ) ? $clauses[ $piece ] : ''; $query = "SELECT $fields FROM $wpdb->terms AS t $join WHERE $where $orderby $order $limits"; $fields = $_fields; if ( 'count' == $fields ) { $term_count = $wpdb->get_var($query); return $term_count; } $terms = $wpdb->get_results($query); if ( 'all' == $fields ) { update_term_cache($terms); } if ( empty($terms) ) { wp_cache_add( $cache_key, array(), 'terms', DAY_IN_SECONDS ); $terms = apply_filters('get_terms', array(), $taxonomies, $args); return $terms; } if ( $child_of ) { $children = _get_term_hierarchy($taxonomies[0]); if ( ! empty($children) ) $terms = _get_term_children($child_of, $terms, $taxonomies[0]); } // Update term counts to include children. if ( $pad_counts && 'all' == $fields ) _pad_term_counts($terms, $taxonomies[0]); // Make sure we show empty categories that have children. if ( $hierarchical && $hide_empty && is_array($terms) ) { foreach ( $terms as $k => $term ) { if ( ! $term->count ) { $children = _get_term_children($term->term_id, $terms, $taxonomies[0]); if ( is_array($children) ) foreach ( $children as $child ) if ( $child->count ) continue 2; // It really is empty unset($terms[$k]); } } } reset ( $terms ); $_terms = array(); if ( 'id=>parent' == $fields ) { while ( $term = array_shift($terms) ) $_terms[$term->term_id] = $term->parent; $terms = $_terms; } elseif ( 'ids' == $fields ) { while ( $term = array_shift($terms) ) $_terms[] = $term->term_id; $terms = $_terms; } elseif ( 'names' == $fields ) { while ( $term = array_shift($terms) ) $_terms[] = $term->name; $terms = $_terms; } if ( 0 < $number && intval(@count($terms)) > $number ) { $terms = array_slice($terms, $offset, $number); } wp_cache_add( $cache_key, $terms, 'terms', DAY_IN_SECONDS ); $terms = apply_filters('get_terms', $terms, $taxonomies, $args); return $terms; }
/** * Get terms, based on query_vars. * * @param 4.6.0 * @access public * * @global wpdb $wpdb WordPress database abstraction object. * * @return array */ public function get_terms() { global $wpdb; $this->parse_query($this->query_vars); $args = $this->query_vars; // Set up meta_query so it's available to 'pre_get_terms'. $this->meta_query = new WP_Meta_Query(); $this->meta_query->parse_query_vars($args); /** * Fires before terms are retrieved. * * @since 4.6.0 * * @param WP_Term_Query $this Current instance of WP_Term_Query. */ do_action('pre_get_terms', $this); $taxonomies = $args['taxonomy']; // Save queries by not crawling the tree in the case of multiple taxes or a flat tax. $has_hierarchical_tax = false; if ($taxonomies) { foreach ($taxonomies as $_tax) { if (is_taxonomy_hierarchical($_tax)) { $has_hierarchical_tax = true; } } } if (!$has_hierarchical_tax) { $args['hierarchical'] = false; $args['pad_counts'] = false; } // 'parent' overrides 'child_of'. if (0 < intval($args['parent'])) { $args['child_of'] = false; } if ('all' == $args['get']) { $args['childless'] = false; $args['child_of'] = 0; $args['hide_empty'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } /** * Filters the terms query arguments. * * @since 3.1.0 * * @param array $args An array of get_terms() arguments. * @param array $taxonomies An array of taxonomies. */ $args = apply_filters('get_terms_args', $args, $taxonomies); // Avoid the query if the queried parent/child_of term has no descendants. $child_of = $args['child_of']; $parent = $args['parent']; if ($child_of) { $_parent = $child_of; } elseif ($parent) { $_parent = $parent; } else { $_parent = false; } if ($_parent) { $in_hierarchy = false; foreach ($taxonomies as $_tax) { $hierarchy = _get_term_hierarchy($_tax); if (isset($hierarchy[$_parent])) { $in_hierarchy = true; } } if (!$in_hierarchy) { return array(); } } $orderby = $this->parse_orderby($this->query_vars['orderby']); $order = $this->parse_order($this->query_vars['order']); if ($taxonomies) { $this->sql_clauses['where']['taxonomy'] = "tt.taxonomy IN ('" . implode("', '", array_map('esc_sql', $taxonomies)) . "')"; } $exclude = $args['exclude']; $exclude_tree = $args['exclude_tree']; $include = $args['include']; $inclusions = ''; if (!empty($include)) { $exclude = ''; $exclude_tree = ''; $inclusions = implode(',', wp_parse_id_list($include)); } if (!empty($inclusions)) { $this->sql_clauses['where']['inclusions'] = 't.term_id IN ( ' . $inclusions . ' )'; } $exclusions = array(); if (!empty($exclude_tree)) { $exclude_tree = wp_parse_id_list($exclude_tree); $excluded_children = $exclude_tree; foreach ($exclude_tree as $extrunk) { $excluded_children = array_merge($excluded_children, (array) get_terms($taxonomies[0], array('child_of' => intval($extrunk), 'fields' => 'ids', 'hide_empty' => 0))); } $exclusions = array_merge($excluded_children, $exclusions); } if (!empty($exclude)) { $exclusions = array_merge(wp_parse_id_list($exclude), $exclusions); } // 'childless' terms are those without an entry in the flattened term hierarchy. $childless = (bool) $args['childless']; if ($childless) { foreach ($taxonomies as $_tax) { $term_hierarchy = _get_term_hierarchy($_tax); $exclusions = array_merge(array_keys($term_hierarchy), $exclusions); } } if (!empty($exclusions)) { $exclusions = 't.term_id NOT IN (' . implode(',', array_map('intval', $exclusions)) . ')'; } else { $exclusions = ''; } /** * Filters the terms to exclude from the terms query. * * @since 2.3.0 * * @param string $exclusions `NOT IN` clause of the terms query. * @param array $args An array of terms query arguments. * @param array $taxonomies An array of taxonomies. */ $exclusions = apply_filters('list_terms_exclusions', $exclusions, $args, $taxonomies); if (!empty($exclusions)) { // Must do string manipulation here for backward compatibility with filter. $this->sql_clauses['where']['exclusions'] = preg_replace('/^\\s*AND\\s*/', '', $exclusions); } if (!empty($args['name'])) { $names = (array) $args['name']; foreach ($names as &$_name) { // `sanitize_term_field()` returns slashed data. $_name = stripslashes(sanitize_term_field('name', $_name, 0, reset($taxonomies), 'db')); } $this->sql_clauses['where']['name'] = "t.name IN ('" . implode("', '", array_map('esc_sql', $names)) . "')"; } if (!empty($args['slug'])) { if (is_array($args['slug'])) { $slug = array_map('sanitize_title', $args['slug']); $this->sql_clauses['where']['slug'] = "t.slug IN ('" . implode("', '", $slug) . "')"; } else { $slug = sanitize_title($args['slug']); $this->sql_clauses['where']['slug'] = "t.slug = '{$slug}'"; } } if (!empty($args['term_taxonomy_id'])) { if (is_array($args['term_taxonomy_id'])) { $tt_ids = implode(',', array_map('intval', $args['term_taxonomy_id'])); $this->sql_clauses['where']['term_taxonomy_id'] = "tt.term_taxonomy_id IN ({$tt_ids})"; } else { $this->sql_clauses['where']['term_taxonomy_id'] = $wpdb->prepare("tt.term_taxonomy_id = %d", $args['term_taxonomy_id']); } } if (!empty($args['name__like'])) { $this->sql_clauses['where']['name__like'] = $wpdb->prepare("t.name LIKE %s", '%' . $wpdb->esc_like($args['name__like']) . '%'); } if (!empty($args['description__like'])) { $this->sql_clauses['where']['description__like'] = $wpdb->prepare("tt.description LIKE %s", '%' . $wpdb->esc_like($args['description__like']) . '%'); } if ('' !== $parent) { $parent = (int) $parent; $this->sql_clauses['where']['parent'] = "tt.parent = '{$parent}'"; } $hierarchical = $args['hierarchical']; if ('count' == $args['fields']) { $hierarchical = false; } if ($args['hide_empty'] && !$hierarchical) { $this->sql_clauses['where']['count'] = 'tt.count > 0'; } $number = $args['number']; $offset = $args['offset']; // Don't limit the query results when we have to descend the family tree. if ($number && !$hierarchical && !$child_of && '' === $parent) { if ($offset) { $limits = 'LIMIT ' . $offset . ',' . $number; } else { $limits = 'LIMIT ' . $number; } } else { $limits = ''; } if (!empty($args['search'])) { $this->sql_clauses['where']['search'] = $this->get_search_sql($args['search']); } // Meta query support. $join = ''; $distinct = ''; // Reparse meta_query query_vars, in case they were modified in a 'pre_get_terms' callback. $this->meta_query->parse_query_vars($this->query_vars); $mq_sql = $this->meta_query->get_sql('term', 't', 'term_id'); $meta_clauses = $this->meta_query->get_clauses(); if (!empty($meta_clauses)) { $join .= $mq_sql['join']; $this->sql_clauses['where']['meta_query'] = preg_replace('/^\\s*AND\\s*/', '', $mq_sql['where']); $distinct .= "DISTINCT"; } $selects = array(); switch ($args['fields']) { case 'all': $selects = array('t.*', 'tt.*'); break; case 'ids': case 'id=>parent': $selects = array('t.term_id', 'tt.parent', 'tt.count', 'tt.taxonomy'); break; case 'names': $selects = array('t.term_id', 'tt.parent', 'tt.count', 't.name', 'tt.taxonomy'); break; case 'count': $orderby = ''; $order = ''; $selects = array('COUNT(*)'); break; case 'id=>name': $selects = array('t.term_id', 't.name', 'tt.count', 'tt.taxonomy'); break; case 'id=>slug': $selects = array('t.term_id', 't.slug', 'tt.count', 'tt.taxonomy'); break; } $_fields = $args['fields']; /** * Filters the fields to select in the terms query. * * Field lists modified using this filter will only modify the term fields returned * by the function when the `$fields` parameter set to 'count' or 'all'. In all other * cases, the term fields in the results array will be determined by the `$fields` * parameter alone. * * Use of this filter can result in unpredictable behavior, and is not recommended. * * @since 2.8.0 * * @param array $selects An array of fields to select for the terms query. * @param array $args An array of term query arguments. * @param array $taxonomies An array of taxonomies. */ $fields = implode(', ', apply_filters('get_terms_fields', $selects, $args, $taxonomies)); $join .= " INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id"; $where = implode(' AND ', $this->sql_clauses['where']); $pieces = array('fields', 'join', 'where', 'distinct', 'orderby', 'order', 'limits'); /** * Filters the terms query SQL clauses. * * @since 3.1.0 * * @param array $pieces Terms query SQL clauses. * @param array $taxonomies An array of taxonomies. * @param array $args An array of terms query arguments. */ $clauses = apply_filters('terms_clauses', compact($pieces), $taxonomies, $args); $fields = isset($clauses['fields']) ? $clauses['fields'] : ''; $join = isset($clauses['join']) ? $clauses['join'] : ''; $where = isset($clauses['where']) ? $clauses['where'] : ''; $distinct = isset($clauses['distinct']) ? $clauses['distinct'] : ''; $orderby = isset($clauses['orderby']) ? $clauses['orderby'] : ''; $order = isset($clauses['order']) ? $clauses['order'] : ''; $limits = isset($clauses['limits']) ? $clauses['limits'] : ''; if ($where) { $where = "WHERE {$where}"; } $this->sql_clauses['select'] = "SELECT {$distinct} {$fields}"; $this->sql_clauses['from'] = "FROM {$wpdb->terms} AS t {$join}"; $this->sql_clauses['orderby'] = $orderby ? "ORDER BY {$orderby} {$order}" : ''; $this->sql_clauses['limits'] = $limits; $this->request = "{$this->sql_clauses['select']} {$this->sql_clauses['from']} {$where} {$this->sql_clauses['orderby']} {$this->sql_clauses['limits']}"; // $args can be anything. Only use the args defined in defaults to compute the key. $key = md5(serialize(wp_array_slice_assoc($args, array_keys($this->query_var_defaults))) . serialize($taxonomies) . $this->request); $last_changed = wp_cache_get('last_changed', 'terms'); if (!$last_changed) { $last_changed = microtime(); wp_cache_set('last_changed', $last_changed, 'terms'); } $cache_key = "get_terms:{$key}:{$last_changed}"; $cache = wp_cache_get($cache_key, 'terms'); if (false !== $cache) { if ('all' === $_fields) { $cache = array_map('get_term', $cache); } return $cache; } if ('count' == $_fields) { return $wpdb->get_var($this->request); } $terms = $wpdb->get_results($this->request); if ('all' == $_fields) { update_term_cache($terms); } // Prime termmeta cache. if ($args['update_term_meta_cache']) { $term_ids = wp_list_pluck($terms, 'term_id'); update_termmeta_cache($term_ids); } if (empty($terms)) { wp_cache_add($cache_key, array(), 'terms', DAY_IN_SECONDS); return array(); } if ($child_of) { foreach ($taxonomies as $_tax) { $children = _get_term_hierarchy($_tax); if (!empty($children)) { $terms = _get_term_children($child_of, $terms, $_tax); } } } // Update term counts to include children. if ($args['pad_counts'] && 'all' == $_fields) { foreach ($taxonomies as $_tax) { _pad_term_counts($terms, $_tax); } } // Make sure we show empty categories that have children. if ($hierarchical && $args['hide_empty'] && is_array($terms)) { foreach ($terms as $k => $term) { if (!$term->count) { $children = get_term_children($term->term_id, $term->taxonomy); if (is_array($children)) { foreach ($children as $child_id) { $child = get_term($child_id, $term->taxonomy); if ($child->count) { continue 2; } } } // It really is empty. unset($terms[$k]); } } } $_terms = array(); if ('id=>parent' == $_fields) { foreach ($terms as $term) { $_terms[$term->term_id] = $term->parent; } } elseif ('ids' == $_fields) { foreach ($terms as $term) { $_terms[] = $term->term_id; } } elseif ('names' == $_fields) { foreach ($terms as $term) { $_terms[] = $term->name; } } elseif ('id=>name' == $_fields) { foreach ($terms as $term) { $_terms[$term->term_id] = $term->name; } } elseif ('id=>slug' == $_fields) { foreach ($terms as $term) { $_terms[$term->term_id] = $term->slug; } } if (!empty($_terms)) { $terms = $_terms; } // Hierarchical queries are not limited, so 'offset' and 'number' must be handled now. if ($hierarchical && $number && is_array($terms)) { if ($offset >= count($terms)) { $terms = array(); } else { $terms = array_slice($terms, $offset, $number, true); } } wp_cache_add($cache_key, $terms, 'terms', DAY_IN_SECONDS); if ('all' === $_fields) { $terms = array_map('get_term', $terms); } $this->terms = $terms; return $this->terms; }
/** * Retrieve the terms in a given taxonomy or list of taxonomies. * * You can fully inject any customizations to the query before it is sent, as * well as control the output with a filter. * * The 'get_terms' filter will be called when the cache has the term and will * pass the found term along with the array of $taxonomies and array of $args. * This filter is also called before the array of terms is passed and will pass * the array of terms, along with the $taxonomies and $args. * * The 'list_terms_exclusions' filter passes the compiled exclusions along with * the $args. * * The 'get_terms_orderby' filter passes the ORDER BY clause for the query * along with the $args array. * * The 'get_terms_fields' filter passes the fields for the SELECT query * along with the $args array. * * @since 2.3.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param string|array $taxonomies Taxonomy name or list of Taxonomy names. * @param array|string $args { * Optional. Array or string of arguments to get terms. * * @type string $orderby Field(s) to order terms by. Accepts term fields ('name', 'slug', * 'term_group', 'term_id', 'id'), 'count' for term taxonomy count, * 'include' to match the 'order' of the $include param, or 'none' * to skip ORDER BY. Defaults to 'name'. * @type string $order Whether to order terms in ascending or descending order. * Accepts 'ASC' (ascending) or 'DESC' (descending). * Default 'ASC'. * @type bool|int $hide_empty Whether to hide terms not assigned to any posts. Accepts * 1|true or 0|false. Default 1|true. * @type array|string $include Array or comma/space-separated string of term ids to include. * Default empty array. * @type array|string $exclude Array or comma/space-separated string of term ids to exclude. * If $include is non-empty, $exclude is ignored. * Default empty array. * @type array|string $exclude_tree Array or comma/space-separated string of term ids to exclude * along with all of their descendant terms. If $include is * non-empty, $exclude_tree is ignored. Default empty array. * @type int $number Maximum number of terms to return. Accepts 1+ or -1 (all). * Default -1. * @type int $offset The number by which to offset the terms query. Default empty. * @type string $fields Term fields to query for. Accepts 'all' (returns an array of * term objects), 'ids' or 'names' (returns an array of integers * or strings, respectively. Default 'all'. * @type string|array $slug Optional. Slug or array of slugs to return term(s) for. Default empty. * @type bool $hierarchical Whether to include terms that have non-empty descendants (even * if $hide_empty is set to true). Default true. * @type string $search Search criteria to match terms. Will be SQL-formatted with * wildcards before and after. Default empty. * @type string $name__like Retrieve terms with criteria by which a term is LIKE $name__like. * Default empty. * @type string $description__like Retrieve terms where the description is LIKE $description__like. * Default empty. * @type bool $pad_counts Whether to pad the quantity of a term's children in the quantity * of each term's "count" object variable. Default false. * @type string $get Whether to return terms regardless of ancestry or whether the terms * are empty. Accepts 'all' or empty (disabled). Default empty. * @type int $child_of Term ID to retrieve child terms of. If multiple taxonomies * are passed, $child_of is ignored. Default 0. * @type int|string $parent Parent term ID to retrieve direct-child terms of. Default empty. * @type string $cache_domain Unique cache key to be produced when this query is stored in an * object cache. Default is 'core'. * } * @return array|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies * do not exist. */ function get_terms( $taxonomies, $args = '' ) { global $wpdb; $empty_array = array(); $single_taxonomy = ! is_array( $taxonomies ) || 1 === count( $taxonomies ); if ( ! is_array( $taxonomies ) ) { $taxonomies = array( $taxonomies ); } foreach ( $taxonomies as $taxonomy ) { if ( ! taxonomy_exists($taxonomy) ) { $error = new WP_Error('invalid_taxonomy', __('Invalid taxonomy')); return $error; } } $defaults = array('orderby' => 'name', 'order' => 'ASC', 'hide_empty' => true, 'exclude' => array(), 'exclude_tree' => array(), 'include' => array(), 'number' => '', 'fields' => 'all', 'slug' => '', 'parent' => '', 'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'description__like' => '', 'pad_counts' => false, 'offset' => '', 'search' => '', 'cache_domain' => 'core' ); $args = wp_parse_args( $args, $defaults ); $args['number'] = absint( $args['number'] ); $args['offset'] = absint( $args['offset'] ); // Save queries by not crawling the tree in the case of multiple taxes or a flat tax. if ( ! $single_taxonomy || ! is_taxonomy_hierarchical( reset( $taxonomies ) ) ) { $args['hierarchical'] = false; $args['pad_counts'] = false; } // 'parent' overrides 'child_of'. if ( 0 < intval( $args['parent'] ) ) { $args['child_of'] = false; } if ( 'all' == $args['get'] ) { $args['child_of'] = 0; $args['hide_empty'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } /** * Filter the terms query arguments. * * @since 3.1.0 * * @param array $args An array of arguments. * @param string|array $taxonomies A taxonomy or array of taxonomies. */ $args = apply_filters( 'get_terms_args', $args, $taxonomies ); $child_of = $args['child_of']; if ( $child_of ) { $hierarchy = _get_term_hierarchy( reset( $taxonomies ) ); if ( ! isset( $hierarchy[ $child_of ] ) ) { return $empty_array; } } $parent = $args['parent']; if ( $parent ) { $hierarchy = _get_term_hierarchy( reset( $taxonomies ) ); if ( ! isset( $hierarchy[ $parent ] ) ) { return $empty_array; } } // $args can be whatever, only use the args defined in defaults to compute the key $filter_key = ( has_filter('list_terms_exclusions') ) ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : ''; $key = md5( serialize( wp_array_slice_assoc( $args, array_keys( $defaults ) ) ) . serialize( $taxonomies ) . $filter_key ); $last_changed = wp_cache_get( 'last_changed', 'terms' ); if ( ! $last_changed ) { $last_changed = microtime(); wp_cache_set( 'last_changed', $last_changed, 'terms' ); } $cache_key = "get_terms:$key:$last_changed"; $cache = wp_cache_get( $cache_key, 'terms' ); if ( false !== $cache ) { /** * Filter the given taxonomy's terms cache. * * @since 2.3.0 * * @param array $cache Cached array of terms for the given taxonomy. * @param string|array $taxonomies A taxonomy or array of taxonomies. * @param array $args An array of arguments to get terms. */ $cache = apply_filters( 'get_terms', $cache, $taxonomies, $args ); return $cache; } $_orderby = strtolower( $args['orderby'] ); if ( 'count' == $_orderby ) { $orderby = 'tt.count'; } else if ( 'name' == $_orderby ) { $orderby = 't.name'; } else if ( 'slug' == $_orderby ) { $orderby = 't.slug'; } else if ( 'include' == $_orderby && ! empty( $args['include'] ) ) { $include = implode( ',', array_map( 'absint', $args['include'] ) ); $orderby = "FIELD( t.term_id, $include )"; } else if ( 'term_group' == $_orderby ) { $orderby = 't.term_group'; } else if ( 'none' == $_orderby ) { $orderby = ''; } elseif ( empty($_orderby) || 'id' == $_orderby ) { $orderby = 't.term_id'; } else { $orderby = 't.name'; } /** * Filter the ORDERBY clause of the terms query. * * @since 2.8.0 * * @param string $orderby ORDERBY clause of the terms query. * @param array $args An array of terms query arguments. * @param string|array $taxonomies A taxonomy or array of taxonomies. */ $orderby = apply_filters( 'get_terms_orderby', $orderby, $args, $taxonomies ); $order = strtoupper( $args['order'] ); if ( ! empty( $orderby ) ) { $orderby = "ORDER BY $orderby"; } else { $order = ''; } if ( '' !== $order && ! in_array( $order, array( 'ASC', 'DESC' ) ) ) { $order = 'ASC'; } $where = "tt.taxonomy IN ('" . implode("', '", array_map( 'esc_sql', $taxonomies ) ) . "')"; $exclude = $args['exclude']; $exclude_tree = $args['exclude_tree']; $include = $args['include']; $inclusions = ''; if ( ! empty( $include ) ) { $exclude = ''; $exclude_tree = ''; $inclusions = implode( ',', wp_parse_id_list( $include ) ); } if ( ! empty( $inclusions ) ) { $inclusions = ' AND t.term_id IN ( ' . $inclusions . ' )'; $where .= $inclusions; } if ( ! empty( $exclude_tree ) ) { $exclude_tree = wp_parse_id_list( $exclude_tree ); $excluded_children = $exclude_tree; foreach ( $exclude_tree as $extrunk ) { $excluded_children = array_merge( $excluded_children, (array) get_terms( $taxonomies[0], array( 'child_of' => intval( $extrunk ), 'fields' => 'ids', 'hide_empty' => 0 ) ) ); } $exclusions = implode( ',', array_map( 'intval', $excluded_children ) ); } else { $exclusions = ''; } if ( ! empty( $exclude ) ) { $exterms = wp_parse_id_list( $exclude ); if ( empty( $exclusions ) ) { $exclusions = implode( ',', $exterms ); } else { $exclusions .= ', ' . implode( ',', $exterms ); } } if ( ! empty( $exclusions ) ) { $exclusions = ' AND t.term_id NOT IN (' . $exclusions . ')'; } /** * Filter the terms to exclude from the terms query. * * @since 2.3.0 * * @param string $exclusions NOT IN clause of the terms query. * @param array $args An array of terms query arguments. * @param string|array $taxonomies A taxonomy or array of taxonomies. */ $exclusions = apply_filters( 'list_terms_exclusions', $exclusions, $args, $taxonomies ); if ( ! empty( $exclusions ) ) { $where .= $exclusions; } if ( ! empty( $args['slug'] ) ) { if ( is_array( $args['slug'] ) ) { $slug = array_map( 'sanitize_title', $args['slug'] ); $where .= " AND t.slug IN ('" . implode( "', '", $slug ) . "')"; } else { $slug = sanitize_title( $args['slug'] ); $where .= " AND t.slug = '$slug'"; } } if ( ! empty( $args['name__like'] ) ) { $where .= $wpdb->prepare( " AND t.name LIKE %s", '%' . $wpdb->esc_like( $args['name__like'] ) . '%' ); } if ( ! empty( $args['description__like'] ) ) { $where .= $wpdb->prepare( " AND tt.description LIKE %s", '%' . $wpdb->esc_like( $args['description__like'] ) . '%' ); } if ( '' !== $parent ) { $parent = (int) $parent; $where .= " AND tt.parent = '$parent'"; } $hierarchical = $args['hierarchical']; if ( 'count' == $args['fields'] ) { $hierarchical = false; } if ( $args['hide_empty'] && !$hierarchical ) { $where .= ' AND tt.count > 0'; } $number = $args['number']; $offset = $args['offset']; // don't limit the query results when we have to descend the family tree if ( $number && ! $hierarchical && ! $child_of && '' === $parent ) { if ( $offset ) { $limits = 'LIMIT ' . $offset . ',' . $number; } else { $limits = 'LIMIT ' . $number; } } else { $limits = ''; } if ( ! empty( $args['search'] ) ) { $like = '%' . $wpdb->esc_like( $args['search'] ) . '%'; $where .= $wpdb->prepare( ' AND ((t.name LIKE %s) OR (t.slug LIKE %s))', $like, $like ); } $selects = array(); switch ( $args['fields'] ) { case 'all': $selects = array( 't.*', 'tt.*' ); break; case 'ids': case 'id=>parent': $selects = array( 't.term_id', 'tt.parent', 'tt.count' ); break; case 'names': $selects = array( 't.term_id', 'tt.parent', 'tt.count', 't.name' ); break; case 'count': $orderby = ''; $order = ''; $selects = array( 'COUNT(*)' ); break; case 'id=>name': $selects = array( 't.term_id', 't.name', 'tt.count' ); break; case 'id=>slug': $selects = array( 't.term_id', 't.slug', 'tt.count' ); break; } $_fields = $args['fields']; /** * Filter the fields to select in the terms query. * * @since 2.8.0 * * @param array $selects An array of fields to select for the terms query. * @param array $args An array of term query arguments. * @param string|array $taxonomies A taxonomy or array of taxonomies. */ $fields = implode( ', ', apply_filters( 'get_terms_fields', $selects, $args, $taxonomies ) ); $join = "INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id"; $pieces = array( 'fields', 'join', 'where', 'orderby', 'order', 'limits' ); /** * Filter the terms query SQL clauses. * * @since 3.1.0 * * @param array $pieces Terms query SQL clauses. * @param string|array $taxonomies A taxonomy or array of taxonomies. * @param array $args An array of terms query arguments. */ $clauses = apply_filters( 'terms_clauses', compact( $pieces ), $taxonomies, $args ); $fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : ''; $join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : ''; $where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : ''; $orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : ''; $order = isset( $clauses[ 'order' ] ) ? $clauses[ 'order' ] : ''; $limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : ''; $query = "SELECT $fields FROM $wpdb->terms AS t $join WHERE $where $orderby $order $limits"; if ( 'count' == $_fields ) { $term_count = $wpdb->get_var($query); return $term_count; } $terms = $wpdb->get_results($query); if ( 'all' == $_fields ) { update_term_cache( $terms ); } if ( empty($terms) ) { wp_cache_add( $cache_key, array(), 'terms', DAY_IN_SECONDS ); /** This filter is documented in wp-includes/taxonomy.php */ $terms = apply_filters( 'get_terms', array(), $taxonomies, $args ); return $terms; } if ( $child_of ) { $children = _get_term_hierarchy( reset( $taxonomies ) ); if ( ! empty( $children ) ) { $terms = _get_term_children( $child_of, $terms, reset( $taxonomies ) ); } } // Update term counts to include children. if ( $args['pad_counts'] && 'all' == $_fields ) { _pad_term_counts( $terms, reset( $taxonomies ) ); } // Make sure we show empty categories that have children. if ( $hierarchical && $args['hide_empty'] && is_array( $terms ) ) { foreach ( $terms as $k => $term ) { if ( ! $term->count ) { $children = get_term_children( $term->term_id, reset( $taxonomies ) ); if ( is_array( $children ) ) { foreach ( $children as $child_id ) { $child = get_term( $child_id, reset( $taxonomies ) ); if ( $child->count ) { continue 2; } } } // It really is empty unset($terms[$k]); } } } reset( $terms ); $_terms = array(); if ( 'id=>parent' == $_fields ) { while ( $term = array_shift( $terms ) ) { $_terms[$term->term_id] = $term->parent; } } elseif ( 'ids' == $_fields ) { while ( $term = array_shift( $terms ) ) { $_terms[] = $term->term_id; } } elseif ( 'names' == $_fields ) { while ( $term = array_shift( $terms ) ) { $_terms[] = $term->name; } } elseif ( 'id=>name' == $_fields ) { while ( $term = array_shift( $terms ) ) { $_terms[$term->term_id] = $term->name; } } elseif ( 'id=>slug' == $_fields ) { while ( $term = array_shift( $terms ) ) { $_terms[$term->term_id] = $term->slug; } } if ( ! empty( $_terms ) ) { $terms = $_terms; } if ( $number && is_array( $terms ) && count( $terms ) > $number ) { $terms = array_slice( $terms, $offset, $number ); } wp_cache_add( $cache_key, $terms, 'terms', DAY_IN_SECONDS ); /** This filter is documented in wp-includes/taxonomy */ $terms = apply_filters( 'get_terms', $terms, $taxonomies, $args ); return $terms; }
/** * Extended get_terms function support * - Limit category * - Limit days * - Selection restrict * - Min usage * * @param string|array $taxonomies * @param string $args * @return array */ function getTerms( $taxonomies, $args = '', $internal_st = false ) { global $wpdb; $empty_array = array(); $single_taxonomy = false; if ( !is_array($taxonomies) ) { $single_taxonomy = true; $taxonomies = array($taxonomies); } foreach ( (array) $taxonomies as $taxonomy ) { if ( ! is_taxonomy($taxonomy) ) { $error = & new WP_Error('invalid_taxonomy', __('Invalid Taxonomy')); return $error; } } $in_taxonomies = "'" . implode("', '", $taxonomies) . "'"; $defaults = array('orderby' => 'name', 'order' => 'ASC', 'hide_empty' => true, 'exclude' => '', 'exclude_tree' => '', 'include' => '', 'number' => '', 'fields' => 'all', 'slug' => '', 'parent' => '', 'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'pad_counts' => false, 'offset' => '', 'search' => '', // Simple tags added 'limit_days' => 0, 'category' => 0, 'min_usage' => 0, 'st_name__like' => '' ); $args = wp_parse_args( $args, $defaults ); // Translate selection order $args['orderby'] = $args['selectionby']; $args['order'] = $args['selection']; $args['number'] = absint( $args['number'] ); $args['offset'] = absint( $args['offset'] ); $args['limit_days'] = absint( $args['limit_days'] ); $args['min_usage'] = absint( $args['min_usage'] ); if ( !$single_taxonomy || !is_taxonomy_hierarchical($taxonomies[0]) || '' !== $args['parent'] ) { $args['child_of'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } if ( 'all' == $args['get'] ) { $args['child_of'] = 0; $args['hide_empty'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } extract($args, EXTR_SKIP); if ( $child_of ) { $hierarchy = _get_term_hierarchy($taxonomies[0]); if ( !isset($hierarchy[$child_of]) ) return $empty_array; } if ( $parent ) { $hierarchy = _get_term_hierarchy($taxonomies[0]); if ( !isset($hierarchy[$parent]) ) return $empty_array; } $_orderby = strtolower($orderby); if ( 'count' == $_orderby ) $orderby = 'tt.count'; if ( 'random' == $_orderby ) $orderby = 'RAND()'; else if ( 'name' == $_orderby ) $orderby = 't.name'; else if ( 'slug' == $_orderby ) $orderby = 't.slug'; else if ( 'term_group' == $_orderby ) $orderby = 't.term_group'; elseif ( empty($_orderby) || 'id' == $_orderby ) $orderby = 't.term_id'; $orderby = apply_filters( 'get_terms_orderby', $orderby, $args ); $where = ''; $inclusions = ''; if ( !empty($include) ) { $exclude = ''; $exclude_tree = ''; $interms = preg_split('/[\s,]+/',$include); if ( count($interms) ) { foreach ( (array) $interms as $interm ) { if (empty($inclusions)) $inclusions = ' AND ( t.term_id = ' . intval($interm) . ' '; else $inclusions .= ' OR t.term_id = ' . intval($interm) . ' '; } } } if ( !empty($inclusions) ) $inclusions .= ')'; $where .= $inclusions; $exclusions = ''; if ( ! empty( $exclude_tree ) ) { $excluded_trunks = preg_split('/[\s,]+/',$exclude_tree); foreach( (array) $excluded_trunks as $extrunk ) { $excluded_children = (array) get_terms($taxonomies[0], array('child_of' => intval($extrunk), 'fields' => 'ids')); $excluded_children[] = $extrunk; foreach( (array) $excluded_children as $exterm ) { if ( empty($exclusions) ) $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' '; else $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' '; } } } if ( !empty($exclude) ) { $exterms = preg_split('/[\s,]+/',$exclude); if ( count($exterms) ) { foreach ( (array) $exterms as $exterm ) { if ( empty($exclusions) ) $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' '; else $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' '; } } } if ( !empty($exclusions) ) $exclusions .= ')'; $exclusions = apply_filters('list_terms_exclusions', $exclusions, $args ); $where .= $exclusions; // $args can be whatever, only use the args defined in defaults to compute the key $filter_key = ( has_filter('list_terms_exclusions') ) ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : ''; $key = md5( serialize( compact(array_keys($defaults)) ) . serialize( $taxonomies ) . $filter_key ); $last_changed = wp_cache_get('last_changed', 'terms'); if ( !$last_changed ) { $last_changed = time(); wp_cache_set('last_changed', $last_changed, 'terms'); } $cache_key = "st_get_terms:$key:$last_changed"; $cache = wp_cache_get( $cache_key, 'terms' ); if ( false !== $cache ) { $cache = apply_filters('get_terms', $cache, $taxonomies, $args); return $cache; } // ST Features : Restrict category if ( $category != 0 ) { if ( !is_array($taxonomies) ) $taxonomies = array($taxonomies); $incategories = preg_split('/[\s,]+/', $category); $incategories = array_map('intval', $incategories); $taxonomies = "'" . implode("', '", $taxonomies) . "'"; $incategories = "'" . implode("', '", $incategories) . "'"; $where .= " AND tr.object_id IN ( "; $where .= "SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tt.term_id IN ($incategories)"; $where .= " ) "; unset($incategories, $category); } // ST Features : Limit posts date if ( $limit_days != 0 ) { $where .= " AND tr.object_id IN ( "; $where .= "SELECT ID WHERE $wpdb->posts WHERE post_date_gmt > '" .date( 'Y-m-d H:i:s', time() - $limit_days * 86400 ). "'"; $where .= " ) "; unset($limit_days); } if ( !empty($slug) ) { $slug = sanitize_title($slug); $where .= " AND t.slug = '$slug'"; } if ( !empty($name__like) ) $where .= " AND t.name LIKE '{$name__like}%'"; if ( '' !== $parent ) { $parent = (int) $parent; $where .= " AND tt.parent = '$parent'"; } // ST Features : Another way to search if ( strpos($st_name__like, ' ') !== false ) { $st_terms_formatted = array(); $st_terms = preg_split('/[\s,]+/', $st_name_like); foreach ( (array) $st_terms as $st_term ) { if ( empty($st_term) ) continue; $st_terms_formatted[] = "t.name LIKE '%".like_escape($st_term)."%'"; } $where .= " AND ( " . explode( ' OR ', $st_terms_formatted ) . " ) "; unset( $st_term, $st_terms_formatted, $st_terms ); } elseif ( !empty($st_name__like) ) { $where .= " AND t.name LIKE '%{$st_name__like}%'"; } // ST Features : Add min usage if ( $hide_empty && !$hierarchical ) { if ( $min_usage == 0 ) $where .= ' AND tt.count > 0'; else $where .= $wpdb->prepare( ' AND tt.count >= %d', $min_usage ); } if ( !empty($search) ) { $search = like_escape($search); $where .= " AND (t.name LIKE '%$search%')"; } // don't limit the query results when we have to descend the family tree if ( ! empty($number) && ! $hierarchical && empty( $child_of ) && '' === $parent ) { if( $offset ) $limit = 'LIMIT ' . $offset . ',' . $number; else $limit = 'LIMIT ' . $number; } else $limit = ''; $selects = array(); if ( 'all' == $fields ) $selects = array('t.*', 'tt.*'); else if ( 'ids' == $fields ) $selects = array('t.term_id', 'tt.parent', 'tt.count'); else if ( 'names' == $fields ) $selects = array('t.term_id', 'tt.parent', 'tt.count', 't.name'); $select_this = implode(', ', apply_filters( 'get_terms_fields', $selects, $args )); $query = "SELECT $select_this FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id INNER JOIN $wpdb->term_relationships AS tr ON tt.term_taxonomy_id = tr.term_taxonomy_id WHERE tt.taxonomy IN ($in_taxonomies) $where GROUP BY t.term_id ORDER BY $orderby $order $limit"; $terms = $wpdb->get_results($query); if ( 'all' == $fields ) { update_term_cache($terms); } if ( empty($terms) ) { wp_cache_add( $cache_key, array(), 'terms' ); $terms = apply_filters('get_terms', array(), $taxonomies, $args); return $terms; } if ( $child_of ) { $children = _get_term_hierarchy($taxonomies[0]); if ( ! empty($children) ) $terms = & _get_term_children($child_of, $terms, $taxonomies[0]); } // Update term counts to include children. if ( $pad_counts && 'all' == $fields ) _pad_term_counts($terms, $taxonomies[0]); // Make sure we show empty categories that have children. if ( $hierarchical && $hide_empty && is_array($terms) ) { foreach ( $terms as $k => $term ) { if ( ! $term->count ) { $children = _get_term_children($term->term_id, $terms, $taxonomies[0]); if( is_array($children) ) foreach ( $children as $child ) if ( $child->count ) continue 2; // It really is empty unset($terms[$k]); } } } reset ( $terms ); $_terms = array(); if ( 'ids' == $fields ) { while ( $term = array_shift($terms) ) $_terms[] = $term->term_id; $terms = $_terms; } elseif ( 'names' == $fields ) { while ( $term = array_shift($terms) ) $_terms[] = $term->name; $terms = $_terms; } if ( 0 < $number && intval(@count($terms)) > $number ) { $terms = array_slice($terms, $offset, $number); } wp_cache_add( $cache_key, $terms, 'terms' ); $terms = apply_filters('get_terms', $terms, $taxonomies, $args); return $terms; }
/** * Extended get_terms function support * - Limit category * - Limit days * - Selection restrict * - Min usage * * @param string|array $taxonomies * @param string $args * @return array */ function getTerms($taxonomies, $args = '', $skip_cache = false) { global $wpdb; $single_taxonomy = false; if (!is_array($taxonomies)) { $single_taxonomy = true; $taxonomies = array($taxonomies); } foreach ((array) $taxonomies as $taxonomy) { if (!is_taxonomy($taxonomy)) { return new WP_Error('invalid_taxonomy', __('Invalid Taxonomy')); } } $in_taxonomies = "'" . implode("', '", $taxonomies) . "'"; $defaults = array('cloud_selection' => 'count-desc', 'hide_empty' => true, 'exclude' => '', 'include' => '', 'number' => '', 'fields' => 'all', 'slug' => '', 'parent' => '', 'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'st_name_like' => '', 'pad_counts' => false, 'limit_days' => 0, 'category' => 0, 'min_usage' => 0); $args = wp_parse_args($args, $defaults); if (!$single_taxonomy || !is_taxonomy_hierarchical($taxonomies[0]) || '' != $args['parent']) { $args['child_of'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } if ('all' == $args['get']) { $args['child_of'] = 0; $args['hide_empty'] = 0; $args['hierarchical'] = false; $args['pad_counts'] = false; } extract($args, EXTR_SKIP); if ($child_of) { $hierarchy = _get_term_hierarchy($taxonomies[0]); if (!isset($hierarchy[$child_of])) { return array(); } } if ($parent) { $hierarchy = _get_term_hierarchy($taxonomies[0]); if (!isset($hierarchy[$parent])) { return array(); } } if ($skip_cache != true) { // Get cache if exist $key = md5(serialize($args) . serialize($taxonomies)); if ($cache = wp_cache_get('get_terms', 'terms')) { if (isset($cache[$key])) { return apply_filters('get_terms', $cache[$key], $taxonomies, $args); } } } // Restrict category $category_sql = ''; if (!empty($category) && $category != '0') { $incategories = preg_split('/[\\s,]+/', $category); $objects_id = get_objects_in_term($incategories, 'category'); $objects_id = array_unique($objects_id); // to be sure haven't duplicates if (empty($objects_id)) { // No posts for this category = no tags for this category return array(); } foreach ((array) $objects_id as $object_id) { $category_sql .= "'" . $object_id . "', "; } $category_sql = substr($category_sql, 0, strlen($category_sql) - 2); // Remove latest ", " $category_sql = 'AND p.ID IN (' . $category_sql . ')'; } // count-asc/count-desc/name-asc/name-desc/random $cloud_selection = strtolower($cloud_selection); switch ($cloud_selection) { case 'count-asc': $order_by = 'tt.count ASC'; break; case 'random': $order_by = 'RAND()'; break; case 'name-asc': $order_by = 't.name ASC'; break; case 'name-desc': $order_by = 't.name DESC'; break; default: // count-desc $order_by = 'tt.count DESC'; break; } // Min usage $restict_usage = ''; $min_usage = (int) $min_usage; if ($min_usage != 0) { $restict_usage = ' AND tt.count >= ' . $min_usage; } $where = ''; $inclusions = ''; if (!empty($include)) { $exclude = ''; $interms = preg_split('/[\\s,]+/', $include); foreach ((array) $interms as $interm) { if (empty($inclusions)) { $inclusions = ' AND ( t.term_id = ' . intval($interm) . ' '; } else { $inclusions .= ' OR t.term_id = ' . intval($interm) . ' '; } } } if (!empty($inclusions)) { $inclusions .= ')'; } $where .= $inclusions; $exclusions = ''; if (!empty($exclude)) { $exterms = preg_split('/[\\s,]+/', $exclude); foreach ((array) $exterms as $exterm) { if (empty($exclusions)) { $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' '; } else { $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' '; } } } if (!empty($exclusions)) { $exclusions .= ')'; } $exclusions = apply_filters('list_terms_exclusions', $exclusions, $args); $where .= $exclusions; if (!empty($slug)) { $slug = sanitize_title($slug); $where .= " AND t.slug = '{$slug}'"; } if (!empty($name__like)) { $where .= " AND t.name LIKE '{$name__like}%'"; } if (strpos($st_name_like, ' ') != false || strpos($st_name_like, ' ') != null) { $tmp = ''; $sts = explode(' ', $st_name_like); foreach ((array) $sts as $st) { if (empty($st)) { continue; } $st = addslashes_gpc($st); $tmp .= " t.name LIKE '%{$st}%' OR "; } // Remove latest OR $tmp = substr($tmp, 0, strlen($tmp) - 4); $where .= " AND ( {$tmp} ) "; unset($tmp); } elseif (!empty($st_name_like)) { $where .= " AND t.name LIKE '%{$st_name_like}%'"; } if ('' != $parent) { $parent = (int) $parent; $where .= " AND tt.parent = '{$parent}'"; } if ($hide_empty && !$hierarchical) { $where .= ' AND tt.count > 0'; } $number_sql = ''; if (strpos($number, ',') != false || strpos($number, ',') != null) { $number_sql = $number; } else { $number = (int) $number; if ($number != 0) { $number_sql = 'LIMIT ' . $number; } } if ('all' == $fields) { $select_this = 't.*, tt.*'; } else { if ('ids' == $fields) { $select_this = 't.term_id'; } else { if ('names' == $fields) { $select_this == 't.name'; } } } // Limit posts date $limitdays_sql = ''; $limit_days = (int) $limit_days; if ($limit_days != 0) { $limitdays_sql = 'AND p.post_date > "' . date('Y-m-d H:i:s', time() - $limit_days * 86400) . '"'; } // Join posts ? $inner_posts = ''; if (!empty($limitdays_sql) | !empty($category_sql)) { $inner_posts = "\r\n\t\t\t\tINNER JOIN {$wpdb->term_relationships} AS tr ON tt.term_taxonomy_id = tr.term_taxonomy_id\r\n\t\t\t\tINNER JOIN {$wpdb->posts} AS p ON tr.object_id = p.ID"; } $query = "SELECT DISTINCT {$select_this}\r\n\t\t\tFROM {$wpdb->terms} AS t\r\n\t\t\tINNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id\r\n\t\t\t{$inner_posts}\r\n\t\t\tWHERE tt.taxonomy IN ( {$in_taxonomies} )\r\n\t\t\t{$limitdays_sql}\r\n\t\t\t{$category_sql}\r\n\t\t\t{$where}\r\n\t\t\t{$restict_usage}\r\n\t\t\tORDER BY {$order_by}\r\n\t\t\t{$number_sql}"; if ('all' == $fields) { $terms = $wpdb->get_results($query); if ($skip_cache != true) { update_term_cache($terms); } } elseif ('ids' == $fields) { $terms = $wpdb->get_col($query); } if (empty($terms)) { return array(); } if ($child_of || $hierarchical) { $children = _get_term_hierarchy($taxonomies[0]); if (!empty($children)) { $terms =& _get_term_children($child_of, $terms, $taxonomies[0]); } } // Update term counts to include children. if ($pad_counts) { _pad_term_counts($terms, $taxonomies[0]); } // Make sure we show empty categories that have children. if ($hierarchical && $hide_empty) { foreach ((array) $terms as $k => $term) { if (!$term->count) { $children = _get_term_children($term->term_id, $terms, $taxonomies[0]); foreach ((array) $children as $child) { if ($child->count) { continue 2; } } // It really is empty unset($terms[$k]); } } } reset($terms); if ($skip_cache != true) { $cache[$key] = $terms; wp_cache_set('get_terms', $cache, 'terms'); } $terms = apply_filters('get_terms', $terms, $taxonomies, $args); return $terms; }