¿Cómo hacer que la búsqueda incluya datos de wp_postmeta?
Tengo un sitio que usa Advanced Custom Fields para crear y almacenar varios fragmentos de información relevante. Estos necesitan ser incluidos en la búsqueda general principal, que por defecto solo busca en el título y el contenido principal.
He encontrado bastante información sobre cómo obtener resultados de búsqueda basados en fragmentos específicos de postmeta, pero tengo un problema con eso. Hay una cantidad potencialmente ilimitada de campos posibles en postmeta para buscar.
La solución podría ser buscar cualquier cosa en postmeta o cualquier cosa con un meta_key que coincida con esta expresión regular: content_section_[0-9]{1,4}_content_.{2,8}
Ejemplos de meta_keys que deberían coincidir son:
content_section_0_content_title
content_section_0_content_title
content_section_4_content_subtitle
content_section_8_content_text
Cualquier forma en que pueda modificar los campos buscados para incluir el postmeta sería muy apreciada.

Añade esto a tu plugin o al archivo functions.php de tu tema. El siguiente ejemplo incluirá 'your_key' en las búsquedas. Puedes incluir todas tus claves repitiendo el array.
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');

Esto solo coincidirá con publicaciones que coincidan con el término de búsqueda en el título/contenido y en el campo meta, lo cual no es cómo funciona típicamente una búsqueda de texto completo.

Esta función debería funcionar, incluso después de la actualización de seguridad de WP 4.8.3.
Uso:
// Haz esto en functions.php
add_meta_field_to_search_query('right_data');
add_meta_field_to_search_query('extra_search_terms');
Implementación:
/* AÑADIR CAMPO META A LA CONSULTA DE BÚSQUEDA */
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;
});
}
Varias personas han hecho esto de diferentes maneras:
http://websmartdesign.nz/searching-structured-post-data-with-wordpress/ https://adambalee.com/search-wordpress-by-custom-fields-without-a-plugin/

El enlace para adambalee.com
funcionó para mí. Simplemente realiza una búsqueda general en todos los meta datos de las publicaciones.

Igualmente, la solución vinculada en https://adambalee.com/search-wordpress-by-custom-fields-without-a-plugin/ funcionó para mí en WordPress 5.1.1...

Esta es una respuesta mejorada de Ahmed:
function me_search_query( $query ) {
if ( $query->is_search ) {
$meta_query_args = array(
array(
'key' => 'your_key', // Cambia 'your_key' por tu clave de metadato real
'value' => $query->query_vars['s'], // Valor de búsqueda
'compare' => 'LIKE', // Comparación tipo 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'];
}
// Asegurarse que este filtro solo se ejecute una vez para la consulta de metadatos
remove_filter( 'get_meta_sql', 'me_replace_and_with_or' );
return $sql;
}
add_filter( 'pre_get_posts', 'me_search_query');
El problema es que WordPress genera consultas de metadatos con el operador "AND", lo que mostraría solo las publicaciones que tienen la cadena de búsqueda en ambos lugares - título Y metadatos, o contenido Y metadatos. Por lo tanto, necesitamos crear un filtro adicional para cambiar "AND" a "OR" (y luego eliminar ese filtro para no afectar nada más).

Cambiar el AND por OR rompe la lógica SQL para filtrar el tipo de POST, por lo que la búsqueda se aplicará a todos los tipos de entradas, incluyendo adjuntos. Todavía estoy intentando encontrar una solución viable que funcione con búsqueda y filtros combinados en un CPT

Si estás dispuesto a usar un plugin, Relevanssi - Una búsqueda mejorada podría valer la pena probarlo.
La versión estándar (gratuita) soporta la búsqueda en metadatos de entradas.

Esta es la solución más simple y actualmente funcional. Ninguna de las anteriores me funcionó. Está probado y funciona con WordPress 5.3.1.
Coloca el siguiente código en tu archivo functions.php para engancharlo al filtro posts_clauses
.
/**
* Incluir campos meta en la búsqueda
*
* @author Mindaugas // meevly.com
* @link https://meevly.com/services/custom-wordpress-themes-and-plugins/
*
* @param array $pieces partes de la consulta.
* @param WP_Query $args objeto de la consulta.
* @return array
*/
function mv_meta_in_search_query( $pieces, $args ) {
global $wpdb;
if ( ! empty( $args->query['s'] ) ) { // solo ejecutar en consultas de búsqueda.
$keywords = explode(' ', get_query_var('s'));
$escaped_percent = $wpdb->placeholder_escape(); // WordPress escapa "%" desde la versión 4.8.3, por lo que no podemos usar el carácter de porcentaje directamente.
$query = "";
foreach ($keywords as $word) {
$query .= " (unique_postmeta_selector.meta_value LIKE '{$escaped_percent}{$word}{$escaped_percent}') OR ";
}
if ( ! empty( $query ) ) { // añadir las opciones WHERE y JOIN necesarias.
$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 );
Y tu consulta debería verse así. Por favor, ten en cuenta que suppress_filters => false
es obligatorio! No funcionará sin ello.
$search_posts_array = array(
'suppress_filters' => false,
's' => $keyword,
);
$search_results = get_posts( $search_posts_array );

No estoy seguro, pero para obtener todas las claves/valores de campos personalizados para la búsqueda predeterminada se requeriría una llamada a la base de datos usando wpdb.
La alternativa a los plugins mencionados por goto10 es una solución mucho más sencilla.
Search Everything, WP Custom Fields Search
