Есть у WordPress одна неприятная особенность: при использовании красивых ссылок и их использовании при поиске кириллических (или любых не-ASCII) слов получается совсем не тот результат, который ожидается.
Например, есть такая ссылка:
http://blog.sjinks.pro/search/%D0%93%D0%B5%D0%BD%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D1%8F/
%D0%93%D0%B5%D0%BD%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D1%8F — это слово «Генерация», закодированное функцией urlencode().
Ожидается, что WordPress будет искать статьи со словом «генерация». Но, так как разработчики WordPress — американцы, они не предполагают, что существуют буквы кроме английских
Собственно, эта беда свойственна многим проектам с англоязычными авторами. Итак…
Проблема заключается в том, что WordPress выдаёт разные результаты для двух казалось бы идентичных запросов:
- «Традиционный поиск» — без использования красивых ссылок:
http://blog.sjinks.pro/?s=%D0%93%D0%B5%D0%BD%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D1%8F

- Поиск с использованием красивых ссылок:
http://blog.sjinks.pro/search/%D0%93%D0%B5%D0%BD%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D1%8F/

В первом случае WordPress вернул 6 результатов, во втором — только один. При этом в первом случае искомое слово отображается правильно, во втором — нет.
Если посмотреть на запросы при помощи плагина SQLMon, увидим такую картину: в первом случае запрос имеет вид
FROM wp_posts
WHERE 1=1
AND (((wp_posts.post_title LIKE '%Генерация%') OR (wp_posts.post_content LIKE '%Генерация%')))
AND wp_posts.post_type IN ('post', 'page', 'attachment')
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')
ORDER BY wp_posts.post_date DESC
LIMIT 0, 10
Во втором случае запрос выглядит страшнее:
FROM wp_posts
WHERE 1=1
AND (((wp_posts.post_title LIKE '%\\%D0\\%93\\%D0\\%B5\\%D0\\%BD\\%D0\\%B5\\%D1\\%80\\%D0\\%B0\\%D1\\%86\\%D0\\%B8\\%D1\\%8F%') OR (wp_posts.post_content LIKE '%\\%D0\\%93\\%D0\\%B5\\%D0\\%BD\\%D0\\%B5\\%D1\\%80\\%D0\\%B0\\%D1\\%86\\%D0\\%B8\\%D1\\%8F%')))
AND wp_posts.post_type IN ('post', 'page', 'attachment')
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')
ORDER BY wp_posts.post_date DESC
LIMIT 0, 10
Создаётся впечатление, что WordPress забыл выполнить urldecode(). Вполне вероятно, что этим никто и не озадачивался: при передаче параметров через строку запроса (как в первом случае) ответственность за перевод значений в «читаемую форму» лежит на PHP. А во втором случае закодированное значение является частью URI, поэтому PHP его не трогает.
Решение тривиально: в файл functions.php темы нужно добавить такой код (можно оформить плагином, но банально лень):
{
global $wp_rewrite;
if ($wp_rewrite->using_permalinks()) {
if (!empty($vars['s']) && empty($_GET['s'])) {
$vars['s'] = urldecode($vars['s']);
}
}
return $vars;
}
add_filter('request', 'my_request');
Хак применяется и на этом блоге, поэтому приведённые скриншоты более не воспроизводимы.
Меня зовут
А в случае использования плагина rus-to-lat или аналогичного, для формирования ЧПУ проблема остается?
Думаю, что да — rus-to-lat просто транслитерирует заголовки статей и страниц. Эта проблема лежит в ядре WordPress, поэтому любой плагин, использующий красивые пермалинки, будет затронут этой ошибкой.
как сделать поиск через /search/key/ вместо /?=key/ ?
Решение с использование JavaScript подойдёт?
через php или html никак не сделать?
С использованием красивых ссылок форма должна уходить на
http://sitename.com/search/<фраза>/. То есть в URL должна подставляться фраза, которую человек ввёл. Без JavaScript это сделать проблемно.Можно, конечно, написать хак, который будет делать так:
wp_redirect(siteurl('search/' . urlencode(stripslashes($_GET['s'])) . '/'), 301);
die();
}
Но это, на мой взгляд, извращение.
Leave a comment below if you dare
If by accident you see this form, please do not use it; use the form below this instead.