Creazione di una tabella in stile amministratore?
Qual è il modo consigliato per creare una pagina con una tabella, nello stile delle tabelle che mostrano post o utenti nell'area di amministrazione?
Sto espandendo il plugin Cache Images, e contiene una tabella con domini e un numero di immagini da quel dominio. Quindi non esiste una tabella equivalente su cui posso basarmi (nella prima versione di questa domanda, chiedevo di una tabella con post, ma lì avrei potuto (forse) espandere la tabella dei post esistente).
Dovrei semplicemente basarmi sulla pagina di panoramica dei post, e iniziare con un <table class="widefat">
, o ci sono funzioni migliori che gestiscono questo ora? Conoscete un esempio pulito e vuoto di una tabella con paginazione su cui potrei basare il mio lavoro?

Questo è ciò che generalmente utilizzo:
<table class="widefat fixed" cellspacing="0">
<thead>
<tr>
<th id="cb" class="manage-column column-cb check-column" scope="col"></th> // questa colonna contiene checkbox
<th id="columnname" class="manage-column column-columnname" scope="col"></th>
<th id="columnname" class="manage-column column-columnname num" scope="col"></th> // "num" aggiunto perché la colonna contiene numeri
</tr>
</thead>
<tfoot>
<tr>
<th class="manage-column column-cb check-column" scope="col"></th>
<th class="manage-column column-columnname" scope="col"></th>
<th class="manage-column column-columnname num" scope="col"></th>
</tr>
</tfoot>
<tbody>
<tr class="alternate">
<th class="check-column" scope="row"></th>
<td class="column-columnname"></td>
<td class="column-columnname"></td>
</tr>
<tr>
<th class="check-column" scope="row"></th>
<td class="column-columnname"></td>
<td class="column-columnname"></td>
</tr>
<tr class="alternate" valign="top"> // questa riga contiene azioni
<th class="check-column" scope="row"></th>
<td class="column-columnname">
<div class="row-actions">
<span><a href="#">Azione</a> |</span>
<span><a href="#">Azione</a></span>
</div>
</td>
<td class="column-columnname"></td>
</tr>
<tr valign="top"> // questa riga contiene azioni
<th class="check-column" scope="row"></th>
<td class="column-columnname">
<div class="row-actions">
<span><a href="#">Azione</a> |</span>
<span><a href="#">Azione</a></span>
</div>
</td>
<td class="column-columnname"></td>
</tr>
</tbody>
</table>
Spero che sia d'aiuto.

è possibile avere anche una paginazione automatica inserita in questo modo? (ad esempio mostrando i post 1-20)

@MichielStandaert se vuoi un risultato paginato puoi usare paginate_links

Grazie! (Ma continuo a chiedermi perché non abbiano usato :odd
per le righe invece di farci aggiungere una classe ogni due righe...)

Usa l'API Core, non solo il suo CSS
Normalmente utilizzi semplicemente un'istanza della classe WP_List_Table
.
Guide:
- Maggiori informazioni nel Codex qui.
- Ecco anche una guida da WP Engineer - troppo lunga per copiarla qui.
- E un'altra guida su Smashing Magazine online.
Vantaggi?
ASSOLUTAMENTE SI!
Puoi aggiungere paginazione, caselle di ricerca, azioni e qualsiasi magia tu possa immaginare (e sia in grado di codificare).

Piccolo suggerimento come link per vedere il markup, le classi per l'interfaccia admin, senza il solo obiettivo di creare tabelle: https://github.com/bueltge/WordPress-Admin-Style

>L'accesso a questa classe è contrassegnato come privato. Ciò significa che non è destinato all'uso da parte degli sviluppatori di plugin e temi, poiché è soggetto a modifiche senza preavviso in qualsiasi versione futura di WordPress. Se desideri comunque utilizzare la classe, dovresti farne una copia da utilizzare e distribuire con il tuo progetto, oppure usarla a tuo rischio.

@AustinPray Una copia? No, per favore non farlo. Sono disponibili versioni beta, RC e altre pre-release di WP. Basta aggiornare la tua implementazione/estensione. Se proprio devi prendere una strada alternativa, scrivi qualcosa di meglio da solo. Il codice core non è così buono.

@kaiser Non sparare al messaggero, non sono parole mie. Stavo citando dal WP Codex. Anche se iscriversi per test di regressione perpetui con ogni beta e RC non suona molto meglio che copiare la classe. Concordo che scrivere la propria classe semplice sia una strada migliore da percorrere.

@AustinPray Nessun rancore :) Il Codex è scritto da persone come te e me. In effetti, potresti andare ora a modificare quella affermazione e la gente la citerebbe.

Sfortunatamente, entrambe le guide sono terribilmente obsolete, a partire da WordPress 5, cosa che ho scoperto a mie spese mentre rompevo cose (Inoltre quella di Smashing Magazine ha evidenti errori di sintassi - qualcuno non ha padroneggiato copia&incolla). Non ho trovato un'alternativa aggiornata (il custom-list-table-example
è solo leggermente migliore) e il Codex ha molte cose mancanti. Sono riuscito a scrivere una semplice implementazione guardando WordPress stesso, in particolare class-wp-users-list-table.php
che è quasi completamente funzionale ma più semplice delle altre classi di WP.

@Guss La risposta è del 2012. Potresti voler aggiungere la tua risposta per offrire una soluzione più aggiornata :)

Utilizza questo esempio (scritto come plugin) per creare le tue tabelle di amministrazione:
http://wordpress.org/extend/plugins/custom-list-table-example/
Utilizza la classe integrata WP_List_Table.

Penso che questa dovrebbe essere la risposta accettata. Vedi anche questo articolo su Smashing Magazine che descrive un approccio simile: http://wp.smashingmagazine.com/2011/11/03/native-admin-tables-wordpress/

Puoi anche utilizzare questo piccolo plugin per visualizzare le possibilità del backend in WP: https://github.com/bueltge/WordPress-Admin-Style

Ci sono molte buone opzioni qui. Ma manca una soluzione rapida e sporca:
<table class="widefat striped fixed">
<thead>
<tr>
<th>Intestazione1</th>
<th>Intestazione2</th>
<th>Intestazione3</th>
</tr>
</thead>
<tbody>
<tr>
<td>Contenuto1</td>
<td>Contenuto2</td>
<td>Contenuto3</td>
</tr>
</tbody>
<tfoot>
<tr>
<th>Piè di pagina1</th>
<th>Piè di pagina2</th>
<th>Piè di pagina3</th>
</tr>
</tfoot>
</table>
Spiegazione
- La classe
widefat
viene utilizzata dalcommon.css
, caricato nell'area di amministrazione, per far sembrare la tabella come una tabella di WordPress. - La classe
striped
la rende a righe alternate (che sorpresa). - La classe
fixed
aggiunge il CSS:table-layout: fixed;

Per chi sta cercando di implementare WP_List_Table
, si prega di notare che tutte le guide che ho trovato sono tristemente obsolete e porteranno a scrivere codice ridondante o addirittura a fare cose che non funzionano più.
Ecco un esempio minimale che funziona in una certa misura. Dovrebbe essere facile da capire senza una "guida" e vi darà un punto di partenza.
Include:
- filtri rapidi (viste)
- casella di ricerca
- azioni sulla riga
Mancano:
- configurazione della dimensione della pagina (in realtà non ho mai visto una pagina Wordpress che utilizzi questa funzionalità)
- azioni bulk
- filtri a tendina
class My_List_Table extends WP_List_Table {
function __construct() {
parent::__construct([
'singular' => 'employee',
'plural' => 'employees',
]);
}
function get_columns() {
return [
'name' => __('Nome'),
'employer' => __('Datore di lavoro'),
'rank' => __('Livello'),
'phone' => __('Telefono'),
'joined' => __('Data di assunzione'),
];
}
/* Opzionale - senza di esso nessuna colonna è ordinabile */
public function get_sortable_columns() {
return [
// le chiavi sono "nome_colonna" come sopra
// i valori sono nomi di campo "ordine" in base a ciò di cui ha bisogno il tuo modello dati
'name' => 'name',
'employer' => 'employer',
'rank' => 'rank',
'joined' => 'joined',
];
}
public function prepare_items() {
// supporto per la casella di ricerca
$search = @$_REQUEST['s'] ? wp_unslash(trim($_REQUEST['s']))) : '';
// ottiene l'impostazione del numero di record per pagina dallo storage delle opzioni
$per_page = $this->get_items_per_page('my_list_table_per_page');
// riempie l'array di dati con gli elementi del tuo modello. Nella mia implementazione questi
// sono istanze di StdClass con vari campi, ma può essere qualsiasi cosa
// vedremo tra un minuto come.
$this->items = get_model_items([
'offset' => ($this->get_pagenum()-1)*$per_page,
'count' => $per_page,
'orderby' => @$_GET["orderby"] ?: 'id', // campo di ordinamento predefinito, se non specificato
'order' => @$_GET["order"] ?: 'ASC', // direzione di ordinamento predefinita
'search' => $search, // passa il campo di ricerca se impostato
'status' => @$_REQUEST['status'] // passa il filtro della vista, se impostato [vedi get_views()]
);
$this->set_pagination_args([
"total_items" => get_model_item_count(),
"per_page" => $per_page,
]);
// `get_model_item_count` dovrebbe essere il numero totale di record dopo
// il filtraggio (viste e ricerca) ma prima dell'impaginazione. Questo può essere difficile/inefficiente
// da fare con MySQL. Se vuoi inserire qui i risultati di `COUNT(*)`,
// nessuno ti biasimerà.
}
public function column_default($item, $column_name) {
// presentazione predefinita della colonna
// La maggior parte dei campi del mio oggetto sono stampabili così come sono, quindi abbiamo un metodo
// generico per gestirlo.
return $item->$column_name;
}
/* Opzionale, a meno che non abbia dati che richiedono una formattazione speciale */
public function column_joined($item) {
// Il campo 'joined' è un oggetto DateTime e non può essere implicitamente
// convertito in stringa dalla logica integrata, quindi dovremo farlo noi
return $item->joined->format("Y-m-d");
}
/* Opzionale - disegna filtri rapidi sopra la tabella */
public function get_views() {
$makelink = function($filter_val, $name) { // strumento per DRYing per i creatori di viste
$filter_name = 'status';
return '<a href="'
. esc_url(add_query_arg($filter_name, $filter_val)) . '" ' .
(@$_REQUEST[$filter_name]==$filter_val ?
'class="current" aria-current="page"' : ''). ">" .
$name . "</a>";
};
return [
'all' => $makelink(false, __('Tutti')),
'green' => $makelink('green', __('Principianti')),
'pros' => $makelink('pro', __('Esperti')),
'bofh' => $makelink('veteran', __('Vecchi veterani')),
];
}
/* Opzionale: azioni sulla riga */
public function handle_row_actions($item, $column_name, $primary) {
$out = parent::handle_row_actions($item, $column_name, $primary);
if ($column_name === $primary)
$out .= $this->row_actions([
'edit' => sprintf('<a href="%s">%s</a>',
add_query_arg('employee_id', $item->id, admin_url('admin.php?page=edit-employee')),
__("Modifica")),
'delete' => sprintf('<a href="%s">%s</a>',
add_query_arg('employee_id', $item->id, admin_url('admin.php?page=delete-employee')),
__("Elimina")),
]);
return $out;
}
}
Quindi la funzione della pagina di amministrazione (per add_menu_page
/add_submenu_page
) potrebbe essere così:
function drawAdminPage() {
$my_list_table = new My_List_Table();
$my_list_table->prepare_items();
?>
<div class="wrap">
<h1 class="wp-heading-inline"><?php _e('Titolo pagina admin')?></h1>
<hr class="wp-header-end">
<?php $my_list_table->views() ?>
<form id="employee-filter" method="get">
<input type="hidden" name="page" value="<?php echo $_REQUEST['page']?>">
<?php $my_list_table->search_box(__('Cerca'), 'employee') ?>
<?php $my_list_table->display(); ?>
</form>
</div>
<?php
}

Potresti voler aggiungere un filtro alla lista del tuo custom post type nell'area di amministrazione? La risposta linkata qui sotto mostra come farlo con una tassonomia, ma potresti facilmente usare altri criteri nel tuo hook restrict_manage_posts
:
Fammi sapere se hai altre domande.

Mi scuso per la domanda poco chiara. Nel mio primo esempio si trattava di una tabella di articoli, e in effetti potrei provare a utilizzare la tabella degli articoli esistente per quello (anche se voglio solo mostrare i titoli degli articoli e poi tutte le colonne personalizzate?). Ma ora ho modificato la mia domanda con un esempio concreto: ho una tabella di domini, quindi non esiste una tabella equivalente esistente che posso espandere.

@Jan: Ah. Sì, penso che tu abbia trovato la verità, che non esiste un modo ben incapsulato per farlo se non scrivere (duplicato) HTML. Ho spesso avuto lo stesso problema. Forse crea un ticket su trac chiedendo questo miglioramento e collega l'URL/ticket# qui così possiamo supportarlo.
