WordPress: подсветка искомого запроса в результатах поиска

Подсветка искомого запроса в результатах поиска WordPressУзнал о забавной финтифлюшке, которую можно применить на сайте, работающем на движке WordPress.

С помощью специального php-кода, вставляемого в файл шаблона, плюс чуток CSS, на странице результатов поиска можно реализовать выделение слов, совпадаемых с поисковым запросом.

Ниже рассказываю, каким образом это делается. Для осуществления задачи нам потребуется файл search.php.

Если у вас на сайте используется поиск, но в папке с шаблоном сайта нет файла search.php, то прошу вас самостоятельно изучить вопрос о том, какие необходимы изменения в шаблоне, чтобы они отобразились только на странице результатов поиска.

Интегрируем

  1. Находим в шаблоне следующий код:
    <?php the_title(); ?>

    И заменяем его на такой код:

    <?php
    	$title = get_the_title();
    	$keys = explode(" ",$s);
    	$title = preg_replace('/('.implode('|', $keys) .')/iu', '<strong class="search-excerpt">\0</strong>', $title);
      echo $title;
    ?>
    
  2. Затем ищем код, похожий на этот:
    <?php the_excerpt(); ?>
    

    или похожий на этот:

    <?php the_content(); ?>
    

    И заменяем его на следующий код:

    <?php
    	$excerpt = get_the_excerpt();
    	$keys = explode(" ",$s);
    	$excerpt = preg_replace('/('.implode('|', $keys) .')/iu', '<strong class="search-excerpt">\0</strong>', $excerpt);
      echo $excerpt;
    ?>
    

    Если у вас в шаблоне использовалась функция the_content(), то, чтобы как и прежде выводился полный текст поста, необходимо в предыдущем куске кода заменить get_the_excerpt() на get_the_content(). Только учтите, что в этом случае возможны случаи некорректного отображения форматирования поста. Поэтому я рекомендую в результатах поиска выводить анонс поста (get_the_excerpt()).

    Чтобы подсвечивать слова только по их полному соответствию запросу, в вышеуказанных кодах замените: '/('.implode('|', $keys) .')/iu' на: '~/b('.implode('|', $keys) .')/b~iu'

  3. Теперь лишь осталось с помощью CSS подсветить слова искомого запроса. Для этого в файле стилей своего шаблона добавляем вот такое правило:
    .search-excerpt {	background: #FF9 }
    
  4. Готово. Наслаждаемся результатом =)

Как HTML-тег, так и стиль к нему (<strong class="search-excerpt"></strong>) вы можете заменить на какой-либо другой, если есть желание. В этом случае внесите соответствующие корректировки в вышеуказанный php-код. Можно, например, сделать так, чтобы в заголовке фон выделенных слов был одним цветом, а в тексте поста другим.

Пример

Ну и, конечно же, посмотрим, как это выглядит прямо на данном блоге. К примеру, запрос “предпросмотр комментария“.

Единственный минус, который я нахожу в данной технике – если в поисковом запросе будет присутствовать какое-то очень короткое слово, например, предлог “в”, то на странице результатов будет выделена каждая буква “в”, которая присутствует в посте в любом слове.

Комментарии (27)

  1. 10 января 2009 г. в 23:28

    Мало того, что он будет выделять буквы “в” в каждом слове, он будет игнорировать вхождения так же, как это делает антимат на болоьшинсвте форумов – т.е. выделять “бля” в “оскорблять”. А в ВП движок вроде учитывает вхождения именно слов, а не подстрок (хотя я, наверное, ошибаюсь), пусть и без словоформ.

    Можно сделать подсветку именно полного вхождения, изменив условие на ‘~/b(‘.implode(‘|’, $keys) .’)/b~iu’. Но, наверное, даже такое изменение будет лишним – подсветкой будут выделены только целые слова, совпадающие с ключевыми, без словоформ (для них условие будет гораздо сложнее).

  2. 11 января 2009 г. в 00:37

    Сергей М.,

    Во-первых, спасибо за условие для полного вхождения. Я изначально такой вариант и хотел предложить, но в регулярных выражения не бум-бум =)

    Во-вторых,

    Мало того, что он будет выделять буквы “в” в каждом слове, он будет игнорировать вхождения так же, как это делает антимат на болоьшинсвте форумов – т.е. выделять “бля” в “оскорблять”.

    я считаю это не критичным. Ведь посетители не матерные слова будут искать. В общем, предоставим выбор веб-мастеру.

  3. Вит
    11 января 2009 г. в 01:08

    Аналогичное можно сделать на клаент-сайд используя JavaScript. Можно стащить код с trac вот тут: http://www.edgewall.org/chrome/common11/js/search.js

  4. 11 января 2009 г. в 13:03

    если делать

    ~/b(‘.implode(‘|’, $keys) .’)/b~iu

    то внутрь могут попасть html. для того чтобы этого не происходило надо использовать вот такой паттерн

    ~(?!<.*)(?)~i

  5. 11 января 2009 г. в 13:10

    CTAPbIu_MABP, с вашим вариантом больше не будет никаких подвохов?

  6. 12 января 2009 г. в 01:51

    Спасибо что подробно расписали, ато порой видишь хоршую тему у поста, а вот разъянений какх-то конкретных нет

  7. 12 января 2009 г. в 12:04

    Dimox, у меня был только один неприятный момент. Я вытаскивал из реферера поисковый запрос и подсвечивал но когда меня нашли по куску кода, например по

    $title = get_the_title();

    оно превратилось в

    $title = ();

    и код стал нечитаемым, а так никаких проблем не было

  8. 12 января 2009 г. в 12:12

    чтото я накосячил во втором куске кода

    $title = get_the_title();

    вот так вот получилось

  9. 12 января 2009 г. в 23:57

    @CTAPbIu_MABP: вообще, ничего удивительного. Особенно, если из рефера от поисковика не только выцепляешь кеи, но и эксплодишь по пробелам.

  10. Anonimous
    13 января 2009 г. в 00:23

    Сталкивался с задачей подсветки результатов поиска.
    Вариант, который предлагает CTAPbIu_MABP сдабоват для html , – к примеру, если в запросе есть слово “class”, то тэг

    <div class="divClass">

    будет успешно испорчен.
    Написать универсальное выражение можно, но оно будет громоздким, а самое главное – очень тормозным.
    Я в своей практике использовал выражение вида

    (?is)(?<=((|\A)[^<]*))(’.implode(’|',$keys).’)

    оно успешно работает в 99% случаев. В зоне риска теги включающие строки с символом “>”. Например:

    <img alt="WORD>word"/>

    В итоге, проблемы могут быть только с подобными alt атрибутами и с javascript включениями в html.

    Выделять полные вхождения можно, используя

    (?is)(?<=((|\A)[^<]*))(\b(’.implode(’|',$keys).’)\b)

    А следующий вариант будет вместо “бля” в “оскорблять” находить полное слово “оскорблять”:

    (?is)(?<=((|\A)[^<]*))(\b\w*(’.implode(’|',$keys).’)\w*\b)

    А ещё, слова в $keys надо эскейпить :)
    Попробуй в поиск вписать \w или \S.
    И с русским здесь что-то не то, по \w должны были найтись все печатные символы, а нашлись только английские и цифры. При таком отношении к кириллице ни моё последнее выражение, ни вариант CTAPbIu_MABP’а работать полноценно не будет.

  11. 13 января 2009 г. в 10:50

    Сергей М., Намекаете на XSS? я все фильтровал и перед регуляркой еще preg_quote делал :)

  12. 26 февраля 2009 г. в 23:55

    я тут случайно нашел этот пост… оказалось пропустил камент от анончика. Анончик все так красиво расписал тока вот одно маленькое НО: регулярка была обрезана и не работает, так что не понятно что проверял анончик. Нормальная регулярка вот:

    ~(?!<.*)(?<!\w)('.implode('|',$keys).')(?!\w|[^<>]*>)~i

    более того анончик не прав дважды моя регулярка нормально работает с кириллицей

    1. 4 апреля 2009 г. в 08:08 / ответ на коммент CTAPbIu_MABP

      моя регулярка нормально работает с кириллицей

      Зависит от того, как и с каким PCRE собран PHP. У меня, например, на 5.2.8 в Ubuntu 8.10 не работает, приходится использовать Юникодные выражения (что, опять же, завязывается на версию PCRE).

      1. 4 апреля 2009 г. в 10:06 / ответ на коммент Vladimir

        У меня php 5.2.6 на fedora 9 и все нормально…
        у тебя кодировка utf8?

  13. 26 февраля 2009 г. в 23:56

    вот блин еще раз пишу регулярку…

    ~(?!<.*)(?<!\w)('.implode('|',$keys).')(?!\w|[^<>]*>)~i

  14. 5 марта 2009 г. в 00:46

    У меня нету файла search.php, может кто-нить из здешних гуру поможет мне установить подсветку?

    1. 5 марта 2009 г. в 11:29 / ответ на коммент Ян

      Сделай копию из файла index.php или archive.php.

      1. 5 марта 2009 г. в 15:56 / ответ на коммент Dimox

        Сделать копию чего именно из index.php или archive.php и куда? Сори, но ничего не понял.

        1. 5 марта 2009 г. в 18:46 / ответ на коммент Ян

          Т.е. создай файл search.php и скопируй в него содержимое из index.php или archive.php.

          1. 5 марта 2009 г. в 19:05 / ответ на коммент Dimox

            Понятно. Дальше делать всё по инструкции? Тогда возникает 2 вопроса: в обоих файлах нету строчек

            <?php the_excerpt(); ?> и 
            <?php the_content(); ?>

            , а

            <?php the_title(); ?>

            встречается дважды.

            1. 5 марта 2009 г. в 23:11 / ответ на коммент Ян

              Сложно что-либо подсказать, не видя исходный код.

              1. 6 марта 2009 г. в 17:33 / ответ на коммент Dimox

                Ок, скину на мыло.

  15. 21 июня 2009 г. в 12:54

    Здорово, но вообще вроде давно есть плагин search unleashed, который мало того, что подсвечивает все это дело, но и индексирует не только заголовки\текст записи, но и комменты, а при поиске(или заходе посетителя из поисковика) выдает окошко, мол Вы пришли сюда в поиске следующих слов и подсвечивает эти слова в записи:

    http://clip2net.com/clip/m10803/1245578026-clip-27kb.jpg

    1. 21 июня 2009 г. в 17:35 / ответ на коммент Sonikelf

      В свое время я пользовался этим плагином, но потом отключил за ненадобностью, итак уже много различных плагинов на блоге используется.

  16. Роман
    26 августа 2009 г. в 22:30

    А у меня ниче не получилось. Как было – так и осталось. Кто-нибудь может помочь? ICQ 100-999-1
    Пойду еще в гугль, спрошу плагин

  17. 20 октября 2009 г. в 12:41

    Чет я тоже сделал и не помогло :(

  18. Артём
    30 декабря 2009 г. в 21:46

    Я такое переложил на плечи пользователя, т.е. на JavaScript, т.к. некоторый текст, который также должен был подсвечиваться, у меня находился в HTML коде.
    Скрипт бежит по коду страницы, находит искомый результат и окружает его тэгами с классиком определенным в css для подсветки.
    код по ссылке http://ar4ibal.pp.ua/?target=view&event=view_post&post_id=18

Ваш комментарий

Жирный текст

Ссылка

Цитата

Внутристрочный код

CSS-код

HTML-код

JavaScript-код

PHP-код