it-swarm.cn

如何通过自定义字段对WordPress自定义帖子类型的管理区域进行排序

编辑我的一个自定义帖子类型时,我希望能够按自定义字段而不是发布日期列出所有条目(对于自定义帖子类型可能不相关)。我从一篇关于自定义帖子类型的博客文章的评论中得到了一个主角,并且作者说这是可能的,他甚至做了它,所以你可以点击列名称进行自定义排序。他提到了我在自己的评论中提到的 posts_orderby 函数,但现在我可以找到博客文章了。有什么建议?我看到了一个使用的解决方案

add_action('wp', 'check_page');

并且check_page函数使用 add_filter 来更改查询,但我很确定它只能在主题文件中工作,而不能在管理区域中工作。

52
tooshel

正如您可能想象的那样,由于缺乏答案,解决方案并非完全无关紧要。我所做的是创建一个有点自包含的示例,假定自定义帖子类型为“movie”,自定义字段键为“Genre”。

免责声明:这适用于WP3.0,但我无法确定它是否适用于早期版本。

你基本上需要钩住两(2)个钩子才能使它工作,而另外两个钩子(2)使它变得明显和有用。

第一个钩子是'restrict_manage_posts',它允许您在帖子列表上方的区域中发出HTML <select>,其中“批量操作”和“显示日期”过滤。提供的代码将生成“Sort by:”功能,如此屏幕片段所示:

How to Create Sort By functionality for a Custom Post Type in the WordPress Admin
(来源: mikeschinkel.com

代码使用直接SQL,因为没有WordPress API函数来提供帖子类型的所有meta_keys列表(听起来像未来 trac 给我的票......)无论如何,这里是代码。注意它从$_GET中获取帖子类型并验证以确保它既是一个有效的帖子类型post_type_exists()又是一个movie帖子类型(这两个检查都是矫枉过正但我这样做是为了告诉你如果你不想努力编码帖子类型。)最后我使用sortby URL参数,因为它与WordPress中的任何其他内容都不冲突:

add_action('restrict_manage_posts','restrict_manage_movie_sort_by_genre');
function restrict_manage_movie_sort_by_genre() {
    if (isset($_GET['post_type'])) {
        $post_type = $_GET['post_type'];
        if (post_type_exists($post_type) && $post_type=='movie') {
            global $wpdb;
            $sql=<<<SQL
SELECT pm.meta_key FROM {$wpdb->postmeta} pm
INNER JOIN {$wpdb->posts} p ON p.ID=pm.post_id
WHERE p.post_type='movie' AND pm.meta_key='Genre'
GROUP BY pm.meta_key
ORDER BY pm.meta_key
SQL;
            $results = $wpdb->get_results($sql);
            $html = array();
            $html[] = "<select id=\"sortby\" name=\"sortby\">";
            $html[] = "<option value=\"None\">No Sort</option>";
            $this_sort = $_GET['sortby'];
            foreach($results as $meta_key) {
                $default = ($this_sort==$meta_key->meta_key ? ' selected="selected"' : '');
                $value = esc_attr($meta_key->meta_key);
                $html[] = "<option value=\"{$meta_key->meta_key}\"$default>{$value}</option>";
            }
            $html[] = "</select>";
            echo "Sort by: " . implode("\n",$html);
        }
    }
}

第二个必需步骤是使用parse_query挂钩,该挂钩是在WordPress决定应该运行什么查询之后但在运行查询之前调用的。在这里,我们在查询的meta_key数组中设置orderbyquery_var的值 query_posts()orderby参数的Codex 中记录。我们测试以确保:

  1. 我们在管理员(is_admin()),
  2. 我们在页面上列出了admin($pagenow=='edit.php')中的帖子,
  3. 已使用post_type URL参数调用该页面,该参数等于movie,和
  4. 该页面也使用sortby URL参数调用,并且未传递值为“None

如果所有这些测试都通过了,那么我们将query_vars记录为_(here )设置为meta_value,将sortby值设置为'Genre':

add_filter( 'parse_query', 'sort_movie_by_meta_value' );
function sort_movie_by_meta_value($query) {
    global $pagenow;
    if (is_admin() && $pagenow=='edit.php' &&
        isset($_GET['post_type']) && $_GET['post_type']=='movie' && 
        isset($_GET['sortby'])  && $_GET['sortby'] !='None')  {
        $query->query_vars['orderby'] = 'meta_value';
        $query->query_vars['meta_key'] = $_GET['sortby'];
    }
}

这就是你需要做的一切;不需要“posts_order”或“wp”挂钩!当然,你确实需要做更多的事情;你需要在你的页面上添加一些列出帖子的列,这样你才能真正看到它正在排序的值,否则用户会感到很困惑。所以添加manage_{$post_type}_posts_columns钩子,在本例中为manage_movie_posts_columns。这个钩子传递了默认的列数组,为简单起见,我只用两个标准列替换它;复选框(cb)和帖子名称(title)。 (您可以使用print_r()检查posts_columns以查看默认情况下还有其他内容。)

当有sortby URL参数且不是None时,我决定添加“Sorted By:”:

add_action('manage_movie_posts_columns', 'manage_movie_posts_columns');
function manage_movie_posts_columns($posts_columns) {
    $posts_columns = array(
        'cb' => $posts_columns['cb'],
        'title' => 'Movie Name',
        );
    if (isset($_GET['sortby']) && $_GET['sortby'] !='None') 
        $posts_columns['meta_value'] = 'Sorted By';

    return $posts_columns;
}

最后,当有适当的帖子类型的帖子以及is_admin()manage_pages_custom_column的可能冗余测试时,我们使用$pagenow=='edit.php'钩子来实际显示值。当存在sortby URL参数时,我们提取自定义字段值,该值通过列表中的显示进行排序。这是它的样子(记住,这是测试数据所以没有关于电影分类的花生画廊的评论!:):

Custom Columns added for a Custom Post Type in the WordPress Admin
(来源: mikeschinkel.com

以下是代码:

add_action('manage_pages_custom_column', 'manage_movie_pages_custom_column',10,2);
function manage_movie_pages_custom_column($column_name,$post_id) {
    global $pagenow;
    $post = get_post($post_id);
    if ($post->post_type=='movie' && is_admin() && $pagenow=='edit.php')  {
        switch ($column_name) {
            case 'meta_value':
                if (isset($_GET['sortby']) && $_GET['sortby'] !='None') {
                    echo get_post_meta($post_id,$_GET['sortby'],true);
                }
                break;
        }
    }
}

请注意,这只会为movie选取第一个“Genre”,即在给定键的多个值的情况下的第一个meta_value。但话又说回来,我不确定它会如何起作用!

对于那些不熟悉放置此代码的人,您可以将其放在插件中,或者更可能放在当前主题的functions.php文件中的新手中。

这有多大帮助。

66
MikeSchinkel

从WordPress 3.1开始(我正在使用测试版)列现在可以通过他们的标题进行排序。

以下帖子详细介绍了如何实现它们。

http://scribu.net/wordpress/custom-sortable-columns.html

8
Leo Plaw