J'ai un filtre simple qui s'exécute sur la requête principale de la page d'accueil. Il devrait exclure toutes les publications ayant une méta-valeur particulière (en n'incluant que les publications pour lesquelles le paramètre meta_key n'est pas défini, ou celles dont la valeur meta_key ne correspond pas à ce que nous ' re excluant). Mais, pour une raison quelconque, il ne se comporte pas comme prévu.
/**
* 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' );
Chaque moitié de cette méta requête fonctionne parfaitement bien toute seule. Je peux voir toutes les publications où la clé n'existe pas ou toutes les publications où la clé existe et n'est pas vraie. Lorsqu'il est utilisé conjointement, comme indiqué ci-dessus, je ne vois que les publications où la clé existe et n'est pas vraie (la partie NOT EXISTS est complètement ignorée).
Voici le code SQL généré (selon le filtre 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
Vous pouvez voir que quand il s'agit des méta, il utilise bien OR dans la clause WHERE, plutôt que AND comme le bogue référencé le met en évidence: https://core.trac.wordpress.org/ticket/23268
J'espère que quelqu'un pourra vous fournir des informations indispensables, car je suis complètement déconcerté.
Oui, ça se comporte bizarre. Non, tirez-moi, je ne peux pas savoir exactement pourquoi et comment (les jointures empilées le sont probablement).
Je dis le retourner. Les seuls messages que vous ne voulez pas voir sont ceux avec la clé personnalisée true
. Interrogez séparément leurs ID, introduisez le résultat dans post__not_in
, abandonnez entièrement cette méta-requête.
Je me range aux côtés des utilisateurs de Twitter qui soupçonnaient le problème du code SQL composite. Je viens d'écrire une fonction différente pour exécuter mon propre SQL sur les posts_clauses, au lieu d'utiliser pre_get_posts, hook et les posts attendus sont correctement renvoyés.
Voici un exemple suivant les mêmes exigences que ci-dessus:
/**
* 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 );
Je pense que votre problème est d’utiliser le vrai booléen comme valeur à exclure. J'ai changé la valeur d'exclusion en une chaîne, 'asdf' et j'ai changé la chaîne factice et cela a fonctionné.
La requête SQL a été copiée et collée à partir d'un vidage de l'objet global $ wp_query. La base de données a 5 postes comme on peut le voir à partir de la 1ère requête. 3 de la publication ont la clé d'exclusion méta et 1 d'entre eux contient la valeur d'exclusion méta.
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)