web-dev-qa-db-ja.com

$ this-> itemsがいっぱいになったときにリストテーブルがレンダリングされない

listテーブル をカスタム管理ページに追加しようとしています。 このガイド and このリファレンス実装をフォローしています

残念ながら、データを追加するために$this->itemsを定義すると、管理ページに nothing が表示され(リストテーブルの周りのhtmlでもない)、エラーメッセージは表示されません。その行をコメントアウトすると(135行)、明らかにデータが欠落していることを除いてそれは機能します。

私のコード:

<?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
}
?>

上記のコードは、require_once()とともにfunctions.phpに含まれる別のファイルにあります。

私はワードプレス4.1.1を使用しています

ここで何が起こっているの?なぜeverythingが消えてエラーが出ないのでしょうか?

5
gandalf3

最初にWP_List_Tableを実装したときにも同じエラーをしました。

問題は、WP_List_Table::display() WordPressを順番に呼び出すと、次のことが呼び出されることです。

最後の関数は行ごとに呼び出されます。そのコードを見れば( source を見てください)、それは持っています:

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 );
}

そのためWordPressはすべての行に対してWP_List_Table::column_default()を呼び出しますが、そのメソッド は存在しません

あなたのクラスに追加:

public function column_default($item, $column_name) {
    return $item[$column_name];
}

そしてあなたのデータは正しく表示されます。

データを追加しないと、エラーが発生しません。データがないと、WordPressはdisplay_rows()やその後の他のメソッドを呼び出しません。


ボーナスノート:

  1. prepare_items()メソッドでは変数$perpageを使用しますが、$per_pageとして定義すると(アンダースコアに注意してください)、ゼロ除算の警告が発生します(そしてページ付けは機能しません)

  2. コードmysql_real_escape_string($_GET["orderby"]) not safeです。なぜなら'orderby' SQL句のmysql_real_escape_string()では十分ではないからです。 ( 最近のYoast SQLインジェクションのバグ を参照).

    次のようにしてください。

    $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;
    }
    

    そして'order'節にも似たようなことをしてください:たぶんそれはASCDESCのどちらかであることができるだけです:他に何も許さないでください。

9
gmazzap

今家にいる、私は実際にあなたのコードを実行しました。私はこれを得た:

致命的なエラー:.../wp-admin/includes/class-wp-list-table.phpの88行目の未定義関数convert_to_screen()を呼び出す

注:

開発時には Debugging_in_WordPress をオンにしてください。

とにかくこれは私をStackoverflowについての次の質問に導きました:

@ brasofiloの回答は大いに役に立ちましたが、彼はWordPress Developmentの大手企業の1人なので、驚くことではありません。

とにかく彼の答えに続いて、あなたはメソッドcolumn_defaultが欠けています、さらに_constructメソッドは異なっています。しかし、あなたは自分自身でそれを読むことができます、ここでいくつかの実用的な - 削除された - コードがあります:

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;
    }
}
2
Nicolai