问题描述

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

add_action('wp', 'check_page');

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

最佳解决方案

正如你可能想象的缺乏提供的答案,解决方案并不是微不足道的。我所做的是创建一个有点 self-contained 示例,它假定自定义帖子类型的 「movie」 和”Genre” 的自定义字段键。

免责声明:这适用于 WP3.0,但我无法确定它将与早期版本一起使用。

你基本上需要钩两 (2) 个钩来使它工作,另外两个 (2) 使它变得明显有用。

第一个钩子是’restrict_manage_posts‘,它允许您在 「批量操作」 和 「显示日期」 过滤器的帖子列表上方发布一个 HTML <select> 。提供的代码将生成 「Sort by:」 功能,如此屏幕代码片段所示:

代码使用直接 SQL,因为没有一个 WordPress API 函数来提供一个 post 类型的所有 meta_key 的列表 (听起来像是一个未来的 trac 票给我…) 无论如何,这里是代码。请注意,它从 $_GET 抓取帖子类型,并确认它是一个有效的帖子类型 post_type_exists()以及作为一个 movie 的帖子类型 (这两个检查是过度的,但我做到了,如果你不想要到 hard-code 的帖子类型。) 最后我使用 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);
        }
    }
}

第二个必需步骤是使用在 WordPress 决定一个应该运行的查询之后但在运行查询之前调用的 parse_query 钩子。在这里,我们可以在 query_posts()参数的 orderby 参数中的 query_var 数组中设置 orderbymeta_key 的值。我们测试以确保:

  1. 我们在管理员 (is_admin()),
  2. 我们在页面上列出管理员 ($pagenow=='edit.php') 中的帖子,
  3. 已使用等于 moviepost_type URL 参数调用该页面,以及
  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 参数时,我决定添加一个 「Sorted By:」,当它不是 None 时:

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;
}

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

这里是代码:

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 文件中使用新手。

这有助于

次佳解决方案

从 WordPress 3.1(我正在使用 beta) 列现在可以通过他们的标题排序。

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

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

参考文献

注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。