主题实现后台添加顶级菜单和列出数据

很多时候我们想把自己的主题制作成能够支持在后台添加一个菜单,并且列出自己创建表的数据,那么怎么做了,别急,下面我就分享下我自己的。

就像下面的这个效果:

在这个例子中我新建了一个表,用于记录活动的,下面是sql,你可以用sql工具导进去

-- ----------------------------
-- Table structure for `wp_participate_history`
-- ----------------------------DROP TABLE IF EXISTS `wp_participate_history`;
CREATE TABLE `wp_participate_history` (
  `par_id` int(11) NOT NULL auto_increment,
  `par_postid` int(11) NOT NULL,
  `par_posttitle` text NOT NULL,
  `par_type` varchar(20) default NULL,
  `par_userid` int(10) NOT NULL default '0',
  `par_username` varchar(50) NOT NULL,
  `par_time` int(11) NOT NULL,
  `get_sticker` int(11) NOT NULL,
  `status` int(1) NOT NULL default '0',
  PRIMARY KEY  (`par_id`)
) ENGINE=MyISAM AUTO_INCREMENT=213 DEFAULT CHARSET=utf8;
 
-- ----------------------------
-- Records of wp_participate_history
-- ----------------------------
INSERT INTO `wp_participate_history` VALUES ('7', '1366', 'eeeeeeeeeeeeeeee', 'event', '1', 'Administrator', '1354700553', '20', '2');
INSERT INTO `wp_participate_history` VALUES ('10', '1349', 'For Everyone', 'everyone', '2', 'test', '1354756577', '0', '1');

首先找到你自己主题下面的function.php,然后在里面加上如下代码

add_action('admin_menu', 'add_menu_items');
function add_menu_items(){
    add_menu_page(__('Attendance'), __('Attendance'), 8, 'manage_attendence', 'my_attendance_render', '', 7);
}
function my_attendance_render() {
    require_once TEMPLATEPATH . '/class-wp-attendance-list-table.php';
}

然后就在你的主题下面新建一个class-wp-attendance-list-table.php文件

下面我们就来制作自己的list-table了

/**
 * @author Gyrate
 * @link   
 * @name   
 * @version 1.0
 *
 * 如果你想看下本例子的效果:把下来的php代码粘贴到你主题下面的function.php里面,然后再在数据库中运行下面的sql语句即可
 * To use this example,just put this file into your theme directory.and add the code below into your function.php
 * Then run the sql code in your database
 * CODE TO function.php:
    add_action('admin_menu', 'add_menu_items');
    function add_menu_items(){
        add_menu_page(__('Attendance'), __('Attendance'), 8, 'manage_attendence', 'my_attendance_render', '', 7);
    }
    function my_attendance_render() {
        require_once TEMPLATEPATH . '/class-wp-attendance-list-table.php';
    }
 * SQL CODE:
   DROP TABLE IF EXISTS `wp_participate_history`;
    CREATE TABLE `wp_participate_history` (
      `par_id` int(11) NOT NULL auto_increment,
      `par_postid` int(11) NOT NULL,
      `par_posttitle` text NOT NULL,
      `par_type` varchar(20) default NULL,
      `par_userid` int(10) NOT NULL default '0',
      `par_username` varchar(50) NOT NULL,
      `par_time` int(11) NOT NULL,
      `get_sticker` int(11) NOT NULL,
      `status` int(1) NOT NULL default '0',
      PRIMARY KEY  (`par_id`)
    ) ENGINE=MyISAM AUTO_INCREMENT=213 DEFAULT CHARSET=utf8;   
    INSERT INTO `wp_participate_history` VALUES ('7', '1366', 'test title', 'event', '1', 'Administrator', '1354700553', '20', '2');
    INSERT INTO `wp_participate_history` VALUES ('10', '1349', 'For Everyone', 'everyone', '2', 'test', '1354756577', '0', '1');
 */
 
 
/*1.0首先我们得确保能够继承WP_List_Table类
 *(we should make sure that we can use WP_List_Table)
 * */
if(!class_exists('WP_List_Table')){
    require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}
//2.0一些定义(some defines that may use in the example)
global $wpdb;
defined("TABLE_PARTICIPTE_HISTORY") || define("TABLE_PARTICIPTE_HISTORY", $wpdb->prefix . "participate_history");
defined("CUSTOM_POST_TYPE1") || define('CUSTOM_POST_TYPE1','event');
 
/* 3.0
 * ====================================================================================
 * --+  创建类,我会解释每个类的作用的和写的步骤                            +--
 * --+  (create our list class,I have give                  +--
 * --+   the steps and  alse some explanation of functions) +--
 * --+  start  Attendance_List_Table                        +--
 * ====================================================================================
 */
//
class Attendance_List_Table extends WP_List_Table {
    public  $screen;
    public  $redirect='admin.php?page=manage_attendence';
    /**
     *  3.1
     *  构造方法,用于设置一些默认的参数、筛选条件、需要覆盖的配置等,当然也可以定义下你自己的这个列表支持不支持ajax
     *  Constructor. This sets default arguments and filters. Developers should override this,
     *  calling the parent constructor to provide values for singular and plural labels,
     *  as well as whether the class supports AJAX.
     */
    function __construct() {
        $this->screen = get_current_screen();
        global $wpdb;
        parent::__construct( array(
            'plural' => 'attendance',
            'singular' => 'attendance',
            'ajax' => false
        ));
    }
 
    /**
     * 3.2
     * 这个方法主要是设置下需要显示的数据、处理一下排序、分页和其他操作什么的,不过次方法父类是不会自动加载,需要在调用类处调用下
     * Developers should use this class to query and filter data, handle sorting, and pagination,
     * and any other data-manipulation required prior to rendering.
     * This method should be called explicitly after instantiating your class, and before rendering.
     */
    function prepare_items() {
        global $wpdb, $_wp_column_headers,$attendance_search;
        $attendance_search = isset( $_REQUEST['s'] ) ? trim( $_REQUEST['s'] ) : $attendance_search;
        $attendance_status = isset( $_REQUEST['attendance_status'] ) ? (int) trim( $_REQUEST['attendance_status'] ) : 0;
         
        $where=' WHERE 1=1';
        $attendance_status&& $where.=" AND status=$attendance_status";
        $attendance_search&& $where.=" AND par_posttitle LIKE '%$attendance_search%' ";
        /* -- Preparing your query -- */
        $query = "SELECT * FROM ".TABLE_PARTICIPTE_HISTORY." $where";
        /* -- Ordering parameters -- */
        //Parameters that are going to be used to order the result
        $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; }
     
        /* -- Pagination parameters -- */
        //Number of elements in your table?
        $totalitems = $wpdb->query($query); //return the total number of affected rows
         
        //How many to display per page?
        $perpage = 5;
        //Which page is this?
        $paged = !empty($_GET["paged"]) ? mysql_real_escape_string($_GET["paged"]) : '';
        //Page Number
        if(empty($paged) || !is_numeric($paged) || $paged< =0 ){ $paged=1; }
        //How many pages do we have in total?
        $totalpages = ceil($totalitems/$perpage);
        //adjust the query to take pagination into account
        if(!empty($paged) && !empty($perpage)){
            $offset=($paged-1)*$perpage;
            $query.=' LIMIT '.(int)$offset.','.(int)$perpage;
        }
     
        /**
         * 3.2.1
         * -- 分页设置Register the pagination --
         * 这个是必须要的,也就是说上面的几行代码都是为这个做准备的,此方法会在父类中自动调用,所以在这里你就需要设置下分页的相关参数
         * 有三个参数,这里说明下:
         * total_items——总共有多少条数据
         * per_page——每页显示的数据,你懂的
         * total_pages——总共页码,一般都是ceil(总条数/每页现实数);
         * This method should be called internally (usually from prepare_items()) to set basic pagination arguments. Available arguments include:
         * total_items - the total number of items to be displayed. Usually as simple as count($data)
         * per_page - the number of items to show per page
         * total_pages - the total number of pages. Can be left blank or calculated manually, like so: ceil($total_items/$per_page)
         */
        $this->set_pagination_args( array(
                "total_items" => $totalitems,
                "total_pages" => $totalpages,
                "per_page" => $perpage,
        ) );
        //The pagination links are automatically built according to those parameters
     
        /* -- Register the Columns -- */
        $columns = $this->get_columns();
        $_wp_column_headers[$this->screen->id]=$columns;
        $this->_column_headers = array(
             $this->get_columns(),       // columns
             array(),           // hidden
             $this->get_sortable_columns(),  // sortable
        );
        /* -- Fetch the items -- */
        $this->items = $wpdb->get_results($query);
    }
     
    /**
     * 3.3
     * 当查询没有数据的时候,在循环的li里面默认显示,当然这个你也可以不用再写,无关紧要
     * Returns the message to be displayed when there are no items.
     */
    function no_items() {_e( 'No Attendance found.' );}
    /**
     * 3.4
     * 这个主要是用于来自定义列表右边的搜索框,这个方法里面你需要中心写下搜索框的代码,世界输出一个搜索的表格即可,
     * 当然要是你没啥特别要求的话,可以不用定义这个,无关紧要
     * This renders a search box. To use this, you will still need to manually wrap your list table (including search box) in a form.
     */
    //function search_box() {}
     
    /**
     * 3.5
     * 这个主要是用于来定义上面的显示结果的分类,就像我们看到用户列表中就分了不同的角色来显示,在这里我就分了所以的、出席了的和只报名了的
     * Returns an associative array listing all the views that can be used with this table.
     */
    function get_views(){
        $attendance_status=$this->get_attendance_status();
        $attendance_count=$this->get_status_count();
        foreach ($attendance_status as $status=>$desc){
            $_REQUEST["attendance_status"]==$status && $class='class="current"';
            $status_attendance[]   = "<a $class href='" . esc_url( add_query_arg( 'attendance_status', $status, $this->redirect ) ) . "'>".sprintf( _nx( ''.$desc.' <span class=count>(%s)</span>', ''.$desc.' <span class=count>(%s)</span>', $attendance_count[$status], 'posts' ), number_format_i18n( $attendance_count[$status] ) ) ."</a>";
            unset($class);
        }
        return $status_attendance;
    }
    /**
     * 这两个函数:get_status_count()和get_attendance_status()都是我自己定义的,非父类所要求,这个你可以跳过
     * get_status_count()and get_attendance_status() are not extended from father class,they are just my customizing functions,just skip
     */
    function get_status_count(){
        global $wpdb;
        $attendance_status=$this->get_attendance_status();
        foreach ($attendance_status as $status=>$desc){
            $status && $where=" WHERE status=".(int)$status;
            $count[$status]=$wpdb->get_var("SELECT count(par_id) sum FROM ".TABLE_PARTICIPTE_HISTORY." $where");
        }
        return $count;
    }
    function get_attendance_status(){
        return array(
            0=>"All",
            1=>"Attended",
            2=>"Has Singed"
        );
    }
    /**
     * 3.6
     * 这个方法主要是用来显示批量操作的,像批量删除、批量通过等等,以下拉列表的方式显示,我这里的identify主要是用于确认出席的操作
     * Override this method to return an associative array ( action_slug => action_title ) containing all the bulk actions available for the table.
     */
    function get_bulk_actions() {
        return array(
                'delete' => __( 'Delete' ),
                'identify' => __( 'Identified' )
        );
    }
    /**
     * 3.7
     * 主要显示thead的部分,懂吧?返回的格式就是我写的那样
     * This method should be overridden to return an associative array of columns.
     * The associative array should follow the format 'slug'=>'Title'
     * and is frequently used to provide part of the _column_headers property.
     */
    function get_columns() {
        return array(
                'cb'        => '<input type="checkbox" />',
                'par_posttitle'=>__('Items Name'),
                'par_username'=>__('User Name'),
                'get_sticker'=>__('Paid Sticker'),
                'par_type'=>__('Attendance Type'),
                'status'=>__('Status'),
                'par_time'=>__('Sing Time'),
        );
    }
     
    /**
     * 3.8
     * 此方法主要是用来列出那些字段需要排序的,也就是我们看到的table上面的thead上可以点击排序的那些字段
     * This method should be overridden to return an associative array of columns that you want to make sortable.
     * The associative array should follow the format 'column_slug'=>array('sortby',true),
     * where the second property states whether the field is presorted.
     * This is frequently used to provide part of the _column_headers property.
     */
    public function get_sortable_columns() {
        return array(
                'par_posttitle'=>array('par_posttitle',false),
                'par_time'=>array('par_time',false),
                'get_sticker'=>array('get_sticker',false),
        );
    }
     
    /**
     * 3.9
     * 主要是显示所有查询出来的的数据
     * This loops through the items property and renders them to the page as table rows.
     * Generally, you don't need to call this explicitly as it is handled automatically on display().
     */
    function display_rows() {
        foreach ( $this->items as $userid => $attendance_object ) {
            $style = ( ' class="alternate"' == $style ) ? '' : ' class="alternate"';
            echo "\n\t", $this->single_row( $attendance_object, $style);
        }
    }
     
    /**
     * 3.10
     * 主要是显示所有查询出来每一条数据
     * This echos a single item (from the items property) to the page.
     * Generally, you don't need to call this explicitly as it is handled automatically on display().
     */
    function single_row( $attendance_object, $style = '') {
        list( $columns, $hidden ) = $this->get_column_info();
        $r = "<tr id='atendance-$attendance_object->par_id'$style>";
        $checkbox = '<label class="screen-reader-text" for="cb-select-' . $attendance_object->par_id . '">' . sprintf( __( 'Select %s' ), $attendance_object->par_id ) . '</label>'
                . "<input type='checkbox' name='users[]' id='user_{$attendance_object-/>par_id}'  value='{$attendance_object->par_id}' />";
        $actions = array();
         
        $attendance_object->status==1&&$actions['identify'] = "<a href='" . wp_nonce_url( "$this->redirect&action=identify&users=$attendance_object->par_id", 'bulk-users' ) . "'>" . __( 'Identify' ) . "</a>";
        $actions['delete']   = "<a href='" . wp_nonce_url( "$this->redirect&action=delete&users=$attendance_object->par_id", 'bulk-users' ) . "'>" . __( 'Delete' ) . "</a>";
        $edit .= $this->row_actions( $actions );
        foreach ( $columns as $column_name => $column_display_name ) {
            $class = "class=\"$column_name column-$column_name\"";
            $style = '';
            if ( in_array( $column_name, $hidden ) )$style = ' style="display:none;"';
            $attributes = "$class$style";
            switch ( $column_name ) {
                case 'cb':
                    $r .= "<th scope='row' class='check-column'>$checkbox</th>";
                    break;
                case 'par_posttitle':
                    $r .= "<td $attributes>$attendance_object->par_posttitle  $edit</td>";
                    break;
                case 'par_type':
                    $estr=$attendance_object->par_type==CUSTOM_POST_TYPE1 ? "Event" : "Activity For ".$attendance_object->par_type;
                    $r .= "<td $attributes>$estr</td>";
                    break;
                case 'par_username':
                    $r .= "<td $attributes>$attendance_object->par_username</td>";
                    break;
                case 'par_time':
                    $r .= "<td $attributes>".date('d/m/Y H:i',$attendance_object->par_time)."</td>";
                    break;
                case 'get_sticker':
                    $r .= "<td $attributes>$attendance_object->get_sticker</td>";
                    break;
                case 'status':
                    $attendance_status=$this->get_attendance_status();
                    $s=$attendance_status[(int)$attendance_object->status] ? $attendance_status[(int)$attendance_object->status] : "unknown";
                    $r .= "<td $attributes>$s</td>";
                    break;
                default:
                    /**
                     * 3.11
                     * 解释下这里的manage_attendance_custom_column
                     */
                    $r .= "<td $attributes>";
                    $r .= apply_filters( 'manage_attendance_custom_column', '', $column_name, $attendance_object->par_id );
                    $r .= "</td>";
                    break;
            }
        }// end of foreach
        $r .= '</tr>';
        return $r;
    }// end of single_row
}// end of class
 
 
/**
 * ====================================================================================
 * --+  end of Attendance_List_Table       +--
 * --+  begin function to handle the list  +--
 * 下面我就列出你须要重新定义的方法,
 * I'll list the functions that must be over-ridden:
 * ajax_user_can,prepare_items,get_columns
 *
 *
 * 当你在制作一个简单的列表的时候需要定义一下胰腺癌方法
 * while you try to add a simple list,these are the one you should over ride
 * __construct,prepare_items,set_pagination_args,get_columns,display_rows,single_row
 * ====================================================================================
 */
 
 /**
  * 4.0
  * 在调用的地方需要的是,怎么去调用
  * how to user the class?
  * 4.1
  *     $wp_attendance_list_table=new Attendance_List_Table();
  *     $wp_attendance_list_table->prepare_items();
  *     <div class="wrap">
  *         <h2>title</h2>
  *         <form id="manage_attendence" action="" method="post">
  *             $wp_attendance_list_table->display();
  *         </form>
  *     </div>
  */
$wp_attendance_list_table=new Attendance_List_Table();
$wp_attendance_list_table->prepare_items();
if ( empty($_REQUEST) ) {
    $referer = '<input type="hidden" name="wp_http_referer" value="'. esc_attr(stripslashes($_SERVER['REQUEST_URI'])) . '" />';
} elseif ( isset($_REQUEST['wp_http_referer']) ) {
    $redirect = remove_query_arg(array('wp_http_referer', 'updated', 'delete_count'), stripslashes($_REQUEST['wp_http_referer']));
    $referer = '<input type="hidden" name="wp_http_referer" value="' . esc_attr($redirect) . '" />';
} else {
    $redirect = 'admin.php?page=manage_attendence';
}
global $wpdb;
$action = $wp_attendance_list_table->current_action()?$wp_attendance_list_table->current_action():trim($_REQUEST["action"]);
switch ( $action ) {
    case "delete":
        if ( empty($_REQUEST['users']) ) {
            wp_redirect($redirect);
            die();
        }
        $userids = array_map( 'intval', (array) $_REQUEST['users'] );
        $delete_count = 0;
        $update = 'del';
        foreach ( $userids as $id ) {
            $delete_count+=$wpdb->query("DELETE FROM ".TABLE_PARTICIPTE_HISTORY." WHERE par_id = $id ");
        }
         
        $redirect = add_query_arg( array('delete_count' => $delete_count, 'update' => $update), $redirect);
        wp_redirect($redirect);
        break
    ;
    case "identify":
        if ( empty($_REQUEST['users']) ) {
            wp_redirect($redirect);
            die();
        }
        $userids = array_map( 'intval', (array) $_REQUEST['users'] );
        $identify_count = 0;
        $update = 'identify';
        foreach ( $userids as $id ){
            $par_userid=$wpdb->get_var("SELECT par_userid FROM ".TABLE_PARTICIPTE_HISTORY." WHERE par_id = $id ");
            $pay_stickers=$wpdb->get_var("SELECT pay_stickers FROM ".TABLE_PARTICIPTE_HISTORY." WHERE par_id = $id ");
            $identify_count+=$wpdb->query("UPDATE ".TABLE_PARTICIPTE_HISTORY." SET status=2 WHERE par_id = $id ");
            if($identify_count){
                update_user_meta($par_userid, "available_stickers", intval(get_user_meta($par_userid,"available_stickers",true))+intval($pay_stickers) );
                update_user_meta($par_userid, "collected_stickers", intval(get_user_meta($par_userid,"collected_stickers",true))+intval($pay_stickers) );
            }
        }
         
        $redirect = add_query_arg( array('identify_count' => $identify_count, 'update' => $update), $redirect);
        wp_redirect($redirect);
        break
    ;
}
$messages = array();
if ( isset($_GET['update']) ) {
    switch($_GET['update']) {
        case 'del':
            $delete_count = isset($_GET['delete_count']) ? (int) $_GET['delete_count'] : 0;
            $messages[] = '<div id="message" class="updated"><p>' . sprintf( "%s attendaces deleted",  $delete_count  ) . '</p></div>';
            break;
        case 'identify':
            $identify_count = isset($_GET['identify_count']) ? (int) $_GET['identify_count'] : 0;
            $messages[] = '<div id="message" class="updated"><p>' . sprintf( '%s attendaces identify.', $identify_count  ) . '</p></div>';
            break;
    }
};
$attendance_search && $messages[] = printf( '<span class="subtitle">' . __('Search results for “%s”') . '</span>', esc_html( $attendance_search ) ); ;
empty($messages)&&$messages[] = '<div id="message" class="updated"><p>' . __( '"Identify" referes to confirming attendance.' ) . '</p></div>';
?>
< ?php if ( ! empty($messages) ) {foreach ( $messages as $msg )echo $msg;} ?>
<div class="wrap">
    < ?php screen_icon("users"); ?>
    <h2>< ?php _e('Manage Attendence'); ?></h2>
    < ?php $wp_attendance_list_table->views(); ?>
    <form id="manage_attendence" action="admin.php?page=manage_attendence" method="post">
    < ?php $wp_attendance_list_table->search_box( __( 'Search Attendence' ),'attendence' ); ?>
    < ?php $wp_attendance_list_table->display(); ?>
    </form>
    <br class="clear" />
</div>

有部分代码我是直接复制原来的,所以有的变量没变,其实也没啥的,能用就行,呵呵~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值