具有三个可能的元值的一个元键的可排序管理列

时间:2019-01-24 作者:RachieVee

我已经查看了2到3个类似的关于可排序列的线程,以及使它们工作所涉及的元查询。似乎没有人能解决我的问题。

我正在使用pre_get_posts 筛选以挂钩管理列的可排序逻辑。我有一个post meta复选框,我想对其进行排序,它的关键是_prioritize_s.

选中时,该值为\'yes\'. 如果从未检查过,则键和值都不存在。如果之前检查过,然后取消选中,则该键存在,但该值为空字符串。

以下是我想要订购的方式:

元密钥_prioritize_s = \'是的,从最新的帖子到最旧的帖子_prioritize_s = 空字符串OR NOT EXISTS, 从最新到最旧的帖子,这里是我的。这是可行的,但日期顺序似乎不能正常工作,我需要将NOT EXISTS 使用值可以是空字符串的查询?

class Featured_Admin_column {

    public $column_names = [
        \'prioritized_post\' => \'_prioritize_s\',
    ];

    function init() {
        $this->hooks();
    }

    function hooks() {
        add_filter( \'manage_edit-post_sortable_columns\', [ $this, \'create_sortable_columns\' ] );
        add_action( \'pre_get_posts\', [ $this, \'set_meta_for_sortable_columns\' ] );

    }

    function create_sortable_columns( $columns ) {
        $columns[\'prioritized_post\'] = \'priority\';

        return $columns;
    }

    function set_meta_for_sortable_columns( $query ) {
        if ( ! is_admin() ) {
            return;
        }

        $orderby = $query->get( \'orderby\' );
        if ( \'priority\' == $orderby ) {
            $query->set( \'meta_query\', array(
                \'relation\' => \'OR\',
                array(
                    \'key\'   => \'_prioritize_s\',
                    \'value\' => \'yes\',
                ),
                //The 2 arrays below should be grouped together somehow...
                array(
                    \'key\'   => \'_prioritize_s\',
                    \'value\' => \'\',
                ),
                array(
                    \'key\'     => \'_prioritize_s\',
                    \'compare\' => \'NOT EXISTS\'
                )
            ) );

            $query->set( \'orderby\', \'meta_value date\' );
        }
    }
<小时>Update: 我尝试了更多的处理这个问题,并且认为WP可能也会将空白值视为null。当我尝试将元查询放在页面模板上时echo 在处理管理列之前,我尝试减少2个数组而不是3个数组的元查询。我得到两个帖子,有和没有帖子元_prioritize_s 尽管在中使用了数组,但日期顺序仍然不正常orderby. 我错过了什么?

$test_sorting_by_priority = get_posts( [
    \'posts_per_page\' => - 1,
    \'order\'          => \'DESC\',
    \'orderby\' => array(
        \'exists\' => \'date\',
        \'empty\' => \'date\',
    ),
    \'meta_query\'     => array(
        \'relation\' => \'OR\',
        \'exists\'   => array(
            \'key\'     => \'_prioritize_s\',
            \'value\'   => \'yes\',
            \'compare\' => \'EXISTS\',
        ),
        \'empty\'    => array(
            \'key\'     => \'_prioritize_s\',
            \'compare\' => \'NOT EXISTS\'
        ),
    ),
] );

foreach ( $test_sorting_by_priority as $test ) {
    $empty_or_null = isset( $test->{\'_prioritize_s\'}) ? $test->{\'_prioritize_s\'} : \'null\';

    echo $test->ID . \' ================== <b>\' . $test->post_date . \' ===== \' . $empty_or_null . \'</b> <br/>\';
}

1 个回复
最合适的回答,由SO网友:Krzysiek Dróżdż 整理而成

好的,所以这个问题很容易解释。这些帖子分为三个不同的组:

这是因为空值(“”)与null(不存在的值)不同。

解决此问题的一种方法是使用自定义posts_orderby 滤器您可以使用case 声明:

order by case when priority = \'yes\' then 1 else 0 end, date desc
所以它可能是这样的:

function set_meta_for_sortable_columns( $query ) {
    if ( ! is_admin() ) {
        return;
    }

    $orderby = $query->get( \'orderby\' );
    if ( \'priority\' == $orderby ) {
        $query->set( \'meta_query\', array(
            \'relation\' => \'OR\',
            array(
                \'key\'   => \'_prioritize_s\',
                \'value\' => \'yes\',
            ),
            //The 2 arrays below should be grouped together somehow...
            array(
                \'key\'   => \'_prioritize_s\',
                \'value\' => \'\',
            ),
            array(
                \'key\'     => \'_prioritize_s\',
                \'compare\' => \'NOT EXISTS\'
            )
        ) );

        $query->set( \'orderby\', \'meta_value date\' );
        add_filter( \'posts_orderby\', [$this, \'modify_posts_orderby_for_correct_sorting\'] );
    }
}

function modify_posts_orderby_for_correct_sorting( $orderby ) {
    remove_filter( \'posts_orderby\', [$this, \'modify_posts_orderby_for_correct_sorting\'] );  // so this filter is run only during that one query

    global $wpdb;
    $orderby = str_replace( "{$wpdb->postmeta}.meta_value", "case when {$wpdb->postmeta}.meta_value = \'yes\' then 1 else 0 end", $orderby );

    return $orderby;
}
我们在这里所做的是:

我们以这种方式修改默认查询,它将包括_prioritize_s meta并按该meta值排序(稍后按日期排序)。这将导致SQL查询的orderby部分,如下所示:{$wpdb->postmeta}.meta_value ASC, post.post_date ASCBut... 更简单的方法(IMHO)是更改在该元字段中存储值的方式。如果只存储“yes”值,排序就会容易得多。

因此,在保存该值的代码中,仅当meta字段为“是”时才设置该字段,否则删除该字段。