Voici mon problème. J'ai un type d'article personnalisé auquel j'attache une taxonomie personnalisée. Cette taxonomie permettra à l'administrateur de fournir des suggestions de recherche garantissant que la publication est trouvée lorsqu'un utilisateur effectue une recherche. Cette taxonomie est également utilisée sur le serveur frontal pour compléter automatiquement le champ de recherche avec ces suggestions.
Le système fonctionne correctement, sauf lorsque le terme contient une barre oblique, un espace ou d’autres caractères "spéciaux".
<?php
$keyword = 'Ski-in%2FSki-out';//Submitted via $_GET
$keyword = urldecode($keyword); // (string)'Ski-in/Ski-out'
$taxQuery = new WP_Query(array(
'post_type' => 'ml_properties',
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => 'mc_tax_lifestyle',
'field' => 'name',
'terms' => array($keyword),
'operator' => 'IN'
)
)
));
?>
J'ai étudié la possibilité d'utiliser les fonctionnalités d'échappement fournies par WordPress, mais je n'ai pas eu de chance là-bas. Je pensais que ce serait un problème simple, mais soit mon Google-fu n’est pas puissant, soit je n’ai aucune chance.
J'ai également vérifié que Ski-in/Ski-out
est la chaîne exacte stockée dans MySQL. J'ai examiné l'utilisation de esc_attr()
, $wpdb->esc_like()
et esc_sql()
mais aucune n'a d'effet.
Peut-être qu'il me manque quelque chose d'évident?
Je ne suis pas sûr qu'il s'agisse d'un bug, mais une enquête plus approfondie est nécessaire. J'ai effectué quelques tests rapides sur le champ name
dans un tax_query
, et chaque fois qu'un nom de terme a un caractère spécial ou plusieurs mots, le tax_query
est exclu de la requête SQL.
J'ai utilisé deux termes ici, votre terme Ski-in/Ski-out
et l'un des termes de mon site de test Uit die koskas
. Maintenant, si je lance ma requête personnalisée comme suit
$taxQuery = new \WP_Query(array(
'post_type' => 'post',
'tax_query' => array(
array(
'taxonomy' => 'category',
'field' => 'name',
'terms' => 'Ski-in/Ski-out',
'operator' => 'IN'
)
)
));
?><pre><?php var_dump($taxQuery->request); ?></pre><?php
la var_dump()
de la demande me donne ceci
string(254) "SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
WHERE 1=1
AND (
0 = 1
)
AND wp_posts.post_type = 'post'
AND (wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'private')
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT 0, 4"
Le tax_query
n'est pas ajouté à la requête SQL
Si vous prenez un seul mot Word sans caractère spécial, la requête fonctionne. Ici, j'ai testé avec un terme appelé Ongekategoriseerd
$taxQuery = new \WP_Query(array(
'post_type' => 'post',
'tax_query' => array(
array(
'taxonomy' => 'category',
'field' => 'name',
'terms' => 'Ongekategoriseerd',
'operator' => 'IN'
)
)
));
?><pre><?php var_dump($taxQuery->request); ?></pre><?php
Cela me donne la requête SQL correcte
string(378) "SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts
INNER JOIN wp_term_relationships
ON (wp_posts.ID = wp_term_relationships.object_id)
WHERE 1=1
AND (
wp_term_relationships.term_taxonomy_id
IN (1)
)
AND wp_posts.post_type = 'post'
AND (wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'private')
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT 0, 4"
Je ne sais pas encore si c'est intentionnel ou s'il s'agit d'un bogue, mais en attendant, vous pouvez consulter le code source WP_Query
et voir comment le tax_query
est construit. Je vais me renseigner également dans un proche avenir
J'ai rapidement parcouru la classe WP_Query
avant de partir travailler. Vers la fin de la classe, WP_Query
effectue des tests de compatibilité avec les versions antérieures et, à première vue, il peut sembler que c’est là que tout échoue, ce qui échoue à son tour en ajoutant le lien de jointure à la requête SQL.
Je ne trouve pas de ticket de correspondance sur ce problème. S'il y en a un et que tout le monde a un lien, n'hésitez pas à mettre à jour ma réponse ou à poster des commentaires.
Si vous devez et devez utiliser le nom de terme, vous devez créer vous-même une fonction d'assistance à l'aide de get_term_by()
. Vous pouvez ensuite utiliser le terme nom pour obtenir le terme objet, puis utiliser le terme ID pour l'utiliser dans un tax_query
Le problème n'était pas dans WP_Query
lui-même ( quel désordre en parcourant ces classes ). WP_Query
utilise WP_Tax_Query
pour construire le tax_query
. Vérifiez la dernière ligne juste avant l'appel do_action
dans la méthode parse_tax_query
dans WP_Query
$this->tax_query = new WP_Tax_Query( $tax_query );
Génial, je passe à la classe WP_Tax_Query
. Cette classe a la méthode suivante, transform_query
qui transforme une requête unique d'un champ à un autre. C’est là que tout se brise lorsque vous définissez votre paramètre field
sur name
Si field
est défini sur name
, le nom est nettoyé à l’aide de sanitize_title_for_query
$terms = "'" . implode( "','", array_map( 'sanitize_title_for_query', $query['terms'] ) ) . "'";
Cela supprime les barres obliques et convertit les espaces vides en hypens. Cela signifie que Ski-in/Ski-out
est converti en ski-inski-out
et que Uit die koskas
est converti en uit-die-koskas
. Parce que votre nom de terme n'est pas valide, la requête suivante qui obtient le terme id et ses enfants,
$terms = $wpdb->get_col( "
SELECT $wpdb->term_taxonomy.$resulting_field
FROM $wpdb->term_taxonomy
INNER JOIN $wpdb->terms USING (term_id)
WHERE taxonomy = '{$query['taxonomy']}'
AND $wpdb->terms.{$query['field']} IN ($terms)
" );
échoue et retourne un tableau vide
array(0) {
}
IMHO, l'assainissement ici est faux et devrait être remplacé par une méthode plus appropriée qui permet des espaces simples et des barres obliques. Quel est le but d'avoir un champ name
si vous ne pouvez pas utiliser les noms de terme correctement. Cet assainissement supprime l'utilisation du champ name
dans un tax_query
dans les cas mentionnés ci-dessus.
Comme je l'ai déjà indiqué précédemment, la meilleure méthode si vous devez utiliser des noms de terme est de créer cette fonction d'assistance dans laquelle vous utilisez get_term_by()
pour obtenir l'ID d'un terme, puis utilisez cet ID dans votre tax_query
.
Grâce à @manifestphil dans les commentaires, il existe un changeset # 31346 sur ce problème complètement fou de désinfection excessive. Espérons que cela soit corrigé dans les prochaines versions