wp/wp-admin/includes/class-wp-list-table.php
changeset 5 5e2f62d02dcd
parent 0 d970ebf37754
child 7 cf61fcea0001
equal deleted inserted replaced
4:346c88efed21 5:5e2f62d02dcd
     1 <?php
     1 <?php
     2 /**
     2 /**
     3  * Base class for displaying a list of items in an ajaxified HTML table.
     3  * Base class for displaying a list of items in an ajaxified HTML table.
     4  *
     4  *
     5  * @package WordPress
       
     6  * @subpackage List_Table
       
     7  * @since 3.1.0
     5  * @since 3.1.0
     8  */
     6  * @access private
     9 
       
    10 /**
       
    11  * Base class for displaying a list of items in an ajaxified HTML table.
       
    12  *
     7  *
    13  * @package WordPress
     8  * @package WordPress
    14  * @subpackage List_Table
     9  * @subpackage List_Table
    15  * @since 3.1.0
       
    16  * @access private
       
    17  */
    10  */
    18 class WP_List_Table {
    11 class WP_List_Table {
    19 
    12 
    20 	/**
    13 	/**
    21 	 * The current list of items
    14 	 * The current list of items
    22 	 *
    15 	 *
    23 	 * @since 3.1.0
    16 	 * @since 3.1.0
    24 	 * @var array
    17 	 * @var array
    25 	 * @access protected
    18 	 * @access public
    26 	 */
    19 	 */
    27 	var $items;
    20 	public $items;
    28 
    21 
    29 	/**
    22 	/**
    30 	 * Various information about the current table
    23 	 * Various information about the current table
       
    24 	 *
       
    25 	 * @since 3.1.0
       
    26 	 * @var array
       
    27 	 * @access protected
       
    28 	 */
       
    29 	protected $_args;
       
    30 
       
    31 	/**
       
    32 	 * Various information needed for displaying the pagination
       
    33 	 *
       
    34 	 * @since 3.1.0
       
    35 	 * @var array
       
    36 	 */
       
    37 	protected $_pagination_args = array();
       
    38 
       
    39 	/**
       
    40 	 * The current screen
       
    41 	 *
       
    42 	 * @since 3.1.0
       
    43 	 * @var object
       
    44 	 * @access protected
       
    45 	 */
       
    46 	protected $screen;
       
    47 
       
    48 	/**
       
    49 	 * Cached bulk actions
    31 	 *
    50 	 *
    32 	 * @since 3.1.0
    51 	 * @since 3.1.0
    33 	 * @var array
    52 	 * @var array
    34 	 * @access private
    53 	 * @access private
    35 	 */
    54 	 */
    36 	var $_args;
    55 	private $_actions;
    37 
       
    38 	/**
       
    39 	 * Various information needed for displaying the pagination
       
    40 	 *
       
    41 	 * @since 3.1.0
       
    42 	 * @var array
       
    43 	 * @access private
       
    44 	 */
       
    45 	var $_pagination_args = array();
       
    46 
       
    47 	/**
       
    48 	 * The current screen
       
    49 	 *
       
    50 	 * @since 3.1.0
       
    51 	 * @var object
       
    52 	 * @access protected
       
    53 	 */
       
    54 	var $screen;
       
    55 
       
    56 	/**
       
    57 	 * Cached bulk actions
       
    58 	 *
       
    59 	 * @since 3.1.0
       
    60 	 * @var array
       
    61 	 * @access private
       
    62 	 */
       
    63 	var $_actions;
       
    64 
    56 
    65 	/**
    57 	/**
    66 	 * Cached pagination output
    58 	 * Cached pagination output
    67 	 *
    59 	 *
    68 	 * @since 3.1.0
    60 	 * @since 3.1.0
    69 	 * @var string
    61 	 * @var string
    70 	 * @access private
    62 	 * @access private
    71 	 */
    63 	 */
    72 	var $_pagination;
    64 	private $_pagination;
    73 
    65 
    74 	/**
    66 	/**
    75 	 * Constructor. The child class should call this constructor from its own constructor
    67 	 * The view switcher modes.
    76 	 *
    68 	 *
    77 	 * @param array $args An associative array with information about the current table
    69 	 * @since 4.1.0
    78 	 * @access protected
    70 	 * @var array
    79 	 */
    71 	 * @access protected
    80 	function __construct( $args = array() ) {
    72 	 */
       
    73 	protected $modes = array();
       
    74 
       
    75 	/**
       
    76 	 * Stores the value returned by ->get_column_info()
       
    77 	 *
       
    78 	 * @var array
       
    79 	 */
       
    80 	protected $_column_headers;
       
    81 
       
    82 	protected $compat_fields = array( '_args', '_pagination_args', 'screen', '_actions', '_pagination' );
       
    83 
       
    84 	protected $compat_methods = array( 'set_pagination_args', 'get_views', 'get_bulk_actions', 'bulk_actions',
       
    85 		'row_actions', 'months_dropdown', 'view_switcher', 'comments_bubble', 'get_items_per_page', 'pagination',
       
    86 		'get_sortable_columns', 'get_column_info', 'get_table_classes', 'display_tablenav', 'extra_tablenav',
       
    87 		'single_row_columns' );
       
    88 
       
    89 	/**
       
    90 	 * Constructor.
       
    91 	 *
       
    92 	 * The child class should call this constructor from its own constructor to override
       
    93 	 * the default $args.
       
    94 	 *
       
    95 	 * @since 3.1.0
       
    96 	 * @access public
       
    97 	 *
       
    98 	 * @param array|string $args {
       
    99 	 *     Array or string of arguments.
       
   100 	 *
       
   101 	 *     @type string $plural   Plural value used for labels and the objects being listed.
       
   102 	 *                            This affects things such as CSS class-names and nonces used
       
   103 	 *                            in the list table, e.g. 'posts'. Default empty.
       
   104 	 *     @type string $singular Singular label for an object being listed, e.g. 'post'.
       
   105 	 *                            Default empty
       
   106 	 *     @type bool   $ajax     Whether the list table supports AJAX. This includes loading
       
   107 	 *                            and sorting data, for example. If true, the class will call
       
   108 	 *                            the {@see _js_vars()} method in the footer to provide variables
       
   109 	 *                            to any scripts handling AJAX events. Default false.
       
   110 	 *     @type string $screen   String containing the hook name used to determine the current
       
   111 	 *                            screen. If left null, the current screen will be automatically set.
       
   112 	 *                            Default null.
       
   113 	 * }
       
   114 	 */
       
   115 	public function __construct( $args = array() ) {
    81 		$args = wp_parse_args( $args, array(
   116 		$args = wp_parse_args( $args, array(
    82 			'plural' => '',
   117 			'plural' => '',
    83 			'singular' => '',
   118 			'singular' => '',
    84 			'ajax' => false,
   119 			'ajax' => false,
    85 			'screen' => null,
   120 			'screen' => null,
    99 
   134 
   100 		if ( $args['ajax'] ) {
   135 		if ( $args['ajax'] ) {
   101 			// wp_enqueue_script( 'list-table' );
   136 			// wp_enqueue_script( 'list-table' );
   102 			add_action( 'admin_footer', array( $this, '_js_vars' ) );
   137 			add_action( 'admin_footer', array( $this, '_js_vars' ) );
   103 		}
   138 		}
       
   139 
       
   140 		if ( empty( $this->modes ) ) {
       
   141 			$this->modes = array(
       
   142 				'list'    => __( 'List View' ),
       
   143 				'excerpt' => __( 'Excerpt View' )
       
   144 			);
       
   145 		}
       
   146 	}
       
   147 
       
   148 	/**
       
   149 	 * Make private properties readable for backwards compatibility.
       
   150 	 *
       
   151 	 * @since 4.0.0
       
   152 	 * @access public
       
   153 	 *
       
   154 	 * @param string $name Property to get.
       
   155 	 * @return mixed Property.
       
   156 	 */
       
   157 	public function __get( $name ) {
       
   158 		if ( in_array( $name, $this->compat_fields ) ) {
       
   159 			return $this->$name;
       
   160 		}
       
   161 	}
       
   162 
       
   163 	/**
       
   164 	 * Make private properties settable for backwards compatibility.
       
   165 	 *
       
   166 	 * @since 4.0.0
       
   167 	 * @access public
       
   168 	 *
       
   169 	 * @param string $name  Property to check if set.
       
   170 	 * @param mixed  $value Property value.
       
   171 	 * @return mixed Newly-set property.
       
   172 	 */
       
   173 	public function __set( $name, $value ) {
       
   174 		if ( in_array( $name, $this->compat_fields ) ) {
       
   175 			return $this->$name = $value;
       
   176 		}
       
   177 	}
       
   178 
       
   179 	/**
       
   180 	 * Make private properties checkable for backwards compatibility.
       
   181 	 *
       
   182 	 * @since 4.0.0
       
   183 	 * @access public
       
   184 	 *
       
   185 	 * @param string $name Property to check if set.
       
   186 	 * @return bool Whether the property is set.
       
   187 	 */
       
   188 	public function __isset( $name ) {
       
   189 		if ( in_array( $name, $this->compat_fields ) ) {
       
   190 			return isset( $this->$name );
       
   191 		}
       
   192 	}
       
   193 
       
   194 	/**
       
   195 	 * Make private properties un-settable for backwards compatibility.
       
   196 	 *
       
   197 	 * @since 4.0.0
       
   198 	 * @access public
       
   199 	 *
       
   200 	 * @param string $name Property to unset.
       
   201 	 */
       
   202 	public function __unset( $name ) {
       
   203 		if ( in_array( $name, $this->compat_fields ) ) {
       
   204 			unset( $this->$name );
       
   205 		}
       
   206 	}
       
   207 
       
   208 	/**
       
   209 	 * Make private/protected methods readable for backwards compatibility.
       
   210 	 *
       
   211 	 * @since 4.0.0
       
   212 	 * @access public
       
   213 	 *
       
   214 	 * @param callable $name      Method to call.
       
   215 	 * @param array    $arguments Arguments to pass when calling.
       
   216 	 * @return mixed|bool Return value of the callback, false otherwise.
       
   217 	 */
       
   218 	public function __call( $name, $arguments ) {
       
   219 		if ( in_array( $name, $this->compat_methods ) ) {
       
   220 			return call_user_func_array( array( $this, $name ), $arguments );
       
   221 		}
       
   222 		return false;
   104 	}
   223 	}
   105 
   224 
   106 	/**
   225 	/**
   107 	 * Checks the current user's permissions
   226 	 * Checks the current user's permissions
   108 	 * @uses wp_die()
       
   109 	 *
   227 	 *
   110 	 * @since 3.1.0
   228 	 * @since 3.1.0
   111 	 * @access public
   229 	 * @access public
   112 	 * @abstract
   230 	 * @abstract
   113 	 */
   231 	 */
   114 	function ajax_user_can() {
   232 	public function ajax_user_can() {
   115 		die( 'function WP_List_Table::ajax_user_can() must be over-ridden in a sub-class.' );
   233 		die( 'function WP_List_Table::ajax_user_can() must be over-ridden in a sub-class.' );
   116 	}
   234 	}
   117 
   235 
   118 	/**
   236 	/**
   119 	 * Prepares the list of items for displaying.
   237 	 * Prepares the list of items for displaying.
   121 	 *
   239 	 *
   122 	 * @since 3.1.0
   240 	 * @since 3.1.0
   123 	 * @access public
   241 	 * @access public
   124 	 * @abstract
   242 	 * @abstract
   125 	 */
   243 	 */
   126 	function prepare_items() {
   244 	public function prepare_items() {
   127 		die( 'function WP_List_Table::prepare_items() must be over-ridden in a sub-class.' );
   245 		die( 'function WP_List_Table::prepare_items() must be over-ridden in a sub-class.' );
   128 	}
   246 	}
   129 
   247 
   130 	/**
   248 	/**
   131 	 * An internal method that sets all the necessary pagination arguments
   249 	 * An internal method that sets all the necessary pagination arguments
   132 	 *
   250 	 *
   133 	 * @param array $args An associative array with information about the pagination
   251 	 * @param array $args An associative array with information about the pagination
   134 	 * @access protected
   252 	 * @access protected
   135 	 */
   253 	 */
   136 	function set_pagination_args( $args ) {
   254 	protected function set_pagination_args( $args ) {
   137 		$args = wp_parse_args( $args, array(
   255 		$args = wp_parse_args( $args, array(
   138 			'total_items' => 0,
   256 			'total_items' => 0,
   139 			'total_pages' => 0,
   257 			'total_pages' => 0,
   140 			'per_page' => 0,
   258 			'per_page' => 0,
   141 		) );
   259 		) );
   142 
   260 
   143 		if ( !$args['total_pages'] && $args['per_page'] > 0 )
   261 		if ( !$args['total_pages'] && $args['per_page'] > 0 )
   144 			$args['total_pages'] = ceil( $args['total_items'] / $args['per_page'] );
   262 			$args['total_pages'] = ceil( $args['total_items'] / $args['per_page'] );
   145 
   263 
   146 		// redirect if page number is invalid and headers are not already sent
   264 		// Redirect if page number is invalid and headers are not already sent.
   147 		if ( ! headers_sent() && ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages'] ) {
   265 		if ( ! headers_sent() && ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages'] ) {
   148 			wp_redirect( add_query_arg( 'paged', $args['total_pages'] ) );
   266 			wp_redirect( add_query_arg( 'paged', $args['total_pages'] ) );
   149 			exit;
   267 			exit;
   150 		}
   268 		}
   151 
   269 
   152 		$this->_pagination_args = $args;
   270 		$this->_pagination_args = $args;
   153 	}
   271 	}
   154 
   272 
   155 	/**
   273 	/**
   156 	 * Access the pagination args
   274 	 * Access the pagination args.
   157 	 *
   275 	 *
   158 	 * @since 3.1.0
   276 	 * @since 3.1.0
   159 	 * @access public
   277 	 * @access public
   160 	 *
   278 	 *
   161 	 * @param string $key
   279 	 * @param string $key Pagination argument to retrieve. Common values include 'total_items',
   162 	 * @return array
   280 	 *                    'total_pages', 'per_page', or 'infinite_scroll'.
   163 	 */
   281 	 * @return int Number of items that correspond to the given pagination argument.
   164 	function get_pagination_arg( $key ) {
   282 	 */
       
   283 	public function get_pagination_arg( $key ) {
   165 		if ( 'page' == $key )
   284 		if ( 'page' == $key )
   166 			return $this->get_pagenum();
   285 			return $this->get_pagenum();
   167 
   286 
   168 		if ( isset( $this->_pagination_args[$key] ) )
   287 		if ( isset( $this->_pagination_args[$key] ) )
   169 			return $this->_pagination_args[$key];
   288 			return $this->_pagination_args[$key];
   175 	 * @since 3.1.0
   294 	 * @since 3.1.0
   176 	 * @access public
   295 	 * @access public
   177 	 *
   296 	 *
   178 	 * @return bool
   297 	 * @return bool
   179 	 */
   298 	 */
   180 	function has_items() {
   299 	public function has_items() {
   181 		return !empty( $this->items );
   300 		return !empty( $this->items );
   182 	}
   301 	}
   183 
   302 
   184 	/**
   303 	/**
   185 	 * Message to be displayed when there are no items
   304 	 * Message to be displayed when there are no items
   186 	 *
   305 	 *
   187 	 * @since 3.1.0
   306 	 * @since 3.1.0
   188 	 * @access public
   307 	 * @access public
   189 	 */
   308 	 */
   190 	function no_items() {
   309 	public function no_items() {
   191 		_e( 'No items found.' );
   310 		_e( 'No items found.' );
   192 	}
   311 	}
   193 
   312 
   194 	/**
   313 	/**
   195 	 * Display the search box.
   314 	 * Display the search box.
   198 	 * @access public
   317 	 * @access public
   199 	 *
   318 	 *
   200 	 * @param string $text The search button text
   319 	 * @param string $text The search button text
   201 	 * @param string $input_id The search input id
   320 	 * @param string $input_id The search input id
   202 	 */
   321 	 */
   203 	function search_box( $text, $input_id ) {
   322 	public function search_box( $text, $input_id ) {
   204 		if ( empty( $_REQUEST['s'] ) && !$this->has_items() )
   323 		if ( empty( $_REQUEST['s'] ) && !$this->has_items() )
   205 			return;
   324 			return;
   206 
   325 
   207 		$input_id = $input_id . '-search-input';
   326 		$input_id = $input_id . '-search-input';
   208 
   327 
   216 			echo '<input type="hidden" name="detached" value="' . esc_attr( $_REQUEST['detached'] ) . '" />';
   335 			echo '<input type="hidden" name="detached" value="' . esc_attr( $_REQUEST['detached'] ) . '" />';
   217 ?>
   336 ?>
   218 <p class="search-box">
   337 <p class="search-box">
   219 	<label class="screen-reader-text" for="<?php echo $input_id ?>"><?php echo $text; ?>:</label>
   338 	<label class="screen-reader-text" for="<?php echo $input_id ?>"><?php echo $text; ?>:</label>
   220 	<input type="search" id="<?php echo $input_id ?>" name="s" value="<?php _admin_search_query(); ?>" />
   339 	<input type="search" id="<?php echo $input_id ?>" name="s" value="<?php _admin_search_query(); ?>" />
   221 	<?php submit_button( $text, 'button', false, false, array('id' => 'search-submit') ); ?>
   340 	<?php submit_button( $text, 'button', '', false, array('id' => 'search-submit') ); ?>
   222 </p>
   341 </p>
   223 <?php
   342 <?php
   224 	}
   343 	}
   225 
   344 
   226 	/**
   345 	/**
   230 	 * @since 3.1.0
   349 	 * @since 3.1.0
   231 	 * @access protected
   350 	 * @access protected
   232 	 *
   351 	 *
   233 	 * @return array
   352 	 * @return array
   234 	 */
   353 	 */
   235 	function get_views() {
   354 	protected function get_views() {
   236 		return array();
   355 		return array();
   237 	}
   356 	}
   238 
   357 
   239 	/**
   358 	/**
   240 	 * Display the list of views available on this table.
   359 	 * Display the list of views available on this table.
   241 	 *
   360 	 *
   242 	 * @since 3.1.0
   361 	 * @since 3.1.0
   243 	 * @access public
   362 	 * @access public
   244 	 */
   363 	 */
   245 	function views() {
   364 	public function views() {
   246 		$views = $this->get_views();
   365 		$views = $this->get_views();
   247 		$views = apply_filters( 'views_' . $this->screen->id, $views );
   366 		/**
       
   367 		 * Filter the list of available list table views.
       
   368 		 *
       
   369 		 * The dynamic portion of the hook name, `$this->screen->id`, refers
       
   370 		 * to the ID of the current screen, usually a string.
       
   371 		 *
       
   372 		 * @since 3.5.0
       
   373 		 *
       
   374 		 * @param array $views An array of available list table views.
       
   375 		 */
       
   376 		$views = apply_filters( "views_{$this->screen->id}", $views );
   248 
   377 
   249 		if ( empty( $views ) )
   378 		if ( empty( $views ) )
   250 			return;
   379 			return;
   251 
   380 
   252 		echo "<ul class='subsubsub'>\n";
   381 		echo "<ul class='subsubsub'>\n";
   264 	 * @since 3.1.0
   393 	 * @since 3.1.0
   265 	 * @access protected
   394 	 * @access protected
   266 	 *
   395 	 *
   267 	 * @return array
   396 	 * @return array
   268 	 */
   397 	 */
   269 	function get_bulk_actions() {
   398 	protected function get_bulk_actions() {
   270 		return array();
   399 		return array();
   271 	}
   400 	}
   272 
   401 
   273 	/**
   402 	/**
   274 	 * Display the bulk actions dropdown.
   403 	 * Display the bulk actions dropdown.
   275 	 *
   404 	 *
   276 	 * @since 3.1.0
   405 	 * @since 3.1.0
   277 	 * @access public
   406 	 * @access protected
   278 	 */
   407 	 *
   279 	function bulk_actions() {
   408 	 * @param string $which The location of the bulk actions: 'top' or 'bottom'.
       
   409 	 *                      This is designated as optional for backwards-compatibility.
       
   410 	 */
       
   411 	protected function bulk_actions( $which = '' ) {
   280 		if ( is_null( $this->_actions ) ) {
   412 		if ( is_null( $this->_actions ) ) {
   281 			$no_new_actions = $this->_actions = $this->get_bulk_actions();
   413 			$no_new_actions = $this->_actions = $this->get_bulk_actions();
   282 			// This filter can currently only be used to remove actions.
   414 			/**
   283 			$this->_actions = apply_filters( 'bulk_actions-' . $this->screen->id, $this->_actions );
   415 			 * Filter the list table Bulk Actions drop-down.
       
   416 			 *
       
   417 			 * The dynamic portion of the hook name, `$this->screen->id`, refers
       
   418 			 * to the ID of the current screen, usually a string.
       
   419 			 *
       
   420 			 * This filter can currently only be used to remove bulk actions.
       
   421 			 *
       
   422 			 * @since 3.5.0
       
   423 			 *
       
   424 			 * @param array $actions An array of the available bulk actions.
       
   425 			 */
       
   426 			$this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions );
   284 			$this->_actions = array_intersect_assoc( $this->_actions, $no_new_actions );
   427 			$this->_actions = array_intersect_assoc( $this->_actions, $no_new_actions );
   285 			$two = '';
   428 			$two = '';
   286 		} else {
   429 		} else {
   287 			$two = '2';
   430 			$two = '2';
   288 		}
   431 		}
   289 
   432 
   290 		if ( empty( $this->_actions ) )
   433 		if ( empty( $this->_actions ) )
   291 			return;
   434 			return;
   292 
   435 
   293 		echo "<select name='action$two'>\n";
   436 		echo "<label for='bulk-action-selector-" . esc_attr( $which ) . "' class='screen-reader-text'>" . __( 'Select bulk action' ) . "</label>";
       
   437 		echo "<select name='action$two' id='bulk-action-selector-" . esc_attr( $which ) . "'>\n";
   294 		echo "<option value='-1' selected='selected'>" . __( 'Bulk Actions' ) . "</option>\n";
   438 		echo "<option value='-1' selected='selected'>" . __( 'Bulk Actions' ) . "</option>\n";
   295 
   439 
   296 		foreach ( $this->_actions as $name => $title ) {
   440 		foreach ( $this->_actions as $name => $title ) {
   297 			$class = 'edit' == $name ? ' class="hide-if-no-js"' : '';
   441 			$class = 'edit' == $name ? ' class="hide-if-no-js"' : '';
   298 
   442 
   299 			echo "\t<option value='$name'$class>$title</option>\n";
   443 			echo "\t<option value='$name'$class>$title</option>\n";
   300 		}
   444 		}
   301 
   445 
   302 		echo "</select>\n";
   446 		echo "</select>\n";
   303 
   447 
   304 		submit_button( __( 'Apply' ), 'action', false, false, array( 'id' => "doaction$two" ) );
   448 		submit_button( __( 'Apply' ), 'action', '', false, array( 'id' => "doaction$two" ) );
   305 		echo "\n";
   449 		echo "\n";
   306 	}
   450 	}
   307 
   451 
   308 	/**
   452 	/**
   309 	 * Get the current action selected from the bulk actions dropdown.
   453 	 * Get the current action selected from the bulk actions dropdown.
   311 	 * @since 3.1.0
   455 	 * @since 3.1.0
   312 	 * @access public
   456 	 * @access public
   313 	 *
   457 	 *
   314 	 * @return string|bool The action name or False if no action was selected
   458 	 * @return string|bool The action name or False if no action was selected
   315 	 */
   459 	 */
   316 	function current_action() {
   460 	public function current_action() {
       
   461 		if ( isset( $_REQUEST['filter_action'] ) && ! empty( $_REQUEST['filter_action'] ) )
       
   462 			return false;
       
   463 
   317 		if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] )
   464 		if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] )
   318 			return $_REQUEST['action'];
   465 			return $_REQUEST['action'];
   319 
   466 
   320 		if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] )
   467 		if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] )
   321 			return $_REQUEST['action2'];
   468 			return $_REQUEST['action2'];
   331 	 *
   478 	 *
   332 	 * @param array $actions The list of actions
   479 	 * @param array $actions The list of actions
   333 	 * @param bool $always_visible Whether the actions should be always visible
   480 	 * @param bool $always_visible Whether the actions should be always visible
   334 	 * @return string
   481 	 * @return string
   335 	 */
   482 	 */
   336 	function row_actions( $actions, $always_visible = false ) {
   483 	protected function row_actions( $actions, $always_visible = false ) {
   337 		$action_count = count( $actions );
   484 		$action_count = count( $actions );
   338 		$i = 0;
   485 		$i = 0;
   339 
   486 
   340 		if ( !$action_count )
   487 		if ( !$action_count )
   341 			return '';
   488 			return '';
   354 	/**
   501 	/**
   355 	 * Display a monthly dropdown for filtering items
   502 	 * Display a monthly dropdown for filtering items
   356 	 *
   503 	 *
   357 	 * @since 3.1.0
   504 	 * @since 3.1.0
   358 	 * @access protected
   505 	 * @access protected
   359 	 */
   506 	 *
   360 	function months_dropdown( $post_type ) {
   507 	 * @param string $post_type
       
   508 	 */
       
   509 	protected function months_dropdown( $post_type ) {
   361 		global $wpdb, $wp_locale;
   510 		global $wpdb, $wp_locale;
       
   511 
       
   512 		/**
       
   513 		 * Filter whether to remove the 'Months' drop-down from the post list table.
       
   514 		 *
       
   515 		 * @since 4.2.0
       
   516 		 *
       
   517 		 * @param bool   $disable   Whether to disable the drop-down. Default false.
       
   518 		 * @param string $post_type The post type.
       
   519 		 */
       
   520 		if ( apply_filters( 'disable_months_dropdown', false, $post_type ) ) {
       
   521 			return;
       
   522 		}
   362 
   523 
   363 		$months = $wpdb->get_results( $wpdb->prepare( "
   524 		$months = $wpdb->get_results( $wpdb->prepare( "
   364 			SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
   525 			SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
   365 			FROM $wpdb->posts
   526 			FROM $wpdb->posts
   366 			WHERE post_type = %s
   527 			WHERE post_type = %s
   367 			ORDER BY post_date DESC
   528 			ORDER BY post_date DESC
   368 		", $post_type ) );
   529 		", $post_type ) );
   369 
   530 
   370 		/**
   531 		/**
   371 		 * Filter the months dropdown results.
   532 		 * Filter the 'Months' drop-down results.
   372 		 *
   533 		 *
   373 		 * @since 3.7.0
   534 		 * @since 3.7.0
   374 		 *
   535 		 *
   375 		 * @param object $months    The months dropdown query results.
   536 		 * @param object $months    The months drop-down query results.
   376 		 * @param string $post_type The post type.
   537 		 * @param string $post_type The post type.
   377 		 */
   538 		 */
   378 		$months = apply_filters( 'months_dropdown_results', $months, $post_type );
   539 		$months = apply_filters( 'months_dropdown_results', $months, $post_type );
   379 
   540 
   380 		$month_count = count( $months );
   541 		$month_count = count( $months );
   382 		if ( !$month_count || ( 1 == $month_count && 0 == $months[0]->month ) )
   543 		if ( !$month_count || ( 1 == $month_count && 0 == $months[0]->month ) )
   383 			return;
   544 			return;
   384 
   545 
   385 		$m = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0;
   546 		$m = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0;
   386 ?>
   547 ?>
   387 		<select name='m'>
   548 		<label for="filter-by-date" class="screen-reader-text"><?php _e( 'Filter by date' ); ?></label>
   388 			<option<?php selected( $m, 0 ); ?> value='0'><?php _e( 'Show all dates' ); ?></option>
   549 		<select name="m" id="filter-by-date">
       
   550 			<option<?php selected( $m, 0 ); ?> value="0"><?php _e( 'All dates' ); ?></option>
   389 <?php
   551 <?php
   390 		foreach ( $months as $arc_row ) {
   552 		foreach ( $months as $arc_row ) {
   391 			if ( 0 == $arc_row->year )
   553 			if ( 0 == $arc_row->year )
   392 				continue;
   554 				continue;
   393 
   555 
   409 	/**
   571 	/**
   410 	 * Display a view switcher
   572 	 * Display a view switcher
   411 	 *
   573 	 *
   412 	 * @since 3.1.0
   574 	 * @since 3.1.0
   413 	 * @access protected
   575 	 * @access protected
   414 	 */
   576 	 *
   415 	function view_switcher( $current_mode ) {
   577 	 * @param string $current_mode
   416 		$modes = array(
   578 	 */
   417 			'list'    => __( 'List View' ),
   579 	protected function view_switcher( $current_mode ) {
   418 			'excerpt' => __( 'Excerpt View' )
       
   419 		);
       
   420 
       
   421 ?>
   580 ?>
   422 		<input type="hidden" name="mode" value="<?php echo esc_attr( $current_mode ); ?>" />
   581 		<input type="hidden" name="mode" value="<?php echo esc_attr( $current_mode ); ?>" />
   423 		<div class="view-switch">
   582 		<div class="view-switch">
   424 <?php
   583 <?php
   425 			foreach ( $modes as $mode => $title ) {
   584 			foreach ( $this->modes as $mode => $title ) {
   426 				$class = ( $current_mode == $mode ) ? 'class="current"' : '';
   585 				$classes = array( 'view-' . $mode );
   427 				echo "<a href='" . esc_url( add_query_arg( 'mode', $mode, $_SERVER['REQUEST_URI'] ) ) . "' $class><img id='view-switch-$mode' src='" . esc_url( includes_url( 'images/blank.gif' ) ) . "' width='20' height='20' title='$title' alt='$title' /></a>\n";
   586 				if ( $current_mode == $mode )
       
   587 					$classes[] = 'current';
       
   588 				printf(
       
   589 					"<a href='%s' class='%s' id='view-switch-$mode'><span class='screen-reader-text'>%s</span></a>\n",
       
   590 					esc_url( add_query_arg( 'mode', $mode ) ),
       
   591 					implode( ' ', $classes ),
       
   592 					$title
       
   593 				);
   428 			}
   594 			}
   429 		?>
   595 		?>
   430 		</div>
   596 		</div>
   431 <?php
   597 <?php
   432 	}
   598 	}
   435 	 * Display a comment count bubble
   601 	 * Display a comment count bubble
   436 	 *
   602 	 *
   437 	 * @since 3.1.0
   603 	 * @since 3.1.0
   438 	 * @access protected
   604 	 * @access protected
   439 	 *
   605 	 *
   440 	 * @param int $post_id
   606 	 * @param int $post_id          The post ID.
   441 	 * @param int $pending_comments
   607 	 * @param int $pending_comments Number of pending comments.
   442 	 */
   608 	 */
   443 	function comments_bubble( $post_id, $pending_comments ) {
   609 	protected function comments_bubble( $post_id, $pending_comments ) {
   444 		$pending_phrase = sprintf( __( '%s pending' ), number_format( $pending_comments ) );
   610 		$pending_phrase = sprintf( __( '%s pending' ), number_format( $pending_comments ) );
   445 
   611 
   446 		if ( $pending_comments )
   612 		if ( $pending_comments )
   447 			echo '<strong>';
   613 			echo '<strong>';
   448 
   614 
   454 
   620 
   455 	/**
   621 	/**
   456 	 * Get the current page number
   622 	 * Get the current page number
   457 	 *
   623 	 *
   458 	 * @since 3.1.0
   624 	 * @since 3.1.0
   459 	 * @access protected
   625 	 * @access public
   460 	 *
   626 	 *
   461 	 * @return int
   627 	 * @return int
   462 	 */
   628 	 */
   463 	function get_pagenum() {
   629 	public function get_pagenum() {
   464 		$pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0;
   630 		$pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0;
   465 
   631 
   466 		if( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] )
   632 		if( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] )
   467 			$pagenum = $this->_pagination_args['total_pages'];
   633 			$pagenum = $this->_pagination_args['total_pages'];
   468 
   634 
   473 	 * Get number of items to display on a single page
   639 	 * Get number of items to display on a single page
   474 	 *
   640 	 *
   475 	 * @since 3.1.0
   641 	 * @since 3.1.0
   476 	 * @access protected
   642 	 * @access protected
   477 	 *
   643 	 *
       
   644 	 * @param string $option
       
   645 	 * @param int    $default
   478 	 * @return int
   646 	 * @return int
   479 	 */
   647 	 */
   480 	function get_items_per_page( $option, $default = 20 ) {
   648 	protected function get_items_per_page( $option, $default = 20 ) {
   481 		$per_page = (int) get_user_option( $option );
   649 		$per_page = (int) get_user_option( $option );
   482 		if ( empty( $per_page ) || $per_page < 1 )
   650 		if ( empty( $per_page ) || $per_page < 1 )
   483 			$per_page = $default;
   651 			$per_page = $default;
   484 
   652 
       
   653 		/**
       
   654 		 * Filter the number of items to be displayed on each page of the list table.
       
   655 		 *
       
   656 		 * The dynamic hook name, $option, refers to the `per_page` option depending
       
   657 		 * on the type of list table in use. Possible values include: 'edit_comments_per_page',
       
   658 		 * 'sites_network_per_page', 'site_themes_network_per_page', 'themes_network_per_page',
       
   659 		 * 'users_network_per_page', 'edit_post_per_page', 'edit_page_per_page',
       
   660 		 * 'edit_{$post_type}_per_page', etc.
       
   661 		 *
       
   662 		 * @since 2.9.0
       
   663 		 *
       
   664 		 * @param int $per_page Number of items to be displayed. Default 20.
       
   665 		 */
   485 		return (int) apply_filters( $option, $per_page );
   666 		return (int) apply_filters( $option, $per_page );
   486 	}
   667 	}
   487 
   668 
   488 	/**
   669 	/**
   489 	 * Display the pagination.
   670 	 * Display the pagination.
   490 	 *
   671 	 *
   491 	 * @since 3.1.0
   672 	 * @since 3.1.0
   492 	 * @access protected
   673 	 * @access protected
   493 	 */
   674 	 *
   494 	function pagination( $which ) {
   675 	 * @param string $which
   495 		if ( empty( $this->_pagination_args ) )
   676 	 */
       
   677 	protected function pagination( $which ) {
       
   678 		if ( empty( $this->_pagination_args ) ) {
   496 			return;
   679 			return;
   497 
   680 		}
   498 		extract( $this->_pagination_args, EXTR_SKIP );
   681 
       
   682 		$total_items = $this->_pagination_args['total_items'];
       
   683 		$total_pages = $this->_pagination_args['total_pages'];
       
   684 		$infinite_scroll = false;
       
   685 		if ( isset( $this->_pagination_args['infinite_scroll'] ) ) {
       
   686 			$infinite_scroll = $this->_pagination_args['infinite_scroll'];
       
   687 		}
   499 
   688 
   500 		$output = '<span class="displaying-num">' . sprintf( _n( '1 item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . '</span>';
   689 		$output = '<span class="displaying-num">' . sprintf( _n( '1 item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . '</span>';
   501 
   690 
   502 		$current = $this->get_pagenum();
   691 		$current = $this->get_pagenum();
   503 
   692 
   506 		$current_url = remove_query_arg( array( 'hotkeys_highlight_last', 'hotkeys_highlight_first' ), $current_url );
   695 		$current_url = remove_query_arg( array( 'hotkeys_highlight_last', 'hotkeys_highlight_first' ), $current_url );
   507 
   696 
   508 		$page_links = array();
   697 		$page_links = array();
   509 
   698 
   510 		$disable_first = $disable_last = '';
   699 		$disable_first = $disable_last = '';
   511 		if ( $current == 1 )
   700 		if ( $current == 1 ) {
   512 			$disable_first = ' disabled';
   701 			$disable_first = ' disabled';
   513 		if ( $current == $total_pages )
   702 		}
       
   703 		if ( $current == $total_pages ) {
   514 			$disable_last = ' disabled';
   704 			$disable_last = ' disabled';
   515 
   705 		}
   516 		$page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
   706 		$page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
   517 			'first-page' . $disable_first,
   707 			'first-page' . $disable_first,
   518 			esc_attr__( 'Go to the first page' ),
   708 			esc_attr__( 'Go to the first page' ),
   519 			esc_url( remove_query_arg( 'paged', $current_url ) ),
   709 			esc_url( remove_query_arg( 'paged', $current_url ) ),
   520 			'&laquo;'
   710 			'&laquo;'
   525 			esc_attr__( 'Go to the previous page' ),
   715 			esc_attr__( 'Go to the previous page' ),
   526 			esc_url( add_query_arg( 'paged', max( 1, $current-1 ), $current_url ) ),
   716 			esc_url( add_query_arg( 'paged', max( 1, $current-1 ), $current_url ) ),
   527 			'&lsaquo;'
   717 			'&lsaquo;'
   528 		);
   718 		);
   529 
   719 
   530 		if ( 'bottom' == $which )
   720 		if ( 'bottom' == $which ) {
   531 			$html_current_page = $current;
   721 			$html_current_page = $current;
   532 		else
   722 		} else {
   533 			$html_current_page = sprintf( "<input class='current-page' title='%s' type='text' name='paged' value='%s' size='%d' />",
   723 			$html_current_page = sprintf( "%s<input class='current-page' id='current-page-selector' title='%s' type='text' name='paged' value='%s' size='%d' />",
       
   724 				'<label for="current-page-selector" class="screen-reader-text">' . __( 'Select Page' ) . '</label>',
   534 				esc_attr__( 'Current page' ),
   725 				esc_attr__( 'Current page' ),
   535 				$current,
   726 				$current,
   536 				strlen( $total_pages )
   727 				strlen( $total_pages )
   537 			);
   728 			);
   538 
   729 		}
   539 		$html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) );
   730 		$html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) );
   540 		$page_links[] = '<span class="paging-input">' . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . '</span>';
   731 		$page_links[] = '<span class="paging-input">' . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . '</span>';
   541 
   732 
   542 		$page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
   733 		$page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
   543 			'next-page' . $disable_last,
   734 			'next-page' . $disable_last,
   552 			esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ),
   743 			esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ),
   553 			'&raquo;'
   744 			'&raquo;'
   554 		);
   745 		);
   555 
   746 
   556 		$pagination_links_class = 'pagination-links';
   747 		$pagination_links_class = 'pagination-links';
   557 		if ( ! empty( $infinite_scroll ) )
   748 		if ( ! empty( $infinite_scroll ) ) {
   558 			$pagination_links_class = ' hide-if-js';
   749 			$pagination_links_class = ' hide-if-js';
       
   750 		}
   559 		$output .= "\n<span class='$pagination_links_class'>" . join( "\n", $page_links ) . '</span>';
   751 		$output .= "\n<span class='$pagination_links_class'>" . join( "\n", $page_links ) . '</span>';
   560 
   752 
   561 		if ( $total_pages )
   753 		if ( $total_pages ) {
   562 			$page_class = $total_pages < 2 ? ' one-page' : '';
   754 			$page_class = $total_pages < 2 ? ' one-page' : '';
   563 		else
   755 		} else {
   564 			$page_class = ' no-pages';
   756 			$page_class = ' no-pages';
   565 
   757 		}
   566 		$this->_pagination = "<div class='tablenav-pages{$page_class}'>$output</div>";
   758 		$this->_pagination = "<div class='tablenav-pages{$page_class}'>$output</div>";
   567 
   759 
   568 		echo $this->_pagination;
   760 		echo $this->_pagination;
   569 	}
   761 	}
   570 
   762 
   571 	/**
   763 	/**
   572 	 * Get a list of columns. The format is:
   764 	 * Get a list of columns. The format is:
   573 	 * 'internal-name' => 'Title'
   765 	 * 'internal-name' => 'Title'
   574 	 *
   766 	 *
   575 	 * @since 3.1.0
   767 	 * @since 3.1.0
   576 	 * @access protected
   768 	 * @access public
   577 	 * @abstract
   769 	 * @abstract
   578 	 *
   770 	 *
   579 	 * @return array
   771 	 * @return array
   580 	 */
   772 	 */
   581 	function get_columns() {
   773 	public function get_columns() {
   582 		die( 'function WP_List_Table::get_columns() must be over-ridden in a sub-class.' );
   774 		die( 'function WP_List_Table::get_columns() must be over-ridden in a sub-class.' );
   583 	}
   775 	}
   584 
   776 
   585 	/**
   777 	/**
   586 	 * Get a list of sortable columns. The format is:
   778 	 * Get a list of sortable columns. The format is:
   593 	 * @since 3.1.0
   785 	 * @since 3.1.0
   594 	 * @access protected
   786 	 * @access protected
   595 	 *
   787 	 *
   596 	 * @return array
   788 	 * @return array
   597 	 */
   789 	 */
   598 	function get_sortable_columns() {
   790 	protected function get_sortable_columns() {
   599 		return array();
   791 		return array();
   600 	}
   792 	}
   601 
   793 
   602 	/**
   794 	/**
   603 	 * Get a list of all, hidden and sortable columns, with filter applied
   795 	 * Get a list of all, hidden and sortable columns, with filter applied
   605 	 * @since 3.1.0
   797 	 * @since 3.1.0
   606 	 * @access protected
   798 	 * @access protected
   607 	 *
   799 	 *
   608 	 * @return array
   800 	 * @return array
   609 	 */
   801 	 */
   610 	function get_column_info() {
   802 	protected function get_column_info() {
   611 		if ( isset( $this->_column_headers ) )
   803 		if ( isset( $this->_column_headers ) )
   612 			return $this->_column_headers;
   804 			return $this->_column_headers;
   613 
   805 
   614 		$columns = get_column_headers( $this->screen );
   806 		$columns = get_column_headers( $this->screen );
   615 		$hidden = get_hidden_columns( $this->screen );
   807 		$hidden = get_hidden_columns( $this->screen );
   616 
   808 
   617 		$_sortable = apply_filters( "manage_{$this->screen->id}_sortable_columns", $this->get_sortable_columns() );
   809 		$sortable_columns = $this->get_sortable_columns();
       
   810 		/**
       
   811 		 * Filter the list table sortable columns for a specific screen.
       
   812 		 *
       
   813 		 * The dynamic portion of the hook name, `$this->screen->id`, refers
       
   814 		 * to the ID of the current screen, usually a string.
       
   815 		 *
       
   816 		 * @since 3.5.0
       
   817 		 *
       
   818 		 * @param array $sortable_columns An array of sortable columns.
       
   819 		 */
       
   820 		$_sortable = apply_filters( "manage_{$this->screen->id}_sortable_columns", $sortable_columns );
   618 
   821 
   619 		$sortable = array();
   822 		$sortable = array();
   620 		foreach ( $_sortable as $id => $data ) {
   823 		foreach ( $_sortable as $id => $data ) {
   621 			if ( empty( $data ) )
   824 			if ( empty( $data ) )
   622 				continue;
   825 				continue;
   639 	 * @since 3.1.0
   842 	 * @since 3.1.0
   640 	 * @access public
   843 	 * @access public
   641 	 *
   844 	 *
   642 	 * @return int
   845 	 * @return int
   643 	 */
   846 	 */
   644 	function get_column_count() {
   847 	public function get_column_count() {
   645 		list ( $columns, $hidden ) = $this->get_column_info();
   848 		list ( $columns, $hidden ) = $this->get_column_info();
   646 		$hidden = array_intersect( array_keys( $columns ), array_filter( $hidden ) );
   849 		$hidden = array_intersect( array_keys( $columns ), array_filter( $hidden ) );
   647 		return count( $columns ) - count( $hidden );
   850 		return count( $columns ) - count( $hidden );
   648 	}
   851 	}
   649 
   852 
   650 	/**
   853 	/**
   651 	 * Print column headers, accounting for hidden and sortable columns.
   854 	 * Print column headers, accounting for hidden and sortable columns.
   652 	 *
   855 	 *
   653 	 * @since 3.1.0
   856 	 * @since 3.1.0
   654 	 * @access protected
   857 	 * @access public
   655 	 *
   858 	 *
   656 	 * @param bool $with_id Whether to set the id attribute or not
   859 	 * @param bool $with_id Whether to set the id attribute or not
   657 	 */
   860 	 */
   658 	function print_column_headers( $with_id = true ) {
   861 	public function print_column_headers( $with_id = true ) {
   659 		list( $columns, $hidden, $sortable ) = $this->get_column_info();
   862 		list( $columns, $hidden, $sortable ) = $this->get_column_info();
   660 
   863 
   661 		$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
   864 		$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
   662 		$current_url = remove_query_arg( 'paged', $current_url );
   865 		$current_url = remove_query_arg( 'paged', $current_url );
   663 
   866 
   721 	 * Display the table
   924 	 * Display the table
   722 	 *
   925 	 *
   723 	 * @since 3.1.0
   926 	 * @since 3.1.0
   724 	 * @access public
   927 	 * @access public
   725 	 */
   928 	 */
   726 	function display() {
   929 	public function display() {
   727 		extract( $this->_args );
   930 		$singular = $this->_args['singular'];
   728 
   931 
   729 		$this->display_tablenav( 'top' );
   932 		$this->display_tablenav( 'top' );
   730 
   933 
   731 ?>
   934 ?>
   732 <table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>" cellspacing="0">
   935 <table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
   733 	<thead>
   936 	<thead>
   734 	<tr>
   937 	<tr>
   735 		<?php $this->print_column_headers(); ?>
   938 		<?php $this->print_column_headers(); ?>
   736 	</tr>
   939 	</tr>
   737 	</thead>
   940 	</thead>
   738 
   941 
       
   942 	<tbody id="the-list"<?php
       
   943 		if ( $singular ) {
       
   944 			echo " data-wp-lists='list:$singular'";
       
   945 		} ?>>
       
   946 		<?php $this->display_rows_or_placeholder(); ?>
       
   947 	</tbody>
       
   948 
   739 	<tfoot>
   949 	<tfoot>
   740 	<tr>
   950 	<tr>
   741 		<?php $this->print_column_headers( false ); ?>
   951 		<?php $this->print_column_headers( false ); ?>
   742 	</tr>
   952 	</tr>
   743 	</tfoot>
   953 	</tfoot>
   744 
   954 
   745 	<tbody id="the-list"<?php if ( $singular ) echo " data-wp-lists='list:$singular'"; ?>>
       
   746 		<?php $this->display_rows_or_placeholder(); ?>
       
   747 	</tbody>
       
   748 </table>
   955 </table>
   749 <?php
   956 <?php
   750 		$this->display_tablenav( 'bottom' );
   957 		$this->display_tablenav( 'bottom' );
   751 	}
   958 	}
   752 
   959 
   753 	/**
   960 	/**
   754 	 * Get a list of CSS classes for the <table> tag
   961 	 * Get a list of CSS classes for the list table table tag.
   755 	 *
   962 	 *
   756 	 * @since 3.1.0
   963 	 * @since 3.1.0
   757 	 * @access protected
   964 	 * @access protected
   758 	 *
   965 	 *
   759 	 * @return array
   966 	 * @return array List of CSS classes for the table tag.
   760 	 */
   967 	 */
   761 	function get_table_classes() {
   968 	protected function get_table_classes() {
   762 		return array( 'widefat', 'fixed', $this->_args['plural'] );
   969 		return array( 'widefat', 'fixed', 'striped', $this->_args['plural'] );
   763 	}
   970 	}
   764 
   971 
   765 	/**
   972 	/**
   766 	 * Generate the table navigation above or below the table
   973 	 * Generate the table navigation above or below the table
   767 	 *
   974 	 *
   768 	 * @since 3.1.0
   975 	 * @since 3.1.0
   769 	 * @access protected
   976 	 * @access protected
   770 	 */
   977 	 * @param string $which
   771 	function display_tablenav( $which ) {
   978 	 */
       
   979 	protected function display_tablenav( $which ) {
   772 		if ( 'top' == $which )
   980 		if ( 'top' == $which )
   773 			wp_nonce_field( 'bulk-' . $this->_args['plural'] );
   981 			wp_nonce_field( 'bulk-' . $this->_args['plural'] );
   774 ?>
   982 ?>
   775 	<div class="tablenav <?php echo esc_attr( $which ); ?>">
   983 	<div class="tablenav <?php echo esc_attr( $which ); ?>">
   776 
   984 
   777 		<div class="alignleft actions bulkactions">
   985 		<div class="alignleft actions bulkactions">
   778 			<?php $this->bulk_actions(); ?>
   986 			<?php $this->bulk_actions( $which ); ?>
   779 		</div>
   987 		</div>
   780 <?php
   988 <?php
   781 		$this->extra_tablenav( $which );
   989 		$this->extra_tablenav( $which );
   782 		$this->pagination( $which );
   990 		$this->pagination( $which );
   783 ?>
   991 ?>
   790 	/**
   998 	/**
   791 	 * Extra controls to be displayed between bulk actions and pagination
   999 	 * Extra controls to be displayed between bulk actions and pagination
   792 	 *
  1000 	 *
   793 	 * @since 3.1.0
  1001 	 * @since 3.1.0
   794 	 * @access protected
  1002 	 * @access protected
   795 	 */
  1003 	 *
   796 	function extra_tablenav( $which ) {}
  1004 	 * @param string $which
   797 
  1005 	 */
   798 	/**
  1006 	protected function extra_tablenav( $which ) {}
   799 	 * Generate the <tbody> part of the table
  1007 
   800 	 *
  1008 	/**
   801 	 * @since 3.1.0
  1009 	 * Generate the tbody element for the list table.
   802 	 * @access protected
  1010 	 *
   803 	 */
  1011 	 * @since 3.1.0
   804 	function display_rows_or_placeholder() {
  1012 	 * @access public
       
  1013 	 */
       
  1014 	public function display_rows_or_placeholder() {
   805 		if ( $this->has_items() ) {
  1015 		if ( $this->has_items() ) {
   806 			$this->display_rows();
  1016 			$this->display_rows();
   807 		} else {
  1017 		} else {
   808 			list( $columns, $hidden ) = $this->get_column_info();
       
   809 			echo '<tr class="no-items"><td class="colspanchange" colspan="' . $this->get_column_count() . '">';
  1018 			echo '<tr class="no-items"><td class="colspanchange" colspan="' . $this->get_column_count() . '">';
   810 			$this->no_items();
  1019 			$this->no_items();
   811 			echo '</td></tr>';
  1020 			echo '</td></tr>';
   812 		}
  1021 		}
   813 	}
  1022 	}
   814 
  1023 
   815 	/**
  1024 	/**
   816 	 * Generate the table rows
  1025 	 * Generate the table rows
   817 	 *
  1026 	 *
   818 	 * @since 3.1.0
  1027 	 * @since 3.1.0
   819 	 * @access protected
  1028 	 * @access public
   820 	 */
  1029 	 */
   821 	function display_rows() {
  1030 	public function display_rows() {
   822 		foreach ( $this->items as $item )
  1031 		foreach ( $this->items as $item )
   823 			$this->single_row( $item );
  1032 			$this->single_row( $item );
   824 	}
  1033 	}
   825 
  1034 
   826 	/**
  1035 	/**
   827 	 * Generates content for a single row of the table
  1036 	 * Generates content for a single row of the table
   828 	 *
  1037 	 *
   829 	 * @since 3.1.0
  1038 	 * @since 3.1.0
   830 	 * @access protected
  1039 	 * @access public
   831 	 *
  1040 	 *
   832 	 * @param object $item The current item
  1041 	 * @param object $item The current item
   833 	 */
  1042 	 */
   834 	function single_row( $item ) {
  1043 	public function single_row( $item ) {
   835 		static $row_class = '';
  1044 		echo '<tr>';
   836 		$row_class = ( $row_class == '' ? ' class="alternate"' : '' );
       
   837 
       
   838 		echo '<tr' . $row_class . '>';
       
   839 		$this->single_row_columns( $item );
  1045 		$this->single_row_columns( $item );
   840 		echo '</tr>';
  1046 		echo '</tr>';
   841 	}
  1047 	}
   842 
  1048 
       
  1049 	protected function column_default( $item, $column_name ) {}
       
  1050 
       
  1051 	protected function column_cb( $item ) {}
       
  1052 
   843 	/**
  1053 	/**
   844 	 * Generates the columns for a single row of the table
  1054 	 * Generates the columns for a single row of the table
   845 	 *
  1055 	 *
   846 	 * @since 3.1.0
  1056 	 * @since 3.1.0
   847 	 * @access protected
  1057 	 * @access protected
   848 	 *
  1058 	 *
   849 	 * @param object $item The current item
  1059 	 * @param object $item The current item
   850 	 */
  1060 	 */
   851 	function single_row_columns( $item ) {
  1061 	protected function single_row_columns( $item ) {
   852 		list( $columns, $hidden ) = $this->get_column_info();
  1062 		list( $columns, $hidden ) = $this->get_column_info();
   853 
  1063 
   854 		foreach ( $columns as $column_name => $column_display_name ) {
  1064 		foreach ( $columns as $column_name => $column_display_name ) {
   855 			$class = "class='$column_name column-$column_name'";
  1065 			$class = "class='$column_name column-$column_name'";
   856 
  1066 
   882 	 * Handle an incoming ajax request (called from admin-ajax.php)
  1092 	 * Handle an incoming ajax request (called from admin-ajax.php)
   883 	 *
  1093 	 *
   884 	 * @since 3.1.0
  1094 	 * @since 3.1.0
   885 	 * @access public
  1095 	 * @access public
   886 	 */
  1096 	 */
   887 	function ajax_response() {
  1097 	public function ajax_response() {
   888 		$this->prepare_items();
  1098 		$this->prepare_items();
   889 
  1099 
   890 		extract( $this->_args );
       
   891 		extract( $this->_pagination_args, EXTR_SKIP );
       
   892 
       
   893 		ob_start();
  1100 		ob_start();
   894 		if ( ! empty( $_REQUEST['no_placeholder'] ) )
  1101 		if ( ! empty( $_REQUEST['no_placeholder'] ) ) {
   895 			$this->display_rows();
  1102 			$this->display_rows();
   896 		else
  1103 		} else {
   897 			$this->display_rows_or_placeholder();
  1104 			$this->display_rows_or_placeholder();
       
  1105 		}
   898 
  1106 
   899 		$rows = ob_get_clean();
  1107 		$rows = ob_get_clean();
   900 
  1108 
   901 		$response = array( 'rows' => $rows );
  1109 		$response = array( 'rows' => $rows );
   902 
  1110 
   903 		if ( isset( $total_items ) )
  1111 		if ( isset( $this->_pagination_args['total_items'] ) ) {
   904 			$response['total_items_i18n'] = sprintf( _n( '1 item', '%s items', $total_items ), number_format_i18n( $total_items ) );
  1112 			$response['total_items_i18n'] = sprintf(
   905 
  1113 				_n( '1 item', '%s items', $this->_pagination_args['total_items'] ),
   906 		if ( isset( $total_pages ) ) {
  1114 				number_format_i18n( $this->_pagination_args['total_items'] )
   907 			$response['total_pages'] = $total_pages;
  1115 			);
   908 			$response['total_pages_i18n'] = number_format_i18n( $total_pages );
  1116 		}
   909 		}
  1117 		if ( isset( $this->_pagination_args['total_pages'] ) ) {
   910 
  1118 			$response['total_pages'] = $this->_pagination_args['total_pages'];
   911 		die( json_encode( $response ) );
  1119 			$response['total_pages_i18n'] = number_format_i18n( $this->_pagination_args['total_pages'] );
       
  1120 		}
       
  1121 
       
  1122 		die( wp_json_encode( $response ) );
   912 	}
  1123 	}
   913 
  1124 
   914 	/**
  1125 	/**
   915 	 * Send required variables to JavaScript land
  1126 	 * Send required variables to JavaScript land
   916 	 *
  1127 	 *
   917 	 * @access private
  1128 	 * @access public
   918 	 */
  1129 	 */
   919 	function _js_vars() {
  1130 	public function _js_vars() {
   920 		$args = array(
  1131 		$args = array(
   921 			'class'  => get_class( $this ),
  1132 			'class'  => get_class( $this ),
   922 			'screen' => array(
  1133 			'screen' => array(
   923 				'id'   => $this->screen->id,
  1134 				'id'   => $this->screen->id,
   924 				'base' => $this->screen->base,
  1135 				'base' => $this->screen->base,
   925 			)
  1136 			)
   926 		);
  1137 		);
   927 
  1138 
   928 		printf( "<script type='text/javascript'>list_args = %s;</script>\n", json_encode( $args ) );
  1139 		printf( "<script type='text/javascript'>list_args = %s;</script>\n", wp_json_encode( $args ) );
   929 	}
  1140 	}
   930 }
  1141 }