在Sally CJ的善意帮助下question, 我能够创建一个WP查询,但它仍然会给我意外的结果。当我在原始MySQL中编写查询时,它工作得很好,但在WordPress创建的查询中,它就不工作了。
以下是我的WP查询参数:
$args = array(
\'post_type\' => \'tdlrm_store_item\',
\'post_status\' => \'publish\',
\'tax_query\' => array(
array(
\'taxonomy\' => \'store-category\',
\'field\' => \'term_id\',
\'terms\' => 514,
\'include_children\' => false
)
),
\'meta_query\' => array(
array(
\'relation\' => \'OR\',
\'has_tdlrm_mp\' => array(
\'key\' => \'tdlrm_mp\',
\'type\' => \'NUMERIC\',
),
\'no_tdlrm_mp\' => array(
\'key\' => \'tdlrm_mp\',
\'compare\' => \'NOT EXISTS\',
),
),
array(
\'relation\' => \'OR\',
\'has_1C_quantity_total\' => array(
\'key\' => \'1C_quantity_total\',
\'type\' => \'NUMERIC\',
),
\'no_1C_quantity_total\' => array(
\'key\' => \'1C_quantity_total\',
\'compare\' => \'NOT EXISTS\',
),
)
),
\'orderby\' => \'none\',
\'tdlrm_commands\' => array(\'tdlrm_orderby\' => true)
);
这是我的
posts_orderby
过滤器:
add_filter( \'posts_orderby\', function ( $orderby, $query ){
if (!isset($query->query_vars[\'tdlrm_commands\'][\'tdlrm_orderby\'])
|| $query->query_vars[\'tdlrm_commands\'][\'tdlrm_orderby\'] !== true) return $orderby;
global $wpdb;
return "
CASE {$wpdb->postmeta}.meta_key
WHEN \'tdlrm_mp\' THEN 1
WHEN \'1C_quantity_total\' THEN 2
ELSE 3
END ASC,
CASE {$wpdb->postmeta}.meta_key
WHEN \'tdlrm_mp\' THEN {$wpdb->postmeta}.meta_value+0
END ASC,
CASE {$wpdb->postmeta}.meta_key
WHEN \'1C_quantity_total\' THEN {$wpdb->postmeta}.meta_value+0
END DESC,
{$wpdb->posts}.post_date DESC
";
}, 10, 2 );
这是我写的MYSQL查询,试图找出发生了什么。它以这样一种方式订购帖子
tdlrm_mp
元go首先,按元值排序,从低到高,然后是其他,按
1C_quantity_total
元值,从高到低,然后是那些没有
1C_quantity_total
元数据,按发布日期排序。
SELECT
* FROM wp_postmeta
LEFT JOIN wp_posts on wp_postmeta.post_id = wp_posts.ID
LEFT JOIN wp_term_relationships on wp_posts.ID = wp_term_relationships.object_id
WHERE wp_posts.post_type = \'tdlrm_store_item\'
AND wp_posts.post_status = \'publish\'
AND wp_term_relationships.term_taxonomy_id = 514
ORDER BY
CASE wp_postmeta.meta_key
WHEN \'tdlrm_mp\' THEN 1
WHEN \'1C_quantity_total\' THEN 2
ELSE 3
END ASC,
CASE wp_postmeta.meta_key
WHEN \'tdlrm_mp\' THEN wp_postmeta.meta_value+0
END ASC,
CASE wp_postmeta.meta_key
WHEN \'1C_quantity_total\' THEN wp_postmeta.meta_value+0
END DESC,
wp_posts.post_date DESC
LIMIT 0,12
它按预期工作。然而,我从$query中得到了什么->;请求是这样的,但它不起作用:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
LEFT JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
LEFT JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id )
LEFT JOIN wp_postmeta AS mt1 ON ( wp_posts.ID = mt1.post_id AND mt1.meta_key = \'tdlrm_mp\' )
LEFT JOIN wp_postmeta AS mt2 ON ( wp_posts.ID = mt2.post_id )
LEFT JOIN wp_postmeta AS mt3 ON ( wp_posts.ID = mt3.post_id AND mt3.meta_key = \'1C_quantity_total\' )
WHERE 1=1 AND ( wp_term_relationships.term_taxonomy_id IN (514) )
AND ( ( wp_postmeta.meta_key = \'tdlrm_mp\' OR mt1.post_id IS NULL ) AND ( mt2.meta_key = \'1C_quantity_total\' OR mt3.post_id IS NULL ) )
AND wp_posts.post_type = \'tdlrm_store_item\'
AND ((wp_posts.post_status = \'publish\'))
GROUP BY wp_posts.ID
ORDER BY
CASE wp_postmeta.meta_key
WHEN \'tdlrm_mp\' THEN 1
WHEN \'1C_quantity_total\' THEN 2
ELSE 3
END ASC,
CASE wp_postmeta.meta_key
WHEN \'tdlrm_mp\' THEN wp_postmeta.meta_value+0
END ASC,
CASE wp_postmeta.meta_key
WHEN \'1C_quantity_total\' THEN wp_postmeta.meta_value+0
END DESC,
wp_posts.post_date DESC LIMIT 0, 12
第一个帖子是
tdlrm_mp
meta,他们的订单很好,但其余的按日期订购,仅此而已。是什么导致了我编写的MYSQL查询和WP MYSQL查询之间的差异,以及如何使其全部工作?
Update.
事实证明,WordPress会多次加入Posteta表,具体取决于元查询参数。这就是为什么:
//php
$args[\'meta_query\'] = array(
\'relation\' => \'AND\',
array(
\'relation\' => \'OR\',
array(
\'key\' => \'tdlrm_mp\',
\'type\' => \'NUMERIC\',
),
array(
\'key\' => \'tdlrm_mp\',
\'compare\' => \'NOT EXISTS\',
),
),
array(
\'key\' => \'1C_quantity_total\',
\'type\' => \'NUMERIC\',
)
);
//MySQL query by WordPress
"...LEFT JOIN wp_postmeta ON (
wp_posts.ID = wp_postmeta.post_id
)
LEFT JOIN wp_postmeta AS mt1 ON (
wp_posts.ID = mt1.post_id
AND mt1.meta_key = \'tdlrm_mp\'
)
LEFT JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id)
WHERE..."
这意味着
1C_quantity_total
元键必须引用为
mt2.meta_key
, 不
wp_postmeta.meta_key
. 我像这样重写了orderby过滤器,它可以工作:
add_filter( \'posts_orderby\', function ( $orderby, $query ){
if (! isset( $query->query[\'tdlrm_commands\'] ) ||
! $query->query[\'tdlrm_commands\'][\'default_filter\']
) return $orderby;
global $wpdb;
return "
CASE {$wpdb->postmeta}.meta_key
WHEN \'tdlrm_mp\' THEN 1
ELSE 2
END ASC,
CASE {$wpdb->postmeta}.meta_key
WHEN \'tdlrm_mp\' THEN {$wpdb->postmeta}.meta_value+0
END ASC,
CASE mt2.meta_key
WHEN \'1C_quantity_total\' THEN mt2.meta_value+0
END DESC
";
}, 10, 2 );
现在,我不想硬编码表的别名mt2。如果在WordPress的未来版本(如mtB)中别名发生更改,该怎么办?还有,我不确定
1C_quantity_total
在任何情况下都将恰好处于第三个加入的Posteta表中。有没有办法做得更好?例如,“您可以使用”;查找联接的表
1C_quantity_total
实际在中,然后按该表中的值排序;。
Update 2
谢谢Sally CJ帮助我,你太棒了!
在试图解决这个问题的过程中,我遇到了一些问题,这些问题可能对任何来到这里的人都有用:question, question, question, JOIN speed, question, question, question.
最合适的回答,由SO网友:Sally CJ 整理而成
事实证明,WordPress多次加入Posteta表,这取决于元查询参数。
是的,这是正确的,这也是我说(在我的other answer) 在一个orderby
数组,应使用meta_query
其中包含名为/键控的直接项key
(其中值是元键)-如果不知道,WordPress将不知道应该使用哪个表联接/别名。
这意味着1C_quantity_total
元键必须引用为mt2.meta_key
, 不wp_postmeta.meta_key
.
是的,你完全正确!
(对不起,我的错,我修改了其他答案好几次,但实际上我还是忘了更正表别名)
现在,我不想硬编码表的别名mt2。如果thealias在WordPress的未来版本中发生变化(如mtB),该怎么办?还有,我不确定1C_quantity_total
在任何情况下都将恰好位于第三个JoinedPosteta表中。有没有办法做得更好?
是的,有:使用WP_Meta_Query::get_clauses()
获取用于每个元查询子句的正确别名。和一个WP_Query
实例,您可以使用$meta_query
财产,即。WP_Query::$meta_query
.
但是,记住要给出一个独特的array key 到元查询子句,如has_tdlrm_mp
和has_1C_quantity_total
:
$args = array(
...
\'meta_query\' => array(
array(
\'relation\' => \'OR\',
\'has_tdlrm_mp\' => array(
\'key\' => \'tdlrm_mp\',
\'type\' => \'NUMERIC\',
),
\'no_tdlrm_mp\' => array(
\'key\' => \'tdlrm_mp\',
\'compare\' => \'NOT EXISTS\',
),
),
array(
\'relation\' => \'OR\',
\'has_1C_quantity_total\' => array(
\'key\' => \'1C_quantity_total\',
\'type\' => \'NUMERIC\',
),
\'no_1C_quantity_total\' => array(
\'key\' => \'1C_quantity_total\',
\'compare\' => \'NOT EXISTS\',
),
)
),
...
);
因此,通过该元查询,可以获得正确的表别名,如下所示:
$query = new WP_Query( $args );
$meta_clauses = $query->meta_query->get_clauses();
var_dump(
$meta_clauses[\'has_tdlrm_mp\'][\'alias\'],
$meta_clauses[\'has_1C_quantity_total\'][\'alias\'],
);
// Sample output: string(11) "wp_postmeta" string(3) "mt2"
在
posts_orderby
筛选/回调,您可以使用相同的
$query->meta_query->get_clauses()
如上所述:
$meta_clauses = $query->meta_query->get_clauses();
$has_tdlrm_mp = $meta_clauses[\'has_tdlrm_mp\'][\'alias\'];
$has_1C_quantity_total = $meta_clauses[\'has_1C_quantity_total\'][\'alias\'];
return "
CASE {$has_tdlrm_mp}.meta_key
WHEN \'tdlrm_mp\' THEN 1
ELSE 2
END ASC,
CASE {$has_tdlrm_mp}.meta_key
WHEN \'tdlrm_mp\' THEN {$has_tdlrm_mp}.meta_value+0
END ASC,
CASE {$has_1C_quantity_total}.meta_key
WHEN \'1C_quantity_total\' THEN {$has_1C_quantity_total}.meta_value+0
END DESC
";