Estendere il contesto di ricerca nella schermata dell'elenco post in amministrazione
Ho creato un tipo di post personalizzato e ho aggiunto alcuni campi personalizzati. Ora vorrei che la ricerca che gli autori possono effettuare nella schermata dell'elenco dei post personalizzati (nel backend di amministrazione) venga eseguita anche sui campi meta e non solo sul titolo e sul contenuto come di consueto.
Dove posso agganciarmi e quale codice devo utilizzare?
Immagine di esempio
Stefano

Ho risolto il filtraggio della query aggiungendo il join sulla tabella postmeta e modificando la clausola WHERE. Consigli sul filtraggio della clausola WHERE (spesso richiedono ricerca e sostituzione con espressioni regolari) sono qui sul codex:
add_filter( 'posts_join', 'segnalazioni_search_join' );
function segnalazioni_search_join ( $join ) {
global $pagenow, $wpdb;
// Voglio che il filtro venga applicato solo durante una ricerca nella pagina di amministrazione del Custom Post Type chiamato "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;
// Voglio che il filtro venga applicato solo durante una ricerca nella pagina di amministrazione del Custom Post Type chiamato "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"; // Risolve i risultati duplicati
}
return $where;
}

Wow! Proprio quello che stavo cercando. Tuttavia, penso di aver trovato un bug: quando cerco nel titolo del post, ottengo un risultato che viene poi duplicato 5 volte nei risultati!?! http://imgur.com/eE52gIA

Ecco un'altra schermata con la SQL stampata: http://tinypic.com/view.php?pic=124tqb6&s=5 Non riesco a capire perché ottengo 5 elementi!?!

Ho pubblicato una domanda separata su come risolvere il bug dei duplicati: http://wordpress.stackexchange.com/questions/111185/how-do-i-improve-this-admin-query-snippet-to-avoid-generating-duplicate-results

Questo e il post qui sotto mi sono stati utili. Ora devo trovare un modo per includere la ricerca dell'autore del post e mostrare i post scritti da loro.

@Stefano, i risultati della ricerca funzionano. Ho un problema, il campo predefinito "Titolo del post", il record di ricerca si ripete molte volte nel lato admin. Vedi:https://imgur.com/a/W4wmXhO

La risposta di Stefano è ottima ma manca una clausola 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' );
Aggiungi il codice qui sopra, aggiorna e funzionerà senza duplicati.

Questo funzionerà,
function custom_search_query( $query ) {
$custom_fields = array(
// inserisci qui tutti i campi meta che vuoi includere nella ricerca
"rg_first_name",
"rg_1job_designation"
);
$searchterm = $query->query_vars['s'];
// dobbiamo rimuovere il parametro "s" dalla query, perché impedirebbe di trovare i post
$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");

Per favore, indenta correttamente il tuo codice e includi una spiegazione sul perché e come questo funzionerà.

Anche se inizialmente ho votato positivamente, mi sono reso conto che purtroppo questo funzionerà per ogni ricerca nello stesso modo e potrebbe interrompere la ricerca front-end.

Aggiungere un controllo if ( $query->query['post_type'] != 'your_custom_post_type' ){ return; }
all'inizio della funzione impedirà l'esecuzione su altre ricerche. Nota che la tecnica in questa risposta non cerca più il post_title e riaggiungerlo non è banale.

Un ulteriore problema - L'indicatore Risultati di ricerca per “<keyword>” chiama get_search_query()
che a sua volta chiama get_query_var( 's' )
. Poiché "s" è impostato a stringa vuota, Risultati di ricerca per “” avrà sempre un valore vuoto tra le virgolette. Esiste una modifica a questa soluzione che aggira questo problema?

Un altro problema, questa soluzione funzionerà solo per i valori meta ora. Le ricerche per titolo, ad esempio, non funzioneranno.

Soluzione 1: Aggiungi questo codice nel file functions.php, e modifica o aggiungi altri nomi di colonna che hai utilizzato nel tuo custom post type
function extend_admin_search( $query ) {
// utilizza il tuo post type
$post_type = 'document';
// Utilizza i tuoi Custom fields/nomi di colonna per la ricerca
$custom_fields = array(
"_file_name",
);
if( ! is_admin() )
return;
if ( $query->query['post_type'] != $post_type )
return;
$search_term = $query->query_vars['s'];
// Imposta a vuoto, altrimenti non troverà nulla
$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' );
Soluzione 2: (Consigliata) Utilizza questo codice nel file functions.php senza alcuna modifica
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 questo codice puoi cercare nella lista degli articoli nel Pannello di Amministrazione di WordPress utilizzando i valori dei custom post meta insieme al titolo e altri campi predefiniti.
Aggiungi il seguente codice nel file functions.php:
if (!function_exists('extend_admin_search')) {
add_action('admin_init', 'extend_admin_search');
/**
* Aggiunge l'hook per la ricerca degli articoli se siamo nella pagina di amministrazione del nostro tipo di contenuto
*/
function extend_admin_search() {
global $typenow;
if ($typenow === 'your_custom_post_type') {
add_filter('posts_search', 'posts_search_custom_post_type', 10, 2);
}
}
/**
* Aggiunge la condizione di query per i meta personalizzati
* @param string $search la stringa di ricerca finora
* @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;
}
}

Per favore non copiare la tua risposta ad ogni domanda simile. Una volta che avrai una reputazione sufficiente potrai commentare qualsiasi post e fornire un link alla tua risposta.

La versione del codice presente in un paio di risposte che modifica il parametro meta_query della WP_Query di ricerca in pre_get_posts non stava più effettuando la ricerca nel post_title. Aggiungere la capacità di cercare sia nel titolo del post, OPPURE nei valori dei metadati non può essere fatto direttamente in WP_Query senza modificare l'SQL purtroppo, come questa domanda approfondisce: Utilizzo di meta query ('meta_query') con una query di ricerca ('s')
Ho combinato alcune delle tecniche qui presenti per ottenere una versione funzionante che evita preg_replaces e troppe modifiche SQL (avrei voluto evitarle completamente). L'unico svantaggio è che dopo una ricerca, il testo del sottotitolo in cima alla pagina dice "Risultati della ricerca per ''". L'ho semplicemente nascosto con CSS per il custom post type del mio plugin.
/**
* Estende la ricerca del custom post type nell'admin per includere anche i campi meta
* @param WP_Query $query
*/
function extend_cpt_admin_search( $query ) {
// Assicuriamoci di essere nell'area admin e che sia il nostro custom post type
if ( !is_admin() || $query->query['post_type'] != 'your_custom_post_type' ){
return;
}
// Inserisci qui tutti i campi meta che vuoi includere nella ricerca
$custom_fields = array(
"your_custom_meta_field",
"your_custom_meta_field2",
"your_custom_meta_field3"
);
// La stringa inviata tramite il form di ricerca
$searchterm = $query->query_vars['s'];
// Imposta a vuoto, altrimenti non verranno restituiti risultati.
// L'unico svantaggio è che il testo di ricerca visualizzato è vuoto in cima alla pagina.
$query->query_vars['s'] = '';
if ($searchterm != ""){
// Aggiunge il parametro meta_query all'oggetto WP_Query.
// Riferimento: 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'
));
}
// Usa un confronto 'OR' per ogni campo meta aggiuntivo.
if (count($meta_query) > 1){
$meta_query['relation'] = 'OR';
}
// Imposta il parametro meta_query
$query->set('meta_query', $meta_query);
// Per permettere alla ricerca di restituire anche risultati "OR" sul post_title
$query->set('_meta_or_title', $searchterm);
}
}
add_action('pre_get_posts', 'extend_cpt_admin_search');
