Включение терминов пользовательской таксономии в поиск
У меня есть две пользовательские таксономии, применяемые к двум пользовательским типам записей. Список терминов отлично отображается на боковой панели и показывает все связанные с ними записи. Однако при поиске конкретного термина не отображаются записи, содержащие этот термин.
Пример: http://dev.andrewnorcross.com/das/all-case-studies/ Поиск термина "PQRI"
Я не получаю никаких результатов. Есть идеи? Я пробовал использовать различные поисковые плагины, но они либо нарушают мои пользовательские параметры поиска, либо просто не работают.

Я бы также порекомендовал плагин Search Everything, но если вы хотите реализовать это с помощью стандартной функции поиска WordPress, вот код, который я использую в своей теме Atom:
// поиск по всем таксономиям, основано на: http://projects.jesseheap.com/all-projects/wordpress-plugin-tag-search-in-wordpress-23
function atom_search_where($where){
global $wpdb;
if (is_search())
$where .= "OR (t.name LIKE '%".get_search_query()."%' AND {$wpdb->posts}.post_status = 'publish')";
return $where;
}
function atom_search_join($join){
global $wpdb;
if (is_search())
$join .= "LEFT JOIN {$wpdb->term_relationships} tr ON {$wpdb->posts}.ID = tr.object_id INNER JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id=tr.term_taxonomy_id INNER JOIN {$wpdb->terms} t ON t.term_id = tt.term_id";
return $join;
}
function atom_search_groupby($groupby){
global $wpdb;
// группировка по ID записи
$groupby_id = "{$wpdb->posts}.ID";
if(!is_search() || strpos($groupby, $groupby_id) !== false) return $groupby;
// если группировка пуста, используем нашу
if(!strlen(trim($groupby))) return $groupby_id;
// если не пуста, добавляем нашу
return $groupby.", ".$groupby_id;
}
add_filter('posts_where','atom_search_where');
add_filter('posts_join', 'atom_search_join');
add_filter('posts_groupby', 'atom_search_groupby');
Этот код основан на плагине Tag-Search: http://projects.jesseheap.com/all-projects/wordpress-plugin-tag-search-in-wordpress-23

Это отлично! Как можно изменить этот код, чтобы исключить массив ID таксономий из поиска?

Следует отметить, что функции обратного вызова для этих хуков принимают 2 аргумента; второй для всех них — это экземпляр WP_Query, который передается по ссылке. Любые проверки на is_search()
или другие вызовы методов WP_Query (is_search()
, is_home()
и т.д.) всегда должны вызываться непосредственно на экземпляре запроса (например, $query->is_search()
, предполагая, что имя переменной экземпляра — $query
в сигнатуре обратного вызова), а не через функцию шаблона, которая всегда будет ссылаться на основной запрос, а не на запрос, для которого выполняется фильтр.

Кроме того, вероятно, не лучшая идея вставлять непосредственно в SQL-запрос сырую строку поиска, доступную публично... рекомендуемая литература

Хочу добавить, что здесь есть конфликт с WPML, потому что WPML уже использует 'T' в части join, поэтому использование чего-то кастомного вместо tr, tt и t решает эту проблему

@EvanMattson — вы прокомментировали выше, что «вероятно, не лучшая идея вставлять сырую публично доступную строку поиска напрямую в SQL-запрос». Как бы вы порекомендовали устранить этот риск? Я прочитал предоставленную вами ссылку, но не понял, как это связано с исходным ответом. Большое спасибо, Em.

@TheChewy в ответе выше показано использование get_search_query()
напрямую в MySQL-выражении WHERE. Этот код уязвим к SQL-инъекциям, когда любой может выполнять произвольные SQL-запросы на вашем сайте, передавая их через поле поиска. Очевидно, что поисковики работают в какой-то мере именно так, но важно, чтобы этот ввод был правильно подготовлен, чтобы гарантировать, что он интерпретируется как поисковые термины, а не SQL-команды. Именно для этого предназначен метод $wpdb->prepare()
, который описан в рекомендуемом чтении

@TheChewy ты также можешь найти хорошие примеры в документации для wpdb::prepare()
здесь: https://developer.wordpress.org/reference/classes/wpdb/prepare/

@EvanMattson Привет, Эван, спасибо за совет. Я новичок и в php, и в кастомном коде WP, и это сейчас для меня слишком сложно. Не мог бы ты продублировать код с добавлением $wpdb->prepare()
, если это не слишком сложно? Думаю, мне понадобятся недели, чтобы приблизиться к пониманию таких вещей.

Это стандартный поиск WordPress? Потому что похоже, он не включает таксономии (даже стандартные, такие как категории и теги) в поиск. Код ищет в post_title
и post_content
, но если вы хотите включить что-то ещё, вам следует использовать хук posts_search
.

Я попробовал решение Onetrickpony, указанное выше https://wordpress.stackexchange.com/a/5404/37612, которое отлично работает, но обнаружил одну проблему, которая не сработала в моем случае, и хотел бы внести одно небольшое изменение:
- если я искал строку в заголовке таксономии — это работает отлично
если в таксономии есть специальные символы, например, немецкие умлауты (ö,ä,ü), и пользователь ищет oe, ae, ue вместо специальных символов — необходимо добавить поиск по слагу таксономии —
OR t.slug LIKE '%".get_search_query()."%'
если вы ищете комбинацию поискового запроса и фильтра таксономии — это тоже работает отлично
Но проблема возникает, когда вы пытаетесь использовать только фильтр таксономии — хук поиска добавляет пустую строку к запросу, если текст не ищется, и по этой причине вы получаете ВСЕ записи в результатах, а не только те, которые относятся к отфильтрованной таксономии. Простое условие IF решает проблему. Таким образом, весь модифицированный код будет выглядеть так (работает идеально в моем случае!):
function custom_search_where($where){ global $wpdb; if (is_search() && get_search_query()) $where .= "OR ((t.name LIKE '%".get_search_query()."%' OR t.slug LIKE '%".get_search_query()."%') AND {$wpdb->posts}.post_status = 'publish')"; return $where; } function custom_search_join($join){ global $wpdb; if (is_search()&& get_search_query()) $join .= "LEFT JOIN {$wpdb->term_relationships} tr ON {$wpdb->posts}.ID = tr.object_id INNER JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id=tr.term_taxonomy_id INNER JOIN {$wpdb->terms} t ON t.term_id = tt.term_id"; return $join; } function custom_search_groupby($groupby){ global $wpdb; // группировка по ID записи $groupby_id = "{$wpdb->posts}.ID"; if(!is_search() || strpos($groupby, $groupby_id) !== false || !get_search_query()) return $groupby; // если группировка пуста, используем нашу if(!strlen(trim($groupby))) return $groupby_id; // если не пуста, добавляем нашу return $groupby.", ".$groupby_id; } add_filter('posts_where','custom_search_where'); add_filter('posts_join', 'custom_search_join'); add_filter('posts_groupby', 'custom_search_groupby');

Я нашел ответ от onetrickpony отличным, но он обрабатывает любой поиск как единый термин и не работает с поисковыми фразами в кавычках. Я немного изменил его код (в частности, функцию atom_search_where
), чтобы учесть эти две ситуации. Вот моя модифицированная версия его кода:
// поиск по всем таксономиям, основано на: http://projects.jesseheap.com/all-projects/wordpress-plugin-tag-search-in-wordpress-23
function atom_search_where($where){
global $wpdb, $wp_query;
if (is_search()) {
$search_terms = get_query_var( 'search_terms' );
$where .= " OR (";
$i = 0;
foreach ($search_terms as $search_term) {
$i++;
if ($i>1) $where .= " AND"; // --- измените на OR, если не требуется совпадение всех поисковых терминов с таксономиями
$where .= " (t.name LIKE '%".$search_term."%')";
}
$where .= " AND {$wpdb->posts}.post_status = 'publish')";
}
return $where;
}
function atom_search_join($join){
global $wpdb;
if (is_search())
$join .= "LEFT JOIN {$wpdb->term_relationships} tr ON {$wpdb->posts}.ID = tr.object_id INNER JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id=tr.term_taxonomy_id INNER JOIN {$wpdb->terms} t ON t.term_id = tt.term_id";
return $join;
}
function atom_search_groupby($groupby){
global $wpdb;
// группируем по ID записи
$groupby_id = "{$wpdb->posts}.ID";
if(!is_search() || strpos($groupby, $groupby_id) !== false) return $groupby;
// если группировка пуста, используем нашу
if(!strlen(trim($groupby))) return $groupby_id;
// если не пуста, добавляем нашу
return $groupby.", ".$groupby_id;
}
add_filter('posts_where','atom_search_where');
add_filter('posts_join', 'atom_search_join');
add_filter('posts_groupby', 'atom_search_groupby');

У меня такой же уровень информации, как у Яна. Я знаю, что поиск можно расширить с помощью плагинов.
Вероятно, Search Everything (плагин для WordPress) — это то, что вам нужно. Согласно списку возможностей, он теперь поддерживает пользовательские таксономии.

У меня такая же проблема с плагином корзины WooCommerce... Мои результаты поиска не включают пользовательскую таксономию 'product_tag', потому что это не стандартный тег записи. Я нашел решение в другой теме на StackOverflow по этому поводу:
Пример кода от tkelly сработал для меня, когда я заменил термин author
в его примере на product_tag
в соответствии с нашими потребностями для плагинов корзины.
