Фильтр типа записи на панели администрирования

Вопрос или проблема

У меня есть настраиваемый тип записи с пользовательскими мета-данными, которые я хочу фильтровать на странице Администратора. Подобно ссылкам “Все | Опубликованные | Черновики | Корзина”, расположенным выше списка записей. Я никак не могу найти хук для подключения. Существует ли он?

Этот вопрос не совсем то, что я спрашиваю. Я предпочел бы не использовать выпадающий фильтр, а вместо этого — ссылки, как …

Все | Опубликованные | Черновики | Корзина

… в верхней части редактора.

Точно так же, как в Добавление фильтра таксономии в список администратора для пользовательского типа записи? можно использовать фильтр parse_query, но здесь я использую posts_where.


Ряд Все | Опубликованные | ... контролируется views_edit-{$post_type}, а массив $views содержит каждый элемент, который является простым тегом привязки.

Сначала добавим пару ссылок — разделитель и фильтр Meta:

add_filter( 'views_edit-portfolio', 'meta_views_wpse_94630', 10, 1 );

function meta_views_wpse_94630( $views ) 
{
    $views['separator'] = '           ';
    $views['metakey'] = '<a href="https://wordpress.stackexchange.com/questions/94630/edit.php?meta_data=allorany&post_type=portfolio">Meta Key</a>';
    return $views;
}

Ссылка содержит meta_data=allorany (имя пользовательского поля), который будет использоваться для фильтрации по мета-ключу.

введите описание изображения здесь


Затем фильтруем, когда необходимо:

add_action( 'load-edit.php', 'load_custom_filter_wpse_94630' );

function load_custom_filter_wpse_94630()
{
    global $typenow;

    // Настройка типа записи
    if( 'portfolio' != $typenow )
        return;

    add_filter( 'posts_where' , 'posts_where_wpse_94630' );
}

function posts_where_wpse_94630( $where ) 
{
    global $wpdb;       
    if ( isset( $_GET[ 'meta_data' ] ) && !empty( $_GET[ 'meta_data' ] ) ) 
    {
        $meta = esc_sql( $_GET['meta_data'] );
        $where .= " AND ID IN (SELECT post_id FROM $wpdb->postmeta WHERE meta_key='$meta' )";
    }
    return $where;
}

С благодарностью @brasofilo за его ответ, он доставил мне всевозможные проблемы по причине, которую я не мог точно диагностировать. Я думаю, что фильтр posts_where, который добавляется, необходимо удалять, иначе он будет выполняться для всех будущих запросов на странице и создаст путаницу для всего, что пытается запросить другой post_type, так как второй фильтр будет все еще активен.

Вот решение, которое не требует ручного вмешательства в SQL, но работает с объектом Query. Предполагается использование метода добавления параметров URL, как в другом ответе здесь с именем параметра URL cpt_filter

function filter_cpt($query) {

    global $pagenow;

    $cpt = "your_custom_type_name";
    $cpt_key = "some_key_to_filter_on";
    $cpt_value = "some_value_to_filter_for";

    if (is_admin() && $pagenow=='edit.php' &&
        isset($_GET['post_type']) && $_GET['post_type']==$cpt &&
        isset($_GET['cpt_filter'])  && $_GET['cpt_filter'] != 'None' &&
        $query->query['post_type'] == $cpt)  {
      
          $query->query_vars['meta_key'] = $cpt_key;
          $query->query_vars['meta_value'] = $cpt_value;
      }
    }

}

add_filter( 'parse_query', 'filter_cpt' );

Здесь нет проблем с добавлением/удалением фильтров и еластичностью с установкой мета-ключа и значения на нужные параметры.

Почему бы не использовать pre_get_posts? Это позволяет вам изменить объект запроса без всего мусора.

Вот пример, показывающий, как фильтровать записи с использованием произвольного значения мета:

//Фильтруем представления CPT, чтобы отобразить вашу ссылку
add_filter( 'views_edit-{$post_type}', 'my_callback', 10, 1 );
function my_callback( $views ) {
    
    $views['metakey'] = '<a href="edit.php?post_type={$post-type}&modify_query=yes">My Filter</a>';
    return $views;
    
}

//Настройте основной запрос, если ваша переменная $_GET установлена, и запрос для вашего пользовательского типа записи 
add_action('pre_get_posts', 'filter_admin_posts_query');
function filter_admin_posts_query($query){

    if (is_admin() && $query->get('post_type') == "{$post_type}" && $_GET['modify_query'] == "yes") {
        
        $query->set('meta_query', array(
            array(
                'key' => 'some_custom_field',
                'value' => 'some value'
            )
        ));
        
        
    }
    
}

Ответ или решение

Вопрос о фильтрации пользовательских типов записей в панели администратора WordPress является распространенной задачей для разработчиков, работающих с настраиваемыми постами и мета-данными. Давайте разберемся с этой проблемой, используя подход TEA (Theory, Example, Application).

Теория

Основная идея заключается в добавлении фильтрации пользовательских типов записей на странице администратора, так как в стандартной версии WordPress предоставляются только возможности фильтрации по статусам, таким как "Все", "Опубликовано", "Черновики" и "Корзина". Для этой цели можно использовать несколько хуков WordPress, таких как views_edit-{$post_type}, parse_query, posts_where или pre_get_posts, которые предоставляют различные возможности для модификации запросов и интерфейса.

  1. views_edit-{$post_type}: Этот фильтр используется для изменения вида ссылок на странице списка записей. Он позволяет добавлять собственные ссылки в верхнюю часть страницы.

  2. posts_where: Этот фильтр позволяет изменять часть SQL-запроса WHERE, добавляя условия для фильтрации по мета-данным. Однако следует быть осторожным, чтобы не повлиять на другие запросы.

  3. parse_query и pre_get_posts: Эти фильтры дают возможность модифицировать объект запроса (WP_Query), что является более безопасным и гибким путем изменения параметров запроса, таких как meta_query.

Пример

Рассмотрим два подхода, которые продемонстрированы в вопросе.

  1. Использование views_edit-{$post_type} и posts_where:

    Добавление ссылки на фильтрацию по мета-данным:

    add_filter('views_edit-portfolio', 'meta_views_wpse_94630', 10, 1);
    
    function meta_views_wpse_94630($views) {
       $views['metakey'] = '<a href="edit.php?meta_data=allorany&post_type=portfolio">Meta Key</a>';
       return $views;
    }

    Функция фильтрации записей:

    add_action('load-edit.php', 'load_custom_filter_wpse_94630');
    
    function load_custom_filter_wpse_94630() {
       global $typenow;
       if ('portfolio' != $typenow) return;
       add_filter('posts_where', 'posts_where_wpse_94630');
    }
    
    function posts_where_wpse_94630($where) {
       global $wpdb;       
       if (isset($_GET['meta_data']) && !empty($_GET['meta_data'])) {
           $meta = esc_sql($_GET['meta_data']);
           $where .= " AND ID IN (SELECT post_id FROM $wpdb->postmeta WHERE meta_key='$meta')";
       }
       return $where;
    }
  2. Использование pre_get_posts:

    Этот метод более предпочтителен, так как он изменяет объект запроса, а не SQL-запрос напрямую.

    add_filter('views_edit-{$post_type}', 'my_custom_views', 10, 1);
    
    function my_custom_views($views) {
       $views['metakey'] = '<a href="edit.php?post_type={$post_type}&modify_query=yes">My Filter</a>';
       return $views;
    }
    
    add_action('pre_get_posts', 'custom_filter_admin_posts_query');
    
    function custom_filter_admin_posts_query($query) {
       if (is_admin() && $query->get('post_type') == "{$post_type}" && $_GET['modify_query'] == "yes") {
           $query->set('meta_query', array(
               array(
                   'key' => 'some_custom_field',
                   'value' => 'some value'
               )
           ));
       }
    }

Применение

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

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

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

Капча загружается...