我已经查看了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/>\';
}
最合适的回答,由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 ASC
几乎没问题。但这将导致排序错误(因为null!=“”)。这就是为什么我们必须更改orderby子句。因此,我们添加了过滤函数,只将该子句的第一部分(带meta\\u值的部分-我们保留日期部分)替换为带CASE语句的子句因为过滤器应该只修改一个查询,所以我们在过滤器函数中要做的第一件事就是删除它,所以它不会影响该请求中的任何其他查询But... 更简单的方法(IMHO)是更改在该元字段中存储值的方式。如果只存储“yes”值,排序就会容易得多。
因此,在保存该值的代码中,仅当meta字段为“是”时才设置该字段,否则删除该字段。