Extendiendo el contexto de búsqueda en la pantalla de lista de entradas del administrador
He creado un tipo de entrada personalizada y le he añadido algunos campos personalizados. Ahora me gustaría que la búsqueda que los autores pueden realizar en la pantalla de lista de entradas personalizadas (en el panel de administración) también se realice en los campos meta y no solo busque en el título y contenido como es habitual.
¿Dónde puedo conectarme y qué código debo usar?
Imagen de ejemplo
Stefano

Resolví el filtrado de la consulta añadiendo el JOIN en la tabla postmeta y modificando la cláusula WHERE. Consejos sobre cómo filtrar la cláusula WHERE (que a menudo requieren búsqueda y reemplazo con expresiones regulares) están aquí en el codex:
add_filter( 'posts_join', 'segnalazioni_search_join' );
function segnalazioni_search_join ( $join ) {
global $pagenow, $wpdb;
// Quiero que el filtro se aplique solo al realizar una búsqueda en la página de edición del Custom Post Type llamado "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;
// Quiero que el filtro se aplique solo al realizar una búsqueda en la página de edición del Custom Post Type llamado "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"; // Soluciona resultados duplicados
}
return $where;
}

¡Guau! Justo lo que estaba buscando. Sin embargo, creo que puede haber encontrado un error: cuando busco en el título de la publicación, obtengo una coincidencia que luego se duplica en los resultados ¡5 veces!?! http://imgur.com/eE52gIA

Aquí hay otra captura con el SQL impreso: http://tinypic.com/view.php?pic=124tqb6&s=5 No puedo entender por qué obtengo 5 elementos!?!

Publiqué una pregunta separada sobre cómo solucionar el error de duplicados: http://wordpress.stackexchange.com/questions/111185/how-do-i-improve-this-admin-query-snippet-to-avoid-generating-duplicate-results

Estas publicaciones me fueron útiles. Ahora necesito encontrar una manera de incluir la búsqueda por autor y mostrar las publicaciones realizadas por ellos.

@Stefano, los resultados de búsqueda están funcionando. Tengo un problema con el campo predeterminado "Título de la publicación", los registros de búsqueda se repiten muchas veces en el lado del administrador. Ver:https://imgur.com/a/W4wmXhO

La respuesta de Stefano es excelente pero le falta una cláusula 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' );
Agrega el código anterior, actualízalo y funcionará sin duplicados.

Esto funcionará,
function custom_search_query( $query ) {
$custom_fields = array(
// coloca aquí todos los campos meta que quieras buscar
"rg_first_name",
"rg_1job_designation"
);
$searchterm = $query->query_vars['s'];
// debemos eliminar el parámetro "s" de la consulta, porque evitará que se encuentren los posts
$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");

Por favor, indenta correctamente tu código e incluye una explicación sobre por qué y cómo esto funcionará.

Aunque primero le di un voto positivo, me di cuenta de que esto, desafortunadamente, funcionará en cada búsqueda de la misma manera y podría romper la búsqueda en el front end.

Agregar una verificación como if ( $query->query['post_type'] != 'your_custom_post_type' ){ return; }
al principio de la función evitará que esto se ejecute en otras búsquedas. Ten en cuenta que la técnica en esta respuesta ya no busca en post_title y agregar eso nuevamente no es trivial.

Un problema adicional: El indicador Resultados de búsqueda para "<keyword>" llama a get_search_query()
que a su vez llama a get_query_var( 's' )
. Como "s" está configurado como una cadena vacía, Resultados de búsqueda para "" siempre tendrá un valor vacío entre las comillas. ¿Hay algún ajuste a esta solución que evite esto?

Otro problema: esta solución solo funcionará para valores meta ahora. Las búsquedas por título, por ejemplo, no funcionarán.

Solución 1: Agrega este código en el archivo de funciones y cambia o añade más nombres de columnas que hayas utilizado en tu tipo de publicación personalizado
function extend_admin_search( $query ) {
// usa tu tipo de publicación
$post_type = 'document';
// Usa tus campos personalizados/nombres de columnas para buscar
$custom_fields = array(
"_file_name",
);
if( ! is_admin() )
return;
if ( $query->query['post_type'] != $post_type )
return;
$search_term = $query->query_vars['s'];
// Establece como vacío, de lo contrario no encontrará nada
$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' );
Solución 2: (Recomendado) Usa este código en el archivo de funciones sin ningún cambio
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' );

Con este código puedes buscar en la lista de entradas del Panel de Administración de WordPress usando valores de meta personalizados junto con el título y otros campos por defecto.
Por favor, añade el siguiente código en el archivo functions.php:
if (!function_exists('extend_admin_search')) {
add_action('admin_init', 'extend_admin_search');
/**
* Engancha la búsqueda de posts si estamos en la página de admin para nuestro tipo
*/
function extend_admin_search() {
global $typenow;
if ($typenow === 'your_custom_post_type') {
add_filter('posts_search', 'posts_search_custom_post_type', 10, 2);
}
}
/**
* Añade condición de consulta para meta personalizados
* @param string $search la cadena de búsqueda hasta ahora
* @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;
}
}

Por favor no copies tu respuesta a cada pregunta similar. Una vez que tengas suficiente reputación podrás comentar en cualquier publicación y proporcionar un enlace a tu respuesta.

La versión del código aquí en un par de respuestas que modifica el parámetro meta_query de la búsqueda en WP_Query en pre_get_posts ya no buscaba en post_title. Agregar la capacidad de buscar ya sea en el título de la publicación O en los valores meta no se puede hacer directamente en WP_Query sin modificar SQL desafortunadamente, como se explica en esta pregunta: Usar meta query ('meta_query') con una búsqueda ('s')
He combinado algunas de las técnicas aquí para obtener una versión funcional que evita preg_replaces y demasiadas modificaciones SQL (ojalá se pudiera evitar por completo). El único inconveniente es que después de una búsqueda, el texto del subtítulo en la parte superior de la página dice "Resultados de búsqueda para ''". Simplemente lo he ocultado con CSS para el tipo de publicación personalizada de mi plugin.
/**
* Extender la búsqueda de tipos de posts personalizados para que también busque en campos meta
* @param WP_Query $query
*/
function extender_busqueda_admin_cpt( $query ) {
// Asegurarse de que estamos en el área de administración y que es nuestro tipo de post personalizado
if ( !is_admin() || $query->query['post_type'] != 'tu_tipo_de_post_personalizado' ){
return;
}
// Coloca aquí todos los campos meta que quieras buscar
$campos_personalizados = array(
"tu_campo_meta_personalizado",
"tu_campo_meta_personalizado2",
"tu_campo_meta_personalizado3"
);
// El término de búsqueda enviado a través del formulario de búsqueda
$termino_busqueda = $query->query_vars['s'];
// Establecer a vacío, de lo contrario no se devolverán resultados.
// El único inconveniente es que el texto de búsqueda mostrado está vacío en la parte superior de la página.
$query->query_vars['s'] = '';
if ($termino_busqueda != ""){
// Agregar parámetro meta_query adicional al objeto WP_Query.
// Referencia: https://codex.wordpress.org/Class_Reference/WP_Query#Custom_Field_Parameters
$meta_query = array();
foreach($campos_personalizados as $cf) {
array_push($meta_query, array(
'key' => $cf,
'value' => $termino_busqueda,
'compare' => 'LIKE'
));
}
// Usar una comparación 'OR' para cada campo meta personalizado adicional.
if (count($meta_query) > 1){
$meta_query['relation'] = 'OR';
}
// Establecer el parámetro meta_query
$query->set('meta_query', $meta_query);
// Para permitir que la búsqueda también devuelva resultados "OR" en post_title
$query->set('_meta_or_title', $termino_busqueda);
}
}
add_action('pre_get_posts', 'extender_busqueda_admin_cpt');
