I did same error first time I implemented WP_List_Table
.
The problem is that when you call WP_List_Table::display()
WordPress in turn calls:
- WP_List_Table::display_rows_or_placeholder()
- WP_List_Table::display_rows()
- WP_List_Table::single_row()
- WP_List_Table::single_row_columns()
Last function is called for every row. If you look at its code (see source), it has:
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 );
}
So WordPress calls WP_List_Table::column_default()
for every row, but… that method doesn’t exist.
Add to your class:
public function column_default($item, $column_name) {
return $item[$column_name];
}
And your data will be correctly displayed.
When you don’t add data, error doesn’t show up because with no data WordPress never calls display_rows()
and other methods after that.
Bonus Notes:
-
In your
prepare_items()
method you use the variable$perpage
but you define it as$per_page
(notice the underscore), that cause a division-by-zero warning (and pagination doesn’t work) -
the code
mysql_real_escape_string($_GET["orderby"])
is not safe, because for'orderby'
SQL clausemysql_real_escape_string()
is not enough. (see recent Yoast SQL injection bug).Do something like:
$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; }
and do something similar to for
'order'
clause as well: very probably it can only be eitherASC
orDESC
: don’t allow anything else.