web-dev-qa-db-ger.com

Escapezeichen von WP_Query tax_query, wenn ein Begriff Sonderzeichen hat

Hier ist mein Problem. Ich habe einen benutzerdefinierten Beitragstyp, dem ich eine benutzerdefinierte Taxonomie anhänge. Diese Taxonomie ermöglicht es dem Administrator, Suchvorschläge bereitzustellen, die sicherstellen, dass der Beitrag gefunden wird, wenn ein Benutzer sucht. Diese Taxonomie wird auch im Frontend verwendet, um das Suchfeld mit diesen Vorschlägen automatisch zu vervollständigen.

Das System funktioniert einwandfrei, außer wenn der Begriff einen Schrägstrich, ein Leerzeichen oder andere "Sonderzeichen" enthält.

<?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'
        )
    )
));
?>

Ich habe versucht, die von WordPress bereitgestellten Ausweichfunktionen zu nutzen, hatte dort jedoch kein Glück. Ich dachte, das wäre ein einfaches Problem, aber entweder ist mein Google-Fu nicht stark oder ich habe einfach kein Glück.

Ich habe auch überprüft, dass Ski-in/Ski-out die genaue Zeichenfolge ist, die in MySQL gespeichert ist. Ich habe mir die Verwendung von esc_attr(), $wpdb->esc_like() und esc_sql() angesehen, aber keine hat Auswirkungen.

Vielleicht fehlt mir etwas Offensichtliches?

5
Philip Downer

Ich bin nicht sicher, ob dies ein Fehler ist, aber es bedarf weiterer Untersuchungen. Ich habe einige schnelle Tests für das Feld name in einem tax_query durchgeführt. Wenn ein Termname ein Sonderzeichen enthält oder mehr als ein Wort enthält, wird der tax_query von der SQL-Abfrage ausgeschlossen

TEST 1

Ich habe hier zwei Begriffe verwendet, Ihren Begriff Ski-in/Ski-out und einen der Begriffe auf meiner Testseite Uit die koskas. Nun, wenn ich meine benutzerdefinierte Abfrage wie folgt ausführe

$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    

die var_dump() der Anfrage gibt mir dies

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"

Der tax_query wird nicht an die SQL-Abfrage angehängt

TEST 2

Wenn Sie einen einzelnen Wortbegriff ohne Sonderzeichen verwenden, funktioniert die Abfrage. Hier habe ich mit einem Begriff namens Ongekategoriseerd getestet

$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

Dies gibt mir die richtige SQL-Abfrage

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" 

Ich bin mir noch nicht sicher, ob dies beabsichtigt oder ein Fehler ist, aber in der Zwischenzeit können Sie sich den WP_Query-Quellcode ansehen und sehen, wie der tax_query aufgebaut ist. Ich werde mich in naher Zukunft auch darum kümmern

UPDATE 1

Ich habe schnell einen Blick in die WP_Query Klasse geworfen, bevor ich zur Arbeit ging. Gegen Ende der Klasse führt WP_Query einige Abwärtskompatibilitätstests durch, und vom Augenmaß her scheint es, dass hier alles fehlschlägt, was wiederum fehlschlägt, wenn die Join-Klausel an die SQL-Abfrage angehängt wird.

Ich kann kein Trac-Ticket zu diesem Problem finden. Wenn es eines gibt und jemand einen Link hat, können Sie meine Antwort aktualisieren oder in Kommentaren posten.

WORKAROUND

Wenn Sie den Termnamen benötigen und verwenden müssen, sollten Sie sich mit get_term_by() eine Hilfsfunktion erstellen. Sie können dann den Termnamen verwenden, um das Termobjekt abzurufen und die Term-ID von dort zur Verwendung in einem tax_query zu verwenden.

UPDATE 2

FAND ES

Das Problem lag nicht in WP_Query selbst ( was für ein Durcheinander beim Durchsuchen dieser Klassen ). WP_Query verwendet WP_Tax_Query , um den tax_query zu erstellen. Überprüfen Sie die letzte Zeile kurz vor dem do_action-Aufruf in der parse_tax_query-Methode in WP_Query.

$this->tax_query = new WP_Tax_Query( $tax_query );

Großartig, in die Klasse WP_Tax_Query zu wechseln. Diese Klasse hat die folgende Methode transform_query , die eine einzelne Abfrage von einem Feld in ein anderes transformiert. Hier bricht alles zusammen, wenn Sie den Parameter field auf name setzen.

Wenn field auf name eingestellt ist, wird der Name mit sanitize_title_for_query bereinigt.

$terms = "'" . implode( "','", array_map( 'sanitize_title_for_query', $query['terms'] ) ) . "'";

Dadurch werden Schrägstriche entfernt und leere Bereiche in Hypers umgewandelt. Dies bedeutet, dass Ski-in/Ski-out in ski-inski-out und Uit die koskas in uit-die-koskas konvertiert wird. Da Ihr Termname ungültig ist, lautet die folgende Abfrage, die die Term-ID und ihre untergeordneten Elemente abruft:

$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)
" );

schlägt fehl und gibt ein leeres Array zurück

array(0) {
}

FAZIT

Meiner Meinung nach ist die Hygiene hier falsch und sollte durch eine geeignetere Methode ersetzt werden, die einzelne Leerzeichen und Schrägstriche zulässt. Was ist der Zweck eines name-Feldes, wenn Sie Termnamen nicht richtig verwenden können? Diese Bereinigung beendet in den oben genannten Fällen die Verwendung des Felds name in einem tax_query.

Wie bereits erwähnt, besteht die beste Methode zur Verwendung von Termnamen darin, die Hilfsfunktion zu erstellen, in der Sie get_term_by() verwenden, um die ID eines Terms abzurufen, und diese ID dann in Ihrem tax_query zu verwenden.

UPDATE 3

Dank @manifestphil in den Kommentaren gibt es ein changeset # 31346 für genau dieses verrückte Problem der Überdesinfektion. Hoffen wir, dass dies in zukünftigen Versionen behoben wird

6
Pieter Goosen