WP Query Args - Título o Valor Meta
¿Cómo puedo hacer una consulta por meta_value o título?
Si establezco meta_values,
$args['meta_query'] = array(
'relation' => 'OR',
array(
'key' => 'model_name',
'value' => $thesearch,
'compare' => 'like'
)
);
automáticamente se agregan como AND.
Esta búsqueda sería:
WHERE title = 'Search' AND (model_name = 'Search' OR ...)
Necesito
WHERE title = 'Search' OR (model_name = 'Search' OR ...)

Ten en cuenta que la parte relation
en el argumento meta_query
solo se utiliza para definir la relación entre las consultas sub meta.
Puedes probar esta configuración:
$args = [
'_meta_or_title' => $thesearch, // ¡Nuestro nuevo argumento personalizado!
'meta_query' => [
[
'key' => 'model_name',
'value' => $thesearch,
'compare' => 'like'
]
],
];
donde hemos introducido un argumento personalizado _meta_or_title
para activar la consulta meta O título.
Esto es compatible con el siguiente plugin:
<?php
/**
* Plugin Name: Consulta Meta OR Título en WP_Query
* Description: Activado a través del argumento '_meta_or_title' de WP_Query
* Plugin URI: http://wordpress.stackexchange.com/a/178492/26350
* Plugin Author: Birgir Erlendsson (birgire)
* Version: 0.0.1
*/
add_action( 'pre_get_posts', function( $q )
{
if( $title = $q->get( '_meta_or_title' ) )
{
add_filter( 'get_meta_sql', function( $sql ) use ( $title )
{
global $wpdb;
// Solo se ejecuta una vez:
static $nr = 0;
if( 0 != $nr++ ) return $sql;
// Modificar parte WHERE:
$sql['where'] = sprintf(
" AND ( %s OR %s ) ",
$wpdb->prepare( "{$wpdb->posts}.post_title = '%s'", $title ),
mb_substr( $sql['where'], 5, mb_strlen( $sql['where'] ) )
);
return $sql;
});
}
});

La respuesta me llevó a mitad de camino. http://wordpress.stackexchange.com/questions/178574/acf-relationship-field-search-filtering ¿Alguna idea sobre esta siguiente?

He usado esta respuesta para crear una consulta para un valor meta específico en la página edit.php de un tipo de contenido personalizado. No consulto el título en absoluto, porque mi tipo de contenido personalizado no tiene título. Por lo tanto, reemplacé " AND ( %s OR %s ) "
por " OR ( %s ) "
en la consulta SQL y eliminé por completo la línea $wpdb->prepare( "{$wpdb->posts}.post_title = '%s'", $title ),
. ¿Es este un enfoque válido?

@BdN3504 Me alegra saber que te resultó algo útil. Si te entiendo correctamente, tus modificaciones deberían funcionar.

gracias por la respuesta. mis modificaciones sí funcionan, solo que no estoy seguro si es el enfoque correcto. en realidad quiero eliminar los parámetros de título y contenido en la consulta y solo consultar los metadatos. aunque el enfoque actual funciona, no es el más práctico

@BdN3504 ok genial, no conozco una forma nativa (sin usar filtros) para cambiar AND -> OR para toda la consulta de metadatos, pero por supuesto puedes modificar las relaciones de la consulta de metadatos de muchas maneras dentro de meta_query
de WP_Query
.

Gran truco. Si quieres una búsqueda de subcadena para el título, reemplaza post_title = '%s'
con post_title like '%%%s%%'
.

¿Cómo haría una consulta con el valor del título y la taxonomía en lugar del valor meta?

@jeff Una vez escribí un plugin para combinar consultas: https://github.com/birgire/wp-combine-queries. También aquí experimenté con búsqueda (título, extracto, contenido) o consulta de taxonomía. Aquí encontré otra respuesta similar con la que experimenté. También podemos escribir dos WP_Query
separados, luego recolectar y combinar los IDs de posts resultantes en un tercer WP_Query
(si es necesario y si el ordenamiento en PHP no es suficiente) mediante el parámetro de entrada post__in
.

@birgire Opté por la ruta de las dos consultas separadas y funcionó, gracias.

@biergie ¡Gracias por esta increíble solución! Funciona genial, pero mi búsqueda no devuelve resultados cuando uso _meta_or_title + meta query + tax query. Cuando uso tu filtro personalizado y añado un tax_query, el elemento $sql['where']
está vacío. ¿Tienes alguna idea de cómo solucionarlo?

@biergie Gracias. No lo he probado en un tiempo, pero deberías asegurarte de que no haya otros plugins/código afectándolo y, por ejemplo, ejecutarlo con el modo de depuración activado.

@birgire - solo me preguntaba si tú o alguien podría indicar dónde usas el $args. gracias.

No encontré una solución para buscar múltiples palabras clave que puedan estar mezcladas en el título de la publicación, la descripción Y/O en una o varias metas, así que hice mi propia adición a la función de búsqueda.
Todo lo que necesitas es agregar el siguiente código en function.php, y cada vez que uses el argumento 's' en WP_Query() y quieras buscar también en una o varias metas, simplemente añades un argumento 's_meta_keys' que sea un array con las claves de meta(s) en las que deseas buscar:
/************************************************************************\
|** **|
|** Permite que la función de búsqueda de WP_Query() busque **|
|** múltiples palabras clave en metas además de post_title y **|
|** post_content **|
|** **|
|** Por rAthus @ Arkanite **|
|** Creado: 2020-08-18 **|
|** Actualizado: 2020-08-19 **|
|** **|
|** Solo usa el argumento habitual 's' y añade un argumento **|
|** 's_meta_keys' que contenga un array de las claves de meta(s) **|
|** en las que deseas buscar :) **|
|** **|
|** Ejemplo : **|
|** **|
|** $args = array( **|
|** 'numberposts' => -1, **|
|** 'post_type' => 'post', **|
|** 's' => $MI_CADENA_DE_BUSQUEDA, **|
|** 's_meta_keys' => array('META_KEY_1','META_KEY_2'); **|
|** 'orderby' => 'date', **|
|** 'order' => 'DESC', **|
|** ); **|
|** $posts = new WP_Query($args); **|
|** **|
\************************************************************************/
add_action('pre_get_posts', 'mi_busqueda_personalizada'); // añade la función especial de búsqueda en cada consulta get_posts (esto incluye WP_Query())
function mi_busqueda_personalizada($query) {
if ($query->is_search() and $query->query_vars and $query->query_vars['s'] and $query->query_vars['s_meta_keys']) { // si estamos buscando usando el argumento 's' y añadimos un argumento 's_meta_keys'
global $wpdb;
$search = $query->query_vars['s']; // obtiene la cadena de búsqueda
$ids = array(); // inicia el array de IDs de publicaciones coincidentes por palabra clave buscada
foreach (explode(' ',$search) as $term) { // divide las palabras clave y busca resultados coincidentes para cada una
$term = trim($term); // elimina espacios innecesarios
if (!empty($term)) { // verifica que la palabra clave no esté vacía
$query_posts = $wpdb->prepare("SELECT * FROM {$wpdb->posts} WHERE post_status='publish' AND ((post_title LIKE '%%%s%%') OR (post_content LIKE '%%%s%%'))", $term, $term); // busca en título y contenido como lo hace la función normal
$ids_posts = [];
$results = $wpdb->get_results($query_posts);
if ($wpdb->last_error)
die($wpdb->last_error);
foreach ($results as $result)
$ids_posts[] = $result->ID; // recoge los IDs de publicaciones coincidentes
$query_meta = [];
foreach($query->query_vars['s_meta_keys'] as $meta_key) // ahora construye una consulta para buscar en cada clave de meta deseada
$query_meta[] = $wpdb->prepare("meta_key='%s' AND meta_value LIKE '%%%s%%'", $meta_key, $term);
$query_metas = $wpdb->prepare("SELECT * FROM {$wpdb->postmeta} WHERE ((".implode(') OR (',$query_meta)."))");
$ids_metas = [];
$results = $wpdb->get_results($query_metas);
if ($wpdb->last_error)
die($wpdb->last_error);
foreach ($results as $result)
$ids_metas[] = $result->post_id; // recoge los IDs de publicaciones coincidentes
$merged = array_merge($ids_posts,$ids_metas); // fusiona los IDs de título, contenido y metas resultantes de ambas consultas
$unique = array_unique($merged); // elimina duplicados
if (!$unique)
$unique = array(0); // si no hay resultados, añade un ID "0" de lo contrario se devolverán todas las publicaciones
$ids[] = $unique; // añade el array de IDs coincidentes al array principal
}
}
if (count($ids)>1)
$intersected = call_user_func_array('array_intersect',$ids); // si hay varias palabras clave, mantén solo los IDs que se encuentren en todos los arrays coincidentes
else
$intersected = $ids[0]; // de lo contrario, mantén el array único de IDs coincidentes
$unique = array_unique($intersected); // elimina duplicados
if (!$unique)
$unique = array(0); // si no hay resultados, añade un ID "0" de lo contrario se devolverán todas las publicaciones
unset($query->query_vars['s']); // elimina la consulta de búsqueda normal
$query->set('post__in',$unique); // añade un filtro por ID de publicación en su lugar
}
}
Ejemplo de uso:
$busqueda = "palabras clave a buscar";
$args = array(
'numberposts' => -1,
'post_type' => 'post',
's' => $busqueda,
's_meta_keys' => array('short_desc','tags');
'orderby' => 'date',
'order' => 'DESC',
);
$posts = new WP_Query($args);
Este ejemplo buscará las palabras clave "palabras clave a buscar" en los títulos de las publicaciones, descripciones y en las claves de meta 'short_desc' y 'tags'.
Las palabras clave pueden encontrarse en uno o varios de los campos, en cualquier orden, y devolverá cualquier publicación que tenga todas las palabras clave en cualquiera de los campos designados.
Obviamente, puedes forzar la búsqueda en una lista de claves de meta que incluyas en la función y deshacerte de los argumentos adicionales si quieres que TODAS las consultas de búsqueda incluyan estas claves de meta :)
¡Espero que esto ayude a cualquiera que se enfrente al mismo problema que yo!

Soy bastante nuevo en WP, no he probado demasiado este enfoque que se me ocurrió. Quizás puedas ayudarme a verificar si estoy en lo correcto. La solución que he encontrado hasta ahora es implementar la misma lógica de meta_query, solo haciendo algunos reemplazos.
Primero, el uso:
$args = array(
'lang' => 'pt', //esta función no entra en conflicto (ejemplo: polylang)
'post_type' => 'produtos',
'post_status' => 'publish',
'posts_per_page' => 10,
'paged' => 1,
'fields' => 'ids',
);
$args['meta_query] = [
['relation'] => 'OR'; //cualquier relación que desees
[
'key' => 'acf_field', //cualquier campo personalizado (uso regular)
'value' => $search, //cualquier valor (uso regular)
'compare' => 'LIKE', //cualquier comparación (uso regular)
],
[
'key' => 'post_title', //establece el contenido de post de WordPress que desees ('post_content', 'post_title' y 'post_excerpt')
'value' => $search, //cualquier valor
'compare' => 'LIKE', //probado con 'LIKE' y '=', funciona genial y no veo otras necesidades.
],
[
'key' => 'post_exerpt', // puedes agregar tantas veces como necesites
'value' => $search_2,
'compare' => 'LIKE',
],
];
$the_query = new WP_Query( $args ); //solo consulta
wp_reset_postdata(); //limpia tu consulta
Para que funcione, agrega esta función al functions.php de tu tema
function post_content_to_meta_queries($where, $wp_query){
global $wpdb;
//si no hay metaquery, ¡adiós!
$meta_queries = $wp_query->get( 'meta_query' );
if( !$meta_queries || $meta_queries == '' ) return $where;
//si solo una relación
$where = str_replace($wpdb->postmeta . ".meta_key = 'post_title' AND " . $wpdb->postmeta . ".meta_value", $wpdb->posts . ".post_title", $where);
$where = str_replace($wpdb->postmeta . ".meta_key = 'post_content' AND " . $wpdb->postmeta . ".meta_value", $wpdb->posts . ".post_content", $where);
$where = str_replace($wpdb->postmeta . ".meta_key = 'post_excerpt' AND " . $wpdb->postmeta . ".meta_value", $wpdb->posts . ".post_excerpt", $where);
////para relaciones anidadas
//cuenta el número de meta queries para posibles reemplazos
$number_of_relations = count($meta_queries);
//reemplaza 'WHERE' usando la lógica de nombres multidimensionales de postmeta usada por el núcleo de WordPress
$i = 1;
while($i<=$number_of_relations && $number_of_relations > 0){
$where = str_replace("mt".$i.".meta_key = 'post_title' AND mt".$i.".meta_value", $wpdb->posts . ".post_title", $where);
$where = str_replace("mt".$i.".meta_key = 'post_content' AND mt".$i.".meta_value", $wpdb->posts . ".post_content", $where);
$where = str_replace("mt".$i.".meta_key = 'post_excerpt' AND mt".$i.".meta_value", $wpdb->posts . ".post_excerpt", $where);
$i++;
}
return $where;
}
add_filter('posts_where','post_content_to_meta_queries',10,2);
¡Estoy bastante seguro de que se puede mejorar! ¡Espero que ayude!
