Как разрешить поиск по пользовательскому мета-ключу в таблице списка администратора?

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

У меня есть пользовательский тип записи, и я хотел бы искать по заголовкам И пользовательскому мета-ключу. Я попробовал несколько различных вариантов, но могу искать только по заголовкам ИЛИ моему пользовательскому мета-ключу, но не по обоим. Мне не нужно искать по содержимому.

Вот что у меня есть, это успешно ищет по моему мета-ключу, но не ищет по заголовку.

add_action( 'pre_get_posts', 'filter_files_admin_columns' );
function filter_files_admin_columns( $query ) {
    if ( !is_admin() || 'eri-files' !== $query->get( 'post_type' ) ) {
        return;
    }

    // Очистить параметр поиска 's'
    $search_term = $query->get( 's' );
    $query->set( 's', '' );

    if ( !empty( $search_term ) ) {
        $meta_query = [
            'relation'    => 'OR',
            [
                'key'     => '',
                'value'   => $search_term,
                'compare' => 'LIKE',
            ],
        ];
        
        // Определить пользовательские поля для поиска
        $custom_fields = [ '_post_url' ];
        
        // Сформировать мета-запрос
        foreach ( $custom_fields as $custom_field ) {
            $meta_query[] = [
                'key'     => $custom_field,
                'value'   => $search_term,
                'compare' => 'LIKE',
            ];
        }
        
        // Установить meta_query
        $query->set( 'meta_query', $meta_query );
    }
}

Я пытался просто начать с $meta_query = [ 'relation' => 'OR' ];, а также сменить первый ключ на 'post_title', но это не дало результата.

Я понимаю, что очистка поискового термина с помощью $query->set( 's', '' ); предотвращает поиск по заголовку, но без этого я не могу заставить это искать по мета-ключу. Поэтому я пытаюсь вернуть поддержку заголовка. Если есть другой способ заставить его искать по моему мета-ключу, не очищая поисковой термин, дайте мне знать.

После того как я задал тот же вопрос нескольким AI-чат-ботам, CoPilot наконец дал мне ответ, который работает для обоих:

add_action( 'pre_get_posts', 'filter_files_admin_columns' );
function filter_files_admin_columns( $query ) {
    if ( !is_admin() || 'eri-files' !== $query->get( 'post_type' ) ) {
        return;
    }

    add_filter( 'posts_search', 'custom_search_query', 10, 2 );

    function custom_search_query( $search, $wp_query ) {
        global $wpdb;

        if ( empty( $search ) ) {
            return $search;
        }

        $search_term = $wp_query->get( 's' );
        if ( ! $search_term ) {
            return $search;
        }

        $search = "AND ( 
            {$wpdb->posts}.post_title LIKE '%" . esc_sql( $wpdb->esc_like( $search_term ) ) . "%' 
            OR {$wpdb->posts}.ID IN (
                SELECT post_id 
                FROM {$wpdb->postmeta} 
                WHERE meta_key = '_post_url' 
                AND meta_value LIKE '%" . esc_sql( $wpdb->esc_like( $search_term ) ) . "%'
            )
        )";

        return $search;
    }
}

Заголовок записи не хранится в метаданных, поэтому добавление его туда не сработает. Я подозреваю, что сохранение параметра s и добавление meta_query для _post_url (пользовательский мета-ключ) должны сработать (не тестировалось):

add_action( 'pre_get_posts', static function ( $query ) {
    if ( ! is_admin() || 'eri-files' !== $query->get( 'post_type' ) ) {
        return;
    }

    if ( empty( $query->get( 's' ) ) {
        return;
    }

    $query->set( 'meta_query', array(
        array(
            'key'     => '_post_url',
            'value'   => $query->get( 's' ),
            'compare' => 'LIKE',
        ),
    ) );

    // Ограничить поиск до столбца post_title.
    $query->set( 'search_columns', array( 'post_title' ) );
} );

Это должно вернуть записи, где как заголовок записи, так и метаданные _post_url соответствуют поисковому термину.

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

Для того чтобы осуществлять поиск по наименованиям и пользовательским мета-полям в административной панели WordPress, необходимо использовать хук pre_get_posts и дополнительно обработать стандартный механизм поиска. В этом ответе я представлю вам детальный подход к реализации данной задачи.

Определение проблемы

Вы стремитесь к тому, чтобы осуществлять поиск не только по заголовкам ваших пользовательских записей, но и по пользовательским мета-данным, таким как мета-ключ ‘_post_url’. При этом важно сохранить возможность поиска по заголовкам, вместо того, чтобы попусту очищать поисковый запрос, как это было в вашем предыдущем решении.

Рекомендации по реализации

Ниже приведен пример кода, который позволяет выполнять поиск одновременно по заголовкам и пользовательским мета-данным. Этот код добавляется в файл functions.php вашей темы или в специальный плагин.

add_action( 'pre_get_posts', 'filter_files_admin_columns' );

function filter_files_admin_columns( $query ) {
    // Проверяем, что мы в админке, и что текущий пост-тип соответствует нашему.
    if ( !is_admin() || 'eri-files' !== $query->get( 'post_type' ) ) {
        return;
    }

    // Получаем поисковый термин.
    $search_term = $query->get( 's' );
    if ( empty( $search_term ) ) {
        return;
    }

    // Отменяем стандартный механизм поиска.
    add_filter( 'posts_search', 'custom_search_query', 10, 2 );

    function custom_search_query( $search, $wp_query ) {
        global $wpdb;

        // Проверяем, пустой ли запрос.
        if ( empty( $search ) ) {
            return $search;
        }

        // Получаем поисковый термин.
        $search_term = $wp_query->get( 's' );
        if ( ! $search_term ) {
            return $search;
        }

        // Формируем индивидуальный SQL-запрос для поиска по заголовкам и мета-ключу.
        $search = " AND ( 
            {$wpdb->posts}.post_title LIKE '%" . esc_sql( $wpdb->esc_like( $search_term ) ) . "%' 
            OR {$wpdb->posts}.ID IN (
                SELECT post_id 
                FROM {$wpdb->postmeta} 
                WHERE meta_key = '_post_url' 
                AND meta_value LIKE '%" . esc_sql( $wpdb->esc_like( $search_term ) ) . "%'
            )
        )";

        return $search;
    }
}

Объяснение кода

  1. Проверка условий: Мы проверяем, что текущий запрос выполняется в административной панели и что пост-тип соответствует ‘eri-files’.

  2. Получение поискового термина: Если поисковый термин пуст, мы завершаем выполнение функции.

  3. Перезапись механизма поиска: С помощью хука add_filter('posts_search', ...) мы создаем кастомный поиск по заголовкам и мета-данным.

  4. Формирование запроса: Мы используем SQL запроса для поиска в заголовках (post_title) и в экземплярах мета-данных (_post_url). Используем esc_sql и esc_like, чтобы избежать SQL-инъекций и корректно экранировать специальные символы.

Заключение

С помощью описанного метода вы сможете сочетать поиск по заголовкам и мета-данным в административной панели WordPress. Это повысит удобство использования и эффективность работы с пользовательским пост-типом. Убедитесь, что вы протестировали этот код в безопасной среде перед развёртыванием на производственном сайте.

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

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