フロントページのメインのクエリで単純なフィルタを実行しています。特定のメタ値を持つ投稿をすべて除外する必要があります(meta_keyが設定されていない投稿、またはmeta_key値が一致しない投稿のみを除外)除外する)。しかし、何らかの理由で、それは期待どおりに動作していません。
/**
* Hide posts from main query on front page.
*
* @since 1.0.0
*
* @param object $query WP Query object.
* @return object Modified WP Query object.
*/
function wpse_exclude_posts_from_main_query( $query ) {
// Make sure this only runs on the main query on the front page
if ( is_front_page() && $query->is_main_query() ) {
// Exclude posts that have been explicitly set to hidden
$query->set('meta_query', array(
'relation' => 'OR',
// Include posts where the meta key isn't set
array(
'key' => '_wpse_custom_key',
'value' => 'asdf', // A value must exist due to https://core.trac.wordpress.org/ticket/23268
'compare' => 'NOT EXISTS',
),
// Include posts where the meta key isn't explicitly true
array(
'key' => '_wpse_custom_key',
'value' => true,
'compare' => '!=',
),
) );
}
}
add_action( 'pre_get_posts', 'wpse_exclude_posts_from_main_query' );
このメタクエリの各半分は、それ自体では完全にうまく機能します。キーが存在しないすべての投稿、またはキーが存在し、正しくないすべての投稿を表示できます。上記のように、組み合わせて使用すると、キーが存在し、それが正しくない投稿のみが表示されます(NOT EXISTS部分は完全に無視されます)。
生成されているSQLは次のとおりです(posts_requestフィルターに従って)。
SELECT SQL_CALC_FOUND_ROWS wp_posts.*
FROM wp_posts
LEFT JOIN wp_postmeta
ON (
wp_posts.ID = wp_postmeta.post_id
AND wp_postmeta.meta_key = '_wpse_custom_key'
)
INNER JOIN wp_postmeta AS mt1
ON (wp_posts.ID = mt1.post_id)
WHERE 1=1
AND wp_posts.post_type = 'post'
AND wp_posts.post_status = 'publish'
AND (
wp_postmeta.post_id IS NULL
OR (
mt1.meta_key = '_wpse_custom_key'
AND CAST(mt1.meta_value AS CHAR) != '1'
)
)
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT 0, 10
参照されているバグが強調表示されているように、ANDではなくORをWHERE句で実際に使用していることがわかります。 https://core.trac.wordpress.org /チケット/ 23268
私は完全に自慢しているので、誰かがいくつかの非常に必要な洞察を提供できることを願っています。
はい、それは変な振る舞いをします。いいえ、私を撃ってください、私は正確にその理由と方法についての修正を得ることができません(スタック結合はおそらくそれです)。
私はそれを反転すると言います。あなたが見たくない唯一の投稿はtrue
カスタムキーを持つものです。それらのIDを別々に問い合わせ、結果をpost__not_in
に送り、このメタ問い合わせを完全に捨てます。
私は、合成SQLが問題であると疑っていたTwitterの人々と一緒にいます。 pre_get_posts、hookを使用する代わりに、posts_clausesで独自のSQLを実行するための別の関数を書いたところです。期待される投稿は正しく返されます。
これは、上記と同じ要件に従った例です。
/**
* Hide posts from main query on front page.
*
* @since 1.0.0
*
* @param object $query WP Query object.
* @return object Modified WP Query object.
*/
function wpse_exclude_posts_clauses( $pieces, $query ) {
// Make sure this only runs on the main query on the front page
if ( is_front_page() && $query->is_main_query() ) {
$pieces['join'] = "
LEFT JOIN $wpdb->postmeta as hidden_meta
ON (
$wpdb->posts.ID = hidden_meta.post_id
AND hidden_meta.meta_key = '_wpse_custom_key'
)
";
$pieces['where'] = "
AND (
hidden_meta.post_id IS NULL
OR CAST(hidden_meta.meta_value AS CHAR) != '1'
)
";
}
return $pieces;
}
add_filter( 'posts_clauses', 'wpse_exclude_posts_clauses', 10, 2 );
私はあなたの問題は除外する値として真のブール値を使用していると思います。除外値を文字列 'asdf'に変更し、ダミー文字列を変更したところ、うまくいきました。
クエリSQLは、グローバル$ wp_queryオブジェクトのダンプからコピーアンドペーストされました。最初のクエリからわかるように、データベースには5つの投稿があります。投稿のうち3つにexcludeメタキーがあり、1つにexcludeメタ値が含まれています。
mysql> SELECT ID FROM wpomni_posts WHERE post_type ='post' AND post_status = 'publish';
+------+
| ID |
+------+
| 1 |
| 5900 |
| 5904 |
| 5908 |
| 5925 |
+------+
5 rows in set (0.00 sec)
mysql> SELECT SQL_CALC_FOUND_ROWS wpomni_posts.ID FROM wpomni_posts
-> LEFT JOIN wpomni_postmeta
-> ON (wpomni_posts.ID = wpomni_postmeta.post_id
-> AND wpomni_postmeta.meta_key = '_wpse_custom_key')
-> INNER JOIN wpomni_postmeta AS mt1
-> ON (wpomni_posts.ID = mt1.post_id)
-> WHERE 1=1
-> AND wpomni_posts.post_type = 'post'
-> AND (wpomni_posts.post_status = 'publish'
-> OR wpomni_posts.post_status = 'private')
-> AND ( wpomni_postmeta.post_id IS NULL
-> OR (mt1.meta_key = '_wpse_custom_key'
-> AND CAST(mt1.meta_value AS CHAR) != 'asdf') )
-> GROUP BY wpomni_posts.ID
-> ORDER BY wpomni_posts.post_date DESC LIMIT 0, 18;
+------+
| ID |
+------+
| 5925 |
| 5908 |
| 5900 |
| 1 |
+------+
4 rows in set (0.00 sec)
mysql> SELECT * FROM wpomni_postmeta WHERE meta_key = '_wpse_custom_key';
+---------+---------+------------------+----------------+
| meta_id | post_id | meta_key | meta_value |
+---------+---------+------------------+----------------+
| 137033 | 5908 | _wpse_custom_key | 1 |
| 137034 | 5904 | _wpse_custom_key | asdf |
| 137042 | 5925 | _wpse_custom_key | what the blank |
+---------+---------+------------------+----------------+
3 rows in set (0.00 sec)