【问题标题】:How To Display WP_List_Tables on frontend page如何在前端页面上显示 WP_List_Tables
【发布时间】:2018-01-07 18:36:11
【问题描述】:

当前问题: 我已经能够在仪表板管理区域中从我的 WP 的 sql 数据库中成功创建各种表列表,并使用 WP_LIST_TABLE 创建插件,但是在如何使用短代码。通常我会添加如下内容:

 add_shortcode('joblist', 'Job_List_Plugin');

但是在这种情况下,它似乎不起作用。页面没有生成表格,而是您只看到添加到页面的短代码,所以在这种情况下 [joblist]

问题: 如何将简码元素添加到以下代码中,以允许我在前端页面上显示此表以供登录的访问者查看?示例/片段将不胜感激。

 if ( ! class_exists( 'WP_List_Table' ) ) {
    require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
 }

 class Job_List extends WP_List_Table {

    /** Class constructor */
    public function __construct() {
        parent::__construct( [
            'singular' => __( 'Custom List', 'red' ), //singular name of the listed records
            'plural'   => __( 'Custom Lists', 'red' ), //plural name of the listed records
            'ajax'     => false //does this table support ajax?
        ] );
    }


    /**
     * Retrieve members data from the database
     *
     * @param int $per_page
     * @param int $page_number
     *
     * @return mixed
     */
    public static function get_jobs( $per_page = 10, $page_number = 1 ) {

        global $wpdb;
        $query = "SELECT * FROM custom_table ORDER BY PrintOrder";

        if( ! empty( $_REQUEST['s'] ) ){
         $search = esc_sql( $_REQUEST['s'] );
    $query .= " WHERE Description LIKE '%{$search}%'";
    }

        if ( ! empty( $_REQUEST['orderby'] ) ) {
            $query .= ' ORDER BY ' . esc_sql( $_REQUEST['orderby'] );
            $query .= ! empty( $_REQUEST['order'] ) ? ' ' . esc_sql( $_REQUEST['order'] ) : ' ASC';
        }

        $query .= " LIMIT $per_page";
        $query .= ' OFFSET ' . ( $page_number - 1 ) * $per_page;

        $result = $wpdb->get_results( $query, 'ARRAY_A' );

        return $result;
    }

    /**
     * Returns the count of records in the database.
     *
     * @return null|string
     */
    public static function record_count() {
        global $wpdb;

        $query = "SELECT COUNT(*) FROM custom_table";
        if( ! empty( $_REQUEST['s'] ) ){
         $search = esc_sql( $_REQUEST['s'] );
         $query .= " WHERE Description LIKE '%{$search}%'";
        }
        return $wpdb->get_var( $query );
    }

    /** Text displayed when no member data is available */
    public function no_items() {
        _e( 'There is nothing display at this time.', 'red' );
    }

    /**
     * Render a column when no column specific method exist.
     *
     * @param array $item
     * @param string $column_name
     *
     * @return mixed
     */
    public function column_default( $item, $column_name ) {
        switch ( $column_name ) {
        case 'Description':
        case 'Class':
        case 'EmpName':
        case 'StartTime':
            return $item[ $column_name ];
        default:
            return print_r( $item, true ); //Show the whole array for troubleshooting purposes
    }
}


/**
 *  Associative array of columns
 *
 * @return array
 */
function get_columns() {
    $columns = [
        'Description' => __( 'Classification', 'red' ),
        'Class'    => __( 'Class', 'red' ),
        'EmpName'    => __( 'Employer Name', 'red' ),
        'StartTime'    => __( 'Start Time', 'red' )
    ];

    return $columns;
}


/**
 * Columns to make sortable.
 *
 * @return array
 */
public function get_sortable_columns() {
    $sortable_columns = array(
        'Description' => array( 'Classification', true ),
        'Class' => array ( 'Class', true)
    );

    return $sortable_columns;
}
/**
 * Handles data query and filter, sorting, and pagination.
 */
public function prepare_items() {

    $this->_column_headers = $this->get_column_info();

    /** Process bulk action */
    $this->process_bulk_action();

    $per_page     = $this->get_items_per_page( 'jobs_per_page', 7 );
    $current_page = $this->get_pagenum();
    $total_items  = self::record_count();

    $this->set_pagination_args( [
        'total_items' => $total_items, //calculate the total number of items
        'per_page'    => $per_page //determine how many items to show on a page
    ] );

    $this->items = self::get_jobs( $per_page, $current_page );
}




 }

 class Job_List_Plugin {

// class instance
static $instance;

// joblist WP_List_Table object
public $joblist_obj;

// class constructor
public function __construct() {
   add_filter( 'set-screen-option', [ __CLASS__, 'set_screen' ], 10, 3 );
   add_action( 'admin_menu', [ $this, 'plugin_menu' ] );
}


public static function set_screen( $status, $option, $value ) {
    return $value;
}

public function plugin_menu() {

    $hook = add_menu_page(
        'Job List',
        'Job List',
        'manage_options',
        'joblist_viewer',
        [ $this, 'plugin_settings_page' ]
    );

    add_action( "load-$hook", [ $this, 'screen_option' ] );

}


/**
 * Plugin page
 */
public function plugin_settings_page() {
    ?>
    <style>
      table {display: block;overflow-x: scroll;}
      th {min-width:100px;font-size:10px;}
      p.search-box {float:none;}
      #post-body-content {width:98%;}
    </style>
        <h2>IBEW 353 Member Management Portal</h2>
        <p>To locate a specific Member enter their Card Number in the search field provided.</p>
                <div id="post-body-content">
                    <div class="meta-box-sortables ui-sortable">
                        <form method="post">
   <input type="hidden" name="page" value="joblist_viewer" />
                            <?php
                            $this->joblist_obj->prepare_items();
                            $this->joblist_obj->search_box('Search', 'search');
                            $this->joblist_obj->display(); ?>
                        </form>
                    </div>
                </div>
            <br class="clear">
<?php
}

/**
 * Screen options
 */
public function screen_option() {

    $option = 'per_page';
    $args   = [
        'label'   => 'Jobs Per Page:',
        'default' => 5,
        'option'  => 'jobs_per_page'
    ];

    add_screen_option( $option, $args );

    $this->joblist_obj = new Job_List();
}


/** Singleton instance */
public static function get_instance() {
    if ( ! isset( self::$instance ) ) {
        self::$instance = new self();
    }

    return self::$instance;
}

 }

 add_action( 'plugins_loaded', function () {
    Job_List_Plugin::get_instance();
 } );

更新 在@Jared Chu 的帮助下,我取得了一些进展,但现在出现了错误。但至少我看到简码开始起作用了。

这是我编辑的内容。

我添加的第 203 行(类构造)

// class constructor
public function __construct() {
   add_filter( 'set-screen-option', [ __CLASS__, 'set_screen' ], 10, 3 );
   add_action( 'admin_menu', [ $this, 'plugin_menu' ] );
   add_shortcode('joblist', [ $this, 'plugin_settings_page' ] ); // Added shortcode as per suggestion from @Jared Chu
}

公共函数“plugin_settings_page”包含此代码

 /**
 * Plugin page
 */
public function plugin_settings_page() {
    ?>
    <style>
      table {display: block;overflow-x: scroll;}
      th {min-width:100px;font-size:10px;}
      p.search-box {float:none;}
      #post-body-content {width:98%;}
    </style>
        <h2>IBEW 353 Member Management Portal</h2>
        <p>To locate a specific Member enter their Card Number in the search field provided.</p>
                <div id="post-body-content">
                    <div class="meta-box-sortables ui-sortable">
                        <form method="post">
 <input type="hidden" name="page" value="joblist_viewer" />
                            <?php
                            $this->joblist_obj->prepare_items();
                            $this->joblist_obj->search_box('Search', 'search');
                            $this->joblist_obj->display(); ?>
                        </form>
                    </div>
                </div>
            <br class="clear">
<?php
}

但是,当我查看页面时,我将短代码放入其中,但出现以下错误:

致命错误:未捕获的错误:在第 249 行的 C:\wamp64\www\dev1\wp-content\plugins\Job-List-Plugin\index.php 中调用 null 上的成员函数 prepare_items()

【问题讨论】:

  • 您是否收到错误消息?请更好地描述它。
  • 页面未生成表格,而是您只看到添加到页面的简码,因此在这种情况下 [joblist] 更新了问题以反映。
  • 也许这是一个愚蠢的问题,但你把它放在functions.php中了吗?
  • 不,我已经成功创建了一个在仪表板中工作的插件,但我现在也想在我的网站前端显示它并且遇到了困难。没有愚蠢的问题。只有愚蠢的答案:) 希望我的不是大声笑
  • 哈,没关系,这是整个过程的一部分。您的插件中是否有某些东西可能会阻止它在前端呈现?

标签: php mysql wordpress


【解决方案1】:

我自己在尝试在前端显示 WP_List_Table 时遇到了这个问题。我已经有一个正确定义的简码,并在课堂外的管理员中呈现了我的菜单页面。不过,我在使用简码在前端呈现我的列表时遇到了这个错误。

经过两天的研究和谷歌搜索,我终于弄明白了。我需要额外的类才能在前端工作。我的猜测是这些类包含在 wp-admin 模式中,但不包含在前端模式中,因此我们需要在子类中要求它们。

我在这里找到了我的答案,有人要求一些不相关的东西,但有我需要的正确代码:https://wordpress.stackexchange.com/questions/350839/wp-list-table-in-frontend-how-to-style-with-bootstrap4

这些是您需要包含的类和文件:

        require_once(ABSPATH . 'wp-admin/includes/class-wp-list-table.php');
        require_once(ABSPATH . 'wp-admin/includes/screen.php');
        require_once(ABSPATH . 'wp-admin/includes/class-wp-screen.php');
        require_once(ABSPATH . 'wp-admin/includes/template.php');

即使这个问题已经有了答案,如果其他人有同样的问题,我会在这里发布。

编辑:忘记添加我在前端显示表格的方式。我只需在需要呈现表格的页面模板中创建该类的新实例。像这样:

 <main id="dashboard content">
   <?php
   $list = new LB_WP_Table();
   ?>
 </main>

我已使用此答案中的代码作为起点:https://stackoverflow.com/a/18933069

这是我现在的完整代码:

  if( !class_exists( 'WP_List_Table' ) )
  require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );


  require_once(ABSPATH . 'wp-admin/includes/screen.php');
  require_once(ABSPATH . 'wp-admin/includes/class-wp-screen.php');
  require_once(ABSPATH . 'wp-admin/includes/template.php');

class LB_WP_Table extends WP_List_Table {
private $order;
private $orderby;
private $posts_per_page = 5;

public function __construct() {
    parent:: __construct( array(
        'singular' => 'table example',
        'plural'   => 'table examples',
        'ajax'     => true
    ) );

    add_filter( 'get_list_instance', [$this, 'get_instance']);
    add_shortcode('render_list', array($this, 'render_list_table'));
    $this->set_order();
    $this->set_orderby();
    $this->prepare_items();
    $this->display();

}


public function get_instance(){
  return $this;
}

public function render_list_table(){
  $this->set_order();
  $this->set_orderby();
  $this->prepare_items();
  $this->display();
}

private function get_sql_results()
{
    global $wpdb;
    $args = array( 'ID', 'post_title', 'post_date', 'post_content', 'post_type' );
    $sql_select = implode( ', ', $args );
    $sql_results = $wpdb->get_results("
            SELECT $sql_select
                FROM $wpdb->posts
            WHERE post_status = 'publish'
            ORDER BY $this->orderby $this->order "
    );
    return $sql_results;
}

public function set_order()
{
    $order = 'DESC';
    if ( isset( $_GET['order'] ) AND $_GET['order'] )
        $order = $_GET['order'];
    $this->order = esc_sql( $order );
}

public function set_orderby()
{
    $orderby = 'post_date';
    if ( isset( $_GET['orderby'] ) AND $_GET['orderby'] )
        $orderby = $_GET['orderby'];
    $this->orderby = esc_sql( $orderby );
}

/**
 * @see WP_List_Table::ajax_user_can()
 */
public function ajax_user_can()
{
    return current_user_can( 'edit_posts' );
}

/**
 * @see WP_List_Table::no_items()
 */
public function no_items()
{
    _e( 'No posts found.' );
}

/**
 * @see WP_List_Table::get_views()
 */
public function get_views()
{
    return array();
}

/**
 * @see WP_List_Table::get_columns()
 */
public function get_columns()
{
    $columns = array(
        'ID'         => __( 'ID' ),
        'post_title' => __( 'Title' ),
        'post_date'  => __( 'Date' ),
        'post_type'  => __( 'Type' )
    );
    return $columns;
}

/**
 * @see WP_List_Table::get_sortable_columns()
 */
public function get_sortable_columns()
{
    $sortable = array(
        'ID'         => array( 'ID', true ),
        'post_title' => array( 'post_title', true ),
        'post_date'  => array( 'post_date', true )
    );
    return $sortable;
}

/**
 * Prepare data for display
 * @see WP_List_Table::prepare_items()
 */
public function prepare_items()
{
    $columns  = $this->get_columns();
    $hidden   = array();
    $sortable = $this->get_sortable_columns();
    $this->_column_headers = array(
        $columns,
        $hidden,
        $sortable
    );

    // SQL results
    $posts = $this->get_sql_results();
    empty( $posts ) AND $posts = array();

    # >>>> Pagination
    $per_page     = $this->posts_per_page;
    $current_page = $this->get_pagenum();
    $total_items  = count( $posts );
    $this->set_pagination_args( array (
        'total_items' => $total_items,
        'per_page'    => $per_page,
        'total_pages' => ceil( $total_items / $per_page )
    ) );
    $last_post = $current_page * $per_page;
    $first_post = $last_post - $per_page + 1;
    $last_post > $total_items AND $last_post = $total_items;

    // Setup the range of keys/indizes that contain
    // the posts on the currently displayed page(d).
    // Flip keys with values as the range outputs the range in the values.
    $range = array_flip( range( $first_post - 1, $last_post - 1, 1 ) );

    // Filter out the posts we're not displaying on the current page.
    $posts_array = array_intersect_key( $posts, $range );
    # <<<< Pagination

    // Prepare the data
    $permalink = __( 'Edit:' );
    foreach ( $posts_array as $key => $post )
    {
        $link     = get_edit_post_link( $post->ID );
        $no_title = __( 'No title set' );
        $title    = ! $post->post_title ? "<em>{$no_title}</em>" : $post->post_title;
        $posts[ $key ]->post_title = "<a title='{$permalink} {$title}' href='{$link}'>{$title}</a>";
    }
    $this->items = $posts_array;
}

/**
 * A single column
 */
public function column_default( $item, $column_name )
{
    return $item->$column_name;
}

/**
 * Override of table nav to avoid breaking with bulk actions & according nonce field
 */
public function display_tablenav( $which ) {
    ?>
    <div class="tablenav <?php echo esc_attr( $which ); ?>">
        <!--
        <div class="alignleft actions">
            <?php # $this->bulk_actions( $which ); ?>
        </div>
         -->
        <?php
        $this->extra_tablenav( $which );
        $this->pagination( $which );
        ?>
        <br class="clear" />
    </div>
    <?php
}

/**
 * Disables the views for 'side' context as there's not enough free space in the UI
 * Only displays them on screen/browser refresh. Else we'd have to do this via an AJAX DB update.
 *
 * @see WP_List_Table::extra_tablenav()
 */
public function extra_tablenav( $which )
{
    global $wp_meta_boxes;
    $views = $this->get_views();
    if ( empty( $views ) )
        return;

    $this->views();
}
} // class

if (!is_admin()){ // Only do this in frontend
  $list = new LB_WP_Table(); 
}


add_action('admin_menu', function()
{
    add_menu_page(
        'TE',
        '<span style="color:#e57300;">Table Example</span>',
        'edit_pages',
        'table-example',
        function() {
            echo '<div class="wrap">';
            screen_icon('edit');
            echo '<h2>Table Example</h2>';
            new LB_WP_Table();
            echo '</div>';
        },
    'http://sstatic.net/stackexchange/img/favicon.ico',
        1  // create before Dashboard menu item
    );
});

【讨论】:

    【解决方案2】:

    add_shortcode('joblist', 'Job_List_Plugin'); 不正确。

    add_shortcode 第二个 ref 变量必须是函数:

    # 1. Standard usage
    add_shortcode('shortcode_name', 'shortcode_func');
    
    function shortcode_func()
    {
     // Contents of this function will execute when the blogger
    // uses the [shortcode_name] shortcode.
    }
    
    # 2. With PHP 5.3, we can pass an anonymous function.
    add_shortcode('shortcode_name', function() {
       // Contents of this function will execute when the blogger
      // uses the [shortcode_name] shortcode.
    });
    
    #3. Within a class
    class YourPluginClass {
        public function __construct()
        {
            add_shortcode('your_short_code_name', array($this, 'shortcode'));
        }
    
        public function shortcode()
        {
               // Contents of this function will execute when the blogger
              // uses the [shortcode_name] shortcode.
        }
    }
    

    因此,在您的情况下,我们将使用 #3。

    【讨论】:

    • 您好@Jared Chu,感谢您的帮助,我已经为我的问题添加了更新,希望您能进一步了解这个问题。谢谢。
    • joblist_obj为null的问题,可以试试把$this-&gt;joblist_obj = new Job_List();放在add_shortcode这一行上面吗?
    • 致命错误:未捕获的错误:当我在添加短代码行上方的新行中添加未定义函数 convert_to_screen() 时调用。
    • 我认为这是你的课堂问题stackoverflow.com/questions/40867316/…
    • 将您标记为正确答案,就好像您没有给我提供它永远不会起作用的洞察力一样,感谢您为我指明了正确的方向。自从这篇文章以来,我学到了很多东西。对不起,我忘了标记它。
    猜你喜欢
    • 1970-01-01
    • 2020-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-12
    • 1970-01-01
    • 1970-01-01
    • 2019-08-09
    相关资源
    最近更新 更多