Экранирование налогового запроса WP-запроса, когда термин имеет специальный символ(ы)
Вот в чем моя проблема. У меня есть пользовательский тип записи, к которому я прикрепляю пользовательскую таксономию. Эта таксономия позволит администратору предоставлять предложения по поиску, которые гарантируют, что сообщение будет найдено при поиске пользователя. Эта таксономия также используется в интерфейсе для автоматического заполнения поля поиска этими предложениями.
Система работает нормально, за исключением случаев, когда термин содержит косую черту, пробел или другие "специальные" символы.
<?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'
)
)
));
?>
Я изучил возможность использования ускользающие функции, предоставляемые WordPress, но там не повезло. Я думал, что это будет простая проблема, но либо мой Google-fu не силен, либо мне просто не везет.
Я также проверил, что эта Ski-in/Ski-out
является точной строкой, хранящейся в MySQL. Я изучил возможность использования esc_attr()
, $wpdb->esc_like()
и esc_sql()
, но ни один из них не имеет эффекта.
Возможно, я упускаю что-то очевидное?
1 answers
Я не уверен, что это ошибка, но она нуждается в дальнейшем расследовании. Я провел несколько быстрых тестов в поле name
в tax_query
, и всякий раз, когда имя термина содержит специальный символ или содержит более одного слова, tax_query
исключается из SQL-запроса
ТЕСТ 1
Здесь я использую два термина: ваш термин Ski-in/Ski-out
и один из терминов на моем тестовом сайте Uit die koskas
. Теперь, если я выполню свой пользовательский запрос следующим образом
$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
var_dump()
запроса дает мне это
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"
tax_query
не добавляется к SQL-запросу
ТЕСТ 2
Если вы берете термин из одного слова без специального символа, запрос работает. Здесь я протестировал термин под названием 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
Это дает мне правильный SQL-запрос
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"
Я еще не уверен, намеренно ли это или ошибка, но тем временем вы можете взглянуть на исходный код WP_Query
и посмотреть, как tax_query
строится. Я также рассмотрю это в ближайшее время будущее
ОБНОВЛЕНИЕ 1
Я быстро просмотрел класс WP_Query
перед уходом на работу. Ближе к концу класса WP_Query
выполняет некоторые тесты на обратную совместимость, и, судя по значению eye, может показаться, что именно здесь все терпит неудачу, что, в свою очередь, приводит к сбою при добавлении клаусса соединения к SQL-запросу.
Я не могу найти билет trac по этой проблеме, если он есть, и у кого-нибудь есть ссылка, не стесняйтесь обновлять мой ответ или публиковать в комментарии.
ОБХОДНОЙ ПУТЬ
Если вам нужно и нужно использовать название термина, вы должны создать себе вспомогательную функцию, используя get_term_by()
. Затем вы можете использовать имя термина, чтобы получить объект термина, и использовать идентификатор термина оттуда для использования в tax_query
ОБНОВЛЕНИЕ 2
НАШЕЛ ЕГО
Проблема заключалась не в WP_Query
самой по себе ( какой беспорядок, просматривая эти классы ). WP_Query
использует WP_Tax_Query
чтобы построить tax_query
. Проверьте последнюю строку просто перед вызовом do_action
метода parse_tax_query
в WP_Query
$this->tax_query = new WP_Tax_Query( $tax_query );
Отлично, переходим в класс WP_Tax_Query
. Этот класс имеет следующий метод, transform_query
который преобразует один запрос из одного поля в другое. Здесь все ломается, когда вы устанавливаете свой параметр field
в name
С field
, установленным в name
, имя очищается с помощью sanitize_title_for_query
$terms = "'" . implode( "','", array_map( 'sanitize_title_for_query', $query['terms'] ) ) . "'";
Это удаляет косые черты и преобразует пустые пробелы в дефисы. Это означает, что Ski-in/Ski-out
является преобразуется в ski-inski-out
и Uit die koskas
преобразуется в uit-die-koskas
. Поскольку ваше имя термина недопустимо, следующий запрос, который получает идентификатор термина и его дочерние элементы,
$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)
" );
Завершается ошибкой и возвращает пустой массив
array(0) {
}
ЗАКЛЮЧЕНИЕ
ИМХО, санитария здесь неверна и должна быть заменена более подходящим методом, который допускает одиночные пробелы и косые черты. Какова цель наличия поля name
, если вы не можете правильно использовать имена терминов. Эта санитария убивает использование поле name
в tax_query
в вышеупомянутых случаях.
Как я уже говорил ранее, возможно, лучший метод, если вам нужно использовать имена терминов, - это создать вспомогательную функцию, в которой вы используете get_term_by()
, чтобы получить идентификатор из термина, а затем использовать этот идентификатор в своем tax_query
ОБНОВЛЕНИЕ 3
Благодаря @manifestphil в комментариях, есть набор изменений #31346, посвященный именно этой сумасшедшей проблеме чрезмерной очистки. Будем надеяться, что это будет исправлено в будущих выпусках