WordPress开发笔记

WordPress自定义分类法在关联文章类型后台列表上显示下拉筛选功能的实现

如何实现为WordPress自定义分类法在关联文章类型后台列表上提供显示下拉筛选功能?

为你提供了一个完整的解决方案,可以实现为所有现有和未来的自定义分类法自动添加后台下拉筛选功能。下面是具体的实现代码和说明:

完整实现代码

将以下代码添加到你当前主题的 functions.php 文件中:

/**
 * 为所有自定义分类法在文章列表页添加下拉筛选功能
 * 自动适用于现有和未来创建的所有分类法
 */

// 1. 在文章列表顶部添加筛选下拉框
add_action('restrict_manage_posts', 'add_custom_taxonomy_filters');
function add_custom_taxonomy_filters() {
    global $typenow;

    // 只对文章类型为'post'的页面添加筛选,如需其他类型请修改或删除此条件
    if ($typenow != 'post') {
        return;
    }

    // 获取当前文章类型的所有分类法
    $taxonomies = get_object_taxonomies($typenow, 'objects');

    foreach ($taxonomies as $taxonomy) {
        // 跳过内置的'category'和'post_tag',只处理自定义分类法
        // 如果需要包含内置分类法,可以移除这个条件
        if (in_array($taxonomy->name, array('category', 'post_tag'))) {
            continue;
        }

        // 确保分类法是分层且在后端列中显示
        if (!$taxonomy->hierarchical || !$taxonomy->show_admin_column) {
            continue;
        }

        // 获取当前选中的值
        $selected = isset($_GET[$taxonomy->name]) ? $_GET[$taxonomy->name] : '';

        // 生成下拉菜单
        wp_dropdown_categories(array(
            'show_option_all' => sprintf(__('所有 %s'), $taxonomy->labels->name),
            'taxonomy'        => $taxonomy->name,
            'name'            => $taxonomy->name,
            'orderby'         => 'name',
            'selected'        => $selected,
            'value_field'     => 'slug', // 关键参数:使用slug而非ID
            'hierarchical'    => true,
            'show_count'      => false,
            'hide_empty'      => false,
            'echo'            => 1
        ));
    }
}

// 2. 处理筛选查询
add_filter('parse_query', 'convert_taxonomy_term_to_query_var');
function convert_taxonomy_term_to_query_var($query) {
    global $pagenow, $typenow;

    if ($pagenow != 'edit.php' || $typenow != 'post') {
        return $query;
    }

    // 获取所有分类法
    $taxonomies = get_object_taxonomies($typenow, 'names');

    foreach ($taxonomies as $taxonomy) {
        // 跳过内置分类法
        if (in_array($taxonomy, array('category', 'post_tag'))) {
            continue;
        }

        // 如果存在该分类法的筛选参数
        if (isset($_GET[$taxonomy]) && $_GET[$taxonomy] != '') {
            $term_slug = sanitize_text_field($_GET[$taxonomy]);

            // 设置查询参数
            $query->query_vars[$taxonomy] = $term_slug;
            $query->query_vars['tax_query'] = array(
                array(
                    'taxonomy' => $taxonomy,
                    'field'    => 'slug',
                    'terms'    => $term_slug
                )
            );
        }
    }

    return $query;
}

// 3. 为新创建的分类法自动添加筛选功能(通过监控分类法创建事件)
add_action('created_taxonomy', 'refresh_taxonomy_cache_on_new_taxonomy', 10, 2);
function refresh_taxonomy_cache_on_new_taxonomy($taxonomy, $object_type) {
    // 清除对象类型缓存,确保新分类法立即生效
    if (in_array('post', $object_type)) {
        wp_cache_delete('taxonomies-post', 'taxonomies');
    }
}

进阶版本:更强大的自动筛选功能

如果你需要更强大的功能(包括支持非分层分类法、更好的缓存处理等),可以使用以下增强版本:

/**
 * 增强版:为所有分类法自动添加下拉筛选功能
 * 支持分层和非分层分类法,更好的兼容性
 */

class AutoTaxonomyFilter {

    public function __construct() {
        add_action('restrict_manage_posts', array($this, 'add_taxonomy_filters'));
        add_filter('parse_query', array($this, 'apply_taxonomy_filters'));
        add_action('created_taxonomy', array($this, 'on_new_taxonomy'), 10, 2);
    }

    /**
     * 添加分类法筛选下拉框
     */
    public function add_taxonomy_filters() {
        global $typenow;

        // 指定要在哪些文章类型显示筛选框
        $allowed_post_types = apply_filters('auto_tax_filter_post_types', array('post'));

        if (!in_array($typenow, $allowed_post_types)) {
            return;
        }

        $taxonomies = get_object_taxonomies($typenow, 'objects');

        foreach ($taxonomies as $taxonomy) {
            // 跳过内置分类法(可选)
            if (in_array($taxonomy->name, array('category', 'post_tag'))) {
                continue;
            }

            // 可以根据需要调整筛选条件
            if (!$taxonomy->show_ui || !$taxonomy->show_admin_column) {
                continue;
            }

            $this->render_taxonomy_dropdown($taxonomy);
        }
    }

    /**
     * 渲染单个分类法的下拉菜单
     */
    private function render_taxonomy_dropdown($taxonomy) {
        $selected = isset($_GET[$taxonomy->name]) ? $_GET[$taxonomy->name] : '';

        // 对于分层分类法使用标准函数
        if ($taxonomy->hierarchical) {
            wp_dropdown_categories(array(
                'show_option_all' => sprintf(__('所有 %s'), $taxonomy->labels->name),
                'taxonomy'        => $taxonomy->name,
                'name'            => $taxonomy->name,
                'orderby'         => 'name',
                'selected'        => $selected,
                'value_field'     => 'slug',
                'hierarchical'    => true,
                'show_count'      => true,
                'hide_empty'      => false,
                'echo'            => 1
            ));
        } else {
            // 对于非分层分类法(如标签)使用自定义下拉
            $terms = get_terms(array(
                'taxonomy'   => $taxonomy->name,
                'hide_empty' => false
            ));

            if ($terms && !is_wp_error($terms)) {
                echo '<select name="' . esc_attr($taxonomy->name) . '" id="' . esc_attr($taxonomy->name) . '" class="postform">';
                echo '<option value="">' . sprintf(__('所有 %s'), $taxonomy->labels->name) . '</option>';

                foreach ($terms as $term) {
                    printf(
                        '<option value="%s" %s>%s</option>',
                        esc_attr($term->slug),
                        selected($selected, $term->slug, false),
                        esc_html($term->name)
                    );
                }
                echo '</select>';
            }
        }
    }

    /**
     * 应用分类法筛选到查询
     */
    public function apply_taxonomy_filters($query) {
        global $pagenow, $typenow;

        if ($pagenow != 'edit.php' || !$query->is_main_query()) {
            return $query;
        }

        $allowed_post_types = apply_filters('auto_tax_filter_post_types', array('post'));

        if (!in_array($typenow, $allowed_post_types)) {
            return $query;
        }

        $taxonomies = get_object_taxonomies($typenow, 'names');
        $tax_query = array();

        foreach ($taxonomies as $taxonomy) {
            if (isset($_GET[$taxonomy]) && $_GET[$taxonomy] != '') {
                $term_slug = sanitize_text_field($_GET[$taxonomy]);

                $tax_query[] = array(
                    'taxonomy' => $taxonomy,
                    'field'    => 'slug',
                    'terms'    => $term_slug
                );
            }
        }

        if (!empty($tax_query)) {
            $tax_query['relation'] = 'AND';
            $query->set('tax_query', $tax_query);
        }

        return $query;
    }

    /**
     * 当新分类法创建时刷新缓存
     */
    public function on_new_taxonomy($taxonomy, $object_type) {
        foreach ($object_type as $post_type) {
            wp_cache_delete("taxonomies-{$post_type}", 'taxonomies');
        }
    }
}

// 初始化自动筛选功能
new AutoTaxonomyFilter();

/**
 * 扩展支持自定义文章类型(可选)
 * 使用示例:为'product'文章类型也添加筛选
 */
add_filter('auto_tax_filter_post_types', function($post_types) {
    $post_types[] = 'product'; // 添加你的自定义文章类型
    return $post_types;
});

关键配置说明

1. 核心参数解释

  • value_field => 'slug':必须设置为slug,这是筛选能正常工作的关键
  • show_admin_column => true:确保分类法在后台文章列表显示列
  • hierarchical => true:适用于分层分类法(类似分类目录)

2. 自定义配置

  • 修改适用的文章类型:更改 $allowed_post_types 数组来指定哪些文章类型显示筛选框
  • 包含/排除特定分类法:修改跳过条件来包含或排除特定分类法
  • 样式自定义:可以通过CSS对下拉框进行样式美化

3. 使用方法

  1. 将代码添加到主题的 functions.php 文件
  2. 刷新WordPress后台文章列表页
  3. 现在所有现有和未来创建的自定义分类法都会自动显示下拉筛选框

这个解决方案会自动检测所有分类法,包括通过SCF插件创建的新分类法,并立即生效。代码也考虑了缓存刷新机制,确保新创建的分类法能够即时显示筛选功能。


仅为分层分类法添加下拉筛选功能

看来您想更精准地为分层分类法(比如像分类目录那样有层级关系的)添加后台筛选功能。下面我为您提供一个专注且完整的解决方案,并解释如何区分处理分层与非分层分类法。

区分分层与非分层分类法

核心在于判断分类法的 hierarchical 属性。

  • 分层分类法:类似于“分类目录”,支持父子层级关系。在代码上,其 hierarchical 属性为 true。通常使用 wp_dropdown_categories 函数来生成下拉框。
  • 非分层分类法:类似于“标签”,没有层级关系。其 hierarchical 属性为 false。筛选它们的界面通常不同,例如可能是一个标签云而非下拉列表。

完整代码实现

以下代码会自动为您所有的分层分类法在文章列表页添加下拉筛选框。

将下面的代码添加到您当前主题的 functions.php 文件中:

/**
 * 在后台文章列表页为分层分类法添加下拉筛选框
 */
add_action('restrict_manage_posts', 'add_hierarchical_taxonomy_filters');
function add_hierarchical_taxonomy_filters() {
    global $typenow;

    // 1. 指定要在哪些文章类型页面上显示筛选框
    $allowed_post_types = apply_filters('hierarchical_tax_filter_post_types', array('post')); // 默认为文章,可按需添加
    if (!in_array($typenow, $allowed_post_types)) {
        return;
    }

    // 2. 获取当前文章类型的所有分类法
    $taxonomies = get_object_taxonomies($typenow, 'objects');

    foreach ($taxonomies as $taxonomy) {
        // 3. 关键判断:只处理分层分类法,并跳过内置的“标签”
        if (!$taxonomy->hierarchical || $taxonomy->name == 'post_tag') {
            continue;
        }

        // 4. 获取当前选中的术语(用于保持筛选状态)
        $selected = isset($_GET[$taxonomy->name]) ? $_GET[$taxonomy->name] : '';

        // 5. 使用 wp_dropdown_categories 生成下拉菜单
        wp_dropdown_categories(array(
            'show_option_all' => sprintf(__('所有 %s'), $taxonomy->labels->name), // 显示如“所有分类”
            'taxonomy'        => $taxonomy->name,
            'name'            => $taxonomy->name, // name属性必须与分类法名称一致
            'orderby'         => 'name',
            'selected'        => $selected,
            'value_field'     => 'slug', // 关键参数:使用术语别名作为值,确保筛选有效
            'hierarchical'    => true, // 保持层级结构显示
            'show_count'      => false, // 是否在术语后显示文章数量
            'hide_empty'      => false, // 是否显示没有文章的分类
            'echo'            => 1
        ));
    }
}

/**
 * 使分类法筛选生效
 */
add_filter('parse_query', 'apply_hierarchical_taxonomy_filters');
function apply_hierarchical_taxonomy_filters($query) {
    global $pagenow, $typenow;

    if ($pagenow !== 'edit.php' || !$query->is_main_query()) {
        return $query;
    }

    $allowed_post_types = apply_filters('hierarchical_tax_filter_post_types', array('post'));
    if (!in_array($typenow, $allowed_post_types)) {
        return $query;
    }

    // 循环检查每个分类法的筛选参数
    $taxonomies = get_object_taxonomies($typenow, 'names');
    $tax_query = array();

    foreach ($taxonomies as $taxonomy) {
        if (isset($_GET[$taxonomy]) && $_GET[$taxonomy] != '') {
            $term_slug = sanitize_text_field($_GET[$taxonomy]);
            // 将筛选条件加入tax_query
            $tax_query[] = array(
                'taxonomy' => $taxonomy,
                'field'    => 'slug', // 与下拉框中的 value_field 保持一致
                'terms'    => $term_slug
            );
        }
    }

    // 如果有筛选条件,则设置到查询中
    if (!empty($tax_query)) {
        // 如果同时筛选多个分类法,它们之间的关系是“与”
        $tax_query['relation'] = 'AND';
        $query->set('tax_query', $tax_query);
    }

    return $query;
}

关键点说明与自定义

核心逻辑:代码通过 if (!$taxonomy->hierarchical) { continue; } 明确跳过了非分层分类法,确保只为您需要的分类法添加功能。

value_field 参数:这是筛选能否成功的重中之重,必须设置为 'slug'。如果设置为 term_id(默认值),筛选将无法正常工作。

自定义文章类型:默认代码只对内置的“文章”类型生效。如果您需要为自定义文章类型(如 product, book 等)添加此功能,可以使用下面的过滤器:

// 将下面代码也放入 functions.php,在上一段代码之后
add_filter('hierarchical_tax_filter_post_types', 'my_custom_post_type_filter');
function my_custom_post_type_filter($post_types) {
    // 将您的文章类型slug加入数组,例如 'product'
    $post_types[] = 'your_custom_post_type';
    return $post_types;
}

排除特定分类法:如果您想排除某个特定的分层分类法(例如不想让“类别”显示筛选),可以在循环内添加判断,例如:

if ($taxonomy->name == 'category') { continue; // 跳过分类目录 }

增强版:更灵活的配置

如果您希望有更细粒度的控制(比如同时为某些非分层分类法添加自定义筛选),可以考虑基于分类法名称或属性进行判断。下面的表格对比了两种常见的筛选界面需求:

分类法类型特点推荐后台筛选方式备注
分层分类法有父子层级关系,如产品分类、地区下拉选择框 (wp_dropdown_categories)本回答实现的方案,直观展示层级
非分层分类法无层级关系,如标签、关键词文本输入框(标签云)自定义下拉默认界面不同,如需实现下拉筛选,需自定义遍历术语