Поиск сообщений по их URL в панели администратора?

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

На административной странице “посты -> все посты” я бы хотел искать и видеть только те посты, в 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-запросов. Это делает управление и модерацию контента более удобными и эффективными, что, несомненно, важно для поддержания качественного наполнения сайта.

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

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