Многие сверхдержавы WordPress происходят из его гибкой архитектуры данных, что позволяет разработчикам широко настроить свои установки с пользовательскими типами постов, таксономиями и полями. Однако, когда дело доходит до его поиска, WordPress предоставляет нам только одно поле форме, которая часто появляется неадекватным и приводит к сайту админайнов принять внешние поисковые системы, как Google Custom Search, или сторонних плагинов.
В этой статье я покажу вам, как обеспечить вашу установку WordPress с передовой поисковой системой, позволяющей пользователю искать и извлекать содержимое из конкретного пользовательского типа поста, фильтрации результатов пользовательских терминов таксономии и нескольких пользовательских полей Значения.
Дальнейшее чтение на SmashingMag:
- Передний конец список авторов и поиск пользователя для WordPress
- Подробное руководство по WordPress пользовательские шаблоны страницы
- Создание передовой системы уведомлений для WordPress
Статья имеет две части. Во-первых, я представлю теоретическое введение в обработку запросов пользователей, начиная от передачи URL, проходя через выполнение запроса и заканчивая выходным производством. Вторая часть статьи представляет собой конкретное применение того, что мы собираемся узнать в первой части, и там мы будем строить наши передовые поисковой системы.
Итак, давайте начнем изучать некоторые ключевые концепции.
Запросы пользователей
Когда пользователь нажимает на ссылку или вводит URL-адрес, указывающий на страницу веб-сайта, WordPress выполняет ряд операций, хорошо описанных в Обзоре запросовCodex. Короче говоря, это то, что происходит:
- WordPress разбирает запрошенный URL в набор параметров запроса (так называемая спецификация запроса).
- Все
is_
переменные, связанные с запросом, настроены. - Спецификация запроса преобразуется в запрос MyS’L, который выполняется по базе данных.
- Полученный набор данных хранится в
$wp_query
объекте. - WordPress затем обрабатывает 404 ошибки.
- WordPress посылает блог HTTP заголовки.
- Переменные цикла инициализированы.
- Файл шаблона выбирается в соответствии с правилами иерархии шаблонов.
- 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. Теперь пришло время представить конкретный пример их использования, выстраивая передовую поисковую систему контента сайта. Наше тематическое исследование предоставляется на сайте недвижимости.
От теории к коду: Создание поисковой системы
Мы будем следовать следующим шагам:
- Определите структуру данных.
- Зарегистрируйте пользовательский vars запроса.
- Получите значения var запроса и используйте их для создания пользовательского запроса.
- Создайте форму, программно генерирующую значения поля.
1. Определить структуру данных
Цель пользовательских типов постов заключается в добавлении содержимого, которое логически не может быть включено ни в сообщения хима, ни в статических страницах. Пользовательские типы должностей особенно уместны для представления событий, продуктов, книг, фильмов, элементов каталога и так далее. Здесь мы собираемся создать архив объявлений о недвижимости со следующей структурой:
-
пользовательский тип поста:
accommodation
; -
пользовательские таксономии:
typology
(B и B, проживание в семье, отель и т.д.) -
пользовательское поле:
_sm_accommodation_type
(весь дом, отдельная комната, общая комната) -
пользовательское поле:
_sm_accommodation_city
- другие пользовательские поля
Мы должны зарегистрировать тип поста, пользовательские таксономии и пользовательских полей и мета-боксов, как показано на рисунке ниже.
На рисунке показано, как страница 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. Теперь пришло время представить конкретный пример их использования, выстраивая передовую поисковую систему контента сайта. Наше тематическое исследование предоставляется на сайте недвижимости.
От теории к коду: Создание поисковой системы
Мы будем следовать следующим шагам:
- Определите структуру данных.
- Зарегистрируйте пользовательский vars запроса.
- Получите значения var запроса и используйте их для создания пользовательского запроса.
- Создайте форму, программно генерирующую значения поля.
1. Определить структуру данных
Цель пользовательских типов постов заключается в добавлении содержимого, которое логически не может быть включено ни в сообщения хима, ни в статических страницах. Пользовательские типы должностей особенно уместны для представления событий, продуктов, книг, фильмов, элементов каталога и так далее. Здесь мы собираемся создать архив объявлений о недвижимости со следующей структурой:
-
пользовательский тип поста:
accommodation
; -
пользовательские таксономии:
typology
(B и B, проживание в семье, отель и т.д.) -
пользовательское поле:
_sm_accommodation_type
(весь дом, отдельная комната, общая комната) -
пользовательское поле:
_sm_accommodation_city
- другие пользовательские поля
Мы должны зарегистрировать тип поста, пользовательские таксономии и пользовательских полей и мета-боксов, как показано на рисунке ниже.
На рисунке показано, как страница 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
элементов.
Второе поле формы по-прежнему является кнопкой выбора, и оно соответствует 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
элемент, соответствующий 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 результирующей страницы, вам нужно будет предоставить наиболее подходящий файл шаблона.
Бесплатный поиск текста
Форма, которая мы создали до сих пор позволяет пользователю настроить три фильтра из ряда заранее определенных параметров. Теперь мы собираемся улучшить систему поиска, включая текстовое поле в форме, так что пользователи могут искать жилье по пользовательским ключевым словам. Мы можем сделать это благодаря 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()
возвращающее значение (подробнее читайте Кодекс).
Заключительное примечание: в нашем предыдущем примере мы видели, как WordPress загружает файл шаблона архива, чтобы показать результаты запроса. Это потому, что мы не поставили аргумент поиска. Когда строка запроса содержит s
парам, WordPress автоматически загружает файл шаблона поиска, как показано на последнем изображении этого поста.
Выводы
Примеры этой статьи призваны продемонстрировать, что может быть достигнуто с помощью инструментов, предоставляемых WordPress. Конечно, форма может быть улучшена путем добавления новых полей, позволяющих более детальную настройку. Тем не менее, я надеюсь, что я предоставил достаточно подробное представление о функциональных возможностях, которые позволяют построить поисковую систему преодоления пределов встроенной поисковой системы без необходимости внешних услуг и плагинов.
Теперь пришло время кодировать!
Ресурсы
Источник: smashingmagazine.com