WordPress. Фильтр записей по произвольным полям. Часть 3 из 3
04.10.2019
Теги: CMS • RegExp • Web-разработка • WordPress • КаталогТоваров • МетаДанные • Плагин • Форма • ЧПУ
В принципе, наш фильтр уже работает и на этом можно было бы и закруглиться. Но URL страницы с результатми фильтрации выглядит страшно, потому что GET-параметр filter
представляет собой вложенный массив. Давайте улучшим наш плагин и добавим ЧПУ, чтобы из URL сразу было понятно, где мы находимся. В результате URL страницы с результатом фильтрации товаров будет выглядеть так
http://www.server.com/products/filter/size-in-small-large-and-color-in-white-black/
Что мы будем делать:
- Добавим в форму скрытое поле
action
и изменим значение атрибутаaction
(это из кодекса WordPress) - Создадим обработчик данных формы, который будет анализировать массив
$_REQUEST
и выполнять редирект - Создадим два правила перезаписи URL и добавим к публичным переменным запроса еще одну —
filter
- Ну и еще несколько изменений, поскольку формат передачи данных о включенных фильтрах изменился
register_activation_hook(__FILE__, function() { // проверяем права пользователя на установку плагинов if (!current_user_can('activate_plugins')) { return; } // регистрируем тип записи product и таксономию group tokmakov_catalog_register(); // добавляем правила перезаписи URL, связанные с каталогом tokmakov_catalog_rewrite(); flush_rewrite_rules(); });
register_deactivation_hook(__FILE__, function() { // проверяем права пользователя на деактивацию плагинов if (!current_user_can('deactivate_plugins')) { return; } // отменяем регистрацию типа записи product и таксономии group unregister_post_type('product'); unregister_taxonomy('group'); // удаляем правила перезаписи URL, связанные с каталогом flush_rewrite_rules(); });
При активации плагина мы регистрируем тип записи product
, иерархическую таксономию group
, добавляем два правила перезаписи URL для фильтра. И сразу обновляем правила перезаписи URL, чтобы WordPress записал новые правила в таблицу БД wp_options
.
/* * В случае, если внешний код (сам WordPress или какой-то плагин) * сбрасывает правила перезаписи URL, нам нужно добавить два наших * правила, связанных с фильтром */ add_action('generate_rewrite_rules', 'tokmakov_catalog_rewrite');
function tokmakov_catalog_rewrite() { /* * Два правила перезаписи URL: одно для первой страницы результатов * фильтрации товаров, второе — для всех остальных страниц */ add_rewrite_rule( 'products/filter/([-_a-zA-Z0-9]+)/page/(\d+)/?$', 'index.php?post_type=product&filter=$matches[1]&paged=$matches[2]', 'top' ); add_rewrite_rule( 'products/filter/([-_a-zA-Z0-9]+)/?$', 'index.php?post_type=product&filter=$matches[1]', 'top' ); }
/* * Регистрируем тип записи product (товары каталога) и * таксономию group (разделы каталога) */ add_action('init', 'tokmakov_catalog_register');
function tokmakov_catalog_register() { /* * Регистрируем тип записи product (товары каталога) */ $labels = [ 'name' => 'Товары', 'menu_name' => 'Товары', 'singular_name' => 'Товар', 'add_new' => 'Добавить товар', 'add_new_item' => 'Добавить новый товар', 'edit_item' => 'Редактировать товар', 'new_item' => 'Новый товар', 'all_items' => 'Все товары', 'view_item' => 'Посмотреть товар', 'search_items' => 'Найти товары', 'not_found' => 'Ничего не найдено', 'not_found_in_trash' => 'В корзине не найдено' ]; $args = [ 'labels' => $labels, 'description' => 'Коллекции женской, мужской и детской обуви на все времена года.', 'public' => true, 'publicly_queryable' => true, 'show_ui' => true, 'show_in_menu' => true, 'query_var' => true, 'capability_type' => 'post', /* * По умолчанию архив доступен по URL http://server.com/post_type/, * т.е.в нашем случае это будут http://server.com/product/, * http://server.com/product/page/2/. Но у нас архив записей типа * product будет доступен по URL http://server.com/products/, * http://server.com/products/page/2/ */ 'has_archive' => 'products', 'rewrite' => [ /* * Страница товара будет http://server.com/product/some-slug/, * эту настройку можно не задавать, потому что по умолчанию * используется название типа записи, т.е. product. */ 'slug' => 'product', // не добавлять в начало URL общий префикс из настроек 'with_front' => false, // не создавать правила перезаписи URL для feed-ленты товаров 'feeds' => false, // создавать правила перезаписи URL для красивой пагинации 'pages' => true ], 'hierarchical' => false, 'menu_position' => null, 'supports' => [ 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'custom-fields' ], 'taxonomies' => ['group'], ]; register_post_type('product', $args); /* * Регистрируем иерархическую таксономию (разделы каталога) */ $labels = array( 'name' => 'Категории', 'singular_name' => 'Категория', 'menu_name' => 'Категории' , 'all_items' => 'Все категории', 'edit_item' => 'Редактировать категорию', 'view_item' => 'Посмотреть категорию', 'update_item' => 'Сохранить категорию', 'add_new_item' => 'Добавить новую категорию', 'parent_item' => 'Родительская категория', 'search_items' => 'Поиск по категориям', 'back_to_items' => 'Назад на страницу категорий', 'most_used' => 'Популярные категории', ); $args = array( 'labels' => $labels, 'show_admin_column' => true, 'hierarchical' => true, ); register_taxonomy('group', ['product'], $args); }
/* * Добавляем к публичным переменным запроса еще одну — filter */ add_filter('query_vars', function ($vars) { $vars[] = 'filter'; return $vars; });
/* * Функция выводит форму с фильтрами для товаров каталога */ function tokmakov_catalog_filters() { $filters = get_option('tokmakov_catalog_filters'); if (empty($filters)) { return; } /* * Нам нужно знать, какие флажки уже были отмечены */ $var = get_query_var('filter'); $apply = []; // $var = size-in-small-large-and-color-in-white-black if (!empty($var)) { // $parts = [size-in-small-large, color-in-white-black] $parts = explode('-and-', $var); foreach ($parts as $part) { // $temp = [size, small-large] $temp = explode('-in-', $part); // $tmp = [small, large] $tmp = explode('-', $temp[1]); foreach ($tmp as $item) { $apply[$temp[0]][$item] = 1; } } } ?> <form action="<?= admin_url('admin-post.php'); ?>" method="post" id="tokmakov-catalog-filters"> <h3>Фильтры</h3> <input type="hidden" name="action" value="tokmakov_apply_filters" /> <?php foreach ($filters as $slug => $filter): ?> <fieldset> <legend><?= $filter['text']; ?></legend> <?php foreach ($filter['value'] as $value => $text): ?> <?php $checked = false; if (isset($apply[$slug][$value])) { $checked = true; } ?> <input type="checkbox" name="filter[<?= $slug; ?>][<?= $value; ?>]" value="1"<?php checked($checked); ?> /> <?= $text ?> <?php endforeach; ?> </fieldset> <?php endforeach; ?> <input type="submit" name="apply_filter" value="Применить" /> </form> <?php }
/* * После отправки данных формы выполняем редирект на красивый URL * /products/filter/size-in-small-large-and-color-in-white-black/ */ add_action('admin_post_nopriv_tokmakov_apply_filters', 'tokmakov_catalog_process_form'); add_action('admin_post_tokmakov_apply_filters', 'tokmakov_catalog_process_form');
function tokmakov_catalog_process_form() { $filters = get_option('tokmakov_catalog_filters'); $part = []; foreach ($filters as $slug => $filter) { $temp = []; foreach ($filter['value'] as $value => $text) { if (isset($_REQUEST['filter'][$slug][$value])) { $temp[] = $value; } } if (!empty($temp)) { $part[] = $slug . '-in-' . implode('-', $temp); } } $redirect = '/products/'; if (!empty($part)) { $redirect .= 'filter/' . implode('-and-', $part) . '/'; } wp_redirect($redirect, 302); die(); }
Мы использовали метод POST
для отправки данных формы, но можем использовать и GET
, потому что в обработчике формы работаем с массивом $_REQUEST
, который выглядит так:
Array ( [filter] => Array ( [size] => Array ( [small] => 1 [large] => 1 ) [color] => Array ( [white] => 1 [black] => 1 ) ) [apply_filter] => Применить )
Анализируя данные формы, формируем URL, на который выполняется редирект:
/products/filter/size-in-small-large-and-color-in-white-black/
/* * Изменяем основной запрос к базе данных */ add_action('pre_get_posts', function ($query) { // только в публичной части сайта if (is_admin()) { return; } // нас интересует только главный запрос if (!$query->is_main_query()) { return; } // нам нужна страница архива записей... if (!$query->is_post_type_archive) { return; } // ...только одного типа — product if ($query->query['post_type'] != 'product') { return; } // если фильтры еще не созданы, здесь делать нечего $filters = get_option('tokmakov_catalog_filters'); if (empty($filters)) { return; } // если переменная не задана, здесь делать нечего $var = get_query_var('filter'); if (empty($var)) { return; } /* * Определить, какие флажки были отмечены, мы можем из переменной * $var = size-in-small-large-and-color-in-white-black */ $apply = []; // $parts = [size-in-small-large, color-in-white-black] $parts = explode('-and-', $var); foreach ($parts as $part) { // $temp = [size, small-large] $temp = explode('-in-', $part); // $tmp = [small, large] $tmp = explode('-', $temp[1]); foreach ($tmp as $item) { $apply[$temp[0]][$item] = 1; } } $meta_query = []; foreach ($filters as $slug => $filter) { $temp = []; foreach ($filter['value'] as $value => $text) { if (isset($apply[$slug][$value])) { $temp[] = $value; } } if (!empty($temp)) { $meta_query[] = [ 'key' => '_tokmakov_catalog_filter_'.$slug, 'value' => $temp, 'compare' => 'IN' ]; } } if (!empty($meta_query)) { $meta_query['relation'] = 'AND'; $query->set('meta_query', $meta_query); } });
Поскольку мы добавили два правила перезаписи URL, то можем использовать для обращения к странице с включенным фильтром
http://www.server.com/products/filter/size-in-small-large-and-color-in-white-black/
Если бы мы не добавили эти правила, к странице пришлось бы обращаться так:
http://www.server.com/products/?filter=size-in-small-large-and-color-in-white-black
А если бы не было правил перезаписи, которые добавил WordPress — тогда так:
http:///www.server.com/?post_type=product&filter=size-in-small-large-and-color-in-white-black
Для наглядности — несколько снимков экрана с правилами перезаписи URL:
- Правила при активации плагина перед выполнением функции
flush_rewrite_rules()
и после (сравнение) - Правила при активации плагина перед выполнением функции
flush_rewrite_rules()
и после (продолжение) - Правила при деактивации плагина перед выполнением функции
flush_rewrite_rules()
и после (сравнение) - Правила при деактивации плагина перед выполнением функции
flush_rewrite_rules()
и после (продолжение)
Дополнительно
- Creating a WP archive with custom field filter
- Custom Query (Part 07: Custom Filters)
- WordPress. Фильтр записей по произвольным полям. Часть 2 из 3
- WordPress. Фильтр записей по произвольным полям. Часть 1 из 3
- WordPress. Добавляем мета-теги. Часть 3 из 3
- WordPress. Метабоксы. Часть 2 из 2
- WordPress. Плагин «Транслитерация URL»
- WordPress. Добавляем мета-теги. Часть 2 из 3
- WordPress. Обработка POST-запросов. Часть 1
Поиск: CMS • RegExp • Web-разработка • WordPress • Каталог товаров • Форма • ЧПУ • Мета данные • Rewrite • Плагин • Plugin