Come ordinare l'area amministrativa di un custom post type WordPress per un campo personalizzato
Quando modifico uno dei miei custom post type, voglio poter elencare tutte le voci in base a un campo personalizzato invece della data di pubblicazione (che, per un custom post type probabilmente non è rilevante). Ho trovato un indizio dai commenti di un post su un blog riguardo i custom post type e l'autore ha detto che era possibile e che aveva persino fatto in modo che si potesse cliccare sui nomi delle colonne per un ordinamento personalizzato. Ha menzionato la funzione posts_orderby
che ho annotato nei miei commenti ma ora non riesco più a trovare il post del blog. Qualche suggerimento? Ho visto una soluzione che utilizzava
add_action('wp', 'check_page');
E la funzione check_page
utilizzava add_filter
per modificare la query ma sono abbastanza sicuro che funzionerebbe solo nei file del tema, non nell'area amministrativa.

Come puoi probabilmente immaginare dalla mancanza di risposte fornite, la soluzione non è esattamente banale. Ho creato un esempio piuttosto autonomo che presuppone un custom post type di "movie
" e un campo personalizzato con chiave "Genre".
Disclaimer: questo funziona con WP3.0 ma non posso garantire che funzioni con versioni precedenti.
Sostanzialmente servono due (2) hook per farlo funzionare e altri due (2) per renderlo evidente e utile.
Il primo hook è 'restrict_manage_posts
' che permette di emettere un HTML <select>
nell'area sopra l'elenco dei post dove ci sono i filtri "Azioni di massa" e "Mostra date". Il codice fornito genererà la funzionalità "Ordina per:" come si vede in questo snippet dello schermo:
(fonte: mikeschinkel.com)
Il codice utilizza SQL diretto perché non esiste una funzione API di WordPress che fornisca l'elenco di tutte le meta_key per un post type (sembra un futuro ticket trac per me...) Comunque, ecco il codice. Nota che prende il post type da $_GET
e verifica che sia sia un post type valido post_type_exists()
sia un post type movie
(questi due controlli sono eccessivi ma li ho fatti per mostrarti come fare se non vuoi hardcodare il post type). Infine uso il parametro URL sortby
perché non entra in conflitto con nient'altro in WordPress:
add_action('restrict_manage_posts','restrict_manage_movie_sort_by_genre');
function restrict_manage_movie_sort_by_genre() {
if (isset($_GET['post_type'])) {
$post_type = $_GET['post_type'];
if (post_type_exists($post_type) && $post_type=='movie') {
global $wpdb;
$sql=<<<SQL
SELECT pm.meta_key FROM {$wpdb->postmeta} pm
INNER JOIN {$wpdb->posts} p ON p.ID=pm.post_id
WHERE p.post_type='movie' AND pm.meta_key='Genre'
GROUP BY pm.meta_key
ORDER BY pm.meta_key
SQL;
$results = $wpdb->get_results($sql);
$html = array();
$html[] = "<select id=\"sortby\" name=\"sortby\">";
$html[] = "<option value=\"None\">Nessun ordinamento</option>";
$this_sort = $_GET['sortby'];
foreach($results as $meta_key) {
$default = ($this_sort==$meta_key->meta_key ? ' selected="selected"' : '');
$value = esc_attr($meta_key->meta_key);
$html[] = "<option value=\"{$meta_key->meta_key}\"$default>{$value}</option>";
}
$html[] = "</select>";
echo "Ordina per: " . implode("\n",$html);
}
}
}
Il secondo passo necessario è usare l'hook parse_query
che viene chiamato dopo che WordPress decide quale query eseguire ma prima che la esegua. Qui possiamo impostare i valori di orderby
e meta_key
nell'array query_var
della query, che sono documentati nel Codex nel parametro orderby
per query_posts()
. Verifichiamo che:
- Siamo nell'admin (
is_admin()
), - Siamo nella pagina che elenca i post nell'admin (
$pagenow=='edit.php'
), - La pagina è stata chiamata con un parametro URL
post_type
uguale amovie
, e - La pagina è stata chiamata anche con un parametro URL
sortby
e che non sia stato passato il valore 'None'
Se tutti questi test passano, allora impostiamo i query_vars
(come documentato qui) a meta_value
e il nostro valore sortby
per 'Genre':
add_filter( 'parse_query', 'sort_movie_by_meta_value' );
function sort_movie_by_meta_value($query) {
global $pagenow;
if (is_admin() && $pagenow=='edit.php' &&
isset($_GET['post_type']) && $_GET['post_type']=='movie' &&
isset($_GET['sortby']) && $_GET['sortby'] !='None') {
$query->query_vars['orderby'] = 'meta_value';
$query->query_vars['meta_key'] = $_GET['sortby'];
}
}
E questo è tutto ciò che serve; nessun hook "posts_order
" o "wp
" richiesto! Ovviamente in realtà devi fare di più; devi aggiungere alcune colonne nella tua pagina che elenca i post così puoi vedere effettivamente i valori per cui sta ordinando, altrimenti gli utenti saranno molto confusi. Quindi aggiungi un hook manage_{$post_type}_posts_columns
, in questo caso manage_movie_posts_columns
. Questo hook riceve l'array predefinito di colonne e per semplicità l'ho sostituito con due colonne standard; una checkbox (cb
) e un nome del post (title
). (Puoi ispezionare posts_columns
con un print_r()
per vedere cos'altro è disponibile di default.)
Ho deciso di aggiungere un "Ordinato per:" quando c'è un parametro URL sortby
e quando non è None
:
add_action('manage_movie_posts_columns', 'manage_movie_posts_columns');
function manage_movie_posts_columns($posts_columns) {
$posts_columns = array(
'cb' => $posts_columns['cb'],
'title' => 'Nome Film',
);
if (isset($_GET['sortby']) && $_GET['sortby'] !='None')
$posts_columns['meta_value'] = 'Ordinato per';
return $posts_columns;
}
Infine usiamo l'hook manage_pages_custom_column
per visualizzare effettivamente il valore quando c'è un post del tipo di post appropriato e con il test probabilmente ridondante per is_admin()
e $pagenow=='edit.php'
. Quando c'è un parametro URL sortby
estraiamo il valore del campo personalizzato che viene ordinato e lo mostriamo nella nostra lista. Ecco come appare (ricorda, questi sono dati di test quindi niente commenti dalla galleria sulle classificazioni dei film! :):
(fonte: mikeschinkel.com)
Ed ecco il codice:
add_action('manage_pages_custom_column', 'manage_movie_pages_custom_column',10,2);
function manage_movie_pages_custom_column($column_name,$post_id) {
global $pagenow;
$post = get_post($post_id);
if ($post->post_type=='movie' && is_admin() && $pagenow=='edit.php') {
switch ($column_name) {
case 'meta_value':
if (isset($_GET['sortby']) && $_GET['sortby'] !='None') {
echo get_post_meta($post_id,$_GET['sortby'],true);
}
break;
}
}
}
Nota che questo prende solo il primo "Genre" per un movie
, cioè il primo meta_value nel caso di valori multipli per una data chiave. Ma d'altra parte non sono sicuro di come potrebbe funzionare altrimenti!
E per chi non sa dove mettere questo codice, puoi inserirlo in un plugin o più probabilmente per i principianti nel file functions.php
del tuo tema corrente.
Spero che questo aiuti.

+1, solo per lo sforzo. Ma sarebbe ancora meglio se i cerchi fossero disegnati a mano :-)

Qualche idea su come rimuovere completamente il filtro MOSTRA TUTTE LE DATE in modo che vengano visualizzati solo i miei filtri personalizzati per un determinato tipo di post?

@RailsTweeter Usa la tecnica che ho mostrato qui dove i due hook che racchiudono la generazione dell'HTML sono 'months_dropdown_results'
e 'restrict_manage_posts'
.
P.S. I voti positivi sono sempre apprezzati. :)

@MikeSchinkel , ora che esiste una WP API, questo aggiornerà in qualche modo il tuo codice?

A partire da WordPress 3.1 (sto usando la versione beta) le colonne possono ora essere ordinabili tramite i loro titoli.
Il seguente articolo dettaglia come implementarle.

Ecco una semplice soluzione:
/* --------Eventi Ordinabili nella Dashboard - mostra data di inizio, ora, luogo--------- */
/*-------------------------------------------------------------------------------
Colonne Personalizzate
-------------------------------------------------------------------------------*/
function mie_*TIPO DI POST*_colonne($colonne)
{
$colonne = array(
'cb' => '<input type="checkbox" />',
'title' => 'Titolo',
'tuo_campo_personalizzato' => 'Nome Campo Personalizzato',
'date' => 'Data',
);
return $colonne;
}
function mie_colonne_personalizzate($colonna)
{
global $post;
if($colonna == 'tuo_campo_personalizzato')
{
if(get_post_meta($post->ID, 'tuo_campo_personalizzato', true);)
{
echo get_post_meta($post->ID, 'tuo_campo_personalizzato', true);
}
}
}
add_action("manage_posts_custom_column", "mie_colonne_personalizzate");
add_filter("manage_edit-*TIPO DI POST*_colonne", "mie_eventi_colonne");
/*-------------------------------------------------------------------------------
Colonne Ordinabili
-------------------------------------------------------------------------------*/
function mia_colonna_registra_ordinabile( $colonne )
{
$colonne['tuo_campo_personalizzato'] = 'tuo_campo_personalizzato';
return $colonne;
}
add_filter("manage_edit-*TIPO DI POST*_sortable_columns", "mia_colonna_registra_ordinabile" );
Sostituisci semplicemente TIPO DI POST e 'tuo_campo_personalizzato'
