Вопрос или проблема
У меня есть настраиваемый тип записи с пользовательскими мета-данными, которые я хочу фильтровать на странице Администратора. Подобно ссылкам “Все | Опубликованные | Черновики | Корзина”, расположенным выше списка записей. Я никак не могу найти хук для подключения. Существует ли он?
Этот вопрос не совсем то, что я спрашиваю. Я предпочел бы не использовать выпадающий фильтр, а вместо этого — ссылки, как …
Все | Опубликованные | Черновики | Корзина
… в верхней части редактора.
Точно так же, как в Добавление фильтра таксономии в список администратора для пользовательского типа записи? можно использовать фильтр 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
, которые предоставляют различные возможности для модификации запросов и интерфейса.
-
views_edit-{$post_type}
: Этот фильтр используется для изменения вида ссылок на странице списка записей. Он позволяет добавлять собственные ссылки в верхнюю часть страницы. -
posts_where
: Этот фильтр позволяет изменять часть SQL-запроса WHERE, добавляя условия для фильтрации по мета-данным. Однако следует быть осторожным, чтобы не повлиять на другие запросы. -
parse_query
иpre_get_posts
: Эти фильтры дают возможность модифицировать объект запроса (WP_Query
), что является более безопасным и гибким путем изменения параметров запроса, таких какmeta_query
.
Пример
Рассмотрим два подхода, которые продемонстрированы в вопросе.
-
Использование
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; }
-
Использование
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
как наиболее безопасный и удобный метод для изменения запросов.