Строительство Расширенный WordPress Поиск с WP-запрос

Многие сверхдержавы WordPress происходят из его гибкой архитектуры данных, что позволяет разработчикам широко настроить свои установки с пользовательскими типами постов, таксономиями и полями. Однако, когда дело доходит до его поиска, WordPress предоставляет нам только одно поле форме, которая часто появляется неадекватным и приводит к сайту админайнов принять внешние поисковые системы, как Google Custom Search, или сторонних плагинов.

В этой статье я покажу вам, как обеспечить вашу установку WordPress с передовой поисковой системой, позволяющей пользователю искать и извлекать содержимое из конкретного пользовательского типа поста, фильтрации результатов пользовательских терминов таксономии и нескольких пользовательских полей Значения.

Дальнейшее чтение на SmashingMag:

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

Итак, давайте начнем изучать некоторые ключевые концепции.

Запросы пользователей

Когда пользователь нажимает на ссылку или вводит URL-адрес, указывающий на страницу веб-сайта, WordPress выполняет ряд операций, хорошо описанных в Обзоре запросовCodex. Короче говоря, это то, что происходит:

  1. WordPress разбирает запрошенный URL в набор параметров запроса (так называемая спецификация запроса).
  2. Все is_ переменные, связанные с запросом, настроены.
  3. Спецификация запроса преобразуется в запрос MyS’L, который выполняется по базе данных.
  4. Полученный набор данных хранится в $wp_query объекте.
  5. WordPress затем обрабатывает 404 ошибки.
  6. WordPress посылает блог HTTP заголовки.
  7. Переменные цикла инициализированы.
  8. Файл шаблона выбирается в соответствии с правилами иерархии шаблонов.
  9. WordPress запускает петлю.

На первом месте вывод URL-адресов, так что давайте погрузимся в строки запроса и переменные.

WP Запрос Варс: По умолчанию и пользовательские переменные

Кодекс гласит:

Массив query vars доступен для пользователей или разработчиков WordPress для использования для запроса для определенных типов контента или для помощи в теме и / или плагин дизайн и функциональность.

Другими словами, vars запроса WordPress — это те переменные в строке запроса, которые определяют (или влияют) на результаты запроса, выполняемого против базы данных. По умолчанию WordPress предоставляет публичные и частные вопросы, и Кодекс определяет их следующим образом:

Публичные vars запроса доступны и пригодны для удовковы через прямой запрос URL в виде example.net/?var1=value1&var2=value2 . Частные vars запроса не могут быть использованы в URL, хотя WordPress принимает строку запроса с частными vars запросов, значения не будут переданы в запрос и должны быть помещены непосредственно в запрос. Приведен пример ниже.

query_posts('privatevar=myvalue');

Как следствие, это не возможно отправить через строку запроса частных vars, как categoryin categorynot_in , и category__end т.д. (проверить Кодекс для полного списка встроенных в запрос vars) .

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

В качестве примера мы можем запросить определенный тип публикации, добавив post_type параметр в строку запроса; или мы можем запросить пользовательскую таксономию, приложив к строке запроса taxonomy-name=taxonomy-term пару. Например, мы можем создать следующий URL:

mywebsite.com/?post_type=movie&genre=thriller

WordPress будет запрос базы данных и получить все movie типы сообщений, принадлежащих к thriller жанру, где genre пользовательские таксономии.

Это потрясающе, но это еще не все. То, что мы говорили до сих пор, на самом деле, касается только встроенных функций query vars. WordPress позволяет нам идти дальше и создавать наши собственные пользовательские переменные запроса.

Регистрация пользовательских запросов Vars

Прежде чем мы сможем использовать их, пользовательский запрос vars должны быть зарегистрированы. Мы можем выполнить эту задачу благодаря query_vars фильтру. Итак, давайте откроем основной файл плагина (или файла функций темы.php) и напишем следующий код:

/**
 * Register custom query vars
 *
 * @link https://codex.wordpress.org/Plugin_API/Filter_Reference/query_vars
 */
function myplugin_register_query_vars( $vars ) {
    $vars[] = 'author';
    $vars[] = 'editor';
    return $vars;
}
add_filter( 'query_vars', 'myplugin_register_query_vars' );

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

Теперь мы можем включить новые переменные в параметры, которые будут влиять на запрос. Эти параметры будут доступны в наших скриптах благодаря get_query_var() тегу шаблона, как мы увидим позже. Теперь пришло время ввести класс, который управляет запросами в WordPress.

Ее ВеличествоWP_Query

Запрос базы данных не является легкой задачей. Это не только вопрос построения эффективного запроса, но это проблема, которая требует тщательного учета вопросов безопасности. Благодаря WP_Query классу,WordPress дает нам доступ к базе данных быстро (нет необходимости, чтобы наши руки грязные с S’L) и надежно WP_Query (строит безопасные запросы за кулисами).

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

Возьмем в качестве примера общую петлю:

<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
    <!-- code here -->
<?php endwhile; else : ?>
    <!-- code here -->
<?php endif; ?>

Если вы новичок в разработке WordPress, вы можете спросить: «Эй, приятель! Где запрос?

На самом деле, вам не нужно создавать новый экземпляр WP_Query объекта. Сам класс устанавливает запрос, который должен быть выполнен в соответствии с запрашиваемым страницей. Таким образом, если зрителю сайта требуется архив категории, WordPress запустит запрос, извлекающий все сообщения, относящиеся к этой конкретной категории, и петля покажет их.

Но это всего лишь изменяемый основной пример основного запроса. Мы можем сделать гораздо больше, и отфильтровать возвращающийся набор результатов детально, просто передавая массив параметров новому экземпляру WP_Query класса, как это будет делать в следующем примере:

// An array of arguments
$args = array( 'arg_1' => 'val_1', 'arg_2' => 'val_2' );

// The Query
$the_query = new WP_Query( $args );

// The Loop
if ( $the_query->have_posts() ) {

    while ( $the_query->have_posts() ) : $the_query->the_post(); 
        // Your code here
    endwhile;

} else {
        // no posts found
}
/* Restore original Post Data */
wp_reset_postdata();

Все выглядит немного сложнее, не так ли? Но если мы присмотримся, то это не так.

Новый экземпляр WP_Query сохраняет массив аргументов, которые повлияют на данные, извлеченные из базы данных. Кодекс предоставляет полный список параметров,группируя их в семнадцать категорий. Так, например, у нас есть автор Params, Категория Params, только один параметр поиска ( ), s Пользовательские поля params, и так далее (мы вернемся к WP_Query парамс в момент).

Теперь, когда мы мгновенно $query объект, мы можем получить доступ ко всем его методам и свойствам. have_posts проверяет, есть ли сообщение остается печататься, в то время как the_post перемещает петлю вперед к последующей должности и обновляет $post глобальную переменную.

Вне петли, при использовании пользовательского запроса, мы всегда должны сделать звонок wp_reset_postdata() . Эта функция восстанавливает $post глобальную переменную после выполнения пользовательского запроса и необходима, поскольку любой новый запрос $post перезаписывает. Из Кодекса:

Примечание: Если вы используете the_post() с запросом, вам нужно запустить wp_reset_postdata() потом, чтобы шаблон теги использовать текущий пост основного запроса снова.

Теперь вернемся к запросу args.

WP_QueryАргументы

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

Первая группа, Параметры автора, включает в себя те аргументы, которые позволяют нам создавать запросы на основе автора (ы) сообщений (страниц и типов публикаций). К ним относятся:

  • author
  • author_name
  • author__in
  • author__not_in

Если вы хотите получить все сообщения carlo из, вам просто нужно установить следующий запрос:

$query = new WP_Query( array( 'author_name' => 'carlo' ) );

Вторая группа включает параметры категории, т.е. все те аргументы, которые позволяют нам запросить (или исключить) публикации, присвоенные одной или нескольких категориям:

  • cat
  • category_name
  • category__and
  • category__in
  • category__not_in

Если нам понадобились все сообщения, назначенные webdesign в категорию, мы просто должны установить category_name аргумент, как мы будем делать в следующем примере:

$query = new WP_Query( array( 'category_name' => 'webdesign' ) );

Следующий запрос ищет сообщения из более чем одной категории, запятая, стоящая в OR для:

$query = new WP_Query( array( 'category_name' => 'webdesign,webdev' ) );

Мы также можем попросить должности, принадлежащие к обеим webdesign webdev категориям, с плюсом ( + ) смысл AND :

$query = new WP_Query( array( 'category_name' => 'webdesign+webdev' ) );

И мы также можем передать массив идентивере, как в следующих примерах:

$query = new WP_Query( array( 'category__in' => array( 4, 9 ) ) );
$query = new WP_Query( array( 'category__and' => array( 4, 9 ) ) );

И так далее с тегами и таксономиями, поиск ключевых слов, сообщений, страниц и типов сообщений. Для более подробного пошагового запроса обратитесь к Кодексу.

Как мы уже говорили ранее, мы также можем установить несколько аргументов и получить, например, все сообщения в определенной категории, AND написанные определенным автором:

$query = new WP_Query( array( 'author_name' => 'carlo', 'category_name' => 'webdesign' ) );

Когда архитектура данных становится более сложной — и это происходит, когда мы добавляем пользовательские поля и таксономии для размещения типов — тогда может стать необходимым установить один или несколько параметров Custom Field, позволяющих нам получить все сообщения (или пользовательские типы постов) помечены с конкретные значения пользовательских полей. В ближайшее время нам нужно выполнить мета-запрос по базе данных.

WordPress Мета Запросы

Кодекс информирует нас о том, что при работе с мета-запросом WP_Query используется WP_Meta_Query класс. Этот класс, представленный в WordPress 3.2, создает код запросов на основе пользовательских полей.

Чтобы создать запрос на основе одного пользовательского поля, нам просто нужен один или несколько из следующих аргументов:

  • meta_key
  • meta_value
  • meta_value_num
  • meta_compare

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

$args = array( 
    'post_type'     => 'accommodation', 
    'meta_key'      => 'city', 
    'meta_value'        => 'Freiburg', 
    'meta_compare'  => 'LIKE' );

После того как мы установить аргументы, мы можем построить запрос так же, как и раньше:

// The Query
$the_query = new WP_Query( $args );

// The Loop
if ( $the_query->have_posts() ) {

    while ( $the_query->have_posts() ) : $the_query->the_post(); 
        // Your code here
    endwhile;

} else {
        // no posts found
}
/* Restore original Post Data */
wp_reset_postdata();

Скопируйте и вставьте приведенный выше код в файл шаблона, и вы получите архив всех доступных помещений во Фрайбурге.

Это относится к одному пользовательскому полю. Но что делать, если нам нужно построить запрос на основе нескольких пользовательских полей?

meta_queryАргумент

Для такого рода запросов WP_Meta_Query класс (и WP_Query класс также) предоставляет meta_query параметр. Это должен быть массив массивов, как показано в следующем примере:

$args = array(
    'post_type'  => 'accommodation',
    'meta_query' => array(
        array(
            'key'     => 'city',
            'value'   => 'Freiburg',
            'compare' => 'LIKE',
        ),
    )
);

meta_queryЭлемент представляет собой двухмерный массив, элементы которого представляют собой отдельные мета-запросы со следующими аргументами:

Описание типа аргумента
key Строка Идентифицирует пользовательское поле.
value строка-массив Может быть массив только тогда, когда compare ‘IN’ значение, ‘NOT IN’ , или ‘BETWEEN’ ‘NOT BEETWEEN’ .
compare Строка Оператор сравнения. Принятые значения, , , , , , , , , , , , , ’=’ ’!=’ ‘>‘ ‘>=’ ‘<‘ ‘<=’ и ‘LIKE’ ‘NOT LIKE’ ‘IN’ ‘NOT IN’ ‘BETWEEN’ ‘NOT BETWEEN’ ‘EXISTS’ ‘NOT EXISTS’ ‘REGEXP’ ‘NOT REGEXP’ ‘RLIKE’ . Он по умолчанию ’=’ .
type Строка Пользовательский тип поля. Возможные ‘NUMERIC’ значения, ‘BINARY’ , , , , , ‘CHAR’ ‘DATE’ ‘DATETIME’ ‘DECIMAL’ ‘SIGNED’ ‘TIME’ . ‘UNSIGNED’ Он по умолчанию ‘CHAR’ .

Если мы установили несколько пользовательских полей, мы также должны назначить relation аргумент meta_query элементу.

Теперь мы можем создать более продвинутый запрос. Начнем с установки аргументов и создания нового WP_Query экземпляра:

$args = array(
    'post_type' => 'accommodation',
    'meta_query'    => array(
        array( 'key' => 'city', 'value' => 'Paris', 'compare' => 'LIKE' ),
        array( 'key' => 'type', 'value' => 'room', 'compare' => 'LIKE' ),
        'relation' => 'AND'
    )
);
$the_query = new WP_Query( $args );

В данном meta_query споре содержится два массива мета-запроса и третий параметр, устанавливающий связь между мета-запросами. Запрос выполняет поиск в таблице wp’posts для всех accommodation типов сообщений, где пользовательские поля и city хранение соответственно значения и type Paris room .

Давайте скопируем и впинем код в файл шаблона под названием archive-accommodation.php. По запросу WordPress выполнит запрос, ища таблицу wp’posts, и петля покажет результаты, если она доступна.

На данный момент мы все еще пишем код в файле шаблона. Это означает, что наш скрипт статичен, и каждый раз, когда цикл работает, он будет производить тот же выход. Но мы должны позволить пользователям сайта делать пользовательские запросы, и для выполнения этой задачи нам необходимо динамически создавать пользовательские запросы.

pre_get_postsФильтр

pre_get_posts Крюк действия выстрелил после $query создания объекта, но до его выполнения. Чтобы изменить запрос, нам придется подключить пользовательский обратный pre_get_posts вызов.

В предыдущем примере мы запросили базу данных, чтобы получить все публикации в webdesign категории от определенного автора. В следующем примере мы передаем объекту те же $query аргументы, но мы не будем выполнять работу с файлом шаблона, как это было раньше, но вместо этого мы будем использовать основной файл плагина (или функции темы.php). Давайте напишем следующий блок кода:

function myplugin_pre_get_posts( $query ) {
    // check if the user is requesting an admin page 
    // or current query is not the main query
    if ( is_admin() || ! $query->is_main_query() ){
        return;
    }
    $query->set( 'author_name', 'carlo' );
    $query->set( 'category_name', 'webdesign' );
}
add_action( 'pre_get_posts', 'myplugin_pre_get_posts', 1 );

$queryОбъект передается функции обратного вызова по ссылке, а не по значению, а это означает, что любые изменения, внесенные в запрос, непосредственно влияют на исходный $query объект. Кодекс говорит:

pre_get_postsДействие предоставляет разработчикам доступ к $query объекту по ссылке (любые изменения, которые вы вносите $query непосредственно к исходному объекту — значение возврата не требуется).

Поскольку мы манипулизируя исходный $query объект, мы должны обратить внимание на то, над каким запросом мы работаем. is_main_queryМетод проверяет, является ли текущий $query объект… (да!) основной запрос. Кодекс также сообщает нам, что pre_get_posts фильтр может повлиять на панель админ, а также на передние страницы. По этой причине более чем уместно проверить запрашиваемую страницу с is_admin условным тегом.

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

Теперь мы можем закончить наше введение в основные инструменты, доступные для обработки запросов WordPress. Теперь пришло время представить конкретный пример их использования, выстраивая передовую поисковую систему контента сайта. Наше тематическое исследование предоставляется на сайте недвижимости.

От теории к коду: Создание поисковой системы

Мы будем следовать следующим шагам:

  1. Определите структуру данных.
  2. Зарегистрируйте пользовательский vars запроса.
  3. Получите значения var запроса и используйте их для создания пользовательского запроса.
  4. Создайте форму, программно генерирующую значения поля.

1. Определить структуру данных

Цель пользовательских типов постов заключается в добавлении содержимого, которое логически не может быть включено ни в сообщения хима, ни в статических страницах. Пользовательские типы должностей особенно уместны для представления событий, продуктов, книг, фильмов, элементов каталога и так далее. Здесь мы собираемся создать архив объявлений о недвижимости со следующей структурой:

  • пользовательский тип поста: accommodation ;
  • пользовательские таксономии: typology (B и B, проживание в семье, отель и т.д.)
  • пользовательское поле: _sm_accommodation_type (весь дом, отдельная комната, общая комната)
  • пользовательское поле:_sm_accommodation_city
  • другие пользовательские поля

Мы должны зарегистрировать тип поста, пользовательские таксономии и пользовательских полей и мета-боксов, как показано на рисунке ниже.

Accommodation edit page
Страница размещения для отсечения показывает все пользовательские мета-коробки и поля. (Посмотреть большую версию)

На рисунке показано, как страница Edit Accommodation появится после того, как будут зарегистрированы три пользовательских мета-коробки, содержащие пользовательскую таксономию Типологии и несколько пользовательских полей.

Это не наша цель, чтобы проанализировать WordPress архитектуры данных, так как эта тема уже была охвачена здесь, на Smashing Magazine Даниэль, Брайан, Кевин, Джош и Джастин. Читайте их статьи, если вам нужно переподготовку, и вернуться, как только вы будете готовы.

После того как мы определили архитектуру данных, пришло время зарегистрировать vars запроса.

2. Зарегистрируйте переменные запроса

Ранее мы определили query vars как key=value пары, следующие за вопросительным знаком в URL-. Но прежде чем мы сможем справиться с этими парами в наших сценариях, мы должны зарегистрировать их в плагине или файле функций. Для наших целей нам нужны только две переменные, которые позволят выдать запрос на основе значений соответствующих пользовательских полей:

/**
 * Register custom query vars
 *
 * @link https://codex.wordpress.org/Plugin_API/Filter_Reference/query_vars
 */
function sm_register_query_vars( $vars ) {
    $vars[] = 'type';
    $vars[] = 'city';
    return $vars;
} 
add_filter( 'query_vars', 'sm_register_query_vars' );

Ну вот! Мы добавили еще два параметра для запроса базы данных. Теперь имеет смысл создать URL, как этот:

http://example.com/?type=XXX&city=YYY

3. Манипулировать запрос

Теперь давайте добавим новый блок кода в наш скрипт:

/**
 * Build a custom query based on several conditions
 * The pre_get_posts action gives developers access to the $query object by reference
 * any changes you make to $query are made directly to the original object - no return value is requested
 *
 * @link https://codex.wordpress.org/Plugin_API/Action_Reference/pre_get_posts
 *
 */
function sm_pre_get_posts( $query ) {
    // check if the user is requesting an admin page 
    // or current query is not the main query
    if ( is_admin() || ! $query->is_main_query() ){
        return;
    }

    // edit the query only when post type is 'accommodation'
    // if it isn't, return
    if ( !is_post_type_archive( 'accommodation' ) ){
        return;
    }

    $meta_query = array();

    // add meta_query elements
    if( !empty( get_query_var( 'city' ) ) ){
        $meta_query[] = array( 'key' => '_sm_accommodation_city', 'value' => get_query_var( 'city' ), 'compare' => 'LIKE' );
    }

    if( !empty( get_query_var( 'type' ) ) ){
        $meta_query[] = array( 'key' => '_sm_accommodation_type', 'value' => get_query_var( 'type' ), 'compare' => 'LIKE' );
    }

    if( count( $meta_query ) > 1 ){
        $meta_query['relation'] = 'AND';
    }

    if( count( $meta_query ) > 0 ){
        $query->set( 'meta_query', $meta_query );
    }
}
add_action( 'pre_get_posts', 'sm_pre_get_posts', 1 );

Этот код является суммой всего, что мы рассмотрели в первой части статьи. Функция обратного вызова завершает работу, если пользователь находится в панели админ, если текущий запрос не является основным запросом, и если тип публикации не accommodation является.

Позже функция проверяет, доступен ли какой-либо из заданных запросов, которые мы зарегистрировали ранее. Эта задача выполняется благодаря get_query_var функции, которая извлекает общедоступный запрос из запроса HTTP (подробнее читайте get_query_var в Кодексе). Если переменная существует, то обратный вызов определяет один массив для каждого мета-запроса и толкает его в многомерный $meta_query массив.

Наконец, если доступны по крайней мере два мета-запроса, то relation аргумент заталкивается $meta_query и его значение устанавливается на ‘AND’ . После выполнения set метод сохраняет $query для последующего выполнения.

Вам не нужно беспокоиться о дезинфекции данных здесь, потому что WP_Query и WP_Meta_Query классы делают работу за нас (проверить WP_Query и WP_Meta_Query исходный код)

4. Создайте форму поиска

Данные формы представляются GET методом. Это означает, что name value и атрибуты полей формы отправляются в качестве переменных URL (т.е. в виде vars запроса). Таким образом, мы собираемся присвоить name атрибутам полей форм те же значения, что и ранее зарегистрированные vars запроса city (и), в то время как значения поля могут быть type назначены программно, извлекая данные из базы данных, или заполнены пользователем.

Сначала мы создадим короткий код, который позволит амините сайта включать форму поиска в сообщения и страницы сайта. Наш шорт-код будет подключен к init действию:

function sm_setup() {
    add_shortcode( 'sm_search_form', 'sm_search_form' );
}
add_action( 'init', 'sm_setup' );

Далее мы определим функцию обратного вызова, которая будет производить HTML формы, содержащей три выбранных поля, соответствующие пользовательской таксономии и два пользовательских поля.

function sm_search_form( $args ){
    // our code here
}

$args— это массив атрибутов короткого кода. Внутри функции мы добавим следующий код:

// The Query
// meta_query expects nested arrays even if you only have one query
$sm_query = new WP_Query( array( 'post_type' => 'accommodation', 'posts_per_page' => '-1', 'meta_query' => array( array( 'key' => '_sm_accommodation_city' ) ) ) );

// The Loop
if ( $sm_query->have_posts() ) {
    $cities = array();
    while ( $sm_query->have_posts() ) {
        $sm_query->the_post();
        $city = get_post_meta( get_the_ID(), '_sm_accommodation_city', true );

        // populate an array of all occurrences (non duplicated)
        if( !in_array( $city, $cities ) ){
            $cities[] = $city;    
        }
    }
}
} else{
       echo 'No accommodations yet!';
       return;
}

/* Restore original Post Data */
wp_reset_postdata();

if( count($cities) == 0){
    return;
}

asort($cities);

$select_city = '<select name="city" style="width: 100%">';
$select_city .= '<option value="" selected="selected">' . __( 'Select city', 'smashing_plugin' ) . '</option>';
foreach ($cities as $city ) {
    $select_city .= '<option value="' . $city . '">' . $city . '</option>';
}
$select_city .= '</select>' . "n";

reset($cities);

Мы создали запрос, который будет извлекать все accommodation типы сообщений, установить специальное поле с именем _sm_accommodation_city (подчеркивание, предшествующее названию, представляет собой скрытое пользовательское поле).

Петля не будет отображать какое-либо размещение, но добавит элементы в $cities массив из соответствующего значения пользовательского поля. Условие будет пропускать дубликаты. Если нет жилья, выполнение прерывается; в противном случае элементы массива сортируются и используются для печати значений первой группы option элементов.

Кодекс информирует нас о том, что при работе с мета-запросом WP_Query используется WP_Meta_Query класс. Этот класс, представленный в WordPress 3.2, создает код запросов на основе пользовательских полей.

Чтобы создать запрос на основе одного пользовательского поля, нам просто нужен один или несколько из следующих аргументов:

  • meta_key
  • meta_value
  • meta_value_num
  • meta_compare

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

$args = array( 
    'post_type'     => 'accommodation', 
    'meta_key'      => 'city', 
    'meta_value'        => 'Freiburg', 
    'meta_compare'  => 'LIKE' );

После того как мы установить аргументы, мы можем построить запрос так же, как и раньше:

// The Query
$the_query = new WP_Query( $args );

// The Loop
if ( $the_query->have_posts() ) {

    while ( $the_query->have_posts() ) : $the_query->the_post(); 
        // Your code here
    endwhile;

} else {
        // no posts found
}
/* Restore original Post Data */
wp_reset_postdata();

Скопируйте и вставьте приведенный выше код в файл шаблона, и вы получите архив всех доступных помещений во Фрайбурге.

Это относится к одному пользовательскому полю. Но что делать, если нам нужно построить запрос на основе нескольких пользовательских полей?

meta_queryАргумент

Для такого рода запросов WP_Meta_Query класс (и WP_Query класс также) предоставляет meta_query параметр. Это должен быть массив массивов, как показано в следующем примере:

$args = array(
    'post_type'  => 'accommodation',
    'meta_query' => array(
        array(
            'key'     => 'city',
            'value'   => 'Freiburg',
            'compare' => 'LIKE',
        ),
    )
);

meta_queryЭлемент представляет собой двухмерный массив, элементы которого представляют собой отдельные мета-запросы со следующими аргументами:

Описание типа аргумента
key Строка Идентифицирует пользовательское поле.
value строка-массив Может быть массив только тогда, когда compare ‘IN’ значение, ‘NOT IN’ , или ‘BETWEEN’ ‘NOT BEETWEEN’ .
compare Строка Оператор сравнения. Принятые значения, , , , , , , , , , , , , ’=’ ’!=’ ‘>‘ ‘>=’ ‘<‘ ‘<=’ и ‘LIKE’ ‘NOT LIKE’ ‘IN’ ‘NOT IN’ ‘BETWEEN’ ‘NOT BETWEEN’ ‘EXISTS’ ‘NOT EXISTS’ ‘REGEXP’ ‘NOT REGEXP’ ‘RLIKE’ . Он по умолчанию ’=’ .
type Строка Пользовательский тип поля. Возможные ‘NUMERIC’ значения, ‘BINARY’ , , , , , ‘CHAR’ ‘DATE’ ‘DATETIME’ ‘DECIMAL’ ‘SIGNED’ ‘TIME’ . ‘UNSIGNED’ Он по умолчанию ‘CHAR’ .

Если мы установили несколько пользовательских полей, мы также должны назначить relation аргумент meta_query элементу.

Теперь мы можем создать более продвинутый запрос. Начнем с установки аргументов и создания нового WP_Query экземпляра:

$args = array(
    'post_type' => 'accommodation',
    'meta_query'    => array(
        array( 'key' => 'city', 'value' => 'Paris', 'compare' => 'LIKE' ),
        array( 'key' => 'type', 'value' => 'room', 'compare' => 'LIKE' ),
        'relation' => 'AND'
    )
);
$the_query = new WP_Query( $args );

В данном meta_query споре содержится два массива мета-запроса и третий параметр, устанавливающий связь между мета-запросами. Запрос выполняет поиск в таблице wp’posts для всех accommodation типов сообщений, где пользовательские поля и city хранение соответственно значения и type Paris room .

Давайте скопируем и впинем код в файл шаблона под названием archive-accommodation.php. По запросу WordPress выполнит запрос, ища таблицу wp’posts, и петля покажет результаты, если она доступна.

На данный момент мы все еще пишем код в файле шаблона. Это означает, что наш скрипт статичен, и каждый раз, когда цикл работает, он будет производить тот же выход. Но мы должны позволить пользователям сайта делать пользовательские запросы, и для выполнения этой задачи нам необходимо динамически создавать пользовательские запросы.

pre_get_postsФильтр

pre_get_posts Крюк действия выстрелил после $query создания объекта, но до его выполнения. Чтобы изменить запрос, нам придется подключить пользовательский обратный pre_get_posts вызов.

В предыдущем примере мы запросили базу данных, чтобы получить все публикации в webdesign категории от определенного автора. В следующем примере мы передаем объекту те же $query аргументы, но мы не будем выполнять работу с файлом шаблона, как это было раньше, но вместо этого мы будем использовать основной файл плагина (или функции темы.php). Давайте напишем следующий блок кода:

function myplugin_pre_get_posts( $query ) {
    // check if the user is requesting an admin page 
    // or current query is not the main query
    if ( is_admin() || ! $query->is_main_query() ){
        return;
    }
    $query->set( 'author_name', 'carlo' );
    $query->set( 'category_name', 'webdesign' );
}
add_action( 'pre_get_posts', 'myplugin_pre_get_posts', 1 );

$queryОбъект передается функции обратного вызова по ссылке, а не по значению, а это означает, что любые изменения, внесенные в запрос, непосредственно влияют на исходный $query объект. Кодекс говорит:

pre_get_postsДействие предоставляет разработчикам доступ к $query объекту по ссылке (любые изменения, которые вы вносите $query непосредственно к исходному объекту — значение возврата не требуется).

Поскольку мы манипулизируя исходный $query объект, мы должны обратить внимание на то, над каким запросом мы работаем. is_main_queryМетод проверяет, является ли текущий $query объект… (да!) основной запрос. Кодекс также сообщает нам, что pre_get_posts фильтр может повлиять на панель админ, а также на передние страницы. По этой причине более чем уместно проверить запрашиваемую страницу с is_admin условным тегом.

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

Теперь мы можем закончить наше введение в основные инструменты, доступные для обработки запросов WordPress. Теперь пришло время представить конкретный пример их использования, выстраивая передовую поисковую систему контента сайта. Наше тематическое исследование предоставляется на сайте недвижимости.

От теории к коду: Создание поисковой системы

Мы будем следовать следующим шагам:

  1. Определите структуру данных.
  2. Зарегистрируйте пользовательский vars запроса.
  3. Получите значения var запроса и используйте их для создания пользовательского запроса.
  4. Создайте форму, программно генерирующую значения поля.

1. Определить структуру данных

Цель пользовательских типов постов заключается в добавлении содержимого, которое логически не может быть включено ни в сообщения хима, ни в статических страницах. Пользовательские типы должностей особенно уместны для представления событий, продуктов, книг, фильмов, элементов каталога и так далее. Здесь мы собираемся создать архив объявлений о недвижимости со следующей структурой:

  • пользовательский тип поста: accommodation ;
  • пользовательские таксономии: typology (B и B, проживание в семье, отель и т.д.)
  • пользовательское поле: _sm_accommodation_type (весь дом, отдельная комната, общая комната)
  • пользовательское поле:_sm_accommodation_city
  • другие пользовательские поля

Мы должны зарегистрировать тип поста, пользовательские таксономии и пользовательских полей и мета-боксов, как показано на рисунке ниже.

Accommodation edit page
Страница размещения для отсечения показывает все пользовательские мета-коробки и поля. (Посмотреть большую версию)

На рисунке показано, как страница Edit Accommodation появится после того, как будут зарегистрированы три пользовательских мета-коробки, содержащие пользовательскую таксономию Типологии и несколько пользовательских полей.

Это не наша цель, чтобы проанализировать WordPress архитектуры данных, так как эта тема уже была охвачена здесь, на Smashing Magazine Даниэль, Брайан, Кевин, Джош и Джастин. Читайте их статьи, если вам нужно переподготовку, и вернуться, как только вы будете готовы.

После того как мы определили архитектуру данных, пришло время зарегистрировать vars запроса.

2. Зарегистрируйте переменные запроса

Ранее мы определили query vars как key=value пары, следующие за вопросительным знаком в URL-. Но прежде чем мы сможем справиться с этими парами в наших сценариях, мы должны зарегистрировать их в плагине или файле функций. Для наших целей нам нужны только две переменные, которые позволят выдать запрос на основе значений соответствующих пользовательских полей:

/**
 * Register custom query vars
 *
 * @link https://codex.wordpress.org/Plugin_API/Filter_Reference/query_vars
 */
function sm_register_query_vars( $vars ) {
    $vars[] = 'type';
    $vars[] = 'city';
    return $vars;
} 
add_filter( 'query_vars', 'sm_register_query_vars' );

Ну вот! Мы добавили еще два параметра для запроса базы данных. Теперь имеет смысл создать URL, как этот:

http://example.com/?type=XXX&city=YYY

3. Манипулировать запрос

Теперь давайте добавим новый блок кода в наш скрипт:

/**
 * Build a custom query based on several conditions
 * The pre_get_posts action gives developers access to the $query object by reference
 * any changes you make to $query are made directly to the original object - no return value is requested
 *
 * @link https://codex.wordpress.org/Plugin_API/Action_Reference/pre_get_posts
 *
 */
function sm_pre_get_posts( $query ) {
    // check if the user is requesting an admin page 
    // or current query is not the main query
    if ( is_admin() || ! $query->is_main_query() ){
        return;
    }

    // edit the query only when post type is 'accommodation'
    // if it isn't, return
    if ( !is_post_type_archive( 'accommodation' ) ){
        return;
    }

    $meta_query = array();

    // add meta_query elements
    if( !empty( get_query_var( 'city' ) ) ){
        $meta_query[] = array( 'key' => '_sm_accommodation_city', 'value' => get_query_var( 'city' ), 'compare' => 'LIKE' );
    }

    if( !empty( get_query_var( 'type' ) ) ){
        $meta_query[] = array( 'key' => '_sm_accommodation_type', 'value' => get_query_var( 'type' ), 'compare' => 'LIKE' );
    }

    if( count( $meta_query ) > 1 ){
        $meta_query['relation'] = 'AND';
    }

    if( count( $meta_query ) > 0 ){
        $query->set( 'meta_query', $meta_query );
    }
}
add_action( 'pre_get_posts', 'sm_pre_get_posts', 1 );

Этот код является суммой всего, что мы рассмотрели в первой части статьи. Функция обратного вызова завершает работу, если пользователь находится в панели админ, если текущий запрос не является основным запросом, и если тип публикации не accommodation является.

Позже функция проверяет, доступен ли какой-либо из заданных запросов, которые мы зарегистрировали ранее. Эта задача выполняется благодаря get_query_var функции, которая извлекает общедоступный запрос из запроса HTTP (подробнее читайте get_query_var в Кодексе). Если переменная существует, то обратный вызов определяет один массив для каждого мета-запроса и толкает его в многомерный $meta_query массив.

Наконец, если доступны по крайней мере два мета-запроса, то relation аргумент заталкивается $meta_query и его значение устанавливается на ‘AND’ . После выполнения set метод сохраняет $query для последующего выполнения.

Вам не нужно беспокоиться о дезинфекции данных здесь, потому что WP_Query и WP_Meta_Query классы делают работу за нас (проверить WP_Query и WP_Meta_Query исходный код)

4. Создайте форму поиска

Данные формы представляются GET методом. Это означает, что name value и атрибуты полей формы отправляются в качестве переменных URL (т.е. в виде vars запроса). Таким образом, мы собираемся присвоить name атрибутам полей форм те же значения, что и ранее зарегистрированные vars запроса city (и), в то время как значения поля могут быть type назначены программно, извлекая данные из базы данных, или заполнены пользователем.

Сначала мы создадим короткий код, который позволит амините сайта включать форму поиска в сообщения и страницы сайта. Наш шорт-код будет подключен к init действию:

function sm_setup() {
    add_shortcode( 'sm_search_form', 'sm_search_form' );
}
add_action( 'init', 'sm_setup' );

Далее мы определим функцию обратного вызова, которая будет производить HTML формы, содержащей три выбранных поля, соответствующие пользовательской таксономии и два пользовательских поля.

function sm_search_form( $args ){
    // our code here
}

$args— это массив атрибутов короткого кода. Внутри функции мы добавим следующий код:

// The Query
// meta_query expects nested arrays even if you only have one query
$sm_query = new WP_Query( array( 'post_type' => 'accommodation', 'posts_per_page' => '-1', 'meta_query' => array( array( 'key' => '_sm_accommodation_city' ) ) ) );

// The Loop
if ( $sm_query->have_posts() ) {
    $cities = array();
    while ( $sm_query->have_posts() ) {
        $sm_query->the_post();
        $city = get_post_meta( get_the_ID(), '_sm_accommodation_city', true );

        // populate an array of all occurrences (non duplicated)
        if( !in_array( $city, $cities ) ){
            $cities[] = $city;    
        }
    }
}
} else{
       echo 'No accommodations yet!';
       return;
}

/* Restore original Post Data */
wp_reset_postdata();

if( count($cities) == 0){
    return;
}

asort($cities);

$select_city = '<select name="city" style="width: 100%">';
$select_city .= '<option value="" selected="selected">' . __( 'Select city', 'smashing_plugin' ) . '</option>';
foreach ($cities as $city ) {
    $select_city .= '<option value="' . $city . '">' . $city . '</option>';
}
$select_city .= '</select>' . "n";

reset($cities);

Мы создали запрос, который будет извлекать все accommodation типы сообщений, установить специальное поле с именем _sm_accommodation_city (подчеркивание, предшествующее названию, представляет собой скрытое пользовательское поле).

Петля не будет отображать какое-либо размещение, но добавит элементы в $cities массив из соответствующего значения пользовательского поля. Условие будет пропускать дубликаты. Если нет жилья, выполнение прерывается; в противном случае элементы массива сортируются и используются для печати значений первой группы option элементов.

Select box
Все доступные города отображаются в виде опций в выбранном поле.

Второе поле формы по-прежнему является кнопкой выбора, и оно соответствует typology пользовательской таксономии. Значения второй группы option элементов приведены get_terms тегом шаблона. Ниже приводится второй блок кода, генерирующий новое select поле, соответствующее typology таксономии:

$args = array( 'hide_empty' => false );
$typology_terms = get_terms( 'typology', $args );
if( is_array( $typology_terms ) ){
    $select_typology = '<select name="typology" style="width: 100%">';
    $select_typology .= '<option value="" selected="selected">' . __( 'Select typology', 'smashing_plugin' ) . '</option>';
    foreach ( $typology_terms as $term ) {
        $select_typology .= '<option value="' . $term->slug . '">' . $term->name . '</option>';
    }
    $select_typology .= '</select>' . "n";
}

get_termsвозвращает массив всех терминов таксономии, установленных в качестве первого аргумента, или WP_Error объект, если таксономия не существует. Теперь снова foreach цикл распечатывает элементы опции.

Select box
Варианты второго выбора коробки.

Затем мы создаем последний select элемент, соответствующий type пользовательскому полю. Вот код:

$select_type = '<select name="type" style="width: 100%">';
$select_type .= '<option value="" selected="selected">' . __( 'Select room type', 'smashing_plugin' ) . '</option>';
$select_type .= '<option value="entire">' . __( 'Entire house', 'smashing_plugin' ) . '</option>';
$select_type .= '<option value="private">' . __( 'Private room', 'smashing_plugin' ) . '</option>';
$select_type .= '<option value="shared">' . __( 'Shared room', 'smashing_plugin' ) . '</option>';
$select_type .= '</select>' . "n";

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

Наконец, мы можем распечатать форму:

$output = '<form action="' . esc_url( home_url() ) . '" method="GET" role="search">';
$output .= '<div class="smselectbox">' . esc_html( $select_city ) . '</div>';
$output .= '<div class="smselectbox">' . esc_html( $select_typology ) . '</div>';
$output .= '<div class="smselectbox">' . esc_html( $select_type ) . '</div>';
$output .= '<input type="hidden" name="post_type" value="accommodation" />';
$output .= '<p><input type="submit" value="Go!" class="button" /></p></form>';

return $output;

Мы установили скрытое поле ввода для post_type публичного ввода. Когда пользователь отправляет форму, WordPress получает post_type значение и загружает файл шаблона archive.php, или, при наличии, файл архива-post’type.php. С такой формой, если вы собираетесь настроить структуру HTML результирующей страницы, вам нужно будет предоставить наиболее подходящий файл шаблона.

Advanced search form
Изображение показывает расширенную форму поиска, который мы создали в этой статье.

Форма, которая мы создали до сих пор позволяет пользователю настроить три фильтра из ряда заранее определенных параметров. Теперь мы собираемся улучшить систему поиска, включая текстовое поле в форме, так что пользователи могут искать жилье по пользовательским ключевым словам. Мы можем сделать это благодаря s аргументу запроса. Итак, давайте изменим форму следующим образом:

$output = '<form id="smform" action="' . esc_url( home_url() ) . '" method="GET" role="search">';
$output .= '<div class="smtextfield"><input type="text" name="s" placeholder="Search key..." value="' . get_search_query() . '" /></div>';
$output .= '<div class="smselectbox">' . esc_html( $select_city ) . '</div>';
$output .= '<div class="smselectbox">' . esc_html( $select_typology ) . '</div>';
$output .= '<div class="smselectbox">' . esc_html( $select_type ) . '</div>';
$output .= '<input type="hidden" name="post_type" value="accommodation" />';
$output .= '<p><input type="submit" value="Go!" class="button" /></p></form>';

Благодаря текстовому полю мы можем пройти WP_Query новую пару ключей/значений, где ключом является s параметр, а значением является пользовательский ввод или get_search_query() возвращающее значение (подробнее читайте Кодекс).

Advanced search form
Более продвинутая форма поиска.

Заключительное примечание: в нашем предыдущем примере мы видели, как WordPress загружает файл шаблона архива, чтобы показать результаты запроса. Это потому, что мы не поставили аргумент поиска. Когда строка запроса содержит s парам, WordPress автоматически загружает файл шаблона поиска, как показано на последнем изображении этого поста.

Advanced search form
Изображение показывает страницу поиска в двадцать пятнадцать.

Выводы

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

Теперь пришло время кодировать!

Ресурсы

Источник: smashingmagazine.com

Великолепный Журнал

Великолепный, сокрушительный, разящий (см. перевод smashing) независимый журнал о веб-разработке. Основан в 2006 году в Германии. Имеет няшный дизайн и кучу крутых авторов, которых читают 2 млн человек в месяц.

Добавить комментарий

%d такие блоггеры, как: