Иногда бывает нужно добавить дополнительные фильтры в список записей для фильтрации по различным полям и таксономии. Часто фильтрация нужна в списках постов в плагинах, там где у постов есть кастомные поля.
В моем примере я буду добавлять фильтры в список записей типа «hotel_room», я добавлю туда два новых фильтра -«тип номера» и «название гостиницы»:
Как узнать тип записи (поста), куда вам требуется добавить фильтры? Очень просто, нужно на странице, на который вы хотите добавить фильтры, в строке браузера посмотреть GET параметр «post_type», обратите внимание на скриншот выше и вам сразу все станет ясно.
Обратите внимание, что в списке «Записи -> Все записи» параметр post_type отсутствует. То есть, чтобы добавить фильтры на страницу этого списка записей, вам нужно проверять отсутствие параметра post_type.
Если не использовать проверку на тип поста, то ваши новые фильтры будут отображаться во всех списках постов, что я крайне не рекомендую делать.
Итак, давайте добавим два новых фильтра в список записей, в моем случае с типом hotel_room. Для добавления новых фильтров в файл functions.php вашей темы нужно добавить пару новых функций. Файл functions.php находится в папке wp-content/themes/ваша_тема, если его там нет, то просто создайте его.
Добавляем действие «admin_posts_filter_restrict_manage_posts» к функции wordpress «restrict_manage_posts»:
add_action( 'restrict_manage_posts','admin_posts_filter_restrict_manage_posts')
В php коде «действие» (action) выглядит как обычная php функция, но она выполняется только при запуске функции wordpress «restrict_manage_posts». Можно сказать, что механизм действий (add_action) похож на событие, то есть при наступлении события (в нашем случае выполнения функции «restrict_manage_posts»), дополнительно будет вызываться наша новая функция «admin_posts_filter_restrict_manage_posts», которую мы тоже должны добавить в файл functions.php. Чтобы не вызывать нашу функцию лишний раз, в начале ее мы ставим проверку на то, чтобы эта функция вызывалась только на странице списка постов (см. комментарии ниже):
function admin_posts_filter_restrict_manage_posts() { global $wpdb, $pagenow; if ($pagenow != 'edit.php') return; //если страница не список постов, то выходим из функции $out = ''; //переменная в которой будут храниться html код наших фильтров switch ($_GET['post_type']) { //выбираем нужный тип поста (post_type) case 'hotel_room': //тип поста hotel_room //Добавляем новый фильтр - текстовое поле для ввода данных $out = "<input type='text' name='room_name' value='".$_GET["room_name"]."'/>"; //Второй фильтр для наглядности будет использовать таксономию, чтобы получить все термины таксономии (в данном случае тип "room_type", или "тип номеров") нужно выполнить sql запрос: $rows = $wpdb->get_results("SELECT DISTINCT {$wpdb->terms}.term_id, {$wpdb->terms}.name FROM {$wpdb->terms}, {$wpdb->term_taxonomy} WHERE {$wpdb->terms}.term_id = {$wpdb->term_taxonomy}.term_taxonomy_id AND {$wpdb->term_taxonomy}.taxonomy = 'room_type'", ARRAY_A); //Второй параметр в sql запросе "ARRAY_A" означает, что в результате выполнения sql запроса будет возвращен массив "ключ - значение". //Собираем полученные термины таксономии в список select $out .= '<select name="room_type2"> <option value="">-- Тип номера --</option>'; foreach($rows as $row) { if (isset($_GET['room_type2']) && $_GET['room_type2'] == $row['term_id']) $out .= sprintf ('<option value="%s" selected>%s</option>', $row['term_id'], $row['name']); else $out .= sprintf ('<option value="%s">%s</option>', $row['term_id'], $row['name']); } $out .= '</select>'; //Обратите внимание чтобы атрибут "name" у ваших фильтров не совпадал с уже существующими фильтрами, или какими либо переменными в wordpress, делайте названия атрибутов name как можно сложнее //покажем созданные фильтры echo $out; } }
Но это еще не все, сейчас фильтры отображаются в админке, но не работают. Мы настроили их отображение, то есть frontend часть, теперь нужно сделать обработку данных на стороне сервера, то есть backend часть.
Первый вариант — добавить фильтр (функция add_filter) к функции wordpress parse_query(), добавив в функцию значения наших фильтров. Работает только если вы производите поиск по мета-полю поста:
add_filter( 'parse_query', 'admin_posts_filter' );
function admin_posts_filter( $query ) { global $pagenow; if ( is_admin() && $pagenow=='edit.php') { //Сработает если фильтруемое поле - мета-поле if (!empty($_GET['room_name'])) { //GET параметр от нашего фильтра $query->query_vars['meta_key'] = 'room'; $query->query_vars['meta_value'] = $_GET['room_name']; } } }
Но что, если нам нужно фильтровать посты по таксономии, или другим (не мета) полям поста? В этом случае можно внести изменения в сам sql запрос, который формируется для загрузки списка постов. Для этого нужно использовать функцию wordpress posts_where(). Добавим фильтр для этой функции в functions.php:
add_filter( 'posts_where' , 'my_posts_where');
Пример реализации функции для фильтрации по таксономии:
function my_posts_where($where) { global $wp_query; if(!is_admin()) return $where; if($wp_query->get('post_type') !='hotel_room' ) return $where; //Если тип поста (post_type) не равен hotel_room, то выходим из функции global $wpdb; if($_GET['room_type2']){ $term_id = intval($_GET['room_type2']); //id термина таксономии из нашего фильтра $add_where =" AND $wpdb->posts.ID in (SELECT object_id FROM {$wpdb->term_relationships} WHERE term_taxonomy_id = {$term_id})"; $where.=$add_where; } return $where; }
Статьи по теме: