Вопрос или проблема
На административной странице “посты -> все посты” я бы хотел искать и видеть только те посты, в URL которых содержится определенный элемент (например, символ “-3”, обозначающий, что это дубликат поста).
Как это можно сделать?
Вот один из способов поддержки поиска по слагам постов в бэкэнде.
Давайте организуем такой поиск с помощью строки slug:
в поисковом запросе.
Пример
Для поиска слагов, оканчивающихся на -2
, мы хотим иметь возможность искать:
slug:*-2
где * является подстановочным знаком.
Демо Плагин
Вот демонстрационный плагин, который может потребовать дополнительного тестирования и настроек:
add_filter( 'posts_search', function( $search, \WP_Query $q ) use ( &$wpdb )
{
// Ничего не делать
if(
! did_action( 'load-edit.php' )
|| ! is_admin()
|| ! $q->is_search()
|| ! $q->is_main_query()
)
return $search;
// Получить входной поисковый запрос
$s = $q->get( 's' );
// Проверить наличие части "slug:" в входном запросе
if( 'slug:' === mb_substr( trim( $s ), 0, 5 ) )
{
// Переопределить поисковый запрос
$search = $wpdb->prepare(
" AND {$wpdb->posts}.post_name LIKE %s ",
str_replace(
[ '**', '*' ],
[ '*', '%' ],
mb_strtolower(
$wpdb->esc_like(
trim( mb_substr( $s, 5 ) )
)
)
)
);
// Настроить сортировку
$q->set('orderby', 'post_name' );
$q->set('order', 'ASC' );
}
return $search;
}, PHP_INT_MAX, 2 );
Это основано на плагине _name__like
из моего предыдущего ответа здесь.
Вы не можете выполнить такой запрос из интерфейса администратора без явного кодирования этого в теме или плагине. Если вы хотите найти все посты, оканчивающиеся на -3
в их названии, я предлагаю выполнить SQL-запрос, возможно, дополнить его с помощью WP-CLI:
wp post list --fields=url --post__in=$(wp db query "SELECT ID FROM wp_posts WHERE post_name LIKE '%-3';" | paste -s -d,)
Надеюсь, это поможет.
Или вы можете зайти в вашу базу данных mysql, использовать опцию поиска, чтобы найти таблицу wp_posts столбца post_name
И выполнить поиск!
Скриншот :https://prnt.sc/SDQ3QZL1kyZ1
😊
Вы можете “расширить” существующий поиск и обработать результаты поиска, используя хук pre_get_posts.
Вот плагин, который я сделал для поиска в пермалинках.
<?php
/**
* Имя плагина: Поиск по пермалинкам
* Описание: Улучшает поиск в админ-панели WordPress, позволяя искать посты по пермалинкам.
* Версия: 1.0.0
* Автор: Александр Пленневок
* URI автора: https://apptweak.com
* Текстовый домен: permalink-search
* Путь домена: /languages
* Лицензия: GPL v2 или более поздняя
* URI лицензии: http://www.gnu.org/licenses/gpl-2.0.txt
*/
// Выход, если доступ осуществляется напрямую
if (! defined('ABSPATH')) {
exit;
}
/**
* Основной класс плагина поиска по пермалинкам
*/
class Permalink_Search
{
/**
* Конструктор
*/
public function __construct()
{
// Хук в поиск WordPress для админки
add_action('pre_get_posts', array($this, 'extend_admin_search'));
// Добавить уведомление о функции поиска по пермалинкам
add_action('admin_notices', array($this, 'display_search_notice'));
// Загрузить текстовый домен для переводов
add_action('plugins_loaded', array($this, 'load_textdomain'));
}
/**
* Загрузить текстовый домен плагина
*/
public function load_textdomain()
{
load_plugin_textdomain('permalink-search', false, dirname(plugin_basename(__FILE__)) . '/languages');
}
/**
* Показать уведомление о поиске по пермалинкам на страницах редактирования
*/
public function display_search_notice()
{
$screen = get_current_screen();
// Показать только на страницах редактирования
if (! $screen || ! in_array($screen->base, array('edit', 'edit-tags'))) {
return;
}
// Проверить, отклонено ли это уведомление пользователем
if (get_user_meta(get_current_user_id(), 'permalink_search_notice_dismissed', true)) {
return;
}
?>
<div class="notice notice-info is-dismissible permalink-search-notice">
<p>
<?php _e('Теперь вы можете искать по пермалинкам! Используйте "/" в вашем поиске, чтобы найти контент по пути URL.', 'permalink-search'); ?>
<a href="#" class="dismiss-permalink-search-notice">
<?php _e('Отклонить', 'permalink-search'); ?>
</a>
</p>
</div>
<?php
// Добавить встраиваемый скрипт для обработки отклонения уведомления
add_action('admin_footer', array($this, 'notice_dismissal_script'));
}
/**
* Добавить скрипт для обработки отклонения уведомления
*/
public function notice_dismissal_script()
{
?>
<script>
jQuery(document).ready(function($) {
$('.dismiss-permalink-search-notice').on('click', function(e) {
e.preventDefault();
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'dismiss_permalink_search_notice',
nonce: '<?php echo wp_create_nonce('permalink_search_dismiss_notice'); ?>'
}
});
$(this).closest('.permalink-search-notice').fadeOut();
});
});
</script>
<?php
}
/**
* Расширить поиск в админке, включив туда пермалинки
*
* @param WP_Query $query Объект запроса WordPress
*/
public function extend_admin_search($query)
{
// Выполнять только в админке и только для поисковых запросов
if (! is_admin() || ! $query->is_search() || ! $query->is_main_query()) {
return;
}
// Получить текущий экран
$screen = get_current_screen();
// Применять только к экранам редактирования (посты, страницы, пользовательские типы постов)
if (! $screen || 'edit' !== $screen->base) {
return;
}
// Получить поисковый термин
$search_term = $query->get('s');
// Если поисковый термин содержит слэш, возможно, это поиск по пермалинкам
if (false !== strpos($search_term, "https://wordpress.stackexchange.com/")) {
// Удалить стандартный поиск
$query->set('s', '');
// Получить тип поста
$post_type = $query->get('post_type');
// Создать мета-запрос для поиска постов с совпадающими пермалинками
$query->set('meta_query', array(
'relation' => 'OR',
array(
'key' => '_permalink_search_url',
'value' => $search_term,
'compare' => 'LIKE',
)
));
// Необходимо обеспечить кэширование пермалинков для всех постов
$this->cache_permalinks($post_type);
// Добавить пользовательский фильтр для включения поиска по заголовку/контенту
add_filter('posts_where', array($this, 'custom_search_where'), 10, 2);
add_filter('posts_join', array($this, 'custom_search_join'), 10, 2);
add_filter('posts_distinct', array($this, 'custom_search_distinct'));
// Сохранить поисковый термин для использования в фильтрах
$this->search_term = $search_term;
}
}
/**
* Кэшировать пермалинки для всех постов заданного типа
*
* @param string|array $post_type Тип(ы) постов для кэширования пермалинков
*/
public function cache_permalinks($post_type)
{
global $wpdb;
// Получить все посты указанного типа, для которых не кэшированы пермалинки
$query = $wpdb->prepare(
"SELECT ID FROM $wpdb->posts WHERE post_type = %s AND ID NOT IN
(SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_permalink_search_url')",
$post_type
);
$posts = $wpdb->get_col($query);
// Кэшировать пермалинки для каждого поста
foreach ($posts as $post_id) {
$permalink = get_permalink($post_id);
update_post_meta($post_id, '_permalink_search_url', $permalink);
}
}
/**
* Пользовательский WHERE запрос для поиска по пермалинкам
*
* @param string $where WHERE запрос
* @param WP_Query $query Экземпляр WP_Query
* @return string Модифицированный WHERE запрос
*/
public function custom_search_where($where, $query)
{
global $wpdb;
// Добавить поиск по заголовку и содержимому
if (isset($this->search_term)) {
$search_term = '%' . $wpdb->esc_like($this->search_term) . '%';
$where .= $wpdb->prepare(
" OR ($wpdb->posts.post_title LIKE %s OR $wpdb->posts.post_content LIKE %s)",
$search_term,
$search_term
);
}
return $where;
}
/**
* Пользовательский JOIN запрос для поиска по пермалинкам
*
* @param string $join JOIN запрос
* @param WP_Query $query Экземпляр WP_Query
* @return string Модифицированный JOIN запрос
*/
public function custom_search_join($join, $query)
{
return $join;
}
/**
* Обеспечить уникальность результатов
*
* @param string $distinct DISTINCT запрос
* @return string Модифицированный DISTINCT запрос
*/
public function custom_search_distinct($distinct)
{
return "DISTINCT";
}
}
// Инициализировать плагин
$permalink_search = new Permalink_Search();
/**
* Обработать AJAX запрос для отклонения уведомления
*/
function permalink_search_dismiss_notice()
{
// Проверить nonce
if (! isset($_POST['nonce']) || ! wp_verify_nonce($_POST['nonce'], 'permalink_search_dismiss_notice')) {
wp_die(__('Проверка безопасности не пройдена', 'permalink-search'));
}
// Обновить мета-данные пользователя для отклонения уведомления
update_user_meta(get_current_user_id(), 'permalink_search_notice_dismissed', true);
wp_die();
}
add_action('wp_ajax_dismiss_permalink_search_notice', 'permalink_search_dismiss_notice');
/**
* Обновить кэш пермалинков при сохранении поста
*
* @param int $post_id ID поста
*/
function permalink_search_update_cache($post_id)
{
// Пропустить ревизии и автосохранения
if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) {
return;
}
// Обновить кэш пермалинков
$permalink = get_permalink($post_id);
update_post_meta($post_id, '_permalink_search_url', $permalink);
}
add_action('save_post', 'permalink_search_update_cache');
/**
* Обновить кэш пермалинков при изменении слага поста
*
* @param int $post_id ID поста
* @param WP_Post $post Объект поста
* @param WP_Post $post_before Объект поста до обновления
*/
function permalink_search_update_on_slug_change($post_id, $post, $post_before)
{
// Проверить, изменился ли слаг
if ($post->post_name !== $post_before->post_name) {
// Обновить кэш пермалинков
$permalink = get_permalink($post_id);
update_post_meta($post_id, '_permalink_search_url', $permalink);
}
}
add_action('post_updated', 'permalink_search_update_on_slug_change', 10, 3);
Ответ или решение
При создании и администрировании веб-сайта на платформе WordPress возникает множество различных задач, связанных с управлением контентом. Одна из таких задач — это поиск и управление дубликатами постов на административной панели сайта. Например, нередко возникает необходимость найти и просмотреть все сообщения, чей URL содержит определенные элементы (например, окончание "-3"), что указывает на то, что это дублирующийся пост. Давайте разберёмся, как можно реализовать такой функционал.
Теория
Каждая запись в WordPress имеет уникальный URL-адрес, зависящий от так называемого "слага" (slug) — части URL, следующей после домена. Например, в URL https://example.com/post-name
, post-name
— это слаг. Поиск по слагам позволяет эффективно находить и управлять записями, что особенно полезно в случаях, когда необходимо идентифицировать дубликаты.
Стандартная функциональность административной панели WordPress не предусматривает возможности поиска сообщений по частям их URL непосредственно из интерфейса. Однако, WordPress предоставляет обширные возможности для расширения и кастомизации через плагины и непосредственное вмешательство в код сайта.
Пример
В администраторах WordPress поиск по слагу можно организовать, добавив в запросы специфическую конструкцию, например, slug:*-2
, где *
— это метасимвол, обозначающий подстановку любых символов. Для реализации этого необходимы программные изменения через написание пользовательных фильтров и хуков.
Ниже приведен пример простого плагина, который изменяет поведение поиска по записям в админ-панели, позволяя искать их по слагам:
add_filter('posts_search', function($search, \WP_Query $q) use (&$wpdb) {
if (!did_action('load-edit.php') || !is_admin() || !$q->is_search() || !$q->is_main_query())
return $search;
$s = $q->get('s');
if ('slug:' === mb_substr(trim($s), 0, 5)) {
$search = $wpdb->prepare(
" AND {$wpdb->posts}.post_name LIKE %s ",
str_replace(['**', '*'], ['*', '%'], mb_strtolower($wpdb->esc_like(trim(mb_substr($s, 5)))))
);
$q->set('orderby', 'post_name');
$q->set('order', 'ASC');
}
return $search;
}, PHP_INT_MAX, 2);
Этот плагин перехватывает стандартный запрос поиска, и если пользователь вводит в поисковую строку slug:
, он обрабатывает запрос с использованием SQL-синтаксиса для подстановки LIKE
, удобного для подобных задач.
Применение
Реализация подобной функциональности может быть полезна для контент-менеджеров и администраторов, которые управляют большими объемами контента. Например, использование такого плагина облегчает процесс инвентаризации статей, проверку уникальности контента, а также быструю работу с похожими записями, имеющими незначительные отличия в URL.
Кроме того, можно пойти дальше и использовать командную строку для более гибкого поиска. WP-CLI — мощный инструмент для управления WordPress напрямую из командной строки сервера. Например, следующая команда позволяет получить список всех постов, содержащих в URL часть -3
:
wp post list --fields=url --post__in=$(wp db query "SELECT ID FROM wp_posts WHERE post_name LIKE '%-3';" | paste -s -d,)
Также администратор может вручную выполнять SQL-запросы через доступ к базе данных посредством phpMyAdmin или другого SQL клиента, выполнением следующего запроса:
SELECT ID FROM wp_posts WHERE post_name LIKE '%-3';
Точный и удобный поиск по слагам значительно ускоряет рутинные процессы по работе с записями. Важно помнить о безопасности: любые вмешательства в код сайта должны делаться с учетом возможных последствий для безопасности и производительности сайта. Как вариант, можно также комбинировать данные методы с кэшем, что может улучшить производительность системы.
Резюмируя, интеграция поиска по URL (или их частям) в административную часть сайта WordPress — задача, вполне решаемая с помощью плагинов, WP-CLI и SQL-запросов. Это делает управление и модерацию контента более удобными и эффективными, что, несомненно, важно для поддержания качественного наполнения сайта.