剖析 WordPress `WP_Term_Query` 类的源码:它如何封装分类术语查询,并提供灵活的参数。

各位观众,欢迎来到今天的 WordPress 源码解剖现场! 今天我们要扒的是 WordPress 里一个“老实巴交”但又至关重要的类:WP_Term_Query。 别看它名字长,其实就是个“分类术语查询器”。 想象一下,你需要从数据库里捞出一堆分类目录、标签、或者自定义分类法的术语(term),它就是那个帮你整理参数、发送请求、然后把结果打包送回来的“快递员”。

咱们今天就来拆解一下这个“快递员”,看看它到底是怎么工作的。

开场白: 为什么要解剖 WP_Term_Query

你可能会问,WordPress 提供了 get_terms() 函数,直接用它不就好了? 为什么要费劲巴拉地研究 WP_Term_Query 呢? 问得好!

get_terms() 函数底层就是用的 WP_Term_Queryget_terms() 就像是“傻瓜相机”,给你预设好了一些参数,方便快速拍照。 但如果你想玩转光圈、快门、ISO,拍出更有创意的照片,那就需要了解相机的底层原理。 WP_Term_Query 就是那个让你了解底层原理的“工具书”。

理解 WP_Term_Query,你就能:

  • 更灵活地控制术语查询,实现更复杂的业务逻辑。
  • 更好地理解 get_terms() 函数的底层工作机制。
  • 在某些特殊情况下,直接使用 WP_Term_Query,避免不必要的性能损耗。

第一部分: 类的基本结构

首先,我们来看看 WP_Term_Query 类的基本骨架。 这个类定义在 wp-includes/class-wp-term-query.php 文件里。 打开文件,你会看到类似下面的结构:

<?php

/**
 * Core class used to implement the term query.
 *
 * @since 4.6.0
 */
class WP_Term_Query {

    /**
     * SQL query string.
     *
     * @since 4.6.0
     * @access public
     * @var string
     */
    public $request;

    /**
     * List of term IDs.
     *
     * @since 4.6.0
     * @access public
     * @var array
     */
    public $terms;

    /**
     * The term query arguments.
     *
     * @since 4.6.0
     * @access public
     * @var array
     */
    public $query_vars = array();

    /**
     * The taxonomy being queried.
     *
     * @since 4.6.0
     * @access public
     * @var array
     */
    public $taxonomies = array();

    /**
     * A flat array of taxonomy terms.
     *
     * @since 4.6.0
     * @access public
     * @var array
     */
    public $_taxonomies = array();

    /**
     * Cache key for the current query.
     *
     * @since 4.6.0
     * @access public
     * @var string
     */
    public $cache_key;

    /**
     * Whether to prime cache for found terms.
     *
     * @since 4.6.0
     * @access public
     * @var bool
     */
    public $cache_prime;

    /**
     * Constructor.
     *
     * @since 4.6.0
     * @access public
     *
     * @param string|array $query {
     *     Array or string of term query arguments. See {@see WP_Term_Query::get_terms()}
     *     for information on accepted arguments.
     *
     *     @type array       'taxonomy'         Taxonomy or taxonomies to query.
     *     @type string      'search'           Search term.
     *     @type string      'orderby'          How to order matching terms. Accepts 'name', 'slug',
     *                                           'term_group', 'term_id', 'id', 'description', 'count',
     *                                           'none', or a custom field key. Default 'name'.
     *     @type string      'order'            Whether to order terms in ascending or descending order.
     *                                           Accepts 'ASC', 'DESC'. Default 'ASC'.
     *     @type bool        'hide_empty'       Whether to hide terms not assigned to any posts.
     *                                           Default false.
     *     @type array       'include'          Array of term IDs to include. Default empty array.
     *     @type array       'exclude'          Array of term IDs to exclude. Default empty array.
     *     @type array       'exclude_tree'     Array of term IDs to exclude along with all of their
     *                                           descendants. Default empty array.
     *     @type int         'number'           Maximum number of terms to return. Default is to return
     *                                           all terms.
     *     @type int         'offset'           The number of terms to skip. Default 0.
     *     @type string      'fields'           Which fields to return. Accepts 'all', 'ids', 'names',
     *                                           'id=>name', 'id=>parent'. Default 'all'.
     *     @type string|array 'slug'           Slug or array of slugs to filter by.
     *     @type bool        'hierarchical'     Whether to include terms which are hierarchical
     *                                           descendants of the terms included in the 'include'
     *                                           argument. Default true.
     *     @type string      'name__like'       Retrieve terms where the name is LIKE the input string.
     *     @type string      'description__like' Retrieve terms where the description is LIKE the input
     *                                           string.
     *     @type bool        'pad_counts'       Whether to pad the count of each term with the number
     *                                           of its descendants. Default false.
     *     @type string      'get'              What to return. Accepts ''|'all' for all (default),
     *                                           'id=>parent' for term ID => parent term ID pairs,
     *                                           'id=>name' for term ID => term name pairs,
     *                                           'count' for the total term count.
     *     @type string      'name'             Retrieve terms with this name.
     *     @type int         'child_of'         Term ID to retrieve child terms of. Default 0.
     *     @type int         'parent'           Term ID to retrieve direct-child terms of. Default empty.
     *     @type string|array 'childless'        True to limit results to terms that have no children.
     *                                           False to disable the children filter. Default false.
     *     @type string      'cache_domain'     Unique cache domain to preemptively search and store
     *                                           terms in. Default 'core'.
     *     @type bool        'update_term_meta_cache' Whether to prime term meta cache for any found terms.
     *                                           Default true.
     *     @type string      'meta_key'         Meta key to filter by.
     *     @type string      'meta_value'       Meta value to filter by.
     *     @type string      'meta_compare'     Comparison operator to test the 'meta_value'. Accepts
     *                                           '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE',
     *                                           'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'EXISTS'
     *                                           (alias of 'TRUE'), and 'NOT EXISTS' (alias of 'FALSE').
     *                                           Default '='.
     *     @type array       'meta_query'       An associative array of meta query clauses, or array of
     *                                           meta query clauses. See WP_Meta_Query::get_sql() for
     *                                           more information.
     *     @type string      'taxonomy'         Taxonomy or taxonomies to query.
     * }
     */
    public function __construct( $query = '' ) {
        if ( ! empty( $query ) ) {
            $this->query( $query );
        }
    }

    /**
     * Parses arguments passed to the term query with default query parameters.
     *
     * @since 4.6.0
     * @access public
     *
     * @param string|array $query Array of query variables.
     * @return array Array of parsed query variables.
     */
    public function parse_query( $query = '' ) {
        $this->query_vars = wp_parse_args( $query, $this->query_vars );

        $this->query_vars = sanitize_term_field( 'query_vars', $this->query_vars, 0, 'term', 'query' );

        /**
         * Filters the term query arguments.
         *
         * @since 4.6.0
         *
         * @param array $query_vars The array of term query variables.
         * @param WP_Term_Query $this The WP_Term_Query instance.
         */
        $this->query_vars = apply_filters( 'terms_clauses', $this->query_vars, $this );

        return $this->query_vars;
    }

    /**
     * Sets up the WordPress query for retrieving terms.
     *
     * @since 4.6.0
     * @access public
     *
     * @param string|array $query Array of query variables.
     * @return array|int List of terms/term IDs, or number of terms when 'count' is passed as a query var.
     */
    public function query( $query ) {
        $this->query_vars = $this->parse_query( $query );

        /**
         * Fires before the term query.
         *
         * @since 4.6.0
         *
         * @param array $query_vars The array of term query variables.
         * @param WP_Term_Query $this The WP_Term_Query instance.
         */
        do_action( 'pre_get_terms', $this->query_vars, $this );

        $this->terms = $this->get_terms( $this->query_vars );

        return $this->terms;
    }

    /**
     * Generates SQL clauses to be appended to the main SQL query.
     *
     * @since 4.6.0
     * @access protected
     *
     * @param array $args Query arguments.
     * @return array An associative array of SQL clauses.
     */
    protected function get_sql_clauses( $args = array() ) {
        global $wpdb;

        $args = wp_parse_args( $args, array(
            'orderby' => 'name',
            'order'   => 'ASC',
            'fields'  => 'all',
        ) );

        $orderby = $args['orderby'];
        $order   = $args['order'];
        $fields  = $args['fields'];

        $where = '';
        $join  = '';
        $sort  = '';
        $groupby = '';
        $limits = '';

        // Taxonomy query.
        $this->transform_query( $args, 'taxonomy', 'term_taxonomy', 'taxonomy', $this->taxonomies );
        $clauses = $this->get_tax_sql( $args );

        if ( ! empty( $clauses['where'] ) ) {
            $where .= ' AND ' . $clauses['where'];
        }

        if ( ! empty( $clauses['join'] ) ) {
            $join .= $clauses['join'];
        }

        // Meta query.
        $meta_query = new WP_Meta_Query();
        $meta_query->parse_query_vars( $args );
        $meta_sql = $meta_query->get_sql( 'term', $wpdb->terms, 'term_id' );

        if ( ! empty( $meta_sql['where'] ) ) {
            $where .= ' AND ' . $meta_sql['where'];
        }

        if ( ! empty( $meta_sql['join'] ) ) {
            $join .= $meta_sql['join'];
        }

        $search = '';

        if ( isset( $args['search'] ) && '' !== $args['search'] ) {
            $term_search = esc_sql( $wpdb->esc_like( $args['search'] ) );
            $search      = "AND ( t.name LIKE '%{$term_search}%' )";
        }

        /**
         * Filters the terms search SQL clause.
         *
         * @since 5.1.0
         *
         * @param string      $search SQL search clause.
         * @param WP_Term_Query $this The WP_Term_Query instance.
         */
        $search = apply_filters( 'get_terms_search_sql', $search, $this );

        $where .= $search;

        // include / exclude.
        if ( ! empty( $args['include'] ) ) {
            $ids    = implode( ',', array_map( 'intval', $args['include'] ) );
            $where .= " AND t.term_id IN ($ids)";
        } elseif ( ! empty( $args['exclude'] ) ) {
            $ids    = implode( ',', array_map( 'intval', $args['exclude'] ) );
            $where .= " AND t.term_id NOT IN ($ids)";
        }

        if ( ! empty( $args['slug'] ) ) {
            if ( is_array( $args['slug'] ) ) {
                $slug = "'" . implode( "', '", array_map( 'esc_sql', $args['slug'] ) ) . "'";
            } else {
                $slug = "'" . esc_sql( $args['slug'] ) . "'";
            }

            $where .= " AND t.slug IN ($slug)";
        }

        if ( isset( $args['name'] ) ) {
            $name = esc_sql( $args['name'] );
            $where .= " AND t.name = '$name'";
        }

        if ( isset( $args['name__like'] ) ) {
            $name_like = esc_sql( $wpdb->esc_like( $args['name__like'] ) );
            $where .= " AND t.name LIKE '%$name_like%'";
        }

        if ( isset( $args['description__like'] ) ) {
            $description_like = esc_sql( $wpdb->esc_like( $args['description__like'] ) );
            $where .= " AND tt.description LIKE '%$description_like%'";
        }

        if ( ! empty( $args['term_id'] ) ) {
            $term_id = intval( $args['term_id'] );
            $where .= " AND t.term_id = '$term_id'";
        }

        // Hide empty terms.
        if ( isset( $args['hide_empty'] ) && $args['hide_empty'] ) {
            $where .= ' AND tt.count > 0';
        }

        // 'child_of' makes the query slow, so use it with care.
        if ( ! empty( $args['child_of'] ) ) {
            $child_of = intval( $args['child_of'] );
            if ( isset( $args['hierarchical'] ) && ! $args['hierarchical'] ) {
                $where .= " AND tt.parent = $child_of";
            } else {
                $term_children = get_term_children( $child_of, $this->taxonomies[0] );
                if ( empty( $term_children ) ) {
                    $where .= ' AND 0 = 1';
                } else {
                    $ids = implode( ',', array_map( 'intval', $term_children ) );
                    $where .= " AND t.term_id IN ($ids)";
                }
            }
        }

        if ( isset( $args['parent'] ) ) {
            if ( is_numeric( $args['parent'] ) ) {
                $parent = intval( $args['parent'] );
                $where .= " AND tt.parent = '$parent'";
            } else {
                if ( 'any' === $args['parent'] ) {
                    $where .= ' AND tt.parent > 0';
                } else {
                    $where .= ' AND tt.parent = 0';
                }
            }
        }

        if ( isset( $args['childless'] ) ) {
            if ( filter_var( $args['childless'], FILTER_VALIDATE_BOOLEAN ) ) {
                $where .= ' AND tt.term_id NOT IN ( SELECT tt.parent FROM ' . $wpdb->term_taxonomy . ' tt WHERE tt.parent != 0 )';
            }
        }

        /*
         * 'get' => 'all' is the only supported value.
         *
         * Other values of 'get' supported by get_terms() are deprecated
         * as of 4.5.0, as they are wasteful.
         */
        if ( isset( $args['get'] ) && 'count' === $args['get'] ) {
            $fields = 'count';
        }

        switch ( $orderby ) {
            case 'none':
                break;
            case 'term_id':
            case 'id':
                $sort = 'ORDER BY t.term_id';
                break;
            case 'name':
                $sort = 'ORDER BY t.name';
                break;
            case 'slug':
                $sort = 'ORDER BY t.slug';
                break;
            case 'term_group':
                $sort = 'ORDER BY t.term_group';
                break;
            case 'description':
                $sort = 'ORDER BY tt.description';
                break;
            case 'count':
                $sort = 'ORDER BY tt.count';
                break;
            case 'parent':
                $sort = 'ORDER BY tt.parent';
                break;
            case 'include':
                $sort = 'ORDER BY FIELD(t.term_id, ' . implode( ',', array_map( 'intval', $args['include'] ) ) . ')';
                break;
            default:
                $sort = 'ORDER BY t.name';
                break;
        }

        if ( ! empty( $sort ) ) {
            $sort .= ' ' . $order;
        }

        if ( ! empty( $args['number'] ) && ! empty( $args['offset'] ) ) {
            $limits = $wpdb->prepare( 'LIMIT %d, %d', $args['offset'], $args['number'] );
        } elseif ( ! empty( $args['number'] ) ) {
            $limits = $wpdb->prepare( 'LIMIT %d', $args['number'] );
        } elseif ( ! empty( $args['offset'] ) ) {
            $limits = $wpdb->prepare( 'LIMIT %d, %d', $args['offset'], PHP_INT_MAX );
        }

        return compact( 'where', 'join', 'sort', 'fields', 'groupby', 'limits' );
    }

    /**
     * Get terms.
     *
     * @since 4.6.0
     * @access public
     *
     * @param array $query_vars Term query arguments.
     * @return array|int List of terms/term IDs, or number of terms when 'count' is passed as a query var.
     */
    public function get_terms( $query_vars = array() ) {
        global $wpdb;

        $defaults = array(
            'search'                    => '',
            'cache_domain'              => 'core',
            'update_term_meta_cache'    => true,
        );

        $query_vars = wp_parse_args( $query_vars, $defaults );

        /**
         * Fires just before calling the terms query.
         *
         * @since 4.6.0
         *
         * @param WP_Term_Query $this The WP_Term_Query instance.
         */
        do_action( 'pre_get_terms', $this );

        /**
         * Filters the terms query before querying the database.
         *
         * @since 4.6.0
         *
         * @param array         $clauses   An array of SQL clauses.
         * @param WP_Term_Query $this The WP_Term_Query instance.
         */
        $clauses = apply_filters( 'terms_clauses', $this->get_sql_clauses( $query_vars ), $this );

        $fields = isset( $clauses['fields'] ) ? $clauses['fields'] : '';

        // Fields.
        if ( 'count' === $fields ) {
            $fields = 'COUNT(*)';
        } else {
            $fields = 't.*, tt.*';
        }

        // Query.
        $found_terms = array();
        $this->request = "SELECT $fields FROM {$wpdb->terms} AS t INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id {$clauses['join']} WHERE 1=1 {$clauses['where']} {$clauses['groupby']} {$clauses['sort']} {$clauses['limits']}";

        if ( 'count' === $fields ) {
            $this->request = "SELECT $fields FROM {$wpdb->term_taxonomy} AS tt {$clauses['join']} WHERE 1=1 {$clauses['where']} {$clauses['groupby']}";
        }

        $this->request = apply_filters( 'terms_request', $this->request, $query_vars, $this );

        if ( 'count' === $fields ) {
            $count = $wpdb->get_var( $this->request );

            return absint( $count );
        }

        $cache_key = $this->cache_key();
        $cache = wp_cache_get( $cache_key, 'terms' );
        if ( false !== $cache ) {
            $this->terms = $cache;
            /**
             * Fires after terms have been retrieved from the cache.
             *
             * @since 4.6.0
             *
             * @param array         $this->terms The list of terms.
             * @param WP_Term_Query $this The WP_Term_Query instance.
             */
            do_action( 'get_terms_from_cache', $this->terms, $this );

            return $this->terms;
        }

        $terms = $wpdb->get_results( $this->request );

        // Prime term meta cache.
        if ( $query_vars['update_term_meta_cache'] ) {
            update_term_meta_cache( wp_list_pluck( $terms, 'term_id' ) );
        }

        // Convert to WP_Term objects.
        $term_results = array();
        if ( ! empty( $terms ) ) {
            foreach ( $terms as $term ) {
                $term_results[] = get_term( $term );
            }
        }

        $this->terms = $term_results;

        wp_cache_set( $cache_key, $this->terms, 'terms', DAY_IN_SECONDS );

        /**
         * Fires after terms have been retrieved from the database.
         *
         * @since 4.6.0
         *
         * @param array         $this->terms The list of terms.
         * @param WP_Term_Query $this The WP_Term_Query instance.
         */
        do_action( 'get_terms', $this->terms, $this );

        return $this->terms;
    }

    /**
     * Generates a cache key.
     *
     * @since 4.6.0
     * @access public
     *
     * @return string Unique cache key.
     */
    public function cache_key() {
        global $wpdb;

        $key = md5( serialize( array_merge( $this->query_vars, array(
            'taxonomies' => $this->taxonomies,
            'db_version' => get_option( 'db_version' ),
            'blog_id'    => get_current_blog_id(),
        ) ) ) );

        $this->cache_key = sanitize_key( $key );

        return $this->cache_key;
    }

    /**
     * Used internally to transform query variables to format expected in
     * SQL.
     *
     * @since 4.6.0
     * @access protected
     *
     * @param array  $query         Query variables.
     * @param string $query_key     The query key.
     * @param string $db_key        The database key.
     * @param string $key           The key.
     * @param array  $query_var     The query variable.
     */
    protected function transform_query( &$query, $query_key, $db_key, $key, &$query_var ) {
        if ( ! isset( $query[ $query_key ] ) ) {
            return;
        }

        $this->set_query_var( $query[ $query_key ], $query_var );

        if ( ! empty( $query_var ) ) {
            $query[ $db_key ] = $query_var;
        }

        unset( $query[ $query_key ] );
    }

    /**
     * Sets the value of a query variable.
     *
     * @since 4.6.0
     * @access protected
     *
     * @param array|string $value The query variable value.
     * @param array        $var   The query variable.
     */
    protected function set_query_var( $value, &$var ) {
        if ( ! is_array( $value ) ) {
            $value = preg_split( '/[,s]+/', $value );
        }

        $var = array_filter( array_unique( array_map( 'sanitize_key', $value ) ) );
    }

    /**
     * Get SQL for taxonomies.
     *
     * @since 4.6.0
     * @access protected
     *
     * @param array $args Query arguments.
     * @return array SQL clauses relating to taxonomy queries.
     */
    protected function get_tax_sql( $args = array() ) {
        global $wpdb;

        $where = '';
        $join  = '';

        $taxonomies = isset( $args['term_taxonomy'] ) ? $args['term_taxonomy'] : array();

        if ( ! empty( $taxonomies ) ) {
            $taxonomies = "'" . implode( "', '", array_map( 'esc_sql', $taxonomies ) ) . "'";
            $where .= "AND tt.taxonomy IN ($taxonomies)";
        }

        return compact( 'where', 'join' );
    }

    /**
     * Determines whether the query is for a taxonomy archive page.
     *
     * @since 4.6.0
     * @access public
     *
     * @param string|array $taxonomy Optional. Taxonomy name or array of taxonomy names to check against.
     *                                Default empty.
     * @return bool Whether the query is for an existing taxonomy archive page.
     */
    public function is_taxonomy( $taxonomy = '' ) {
        if ( ! is_array( $taxonomy ) ) {
            $taxonomy = array( $taxonomy );
        }

        if ( empty( $taxonomy ) || empty( $this->taxonomies ) ) {
            return false;
        }

        $intersect = array_intersect( $taxonomy, $this->taxonomies );

        return ! empty( $intersect );
    }
}

我们来简单解读一下:

  • $request: 存储最终的 SQL 查询语句。 这是个很重要的属性,你可以通过它看到 WP_Term_Query 最终生成的 SQL,方便调试。
  • $terms: 存储查询结果,也就是符合条件的术语对象数组。
  • $query_vars: 存储查询参数,比如 taxonomyorderbyorder 等等。 这些参数决定了你要查询哪些术语,以及如何排序。
  • $taxonomies: 存储要查询的分类法名称。
  • __construct( $query = '' ): 构造函数,接收一个查询参数数组或者字符串,并调用 query() 方法来执行查询。
  • parse_query( $query = '' ): 解析查询参数,将传入的参数与默认参数合并,并进行安全过滤。
  • query( $query ): 执行查询的核心方法。 它会先调用 parse_query() 解析参数,然后调用 get_terms() 获取查询结果。
  • get_terms( $query_vars = array() ): 真正从数据库中获取术语的方法。 它会根据查询参数生成 SQL 语句,然后执行查询,并将结果返回。
  • get_sql_clauses( $args = array() ): 生成 SQL 语句的各个部分(WHERE, JOIN, ORDER BY, LIMIT)。 这是个很关键的方法,它决定了最终的 SQL 语句长什么样。
  • cache_key(): 生成缓存键,用于缓存查询结果。

第二部分: 查询参数详解

WP_Term_Query 提供了非常丰富的查询参数,可以满足各种各样的查询需求。 这些参数都可以在 get_terms() 函数中使用,也可以直接传递给 WP_Term_Query 的构造函数。

我们来逐一看看这些常用的参数:

参数名 类型 描述 默认值
taxonomy string/array 要查询的分类法名称。 可以是单个分类法名称,也可以是多个分类法名称的数组。
search string 搜索关键词。 可以根据术语的名称进行模糊搜索。
orderby string 排序方式。 常用的值有 name(按名称排序)、slug(按别名排序)、term_id(按 ID 排序)、count(按文章数排序)等。 'name'
order string 排序顺序。 ASC(升序)或 DESC(降序)。 'ASC'
hide_empty bool 是否隐藏没有文章关联的术语。 false
include array 要包含的术语 ID 数组。 只有这些 ID 的术语才会被返回。 array()
exclude array 要排除的术语 ID 数组。 这些 ID 的术语不会被返回。 array()
exclude_tree array 要排除的术语 ID 数组,以及它们的子术语。 array()
number int 返回的术语数量。 如果不设置,则返回所有符合条件的术语。
offset int 偏移量。 从第几个术语开始返回。 0
fields string 返回的字段。 常用的值有 all(返回所有字段,默认值)、ids(只返回 ID 数组)、names(只返回名称数组)、id=>name(返回 ID => 名称的关联数组)。 'all'
slug string/array 要查询的术语别名。 可以是单个别名,也可以是多个别名的数组。
hierarchical bool 是否返回层级关系的术语。 只在 taxonomy 为层级分类法(如分类目录)时有效。 true
name__like string 模糊匹配术语名称。
description__like string 模糊匹配术语描述。
pad_counts bool 是否填充文章数。 对于层级分类法,如果设置为 true,则每个术语的文章数会包含其子术语的文章数。 false
parent int 只返回指定父级术语的子术语。
child_of int 返回指定术语的所有子术语。 0
meta_key string 自定义字段的键名。 可以根据自定义字段的值进行过滤。
meta_value string 自定义字段的值。 需要和 meta_key 配合使用。
meta_compare string 自定义字段的比较操作符。 常用的值有 =!=><LIKE 等。 '='
meta_query array 更复杂的自定义字段查询。 可以组合多个 meta_keymeta_valuemeta_compare 条件。 具体用法可以参考 WP_Meta_Query 类。 array()
update_term_meta_cache bool 是否更新术语的元数据缓存。 如果设置为 true,则会一次性加载所有术语的元数据,可以提高性能。 true
childless bool 是否只返回没有子分类的分类,或者返回所有分类。true:只返回没有子分类的分类,false:返回所有分类,默认值false false

第三部分: 代码示例

光说不练假把式,咱们来几个实际的例子。

例子 1: 获取所有 "category" 分类法的术语,按名称升序排列,隐藏空分类。


$args = array(
    'taxonomy'   => 'category',
    'orderby'    => 'name',
    'order'      => 'ASC',
    'hide_empty' => true,

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注