Добавление дополнительных фильтров в список записей в админке WordPress

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

В моем примере я буду добавлять фильтры в список записей типа «hotel_room», я добавлю туда два новых фильтра -«тип номера» и «название гостиницы»:

Добавление дополнительных фильтров в список постов в админке WordPress - список постовКак узнать тип записи (поста), куда вам требуется добавить фильтры? Очень просто, нужно на странице, на который вы хотите добавить фильтры, в строке браузера посмотреть 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;
}

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *