Filtrare per campo personalizzato in un custom post type nella pagina admin
Ho utilizzato Advanced Custom Fields per creare campi personalizzati per il nome della competizione, risposte ecc. Ho creato un custom post type per le competizioni come mostrato nell'immagine e ho usato il file functions.php di WordPress per creare le colonne dai valori dei miei campi personalizzati.
Sto cercando di ottenere una casella dropdown "Filtra per" con i diversi nomi/etichette delle competizioni come mostrato sotto, ma riesco a trovare solo soluzioni che utilizzano le tassonomie, che preferisco non utilizzare se possibile poiché ho usato solo campi personalizzati per tutto il resto.
È possibile creare un dropdown "Filtra per" personalizzato utilizzando solo campi personalizzati?
E per visualizzare il risultato del filtro prova questo codice
add_filter( 'parse_query', 'prefix_parse_filter' );
function prefix_parse_filter($query) {
global $pagenow;
$current_page = isset( $_GET['post_type'] ) ? $_GET['post_type'] : '';
if ( is_admin() &&
'competition' == $current_page &&
'edit.php' == $pagenow &&
isset( $_GET['competition-name'] ) &&
$_GET['competition-name'] != '' ) {
$competition_name = $_GET['competition-name'];
$query->query_vars['meta_key'] = 'competition_name';
$query->query_vars['meta_value'] = $competition_name;
$query->query_vars['meta_compare'] = '=';
}
}
Modifica la meta key e il meta value come richiesto. Ho utilizzato "competition_name" come meta_key e "competition-name" come nome del menu a tendina select.

L'azione restrict_manage_posts attiva la funzione add_extra_tablenav()
, che è il modo in cui puoi aggiungere menu a discesa aggiuntivi alla tua List Table desiderata.
Nell'esempio seguente, prima ci assicuriamo che il Post Type sia corretto, e poi recuperiamo tutti i valori del database memorizzati con la chiave competition_name
nella tabella postmeta
(devi cambiare il nome della chiave se necessario). La query è abbastanza semplice e verifica solo se la Competizione è pubblicata, prende solo valori unici (non vuoi duplicati nel menu a discesa) e poi li ordina alfabeticamente.
Successivamente controlliamo se ci sono risultati (non ha senso mostrare il menu a discesa se non c'è nulla), e poi costruiamo le opzioni (includendo un valore predefinito per mostrare tutto). Infine viene mostrato il menu a discesa.
Come indicato nel mio commento, questa non è la fine della storia però; avrai bisogno di qualche logica per dire alla List Table di mostrare solo i risultati desiderati quando il filtro è attivo, ma ti lascio dare un'occhiata a questo e poi aprire un'altra domanda se hai bisogno di ulteriore assistenza. Suggerimento - controlla il file /wp-admin/includes/class-wp-posts-list-table.php
, e il suo genitore .../wp-class-list-table.php
/**
* Aggiunge menu a discesa aggiuntivi alle List Tables
*
* @param required string $post_type Il Post Type che viene visualizzato
*/
add_action('restrict_manage_posts', 'add_extra_tablenav');
function add_extra_tablenav($post_type){
global $wpdb;
/** Assicurati che sia il Post Type corretto */
if($post_type !== 'competition')
return;
/** Recupera i risultati dal database */
$query = $wpdb->prepare('
SELECT DISTINCT pm.meta_value FROM %1$s pm
LEFT JOIN %2$s p ON p.ID = pm.post_id
WHERE pm.meta_key = "%3$s"
AND p.post_status = "%4$s"
AND p.post_type = "%5$s"
ORDER BY "%6$s"',
$wpdb->postmeta,
$wpdb->posts,
'competition_name', // La tua meta key - cambia se necessario
'publish', // Stato del post - cambia se necessario
$post_type,
'competition_name'
);
$results = $wpdb->get_col($query);
/** Assicurati che ci siano opzioni da mostrare */
if(empty($results))
return;
// ottieni l'opzione selezionata se ce n'è una
if (isset( $_GET['competition-name'] ) && $_GET['competition-name'] != '') {
$selectedName = $_GET['competition-name'];
} else {
$selectedName = -1;
}
/** Recupera tutte le opzioni che dovrebbero essere mostrate */
$options[] = sprintf('<option value="-1">%1$s</option>', __('Tutte le Competizioni', 'your-text-domain'));
foreach($results as $result) :
if ($result == $selectedName) {
$options[] = sprintf('<option value="%1$s" selected>%2$s</option>', esc_attr($result), $result);
} else {
$options[] = sprintf('<option value="%1$s">%2$s</option>', esc_attr($result), $result);
}
endforeach;
/** Mostra il menu a discesa */
echo '<select class="" id="competition-name" name="competition-name">';
echo join("\n", $options);
echo '</select>';
}

Quando utilizzo questo codice, ottengo l'errore Notice: wpdb::prepare was called incorrectly. The query does not contain the correct number of placeholders (6) for the number of arguments passed (5). Please see Debugging in WordPress for more information. (This message was added in version 4.8.3.) in /[...]/wp-includes/functions.php on line 4773

Se questo non funziona per qualcuno, la mia soluzione è stata quella di aggiungere la colonna che stavo cercando di filtrare alla lista delle colonne ordinabili per il mio custom post type.
// Rendi ordinabili le colonne personalizzate del Custom Post Type
function cpt_custom_columns_sortable( $columns ) {
// Aggiungi le nostre colonne all'array $columns
$columns['item_number'] = 'item_number';
$columns['coat_school'] = 'coat_school';
return $columns;
} add_filter( 'manage_edit-your-custom-post-type-slug_sortable_columns', 'cpt_custom_columns_sortable' );

Sostituisci la query qui sotto per correggere l'errore wpdb:prepare:
$query = $wpdb->prepare('
SELECT DISTINCT pm.meta_value FROM %1$s pm
LEFT JOIN %2$s p ON p.ID = pm.post_id
WHERE pm.meta_key = "%3$s"
AND p.post_status = "%4$s"
AND p.post_type = "%5$s"
ORDER BY "%3$s"',
$wpdb->postmeta,
$wpdb->posts,
'competition_name', // La tua meta key - modificare se necessario
'publish', // Stato del post - modificare se necessario
$post_type,
'competition_name' //necessario una seconda volta per definire "%3$s" in ORDER BY
);

Ho affrontato lo stesso problema quando cercavo di filtrare un custom-post-type con un custom-field
ma ho risolto il problema seguendo questi passaggi.
Ho convertito il nome del custom-field da writer
a _writer
e poi ho aggiornato il seguente codice all'interno della callback function
dell'hook parse_query
in modo da poter aggiungere una meta_query per il custom-field come segue
$query->set( 'meta_query', array(
array(
'key' => '_writer',
'compare' => '=',
'value' => $_GET['_writer'],
'type' => 'numeric',
)
) );
Questa soluzione sopra ha funzionato per me.
Documentazione https://developer.wordpress.org/reference/hooks/pre_get_posts/
Link utili https://developer.wordpress.org/reference/hooks/pre_get_posts/#comment-2571
https://stackoverflow.com/questions/47869905/how-can-i-filter-records-in-custom-post-type-list-in-admin-based-on-user-id-that
