这个元查询有什么问题?(先按元键排序,然后按标题排序,不起作用)

时间:2021-09-23 作者:Artem

下面是我的元查询:

$taxonomy_term = 1494;
$args[\'meta_query\'] = array(
        \'relation\' => \'OR\',
        \'mp_exists\' => array(
            \'key\' => \'tdlrm_mp_\'.$taxonomy_term,
            \'type\' => \'NUMERIC\',
        ),
        \'mp_not_exists\' => array(
            \'key\' => \'tdlrm_mp_\'.$taxonomy_term,
            \'compare\' => \'NOT EXISTS\'
        )
    );
$args[\'orderby\'] = array( \'meta_value_num\' => \'ASC\', \'title\' => \'ASC\' );
其中的岗位\'tdlrm_mp_\'.$taxonomy 密钥存在,按预期放置在第一位。Hovewer,其余的并不是按标题排序的(实际上,我不知道他们是按什么排序的)。我做错了什么?

This answer 没有帮助。我根据this manual.

Update

我在数据库中运行了WP的MySQL查询,并看到Posteta表连接了两次。没有tdlrm\\u mp\\uuu{term}元键的帖子在结果表中仍然有一些其他元键,其余帖子按照该元的值排序。(mp_exists 添加第一个Posteta表,mp_not_exists 添加第二个,其中mp_exists 不存在。在第一个连接的表中还存在一些其他的元键,因此帖子一直按该列排序)。

2 个回复
最合适的回答,由SO网友:Artem 整理而成

结果,我不得不使用“posts\\u orderby”过滤器。我转向Sally CJ对我的questionanother question. 我以为我不需要它,但我错了。

帖子没有得到正确排序的原因是,在WP生成的MySQL查询中,Posteta表被多次连接,导致多个meta_key 列。因此,在第一个meta\\u key列中,meta key不是\'tdlrm_mp_\'.$taxonomy_term, 还有一些其他的meta键,所以帖子只是按照与此列对应的meta值排序,如下所示:

/*
| wp_postmeta.meta_key | wp_postmeta.meta_value | mt1.meta_key  | mt1.meta_value |
----------------------------------------------------------------------------------
| tdlrm_mp_1494        | 1                      | tdlrm_mp_1494 | 1              |
----------------------------------------------------------------------------------
| tdlrm_mp_1494        | 2                      | tdlrm_mp_1494 | 2              |
----------------------------------------------------------------------------------
| some_other_key       | X                      | NULL          | NULL           |
----------------------------------------------------------------------------------
| some_other_key       | Y                      | NULL          | NULL           |
----------------------------------------------------------------------------------
*/
为了解决这个问题,我们需要在ORDER BY中添加case语句,这样meta\\u value列将只用于排序实际具有tdlrm_mp_1494 其中的元键。

我们可以通过设置orderby过滤器来实现这一点。

This is how:

下面是我们的元查询参数。注意orderby 参数设置为false(我们不需要它)。

$taxonomy = 1494; // for demonstration purposes
$args[\'meta_query\'] = array(
        \'relation\' => \'OR\',
        \'mp_exists\' => array(
            \'key\' => \'tdlrm_mp_\'.$taxonomy,
            \'type\' => \'NUMERIC\',
        ),
        \'mp_not_exists\' => array(
            \'key\' => \'tdlrm_mp_\'.$taxonomy,
            \'compare\' => \'NOT EXISTS\'
        )
    );
$args[\'orderby\'] = false;
首先,我们向查询参数中添加一个自定义变量,让WP知道在哪里使用过滤器:

$args[\'tdlrm_commands\'] = array(
        \'filter\' => \'orderby_filter_1\',
        \'key\' => \'tdlrm_mp_\'.$taxonomy
    );
其次,我们添加过滤器(到functions.php或插件文件,无论什么):

add_filter( \'posts_orderby\', function ( $orderby, $query ) {

    //won\'t fire for other queries
    if(
    empty($query->query[\'tdlrm_commands\'][\'do\'])
    || $query->query[\'tdlrm_commands\'][\'do\'] !== \'orderby_filter_1\'
    )
    {
    return $orderby;
    }

    global $wpdb;

    $meta_clauses = $query->meta_query->get_clauses();
    
    //get the key we passed in our custom argument
    $key = $query->query[\'tdlrm_commands\'][\'key\'];

    //get the table alias (remember there are multiple postmeta tables joined together,
    //we need only the one that satisfies our meta query clause, `mp_exists`)
    $has_tdlrm_mp = $meta_clauses[\'mp_exists\'][\'alias\'];


    /*
    in the postmeta table with alias {$has_tdlrm_mp},
    when meta_key equals to {$key},
    use the first clause,
    otherwise, use the second.

    first clause:
    in the postmeta table with alias {$has_tdlrm_mp},
    when meta_key equals to {$key},
    order by its meta value, in the ascending order
    (+0 casts a string to number, otherwise 21 will go after 2 and before 3.)

    second clause:
    if it\'s not, order by title, in the ascending order
    */
    $orderby = " CASE {$has_tdlrm_mp}.meta_key
                    WHEN \'{$key}\' THEN 1
                    ELSE 2
                END ASC,
                CASE {$has_tdlrm_mp}.meta_key
                    WHEN \'{$key}\' THEN {$has_tdlrm_mp}.meta_value+0
                END ASC,
                {$wpdb->posts}.post_title ASC";

    return $orderby;
}, 10, 2 );

SO网友:Buttered_Toast

我认为问题在于你有多个元值,所以你的订单应该更有针对性,就像这样。

$args[\'orderby\'] = array(
    \'mp_exists\'     => \'ASC\',
    \'mp_not_exists\' => \'ASC\',
    \'title\'         => \'ASC\'
);
我不知道你想要订购什么元数据,所以我添加了这两个元数据,并根据需要删除它们。