ORDERBY META_VALUE仅返回具有现有META_KEY的帖子

时间:2015-05-13 作者:gdaniel

我有以下wp\\U查询:

$args = array(
    \'post_type\' => \'news\',
    \'orderby\' => \'meta_key\',
    \'order\' => \'ASC\',
    \'meta_key\'=>\'custom_author_name\',
    \'post_per_page\'=>-1
);

$query = new WP_Query($args);

echo $query->found_posts;
echo=10个结果,因为只有10个news 带有meta_key = custom_author_name. 但是有数百个news 没有具有特定meta\\u键的post\\u meta行的帖子。请注意,没有涉及meta\\u查询。没有分配meta\\u值,因为我只是尝试按meta\\u键对帖子进行排序,而不是按meta\\u值进行筛选。

orderby不应该选择所有帖子吗?然后就点了?

如果是,为什么要过滤结果?如果找不到meta\\u键,为什么不使用空字符串或匹配all?

如果没有,为什么没有?

如果我为每个新闻帖子输入一个meta\\u键(即使它是一个空字符串),那么我会得到预期的结果。但这似乎有很多不需要的表行。

4 个回复
最合适的回答,由SO网友:Manny Fleurmond 整理而成

正如@ambroseya的回答所述,它应该是这样工作的。一旦您声明了一个元查询,即使您没有寻找特定的值,它也只会查询声明了该元键的帖子。如果要包含所有帖子,请使用以下代码按meta键对其进行排序:

$args = array(
    \'post_type\' => \'news\',
    \'orderby\' => \'meta_value\',
    \'order\' => \'ASC\',
    \'meta_query\' => array(
        \'relation\' => \'OR\',
        array( 
            \'key\'=>\'custom_author_name\',
            \'compare\' => \'EXISTS\'           
        ),
        array( 
            \'key\'=>\'custom_author_name\',
            \'compare\' => \'NOT EXISTS\'           
        )
    ),
    \'posts_per_page\'=>-1
);

$query = new WP_Query($args);

echo $query->found_posts;
这样做的目的是使用一个高级元查询来查找声明了和没有声明该元键的帖子。自从EXISTS 是第一个,当你排序的时候meta_value, 它将使用第一个查询。

SO网友:jlad26

我试着用Manny Fleurmond的答案,就像Jake一样,即使在更正了拼写错误后,我也无法让它工作\'orderby\' => \'meta_key\' 应该是\'orderby\' => \'meta_value\'. (为了完整性,应\'posts_per_page\'\'post_per_page\' 但这并不影响正在研究的问题。)

如果您查看由@Manny Fleurmond的答案(纠正了拼写错误)实际生成的SQL查询,您会得到:

SELECT   wp_{prefix}_posts.* FROM wp_{prefix}_posts
LEFT JOIN wp_{prefix}_postmeta ON (wp_{prefix}_posts.ID = wp_{prefix}_postmeta.post_id AND wp_{prefix}_postmeta.meta_key = \'custom_author_name\' )
LEFT JOIN wp_{prefix}_postmeta AS mt1 ON ( wp_{prefix}_posts.ID = mt1.post_id )
WHERE 1=1  AND ( 
    wp_{prefix}_postmeta.post_id IS NULL 
    OR 
    mt1.meta_key = \'custom_author_name\'
) AND wp_{prefix}_posts.post_type = \'news\' AND
(wp_{prefix}_posts.post_status = \'publish\' OR wp_{prefix}_posts.post_author = 1 AND wp_{prefix}_posts.post_status = \'private\')
GROUP BY wp_{prefix}_posts.ID ORDER BY wp_{prefix}_postmeta.meta_value ASC
这说明了WP解析查询变量的方式:它为每个meta\\u查询子句创建一个表,然后确定如何连接它们以及按什么排序。如果只使用一个子句\'compare\' => \'EXISTS\', 但加入第二个\'compare\' => \'NOT EXISTS\' 带有或(我们必须)的条款打乱了订货。结果是,左连接用于连接第一个子句/表和第二个子句/表,而WP将所有内容放在一起的方式意味着使用\'compare\' => \'EXISTS\' 实际上使用来自任何自定义字段的meta\\u值填充,而不仅仅是\'custom_author_name\' 我们感兴趣的领域。因此,我认为,如果特定的post\\u类型的“news”只有一个自定义字段,那么按该子句/表排序只能得到所需的结果。

对我的情况有效的解决方案是按另一个子句/表排序-不存在的那一个。我知道这似乎有违直觉,但由于WP解析查询变量的方式,这张表meta_value 仅由我们要查找的自定义字段填充。

(我解决这个问题的唯一方法是为我的案例运行等效的查询:

SELECT   wp_{prefix}_posts.ID, wp_{prefix}_postmeta.meta_value, mt1.meta_value FROM wp_{prefix}_posts
LEFT JOIN wp_{prefix}_postmeta ON (wp_{prefix}_posts.ID = wp_{prefix}_postmeta.post_id AND wp_{prefix}_postmeta.meta_key = \'custom_author_name\' )
LEFT JOIN wp_{prefix}_postmeta AS mt1 ON ( wp_{prefix}_posts.ID = mt1.post_id )
WHERE 1=1  AND ( 
    wp_{prefix}_postmeta.post_id IS NULL 
    OR 
    mt1.meta_key = \'custom_author_name\'
) AND wp_{prefix}_posts.post_type = \'news\' AND
(wp_{prefix}_posts.post_status = \'publish\' OR wp_{prefix}_posts.post_author = 1 AND wp_{prefix}_posts.post_status = \'private\')
ORDER BY wp_{prefix}_postmeta.meta_value ASC
我所做的就是更改显示的列并删除GROUP BY子句。这让我知道了发生了什么事,那就是邮差。meta\\u value列从所有meta\\u键中提取值,而mt1。meta\\u value列仅从news自定义字段中提取meta\\u值。)

The Solution

正如@Manny Fleurmond所说,这是orderby使用的第一个子句,所以答案就是将这些子句四舍五入,给出以下内容:

$args = array(
    \'post_type\' => \'news\',
    \'orderby\' => \'meta_value\',
    \'order\' => \'ASC\',
    \'meta_query\' => array(
        \'relation\' => \'OR\',
        array( 
            \'key\' => \'custom_author_name\',
            \'compare\' => \'NOT EXISTS\'           
        ),
        array( 
            \'key\' => \'custom_author_name\',
            \'compare\' => \'EXISTS\'           
        )
    ),
    \'posts_per_page\' => -1
);

$query = new WP_Query($args);
或者,可以将子句设置为关联数组,并按相应键排序,如下所示:

$args = array(
    \'post_type\' => \'news\',
    \'orderby\' => \'not_exists_clause\',
    \'order\' => \'ASC\',
    \'meta_query\' => array(
        \'relation\' => \'OR\',
        \'exists_clause\' => array( 
            \'key\' => \'custom_author_name\',
            \'compare\' => \'EXISTS\'           
        ),
        \'not_exists_clause\' => array( 
            \'key\' => \'custom_author_name\',
            \'compare\' => \'NOT EXISTS\'           
        )
    ),
    \'posts_per_page\' => -1
);

$query = new WP_Query($args);

SO网友:ambroseya

这就是它的工作原理。

如果要在不添加表行的情况下执行此操作,则必须执行两个查询。一个使用meta\\u键,结果有限,另一个获取整个列表;然后使用PHP比较这两个查询结果(可能从另一个查询中删除meta\\u键结果以删除重复项,或者在您的设置中有意义的任何内容)。

SO网友:s_ha_dum

不幸的是,事实并非如此WP_Query 作品一旦添加了“元”组件,就创建了一种过滤器。倾倒$query->request 你就会明白我的意思了。

第二WP_Query 根本不支持按元键排序。您可以按特定键的meta值排序,但不能按键本身排序。再次转储查询以了解我的意思。如果尝试,您会注意到“order”组件将退出。

在我看来,最干净的方法是使用几个短过滤器:

function join_meta_wpse_188287($join) {
  remove_filter(\'posts_join\',\'join_meta_wpse_188287\');
  global $wpdb;
  return \' INNER JOIN \'.$wpdb->postmeta.\' ON (\'.$wpdb->posts.\'.ID = \'.$wpdb->postmeta.\'.post_id)\';
}
add_filter(\'posts_join\',\'join_meta_wpse_188287\');

function orderby_meta_wpse_188287($orderby) {
  remove_filter(\'posts_orderby\',\'orderby_meta_wpse_188287\');
  global $wpdb;
  return $wpdb->postmeta.\'.meta_key ASC\';
}
add_filter(\'posts_orderby\',\'orderby_meta_wpse_188287\');

$args = array(
    \'post_type\' => \'news\',
    \'post_per_page\'=>-1
);
$q = new WP_Query($args);
var_dump($q->request); // debug
var_dump(wp_list_pluck($q->posts,\'post_title\')); // debug

结束

相关推荐

Sortable WYSIWYG editor

我在metabox中有一组可排序的wysiwyg编辑器。不幸的是,每当我拖动一行时,我都会遇到这个错误,我不知道是什么导致了它。Uncaught TypeError: Object [object Object] has no method \'destroy\'这是我的可排序代码:$( \"#repeatable-fieldset-one tbody\" ).sortable({ handle: \'.jQuerySortableIcon\',