J'essaie d'ajouter un list table à une page d'administrateur personnalisée. J'ai suivi ce guide et cette implémentation de référence .
Malheureusement, lorsque je définis $this->items
pour ajouter les données, rien s'affiche dans la page d'administration (pas même le code HTML autour de la liste) et il n'y a pas de message d'erreur. Si je commente cette ligne (ligne 135
), alors cela fonctionne sauf pour le manque évident de données.
Mon code:
<?php
add_action('admin_menu', 'add_example_menues');
function add_example_menues() {
add_menu_page('test', 'test', 'administrator', 'test-top', 'build_test_page');
add_submenu_page('test-top', 'All tests', 'All tests', 'administrator', 'test-top');
}
if(!class_exists('WP_List_Table')){
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}
class test_List_Table extends WP_List_Table {
function __construct() {
parent::__construct( array(
'singular' => 'test',
'plural' => 'tests',
'ajax' => false
));
}
function extra_tablenav ($which) {
if ($which == "top") {
echo "Top";
}
if ($which == "bottom") {
echo "Bottom";
}
}
function get_columns() {
$columns = array(
'id' => 'ID',
'title' => 'Title',
'user_id' => 'User ID',
'description' => 'Description'
);
return $columns;
}
function get_sortable_columns() {
return $sortable = array(
'id' => array('id',false),
'title' => array('title',false),
'user_id' => array('user_id',false)
);
}
function prepare_items() {
global $wpdb;
//data normally gotten from non-wp database. Wordpress db user has access, as per this SE post:
//http://wordpress.stackexchange.com/questions/1604/using-wpdb-to-connect-to-a-separate-database
$query = "SELECT `id`, `title`, `user_id`, `description` FROM otherdb.example_table";
//pagination stuff
$orderby = !empty($_GET["orderby"]) ? mysql_real_escape_string($_GET["orderby"]) : 'ASC';
$order = !empty($_GET["order"]) ? mysql_real_escape_string($_GET["order"]) : '';
if(!empty($orderby) & !empty($order)){ $query.=' ORDER BY '.$orderby.' '.$order; }
$totalitems = $wpdb->query($query);
echo "$totalitems";
$per_page = 5;
$paged = !empty($_GET["paged"]) ? mysql_real_escape_string($_GET["paged"]) : '';
if(empty($paged) || !is_numeric($paged) || $paged<=0 ){ $paged=1; }
$totalpages = ceil($totalitems/$perpage);
if(!empty($paged) && !empty($perpage)){
$offset=($paged-1)*$perpage;
$query.=' LIMIT '.(int)$offset.','.(int)$perpage;
}
$this->set_pagination_args( array(
"total_items" => 4,
"total_pages" => 1,
"per_page" => 5,
) );
$columns = $this->get_columns();
$hidden = array();
$sortable = $this->get_sortable_columns();
$this->_column_headers = array($columns, $hidden, $sortable);
//actual data gotten from database, but for SE use hardcoded array
//$data = $wpdb->get_results($query, ARRAY_N);
$example_data = array(
array(
'id' => 1,
'title' => 'nonsense',
'user_id' => 1,
'description' => 'asdf'
),
array(
'id' => 2,
'title' => 'notanumber',
'user_id' => 2,
'description' => '404'
),
array(
'id' => 3,
'title' => 'I Am A Title',
'user_id' => 3,
'description' => 'desc'
),
array(
'id' => 4,
'title' => 'Example',
'user_id' => 4,
'description' => 'useless'
),
array(
'id' => 5,
'title' => 'aeou',
'user_id' => 5,
'description' => 'keyboard layouts'
),
array(
'id' => 6,
'title' => 'example data',
'user_id' => 6,
'description' => 'data example'
),
array(
'id' => 7,
'title' => 'last one',
'user_id' => 7,
'description' => 'done'
)
);
//This is the line:
$this->items = $example_data;
//When the above line is commented, it works as expected (except for the lack of data, of course)
}
}
function build_test_page() {
$testListTable = new test_List_Table();
$testListTable->prepare_items();
?>
<div class="wrap">
<div id="icon-users" class="icon32"><br/></div>
<h2>List Table Test</h2>
<?php $testListTable->display() ?>
</div>
<?php
}
?>
Le code ci-dessus est dans un fichier séparé, inclus dans functions.php
avec un require_once()
.
J'utilise wordpress 4.1.1
Qu'est-ce qui se passe ici? Pourquoi tout disparaîtrait-il et aucune erreur ne serait commise?
J'ai fait la même erreur la première fois que j'ai implémenté WP_List_Table
.
Le problème est que lorsque vous appelez WP_List_Table::display()
, WordPress appelle à son tour:
La dernière fonction est appelée pour chaque ligne. Si vous regardez son code (voir source ), il a:
if ( 'cb' == $column_name ) {
// you don't have 'cb' column, code remove because not relevant
} elseif ( method_exists( $this, 'column_' . $column_name ) ) {
// you don't have method named 'column_{$column_name}',
// code remove because not relevant
} else {
// not relevant line
echo $this->column_default( $item, $column_name );
}
Donc, WordPress appelle WP_List_Table::column_default()
pour chaque ligne, mais ... cette méthode n'existe pas .
Ajouter à votre classe:
public function column_default($item, $column_name) {
return $item[$column_name];
}
Et vos données seront correctement affichées.
Lorsque vous n’ajoutez pas de données, l’erreur ne s’affiche pas car, en l’absence de données, WordPress n’appelle jamais display_rows()
, ni d’autres méthodes par la suite.
Dans votre méthode prepare_items()
, vous utilisez la variable $perpage
mais vous la définissez comme suit: $per_page
(notez le trait de soulignement), ce qui provoque un avertissement division par zéro (et la pagination ne fonctionne pas).
le code mysql_real_escape_string($_GET["orderby"])
est not safe, car pour 'orderby'
la clause SQL mysql_real_escape_string()
n'est pas suffisante. (voir récent bug d'injection Yoast SQL ).
Faites quelque chose comme:
$orderby = 'id'; // default
$by = strtolower(filter_input(INPUT_GET, 'orderby', FILTER_SANITIZE_STRING));
if (in_array($by, array('title', 'description', 'user_id'), true) {
$orderby = $by;
}
et faire quelque chose de similaire à la clause 'order'
également: très probablement, il ne peut s'agir que de ASC
ou de DESC
: n'autorise rien d'autre.
Maintenant à la maison, j'ai en fait couru votre code. J'ai eu ceci:
Erreur fatale: appel de la fonction non définie convert_to_screen () dans .../wp-admin/includes/class-wp-list-table.php à la ligne 88
Note:
Veuillez activer Debugging_in_WordPress lors du développement.
Quoi qu'il en soit, cela m'amène à la question suivante sur Stackoverflow:
La réponse de @ brasofilo a beaucoup aidé, ce qui n’est pas surprenant, car il est l’un des protagonistes de WordPress Development.
Quoi qu'il en soit, à la suite de sa réponse, il vous manque la méthode column_default
, de plus la méthode _construct
est différente. Mais vous pouvez le lire vous-même, voici un code de travail - dépouillé -:
add_action( 'admin_menu', 'add_test_list_table_menues' );
function add_test_list_table_menues() {
add_menu_page(
'test',
'test',
'manage_options',
'test-top',
'test_list_table_output'
);
}
function test_list_table_output() {
echo '<div class="wrap">';
echo '<h2>Test List Table</h2>';
new Test_List_Table();
echo '</div>';
}
if( ! class_exists( 'WP_List_Table' ) ) {
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}
class Test_List_Table extends WP_List_Table {
public function __construct() {
parent::__construct( array(
'singular' => 'test',
'plural' => 'tests',
'ajax' => false
));
$this->prepare_items();
$this->display();
}
function get_columns() {
$columns = array(
'tid' => 'ID',
'title' => 'Title',
'user_id' => 'User ID',
'description' => 'Description'
);
return $columns;
}
function column_default( $item, $column_name ) {
switch( $column_name ) {
case 'tid':
case 'title':
case 'user_id':
case 'description':
return $item[ $column_name ];
default:
return print_r( $item, true ) ;
}
}
function prepare_items() {
$example_data = array(
array(
'tid' => 1,
'title' => 'nonsense',
'user_id' => 1,
'description' => 'asdf'
),
array(
'tid' => 2,
'title' => 'notanumber',
'user_id' => 2,
'description' => '404'
),
array(
'tid' => 3,
'title' => 'I Am A Title',
'user_id' => 3,
'description' => 'desc'
),
array(
'tid' => 4,
'title' => 'Example',
'user_id' => 4,
'description' => 'useless'
),
array(
'tid' => 5,
'title' => 'aeou',
'user_id' => 5,
'description' => 'keyboard layouts'
),
array(
'tid' => 6,
'title' => 'example data',
'user_id' => 6,
'description' => 'data example'
),
array(
'tid' => 7,
'title' => 'last one',
'user_id' => 7,
'description' => 'done'
)
);
$columns = $this->get_columns();
$hidden = array();
$sortable = $this->get_sortable_columns();
$this->_column_headers = array($columns, $hidden, $sortable);
$this->items = $example_data;
}
}