Расширение контекста поиска в списке записей админ-панели

11 мар. 2011 г., 14:09:59
Просмотры: 39.8K
Голосов: 52

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

Где можно сделать хук и какой код нужно использовать?

Пример изображения Пример поиска в админ-панели WordPress

Стефано

2
Комментарии

Старый вопрос, но... я бы хотел предложить скрывать email-адреса и имена на скриншотах...

Erenor Paz Erenor Paz
22 июл. 2018 г. 23:16:45

https://wordpress.stackexchange.com/a/317393/133699

Muhammad Bilal Muhammad Bilal
15 апр. 2023 г. 08:33:15
Все ответы на вопрос 6
5
49

Я решил проблему фильтрации запроса, добавив соединение с таблицей postmeta и изменив условие WHERE. Советы по фильтрации условия WHERE (часто требуют поиска и замены с использованием регулярных выражений) можно найти здесь в codex:

add_filter( 'posts_join', 'segnalazioni_search_join' );
function segnalazioni_search_join ( $join ) {
    global $pagenow, $wpdb;

    // Фильтр применяется только при поиске на странице редактирования произвольного типа записи "segnalazioni".
    if ( is_admin() && 'edit.php' === $pagenow && 'segnalazioni' === $_GET['post_type'] && ! empty( $_GET['s'] ) ) {    
        $join .= 'LEFT JOIN ' . $wpdb->postmeta . ' ON ' . $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id ';
    }
    return $join;
}

add_filter( 'posts_where', 'segnalazioni_search_where' );
function segnalazioni_search_where( $where ) {
    global $pagenow, $wpdb;

    // Фильтр применяется только при поиске на странице редактирования произвольного типа записи "segnalazioni".
    if ( is_admin() && 'edit.php' === $pagenow && 'segnalazioni' === $_GET['post_type'] && ! empty( $_GET['s'] ) ) {
        $where = preg_replace(
            "/\(\s*" . $wpdb->posts . ".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
            "(" . $wpdb->posts . ".post_title LIKE $1) OR (" . $wpdb->postmeta . ".meta_value LIKE $1)", $where );
        $where.= " GROUP BY {$wpdb->posts}.id"; // Решает проблему дублирования результатов
    }
    return $where;
}
18 мар. 2011 г. 11:02:17
Комментарии

Вау! Именно то, что я искал. Однако, кажется, я нашел баг: при поиске по заголовку записи я получаю совпадение, которое затем дублируется в результатах 5 раз!?! http://imgur.com/eE52gIA

jnthnclrk jnthnclrk
22 авг. 2013 г. 17:58:07

Вот еще один скриншот с выводом SQL: http://tinypic.com/view.php?pic=124tqb6&s=5 Не могу понять, почему получается 5 элементов!?!

jnthnclrk jnthnclrk
22 авг. 2013 г. 23:19:45

Задал отдельный вопрос по исправлению бага с дублированием: http://wordpress.stackexchange.com/questions/111185/how-do-i-improve-this-admin-query-snippet-to-avoid-generating-duplicate-results

jnthnclrk jnthnclrk
24 авг. 2013 г. 14:47:01

Этот пост и следующий ниже были полезны для меня. Теперь нужно найти способ включить поиск по автору поста и отображать записи, созданные ими.

Shawn Rebelo Shawn Rebelo
31 июл. 2018 г. 21:27:38

@Stefano, результаты поиска работают. Есть проблема: поле по умолчанию "Заголовок записи", результаты поиска повторяются много раз в админке. Смотрите: https://imgur.com/a/W4wmXhO

Muhammad Bilal Muhammad Bilal
23 окт. 2018 г. 12:16:24
0
14

Ответ Стефано отличный, но в нем не хватает условия DISTINCT:

function segnalazioni_search_distinct( $where ){
    global $pagenow, $wpdb;

    if ( is_admin() && $pagenow=='edit.php' && $_GET['post_type']=='segnalazioni' && $_GET['s'] != '') {
    return "DISTINCT";

    }
    return $where;
}
add_filter( 'posts_distinct', 'segnalazioni_search_distinct' );

Добавьте приведенный выше код, обновите его, и он будет работать без дубликатов.

30 апр. 2014 г. 15:00:25
6

Это сработает:

function custom_search_query( $query ) {
    $custom_fields = array(
        // здесь укажите все мета-поля, по которым нужно производить поиск
        "rg_first_name",
        "rg_1job_designation"
    );
    $searchterm = $query->query_vars['s'];

    // необходимо удалить параметр "s" из запроса, чтобы он не мешал поиску записей
    $query->query_vars['s'] = "";

    if ($searchterm != "") {
        $meta_query = array('relation' => 'OR');
        foreach($custom_fields as $cf) {
            array_push($meta_query, array(
                'key' => $cf,
                'value' => $searchterm,
                'compare' => 'LIKE'
            ));
        }
        $query->set("meta_query", $meta_query);
    };
}
add_filter( "pre_get_posts", "custom_search_query");
31 янв. 2014 г. 13:00:33
Комментарии

Пожалуйста, правильно отступайте ваш код и включите объяснение, почему и как это будет работать.

tfrommen tfrommen
31 янв. 2014 г. 13:28:45

Хотя сначала я проголосовал за это, я понял, что, к сожалению, это будет работать при каждом поиске, и это может сломать фронтенд-поиск.

Maciej Paprocki Maciej Paprocki
13 июн. 2018 г. 16:01:23

Добавление проверки if ( $query->query['post_type'] != 'your_custom_post_type' ){ return; } в начало функции предотвратит выполнение этого кода при других поисках. Обратите внимание, что техника в этом ответе больше не ищет post_title, и добавить это обратно нетривиально.

jwinn jwinn
30 нояб. 2018 г. 20:21:32

Еще одна проблема - индикатор Результаты поиска по запросу «<ключевое слово>» вызывает get_search_query(), который в свою очередь вызывает get_query_var( 's' ). Поскольку "s" установлен в пустую строку, Результаты поиска по запросу «» всегда будет иметь пустое значение между кавычками. Есть ли доработка этого решения, которая обходит эту проблему?

jschrab jschrab
29 янв. 2019 г. 23:01:10

Еще одна проблема - это решение будет работать только для мета-значений сейчас. Поиск по заголовку, например, не будет работать.

Ravi Mattar Ravi Mattar
16 июн. 2022 г. 19:50:28

Ответ 'Seyed Abbas' лучше: поиск по пользовательскому мета-полю и заголовку!

gtamborero gtamborero
21 янв. 2023 г. 20:17:38
Показать остальные 1 комментариев
0

Решение 1: Добавьте этот код в файл функций и измените/добавьте названия столбцов, которые вы используете в своем пользовательском типе записи

function extend_admin_search( $query ) {

    // используйте ваш тип записи
    $post_type = 'document';
    // Используйте ваши пользовательские поля/названия столбцов для поиска
    $custom_fields = array(
        "_file_name",
    );

    if( ! is_admin() )
        return;
    
    if ( $query->query['post_type'] != $post_type )
        return;

    $search_term = $query->query_vars['s'];

    // Установите пустое значение, иначе ничего не найдется
    $query->query_vars['s'] = '';

    if ( $search_term != '' ) {
        $meta_query = array( 'relation' => 'OR' );

        foreach( $custom_fields as $custom_field ) {
            array_push( $meta_query, array(
                'key' => $custom_field,
                'value' => $search_term,
                'compare' => 'LIKE'
            ));
        }

        $query->set( 'meta_query', $meta_query );
    };
}

add_action( 'pre_get_posts', 'extend_admin_search' );

Решение 2: (Рекомендуется) Используйте этот код в файле функций без изменений

function cf_search_join( $join ) {
    global $wpdb;

    if ( is_search() ) {    
        $join .=' LEFT JOIN '.$wpdb->postmeta. ' ON '. $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id ';
    }

    return $join;
}
add_filter('posts_join', 'cf_search_join' );

function cf_search_where( $where ) {
    global $pagenow, $wpdb;

    if ( is_search() ) {
        $where = preg_replace(
            "/\(\s*".$wpdb->posts.".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
            "(".$wpdb->posts.".post_title LIKE $1) OR (".$wpdb->postmeta.".meta_value LIKE $1)", $where );
    }

    return $where;
}
add_filter( 'posts_where', 'cf_search_where' );

function cf_search_distinct( $where ) {
    global $wpdb;

    if ( is_search() ) {
        return "DISTINCT";
    }

    return $where;
}
add_filter( 'posts_distinct', 'cf_search_distinct' );
23 окт. 2018 г. 15:45:54
2

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

Пожалуйста, добавьте следующий код в файл functions.php:

if (!function_exists('extend_admin_search')) {
    add_action('admin_init', 'extend_admin_search');

    /**
     * Подключаем фильтр поиска записей, если мы находимся на странице админки для нашего типа записи
     */
    function extend_admin_search() {
        global $typenow;

        if ($typenow === 'your_custom_post_type') {
            add_filter('posts_search', 'posts_search_custom_post_type', 10, 2);
        }
    }

    /**
     * Добавляем условие запроса для произвольных метаполей
     * @param string $search текущая строка поиска
     * @param WP_Query $query
     * @return string
     */
    function posts_search_custom_post_type($search, $query) {
        global $wpdb;

        if ($query->is_main_query() && !empty($query->query['s'])) {
            $sql    = "
            or exists (
                select * from {$wpdb->postmeta} where post_id={$wpdb->posts}.ID
                and meta_key in ('custom_field1','custom_field2')
                and meta_value like %s
            )
        ";
            $like   = '%' . $wpdb->esc_like($query->query['s']) . '%';
            $search = preg_replace("#\({$wpdb->posts}.post_title LIKE [^)]+\)\K#",
                $wpdb->prepare($sql, $like), $search);
        }

        return $search;
    }
}
21 янв. 2020 г. 10:54:44
Комментарии

Пожалуйста, не копируйте свой ответ на каждый похожий вопрос. Как только вы наберете достаточную репутацию, вы сможете комментировать любые сообщения и предоставлять ссылку на свой ответ.

nmr nmr
21 янв. 2020 г. 13:13:45

Я пытался помочь всем с похожими проблемами и усердно работал, чтобы найти правильный ответ.

Seyed Abbas Seyedi Seyed Abbas Seyedi
22 янв. 2020 г. 13:24:45
0

Версия кода из нескольких ответов, которая модифицирует параметр meta_query в WP_Query для поиска через pre_get_posts, перестала искать по post_title. Возможность искать либо по заголовку записи (post_title), либо по значениям мета-полей нельзя реализовать напрямую в WP_Query без модификации SQL, как подробно объясняется в этом вопросе: Использование meta_query ('meta_query') с поисковым запросом ('s')

Я объединил несколько техник из представленных здесь решений, чтобы получить рабочую версию, которая избегает использования preg_replaces и слишком значительных модификаций SQL (хотя хотелось бы обойтись без них вообще). Единственным недостатком является то, что после выполнения поиска текст подзаголовка в верхней части страницы отображает "Результаты поиска для ''". Для своего пользовательского типа записи (custom post type) я просто скрыл этот текст с помощью CSS.

/**
 * Расширяет поиск для пользовательского типа записи в админ-панели, включая поиск по мета-полям
 * @param  WP_Query $query
 */
function extend_cpt_admin_search( $query ) {
  // Проверяем, что мы в админ-панели и что это наш пользовательский тип записи
  if ( !is_admin() || $query->query['post_type'] != 'your_custom_post_type' ){
    return;
  }

  // Укажите все мета-поля, по которым нужно осуществлять поиск
  $custom_fields = array(
    "your_custom_meta_field",
    "your_custom_meta_field2",
    "your_custom_meta_field3"
  );
  // Строка поиска, переданная через поисковую форму
  $searchterm = $query->query_vars['s'];

  // Устанавливаем пустое значение, иначе результаты не будут возвращены
  // Побочный эффект - отображаемый текст поиска будет пустым в верхней части страницы
  $query->query_vars['s'] = '';

  if ($searchterm != ""){
    // Добавляем параметр meta_query к объекту WP_Query
    // Справочная информация: https://codex.wordpress.org/Class_Reference/WP_Query#Custom_Field_Parameters
    $meta_query = array();
    foreach($custom_fields as $cf) {
      array_push($meta_query, array(
        'key' => $cf,
        'value' => $searchterm,
        'compare' => 'LIKE'
      ));
    }
    // Используем сравнение 'OR' для каждого дополнительного мета-поля
    if (count($meta_query) > 1){
      $meta_query['relation'] = 'OR';
    }
    // Устанавливаем параметр meta_query
    $query->set('meta_query', $meta_query);


    // Чтобы поиск также возвращал результаты по post_title с условием "OR"
    $query->set('_meta_or_title', $searchterm);
  }
}
add_action('pre_get_posts', 'extend_cpt_admin_search');
30 нояб. 2018 г. 21:19:21