Как включить данные из wp_postmeta в поиск WordPress?

8 дек. 2011 г., 15:51:39
Просмотры: 47.7K
Голосов: 16

У меня есть сайт, использующий Advanced Custom Fields для создания и хранения различной релевантной информации. Эти данные необходимо включить в основной общий поиск, который по умолчанию ищет только по заголовку и основному содержимому.

Я нашел много информации о том, как получить результаты поиска на основе определенных частей postmeta, но у меня есть проблема с этим. В postmeta может быть неограниченное количество потенциальных полей для поиска.

Решение может либо искать что угодно в postmeta, либо искать что-либо с meta_key, соответствующим этому регулярному выражению: content_section_[0-9]{1,4}_content_.{2,8}

Примеры meta_keys для соответствия:

content_section_0_content_title
content_section_0_content_title
content_section_4_content_subtitle
content_section_8_content_text

Буду очень признателен за любой способ, которым я могу изменить поля поиска, чтобы включить postmeta.

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

и в чем вопрос?

Naoise Golden Naoise Golden
8 дек. 2011 г. 23:31:53

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

Jodi Warren Jodi Warren
9 дек. 2011 г. 02:53:07
Все ответы на вопрос 6
2
11

Добавьте этот код в ваш плагин или файл functions.php вашей темы. Пример ниже добавит 'your_key' в поиск. Вы можете включить все свои ключи, повторяя массив.


function me_search_query( $query ) {
  if ( $query->is_search ) {
    $meta_query_args = array(
      array(
        'key' => 'your_key',         // ваш ключ метаполя
        'value' => $query->query_vars['s'] = '',
        'compare' => 'LIKE',         // оператор сравнения
      ),
    );
    $query->set('meta_query', $meta_query_args);  // устанавливаем мета-запрос
  };
}
add_filter( 'pre_get_posts', 'me_search_query');  // добавляем фильтр
10 сент. 2015 г. 01:32:09
Комментарии

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

David David
9 июл. 2017 г. 19:16:13

Это будет работать очень медленно, так как мета-значения не индексируются.

vancoder vancoder
18 авг. 2020 г. 21:31:38
3

Эта функция должна работать даже после обновления безопасности WP 4.8.3.

Использование:

// Добавьте это в functions.php

add_meta_field_to_search_query('right_data');
add_meta_field_to_search_query('extra_search_terms');

Реализация:

/* ДОБАВЛЕНИЕ МЕТАПОЛЯ В ПОИСКОВЫЙ ЗАПРОС */

function add_meta_field_to_search_query($field){
  if(isset($GLOBALS['added_meta_field_to_search_query'])){
    $GLOBALS['added_meta_field_to_search_query'][] = '\'' . $field . '\'';

    return;
  }

  $GLOBALS['added_meta_field_to_search_query'] = array();
  $GLOBALS['added_meta_field_to_search_query'][] = '\'' . $field . '\'';

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

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

      return $join;
  });

  add_filter('posts_groupby', function($groupby){
      global $wpdb;

      if (is_search()) {    
          $groupby = "$wpdb->posts.ID";
      }

      return $groupby;
  });

  add_filter('posts_search', function($search_sql){
      global $wpdb;

      $search_terms = get_query_var('search_terms');

      if(!empty($search_terms)){
        foreach ($search_terms as $search_term){
            $old_or = "OR ({$wpdb->posts}.post_content LIKE '{$wpdb->placeholder_escape()}{$search_term}{$wpdb->placeholder_escape()}')";
            $new_or = $old_or . " OR ({$wpdb->postmeta}.meta_value LIKE '{$wpdb->placeholder_escape()}{$search_term}{$wpdb->placeholder_escape()}' AND {$wpdb->postmeta}.meta_key IN (" . implode(', ', $GLOBALS['added_meta_field_to_search_query']) . "))";
            $search_sql = str_replace($old_or, $new_or, $search_sql);
        }
      }

      $search_sql = str_replace( " ORDER BY ", " GROUP BY $wpdb->posts.ID ORDER BY ", $search_sql );

      return $search_sql;
  });
}

Несколько человек реализовали это разными способами:

http://websmartdesign.nz/searching-structured-post-data-with-wordpress/ https://adambalee.com/search-wordpress-by-custom-fields-without-a-plugin/

28 авг. 2017 г. 13:42:45
Комментарии

Ссылка на adambalee.com сработала у меня. Она просто выполняет общий поиск по всем метаполям записей.

Joe Joe
29 янв. 2019 г. 17:09:24

Аналогично, решение по ссылке https://adambalee.com/search-wordpress-by-custom-fields-without-a-plugin/ сработало у меня на WordPress 5.1.1...

jsmod jsmod
29 мар. 2019 г. 17:55:20

ты нашел способ искать только по нескольким пользовательским полям? У меня их много, и почти каждый поиск находит какой-то контент, даже если он только для админа.

v3nt v3nt
16 июн. 2020 г. 18:59:42
1

Это улучшенный ответ Ahmed:

function me_search_query( $query ) {
  if ( $query->is_search ) {
    $meta_query_args = array(
      array(
        'key' => 'your_key',
        'value' => $query->query_vars['s'],
        'compare' => 'LIKE',
      ),
    );
    $query->set('meta_query', $meta_query_args);
    add_filter( 'get_meta_sql', 'me_replace_and_with_or' );
  };
}

function me_replace_and_with_or( $sql ) {
    if ( 1 === strpos( $sql['where'], 'AND' ) ) {
        $sql['where'] = substr( $sql['where'], 4 );
        $sql['where'] = ' OR ' . $sql['where'];
    }

    // Убедимся, что этот фильтр сработает только один раз для мета-запроса
    remove_filter( 'get_meta_sql', 'me_replace_and_with_or' );
    return $sql;
}

add_filter( 'pre_get_posts', 'me_search_query');

Проблема в том, что WordPress генерирует мета-запрос с оператором "AND", что означает показ только тех записей, где поисковая строка присутствует в обоих местах - в заголовке И мета-данных, или в контенте И мета-данных. Поэтому нам нужно создать дополнительный фильтр для замены "AND" на "OR" (и затем удалить этот фильтр, чтобы не нарушить работу других частей системы).

29 дек. 2018 г. 18:28:28
Комментарии

Изменение AND на OR нарушает логику SQL для фильтрации типа записи (POST type), поэтому поиск будет применяться ко всем типам записей, включая вложения. Все еще пытаюсь найти работоспособное решение, которое будет работать с комбинацией поиска и фильтров для пользовательского типа записи (CPT).

Alan Fuller Alan Fuller
2 нояб. 2021 г. 17:12:47
0

Если вы готовы использовать плагин, попробуйте Relevanssi — улучшенный поиск.

Стандартная (бесплатная) версия поддерживает поиск по мета-данным записей.

9 дек. 2011 г. 04:36:01
0

Это самое простое и рабочее решение на данный момент. Ни один из вышеперечисленных вариантов у меня не сработал. Протестировано и работает с Wordpress 5.3.1.

Поместите следующий код в файл functions.php, чтобы подключиться к фильтру posts_clauses.

/**
 * Включение метаполей в поиск
 * 
 * @author Mindaugas // meevly.com
 * @link https://meevly.com/services/custom-wordpress-themes-and-plugins/
 * 
 * @param array $pieces части запроса.
 * @param WP_Query $args объект запроса.
 * @return array
 */
function mv_meta_in_search_query( $pieces, $args ) {
    global $wpdb;

    if ( ! empty( $args->query['s'] ) ) { // выполнять только для поискового запроса.
        $keywords        = explode(' ', get_query_var('s'));
        $escaped_percent = $wpdb->placeholder_escape(); // WordPress экранирует "%" начиная с версии 4.8.3, поэтому мы не можем использовать символ процента напрямую.
        $query           = "";

        foreach ($keywords as $word) {
            $query .= " (unique_postmeta_selector.meta_value LIKE '{$escaped_percent}{$word}{$escaped_percent}') OR ";
        }

        if ( ! empty( $query ) ) { // добавление необходимых условий WHERE и JOIN.
            $pieces['where'] = str_replace( "((({$wpdb->posts}.post_title LIKE '{$escaped_percent}", "( {$query} (({$wpdb->posts}.post_title LIKE '{$escaped_percent}", $pieces['where'] );
            $pieces['join'] = $pieces['join'] . " INNER JOIN {$wpdb->postmeta} AS unique_postmeta_selector ON ({$wpdb->posts}.ID = unique_postmeta_selector.post_id) ";
        }
    }

    return $pieces;
}
add_filter( 'posts_clauses', 'mv_meta_in_search_query', 20, 2 );

И ваш запрос должен выглядеть следующим образом. Обратите внимание, что параметр suppress_filters => false обязателен! Без него работать не будет.

$search_posts_array = array(
    'suppress_filters' => false,
    's'                => $keyword,
);

$search_results = get_posts( $search_posts_array );
9 янв. 2020 г. 13:18:39
0
-1

Я не уверен, но для получения всех ключей/значений произвольных полей для стандартного поиска потребуется запрос к базе данных с использованием wpdb.

Альтернативные плагины, помимо упомянутых goto10, представляют собой гораздо более простое решение. Search Everything, WP Custom Fields Search

9 дек. 2011 г. 05:13:03