wp/wp-admin/includes/class-wp-list-table.php
changeset 9 177826044cd9
parent 7 cf61fcea0001
child 16 a86126ab1dd4
equal deleted inserted replaced
8:c7c34916027a 9:177826044cd9
    89 	/**
    89 	/**
    90 	 * {@internal Missing Summary}
    90 	 * {@internal Missing Summary}
    91 	 *
    91 	 *
    92 	 * @var array
    92 	 * @var array
    93 	 */
    93 	 */
    94 	protected $compat_methods = array( 'set_pagination_args', 'get_views', 'get_bulk_actions', 'bulk_actions',
    94 	protected $compat_methods = array(
    95 		'row_actions', 'months_dropdown', 'view_switcher', 'comments_bubble', 'get_items_per_page', 'pagination',
    95 		'set_pagination_args',
    96 		'get_sortable_columns', 'get_column_info', 'get_table_classes', 'display_tablenav', 'extra_tablenav',
    96 		'get_views',
    97 		'single_row_columns' );
    97 		'get_bulk_actions',
       
    98 		'bulk_actions',
       
    99 		'row_actions',
       
   100 		'months_dropdown',
       
   101 		'view_switcher',
       
   102 		'comments_bubble',
       
   103 		'get_items_per_page',
       
   104 		'pagination',
       
   105 		'get_sortable_columns',
       
   106 		'get_column_info',
       
   107 		'get_table_classes',
       
   108 		'display_tablenav',
       
   109 		'extra_tablenav',
       
   110 		'single_row_columns',
       
   111 	);
    98 
   112 
    99 	/**
   113 	/**
   100 	 * Constructor.
   114 	 * Constructor.
   101 	 *
   115 	 *
   102 	 * The child class should call this constructor from its own constructor to override
   116 	 * The child class should call this constructor from its own constructor to override
   120 	 *                            screen. If left null, the current screen will be automatically set.
   134 	 *                            screen. If left null, the current screen will be automatically set.
   121 	 *                            Default null.
   135 	 *                            Default null.
   122 	 * }
   136 	 * }
   123 	 */
   137 	 */
   124 	public function __construct( $args = array() ) {
   138 	public function __construct( $args = array() ) {
   125 		$args = wp_parse_args( $args, array(
   139 		$args = wp_parse_args(
   126 			'plural' => '',
   140 			$args,
   127 			'singular' => '',
   141 			array(
   128 			'ajax' => false,
   142 				'plural'   => '',
   129 			'screen' => null,
   143 				'singular' => '',
   130 		) );
   144 				'ajax'     => false,
       
   145 				'screen'   => null,
       
   146 			)
       
   147 		);
   131 
   148 
   132 		$this->screen = convert_to_screen( $args['screen'] );
   149 		$this->screen = convert_to_screen( $args['screen'] );
   133 
   150 
   134 		add_filter( "manage_{$this->screen->id}_columns", array( $this, 'get_columns' ), 0 );
   151 		add_filter( "manage_{$this->screen->id}_columns", array( $this, 'get_columns' ), 0 );
   135 
   152 
   136 		if ( !$args['plural'] )
   153 		if ( ! $args['plural'] ) {
   137 			$args['plural'] = $this->screen->base;
   154 			$args['plural'] = $this->screen->base;
   138 
   155 		}
   139 		$args['plural'] = sanitize_key( $args['plural'] );
   156 
       
   157 		$args['plural']   = sanitize_key( $args['plural'] );
   140 		$args['singular'] = sanitize_key( $args['singular'] );
   158 		$args['singular'] = sanitize_key( $args['singular'] );
   141 
   159 
   142 		$this->_args = $args;
   160 		$this->_args = $args;
   143 
   161 
   144 		if ( $args['ajax'] ) {
   162 		if ( $args['ajax'] ) {
   147 		}
   165 		}
   148 
   166 
   149 		if ( empty( $this->modes ) ) {
   167 		if ( empty( $this->modes ) ) {
   150 			$this->modes = array(
   168 			$this->modes = array(
   151 				'list'    => __( 'List View' ),
   169 				'list'    => __( 'List View' ),
   152 				'excerpt' => __( 'Excerpt View' )
   170 				'excerpt' => __( 'Excerpt View' ),
   153 			);
   171 			);
   154 		}
   172 		}
   155 	}
   173 	}
   156 
   174 
   157 	/**
   175 	/**
   213 	/**
   231 	/**
   214 	 * Make private/protected methods readable for backward compatibility.
   232 	 * Make private/protected methods readable for backward compatibility.
   215 	 *
   233 	 *
   216 	 * @since 4.0.0
   234 	 * @since 4.0.0
   217 	 *
   235 	 *
   218 	 * @param callable $name      Method to call.
   236 	 * @param string   $name      Method to call.
   219 	 * @param array    $arguments Arguments to pass when calling.
   237 	 * @param array    $arguments Arguments to pass when calling.
   220 	 * @return mixed|bool Return value of the callback, false otherwise.
   238 	 * @return mixed|bool Return value of the callback, false otherwise.
   221 	 */
   239 	 */
   222 	public function __call( $name, $arguments ) {
   240 	public function __call( $name, $arguments ) {
   223 		if ( in_array( $name, $this->compat_methods ) ) {
   241 		if ( in_array( $name, $this->compat_methods ) ) {
   236 		die( 'function WP_List_Table::ajax_user_can() must be over-ridden in a sub-class.' );
   254 		die( 'function WP_List_Table::ajax_user_can() must be over-ridden in a sub-class.' );
   237 	}
   255 	}
   238 
   256 
   239 	/**
   257 	/**
   240 	 * Prepares the list of items for displaying.
   258 	 * Prepares the list of items for displaying.
       
   259 	 *
   241 	 * @uses WP_List_Table::set_pagination_args()
   260 	 * @uses WP_List_Table::set_pagination_args()
   242 	 *
   261 	 *
   243 	 * @since 3.1.0
   262 	 * @since 3.1.0
   244 	 * @abstract
   263 	 * @abstract
   245 	 */
   264 	 */
   253 	 * @since 3.1.0
   272 	 * @since 3.1.0
   254 	 *
   273 	 *
   255 	 * @param array|string $args Array or string of arguments with information about the pagination.
   274 	 * @param array|string $args Array or string of arguments with information about the pagination.
   256 	 */
   275 	 */
   257 	protected function set_pagination_args( $args ) {
   276 	protected function set_pagination_args( $args ) {
   258 		$args = wp_parse_args( $args, array(
   277 		$args = wp_parse_args(
   259 			'total_items' => 0,
   278 			$args,
   260 			'total_pages' => 0,
   279 			array(
   261 			'per_page' => 0,
   280 				'total_items' => 0,
   262 		) );
   281 				'total_pages' => 0,
   263 
   282 				'per_page'    => 0,
   264 		if ( !$args['total_pages'] && $args['per_page'] > 0 )
   283 			)
       
   284 		);
       
   285 
       
   286 		if ( ! $args['total_pages'] && $args['per_page'] > 0 ) {
   265 			$args['total_pages'] = ceil( $args['total_items'] / $args['per_page'] );
   287 			$args['total_pages'] = ceil( $args['total_items'] / $args['per_page'] );
       
   288 		}
   266 
   289 
   267 		// Redirect if page number is invalid and headers are not already sent.
   290 		// Redirect if page number is invalid and headers are not already sent.
   268 		if ( ! headers_sent() && ! wp_doing_ajax() && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages'] ) {
   291 		if ( ! headers_sent() && ! wp_doing_ajax() && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages'] ) {
   269 			wp_redirect( add_query_arg( 'paged', $args['total_pages'] ) );
   292 			wp_redirect( add_query_arg( 'paged', $args['total_pages'] ) );
   270 			exit;
   293 			exit;
   285 	public function get_pagination_arg( $key ) {
   308 	public function get_pagination_arg( $key ) {
   286 		if ( 'page' === $key ) {
   309 		if ( 'page' === $key ) {
   287 			return $this->get_pagenum();
   310 			return $this->get_pagenum();
   288 		}
   311 		}
   289 
   312 
   290 		if ( isset( $this->_pagination_args[$key] ) ) {
   313 		if ( isset( $this->_pagination_args[ $key ] ) ) {
   291 			return $this->_pagination_args[$key];
   314 			return $this->_pagination_args[ $key ];
   292 		}
   315 		}
   293 	}
   316 	}
   294 
   317 
   295 	/**
   318 	/**
   296 	 * Whether the table has items to display or not
   319 	 * Whether the table has items to display or not
   298 	 * @since 3.1.0
   321 	 * @since 3.1.0
   299 	 *
   322 	 *
   300 	 * @return bool
   323 	 * @return bool
   301 	 */
   324 	 */
   302 	public function has_items() {
   325 	public function has_items() {
   303 		return !empty( $this->items );
   326 		return ! empty( $this->items );
   304 	}
   327 	}
   305 
   328 
   306 	/**
   329 	/**
   307 	 * Message to be displayed when there are no items
   330 	 * Message to be displayed when there are no items
   308 	 *
   331 	 *
   319 	 *
   342 	 *
   320 	 * @param string $text     The 'submit' button label.
   343 	 * @param string $text     The 'submit' button label.
   321 	 * @param string $input_id ID attribute value for the search input field.
   344 	 * @param string $input_id ID attribute value for the search input field.
   322 	 */
   345 	 */
   323 	public function search_box( $text, $input_id ) {
   346 	public function search_box( $text, $input_id ) {
   324 		if ( empty( $_REQUEST['s'] ) && !$this->has_items() )
   347 		if ( empty( $_REQUEST['s'] ) && ! $this->has_items() ) {
   325 			return;
   348 			return;
       
   349 		}
   326 
   350 
   327 		$input_id = $input_id . '-search-input';
   351 		$input_id = $input_id . '-search-input';
   328 
   352 
   329 		if ( ! empty( $_REQUEST['orderby'] ) )
   353 		if ( ! empty( $_REQUEST['orderby'] ) ) {
   330 			echo '<input type="hidden" name="orderby" value="' . esc_attr( $_REQUEST['orderby'] ) . '" />';
   354 			echo '<input type="hidden" name="orderby" value="' . esc_attr( $_REQUEST['orderby'] ) . '" />';
   331 		if ( ! empty( $_REQUEST['order'] ) )
   355 		}
       
   356 		if ( ! empty( $_REQUEST['order'] ) ) {
   332 			echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';
   357 			echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';
   333 		if ( ! empty( $_REQUEST['post_mime_type'] ) )
   358 		}
       
   359 		if ( ! empty( $_REQUEST['post_mime_type'] ) ) {
   334 			echo '<input type="hidden" name="post_mime_type" value="' . esc_attr( $_REQUEST['post_mime_type'] ) . '" />';
   360 			echo '<input type="hidden" name="post_mime_type" value="' . esc_attr( $_REQUEST['post_mime_type'] ) . '" />';
   335 		if ( ! empty( $_REQUEST['detached'] ) )
   361 		}
       
   362 		if ( ! empty( $_REQUEST['detached'] ) ) {
   336 			echo '<input type="hidden" name="detached" value="' . esc_attr( $_REQUEST['detached'] ) . '" />';
   363 			echo '<input type="hidden" name="detached" value="' . esc_attr( $_REQUEST['detached'] ) . '" />';
   337 ?>
   364 		}
       
   365 		?>
   338 <p class="search-box">
   366 <p class="search-box">
   339 	<label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo $text; ?>:</label>
   367 	<label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo $text; ?>:</label>
   340 	<input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>" />
   368 	<input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>" />
   341 	<?php submit_button( $text, '', '', false, array( 'id' => 'search-submit' ) ); ?>
   369 		<?php submit_button( $text, '', '', false, array( 'id' => 'search-submit' ) ); ?>
   342 </p>
   370 </p>
   343 <?php
   371 		<?php
   344 	}
   372 	}
   345 
   373 
   346 	/**
   374 	/**
   347 	 * Get an associative array ( id => link ) with the list
   375 	 * Get an associative array ( id => link ) with the list
   348 	 * of views available on this table.
   376 	 * of views available on this table.
   368 		 * The dynamic portion of the hook name, `$this->screen->id`, refers
   396 		 * The dynamic portion of the hook name, `$this->screen->id`, refers
   369 		 * to the ID of the current screen, usually a string.
   397 		 * to the ID of the current screen, usually a string.
   370 		 *
   398 		 *
   371 		 * @since 3.5.0
   399 		 * @since 3.5.0
   372 		 *
   400 		 *
   373 		 * @param array $views An array of available list table views.
   401 		 * @param string[] $views An array of available list table views.
   374 		 */
   402 		 */
   375 		$views = apply_filters( "views_{$this->screen->id}", $views );
   403 		$views = apply_filters( "views_{$this->screen->id}", $views );
   376 
   404 
   377 		if ( empty( $views ) )
   405 		if ( empty( $views ) ) {
   378 			return;
   406 			return;
       
   407 		}
   379 
   408 
   380 		$this->screen->render_screen_reader_content( 'heading_views' );
   409 		$this->screen->render_screen_reader_content( 'heading_views' );
   381 
   410 
   382 		echo "<ul class='subsubsub'>\n";
   411 		echo "<ul class='subsubsub'>\n";
   383 		foreach ( $views as $class => $view ) {
   412 		foreach ( $views as $class => $view ) {
   384 			$views[ $class ] = "\t<li class='$class'>$view";
   413 			$views[ $class ] = "\t<li class='$class'>$view";
   385 		}
   414 		}
   386 		echo implode( " |</li>\n", $views ) . "</li>\n";
   415 		echo implode( " |</li>\n", $views ) . "</li>\n";
   387 		echo "</ul>";
   416 		echo '</ul>';
   388 	}
   417 	}
   389 
   418 
   390 	/**
   419 	/**
   391 	 * Get an associative array ( option_name => option_title ) with the list
   420 	 * Get an associative array ( option_name => option_title ) with the list
   392 	 * of bulk actions available on this table.
   421 	 * of bulk actions available on this table.
   418 			 *
   447 			 *
   419 			 * This filter can currently only be used to remove bulk actions.
   448 			 * This filter can currently only be used to remove bulk actions.
   420 			 *
   449 			 *
   421 			 * @since 3.5.0
   450 			 * @since 3.5.0
   422 			 *
   451 			 *
   423 			 * @param array $actions An array of the available bulk actions.
   452 			 * @param string[] $actions An array of the available bulk actions.
   424 			 */
   453 			 */
   425 			$this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions );
   454 			$this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions );
   426 			$two = '';
   455 			$two            = '';
   427 		} else {
   456 		} else {
   428 			$two = '2';
   457 			$two = '2';
   429 		}
   458 		}
   430 
   459 
   431 		if ( empty( $this->_actions ) )
   460 		if ( empty( $this->_actions ) ) {
   432 			return;
   461 			return;
       
   462 		}
   433 
   463 
   434 		echo '<label for="bulk-action-selector-' . esc_attr( $which ) . '" class="screen-reader-text">' . __( 'Select bulk action' ) . '</label>';
   464 		echo '<label for="bulk-action-selector-' . esc_attr( $which ) . '" class="screen-reader-text">' . __( 'Select bulk action' ) . '</label>';
   435 		echo '<select name="action' . $two . '" id="bulk-action-selector-' . esc_attr( $which ) . "\">\n";
   465 		echo '<select name="action' . $two . '" id="bulk-action-selector-' . esc_attr( $which ) . "\">\n";
   436 		echo '<option value="-1">' . __( 'Bulk Actions' ) . "</option>\n";
   466 		echo '<option value="-1">' . __( 'Bulk Actions' ) . "</option>\n";
   437 
   467 
   453 	 * @since 3.1.0
   483 	 * @since 3.1.0
   454 	 *
   484 	 *
   455 	 * @return string|false The action name or False if no action was selected
   485 	 * @return string|false The action name or False if no action was selected
   456 	 */
   486 	 */
   457 	public function current_action() {
   487 	public function current_action() {
   458 		if ( isset( $_REQUEST['filter_action'] ) && ! empty( $_REQUEST['filter_action'] ) )
   488 		if ( isset( $_REQUEST['filter_action'] ) && ! empty( $_REQUEST['filter_action'] ) ) {
   459 			return false;
   489 			return false;
   460 
   490 		}
   461 		if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] )
   491 
       
   492 		if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] ) {
   462 			return $_REQUEST['action'];
   493 			return $_REQUEST['action'];
   463 
   494 		}
   464 		if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] )
   495 
       
   496 		if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] ) {
   465 			return $_REQUEST['action2'];
   497 			return $_REQUEST['action2'];
       
   498 		}
   466 
   499 
   467 		return false;
   500 		return false;
   468 	}
   501 	}
   469 
   502 
   470 	/**
   503 	/**
   471 	 * Generate row actions div
   504 	 * Generate row actions div
   472 	 *
   505 	 *
   473 	 * @since 3.1.0
   506 	 * @since 3.1.0
   474 	 *
   507 	 *
   475 	 * @param array $actions The list of actions
   508 	 * @param string[] $actions        An array of action links.
   476 	 * @param bool $always_visible Whether the actions should be always visible
   509 	 * @param bool     $always_visible Whether the actions should be always visible.
   477 	 * @return string
   510 	 * @return string
   478 	 */
   511 	 */
   479 	protected function row_actions( $actions, $always_visible = false ) {
   512 	protected function row_actions( $actions, $always_visible = false ) {
   480 		$action_count = count( $actions );
   513 		$action_count = count( $actions );
   481 		$i = 0;
   514 		$i            = 0;
   482 
   515 
   483 		if ( !$action_count )
   516 		if ( ! $action_count ) {
   484 			return '';
   517 			return '';
       
   518 		}
   485 
   519 
   486 		$out = '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">';
   520 		$out = '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">';
   487 		foreach ( $actions as $action => $link ) {
   521 		foreach ( $actions as $action => $link ) {
   488 			++$i;
   522 			++$i;
   489 			( $i == $action_count ) ? $sep = '' : $sep = ' | ';
   523 			( $i == $action_count ) ? $sep = '' : $sep = ' | ';
   490 			$out .= "<span class='$action'>$link$sep</span>";
   524 			$out                          .= "<span class='$action'>$link$sep</span>";
   491 		}
   525 		}
   492 		$out .= '</div>';
   526 		$out .= '</div>';
   493 
   527 
   494 		$out .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>';
   528 		$out .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>';
   495 
   529 
   526 			$extra_checks .= " AND post_status != 'trash'";
   560 			$extra_checks .= " AND post_status != 'trash'";
   527 		} elseif ( isset( $_GET['post_status'] ) ) {
   561 		} elseif ( isset( $_GET['post_status'] ) ) {
   528 			$extra_checks = $wpdb->prepare( ' AND post_status = %s', $_GET['post_status'] );
   562 			$extra_checks = $wpdb->prepare( ' AND post_status = %s', $_GET['post_status'] );
   529 		}
   563 		}
   530 
   564 
   531 		$months = $wpdb->get_results( $wpdb->prepare( "
   565 		$months = $wpdb->get_results(
       
   566 			$wpdb->prepare(
       
   567 				"
   532 			SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
   568 			SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
   533 			FROM $wpdb->posts
   569 			FROM $wpdb->posts
   534 			WHERE post_type = %s
   570 			WHERE post_type = %s
   535 			$extra_checks
   571 			$extra_checks
   536 			ORDER BY post_date DESC
   572 			ORDER BY post_date DESC
   537 		", $post_type ) );
   573 		",
       
   574 				$post_type
       
   575 			)
       
   576 		);
   538 
   577 
   539 		/**
   578 		/**
   540 		 * Filters the 'Months' drop-down results.
   579 		 * Filters the 'Months' drop-down results.
   541 		 *
   580 		 *
   542 		 * @since 3.7.0
   581 		 * @since 3.7.0
   546 		 */
   585 		 */
   547 		$months = apply_filters( 'months_dropdown_results', $months, $post_type );
   586 		$months = apply_filters( 'months_dropdown_results', $months, $post_type );
   548 
   587 
   549 		$month_count = count( $months );
   588 		$month_count = count( $months );
   550 
   589 
   551 		if ( !$month_count || ( 1 == $month_count && 0 == $months[0]->month ) )
   590 		if ( ! $month_count || ( 1 == $month_count && 0 == $months[0]->month ) ) {
   552 			return;
   591 			return;
       
   592 		}
   553 
   593 
   554 		$m = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0;
   594 		$m = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0;
   555 ?>
   595 		?>
   556 		<label for="filter-by-date" class="screen-reader-text"><?php _e( 'Filter by date' ); ?></label>
   596 		<label for="filter-by-date" class="screen-reader-text"><?php _e( 'Filter by date' ); ?></label>
   557 		<select name="m" id="filter-by-date">
   597 		<select name="m" id="filter-by-date">
   558 			<option<?php selected( $m, 0 ); ?> value="0"><?php _e( 'All dates' ); ?></option>
   598 			<option<?php selected( $m, 0 ); ?> value="0"><?php _e( 'All dates' ); ?></option>
   559 <?php
   599 		<?php
   560 		foreach ( $months as $arc_row ) {
   600 		foreach ( $months as $arc_row ) {
   561 			if ( 0 == $arc_row->year )
   601 			if ( 0 == $arc_row->year ) {
   562 				continue;
   602 				continue;
       
   603 			}
   563 
   604 
   564 			$month = zeroise( $arc_row->month, 2 );
   605 			$month = zeroise( $arc_row->month, 2 );
   565 			$year = $arc_row->year;
   606 			$year  = $arc_row->year;
   566 
   607 
   567 			printf( "<option %s value='%s'>%s</option>\n",
   608 			printf(
       
   609 				"<option %s value='%s'>%s</option>\n",
   568 				selected( $m, $year . $month, false ),
   610 				selected( $m, $year . $month, false ),
   569 				esc_attr( $arc_row->year . $month ),
   611 				esc_attr( $arc_row->year . $month ),
   570 				/* translators: 1: month name, 2: 4-digit year */
   612 				/* translators: 1: month name, 2: 4-digit year */
   571 				sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month ), $year )
   613 				sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month ), $year )
   572 			);
   614 			);
   573 		}
   615 		}
   574 ?>
   616 		?>
   575 		</select>
   617 		</select>
   576 <?php
   618 		<?php
   577 	}
   619 	}
   578 
   620 
   579 	/**
   621 	/**
   580 	 * Display a view switcher
   622 	 * Display a view switcher
   581 	 *
   623 	 *
   582 	 * @since 3.1.0
   624 	 * @since 3.1.0
   583 	 *
   625 	 *
   584 	 * @param string $current_mode
   626 	 * @param string $current_mode
   585 	 */
   627 	 */
   586 	protected function view_switcher( $current_mode ) {
   628 	protected function view_switcher( $current_mode ) {
   587 ?>
   629 		?>
   588 		<input type="hidden" name="mode" value="<?php echo esc_attr( $current_mode ); ?>" />
   630 		<input type="hidden" name="mode" value="<?php echo esc_attr( $current_mode ); ?>" />
   589 		<div class="view-switch">
   631 		<div class="view-switch">
   590 <?php
   632 		<?php
   591 			foreach ( $this->modes as $mode => $title ) {
   633 		foreach ( $this->modes as $mode => $title ) {
   592 				$classes = array( 'view-' . $mode );
   634 			$classes = array( 'view-' . $mode );
   593 				if ( $current_mode === $mode )
   635 			if ( $current_mode === $mode ) {
   594 					$classes[] = 'current';
   636 				$classes[] = 'current';
   595 				printf(
       
   596 					"<a href='%s' class='%s' id='view-switch-$mode'><span class='screen-reader-text'>%s</span></a>\n",
       
   597 					esc_url( add_query_arg( 'mode', $mode ) ),
       
   598 					implode( ' ', $classes ),
       
   599 					$title
       
   600 				);
       
   601 			}
   637 			}
       
   638 			printf(
       
   639 				"<a href='%s' class='%s' id='view-switch-$mode'><span class='screen-reader-text'>%s</span></a>\n",
       
   640 				esc_url( add_query_arg( 'mode', $mode ) ),
       
   641 				implode( ' ', $classes ),
       
   642 				$title
       
   643 			);
       
   644 		}
   602 		?>
   645 		?>
   603 		</div>
   646 		</div>
   604 <?php
   647 		<?php
   605 	}
   648 	}
   606 
   649 
   607 	/**
   650 	/**
   608 	 * Display a comment count bubble
   651 	 * Display a comment count bubble
   609 	 *
   652 	 *
   614 	 */
   657 	 */
   615 	protected function comments_bubble( $post_id, $pending_comments ) {
   658 	protected function comments_bubble( $post_id, $pending_comments ) {
   616 		$approved_comments = get_comments_number();
   659 		$approved_comments = get_comments_number();
   617 
   660 
   618 		$approved_comments_number = number_format_i18n( $approved_comments );
   661 		$approved_comments_number = number_format_i18n( $approved_comments );
   619 		$pending_comments_number = number_format_i18n( $pending_comments );
   662 		$pending_comments_number  = number_format_i18n( $pending_comments );
   620 
   663 
   621 		$approved_only_phrase = sprintf( _n( '%s comment', '%s comments', $approved_comments ), $approved_comments_number );
   664 		$approved_only_phrase = sprintf( _n( '%s comment', '%s comments', $approved_comments ), $approved_comments_number );
   622 		$approved_phrase = sprintf( _n( '%s approved comment', '%s approved comments', $approved_comments ), $approved_comments_number );
   665 		$approved_phrase      = sprintf( _n( '%s approved comment', '%s approved comments', $approved_comments ), $approved_comments_number );
   623 		$pending_phrase = sprintf( _n( '%s pending comment', '%s pending comments', $pending_comments ), $pending_comments_number );
   666 		$pending_phrase       = sprintf( _n( '%s pending comment', '%s pending comments', $pending_comments ), $pending_comments_number );
   624 
   667 
   625 		// No comments at all.
   668 		// No comments at all.
   626 		if ( ! $approved_comments && ! $pending_comments ) {
   669 		if ( ! $approved_comments && ! $pending_comments ) {
   627 			printf( '<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">%s</span>',
   670 			printf(
       
   671 				'<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">%s</span>',
   628 				__( 'No comments' )
   672 				__( 'No comments' )
   629 			);
   673 			);
   630 		// Approved comments have different display depending on some conditions.
   674 			// Approved comments have different display depending on some conditions.
   631 		} elseif ( $approved_comments ) {
   675 		} elseif ( $approved_comments ) {
   632 			printf( '<a href="%s" class="post-com-count post-com-count-approved"><span class="comment-count-approved" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>',
   676 			printf(
   633 				esc_url( add_query_arg( array( 'p' => $post_id, 'comment_status' => 'approved' ), admin_url( 'edit-comments.php' ) ) ),
   677 				'<a href="%s" class="post-com-count post-com-count-approved"><span class="comment-count-approved" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>',
       
   678 				esc_url(
       
   679 					add_query_arg(
       
   680 						array(
       
   681 							'p'              => $post_id,
       
   682 							'comment_status' => 'approved',
       
   683 						),
       
   684 						admin_url( 'edit-comments.php' )
       
   685 					)
       
   686 				),
   634 				$approved_comments_number,
   687 				$approved_comments_number,
   635 				$pending_comments ? $approved_phrase : $approved_only_phrase
   688 				$pending_comments ? $approved_phrase : $approved_only_phrase
   636 			);
   689 			);
   637 		} else {
   690 		} else {
   638 			printf( '<span class="post-com-count post-com-count-no-comments"><span class="comment-count comment-count-no-comments" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></span>',
   691 			printf(
       
   692 				'<span class="post-com-count post-com-count-no-comments"><span class="comment-count comment-count-no-comments" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></span>',
   639 				$approved_comments_number,
   693 				$approved_comments_number,
   640 				$pending_comments ? __( 'No approved comments' ) : __( 'No comments' )
   694 				$pending_comments ? __( 'No approved comments' ) : __( 'No comments' )
   641 			);
   695 			);
   642 		}
   696 		}
   643 
   697 
   644 		if ( $pending_comments ) {
   698 		if ( $pending_comments ) {
   645 			printf( '<a href="%s" class="post-com-count post-com-count-pending"><span class="comment-count-pending" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>',
   699 			printf(
   646 				esc_url( add_query_arg( array( 'p' => $post_id, 'comment_status' => 'moderated' ), admin_url( 'edit-comments.php' ) ) ),
   700 				'<a href="%s" class="post-com-count post-com-count-pending"><span class="comment-count-pending" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>',
       
   701 				esc_url(
       
   702 					add_query_arg(
       
   703 						array(
       
   704 							'p'              => $post_id,
       
   705 							'comment_status' => 'moderated',
       
   706 						),
       
   707 						admin_url( 'edit-comments.php' )
       
   708 					)
       
   709 				),
   647 				$pending_comments_number,
   710 				$pending_comments_number,
   648 				$pending_phrase
   711 				$pending_phrase
   649 			);
   712 			);
   650 		} else {
   713 		} else {
   651 			printf( '<span class="post-com-count post-com-count-pending post-com-count-no-pending"><span class="comment-count comment-count-no-pending" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></span>',
   714 			printf(
       
   715 				'<span class="post-com-count post-com-count-pending post-com-count-no-pending"><span class="comment-count comment-count-no-pending" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></span>',
   652 				$pending_comments_number,
   716 				$pending_comments_number,
   653 				$approved_comments ? __( 'No pending comments' ) : __( 'No comments' )
   717 				$approved_comments ? __( 'No pending comments' ) : __( 'No comments' )
   654 			);
   718 			);
   655 		}
   719 		}
   656 	}
   720 	}
   663 	 * @return int
   727 	 * @return int
   664 	 */
   728 	 */
   665 	public function get_pagenum() {
   729 	public function get_pagenum() {
   666 		$pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0;
   730 		$pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0;
   667 
   731 
   668 		if ( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] )
   732 		if ( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] ) {
   669 			$pagenum = $this->_pagination_args['total_pages'];
   733 			$pagenum = $this->_pagination_args['total_pages'];
       
   734 		}
   670 
   735 
   671 		return max( 1, $pagenum );
   736 		return max( 1, $pagenum );
   672 	}
   737 	}
   673 
   738 
   674 	/**
   739 	/**
   680 	 * @param int    $default
   745 	 * @param int    $default
   681 	 * @return int
   746 	 * @return int
   682 	 */
   747 	 */
   683 	protected function get_items_per_page( $option, $default = 20 ) {
   748 	protected function get_items_per_page( $option, $default = 20 ) {
   684 		$per_page = (int) get_user_option( $option );
   749 		$per_page = (int) get_user_option( $option );
   685 		if ( empty( $per_page ) || $per_page < 1 )
   750 		if ( empty( $per_page ) || $per_page < 1 ) {
   686 			$per_page = $default;
   751 			$per_page = $default;
       
   752 		}
   687 
   753 
   688 		/**
   754 		/**
   689 		 * Filters the number of items to be displayed on each page of the list table.
   755 		 * Filters the number of items to be displayed on each page of the list table.
   690 		 *
   756 		 *
   691 		 * The dynamic hook name, $option, refers to the `per_page` option depending
   757 		 * The dynamic hook name, $option, refers to the `per_page` option depending
   711 	protected function pagination( $which ) {
   777 	protected function pagination( $which ) {
   712 		if ( empty( $this->_pagination_args ) ) {
   778 		if ( empty( $this->_pagination_args ) ) {
   713 			return;
   779 			return;
   714 		}
   780 		}
   715 
   781 
   716 		$total_items = $this->_pagination_args['total_items'];
   782 		$total_items     = $this->_pagination_args['total_items'];
   717 		$total_pages = $this->_pagination_args['total_pages'];
   783 		$total_pages     = $this->_pagination_args['total_pages'];
   718 		$infinite_scroll = false;
   784 		$infinite_scroll = false;
   719 		if ( isset( $this->_pagination_args['infinite_scroll'] ) ) {
   785 		if ( isset( $this->_pagination_args['infinite_scroll'] ) ) {
   720 			$infinite_scroll = $this->_pagination_args['infinite_scroll'];
   786 			$infinite_scroll = $this->_pagination_args['infinite_scroll'];
   721 		}
   787 		}
   722 
   788 
   724 			$this->screen->render_screen_reader_content( 'heading_pagination' );
   790 			$this->screen->render_screen_reader_content( 'heading_pagination' );
   725 		}
   791 		}
   726 
   792 
   727 		$output = '<span class="displaying-num">' . sprintf( _n( '%s item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . '</span>';
   793 		$output = '<span class="displaying-num">' . sprintf( _n( '%s item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . '</span>';
   728 
   794 
   729 		$current = $this->get_pagenum();
   795 		$current              = $this->get_pagenum();
   730 		$removable_query_args = wp_removable_query_args();
   796 		$removable_query_args = wp_removable_query_args();
   731 
   797 
   732 		$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
   798 		$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
   733 
   799 
   734 		$current_url = remove_query_arg( $removable_query_args, $current_url );
   800 		$current_url = remove_query_arg( $removable_query_args, $current_url );
   738 		$total_pages_before = '<span class="paging-input">';
   804 		$total_pages_before = '<span class="paging-input">';
   739 		$total_pages_after  = '</span></span>';
   805 		$total_pages_after  = '</span></span>';
   740 
   806 
   741 		$disable_first = $disable_last = $disable_prev = $disable_next = false;
   807 		$disable_first = $disable_last = $disable_prev = $disable_next = false;
   742 
   808 
   743  		if ( $current == 1 ) {
   809 		if ( $current == 1 ) {
   744 			$disable_first = true;
   810 			$disable_first = true;
   745 			$disable_prev = true;
   811 			$disable_prev  = true;
   746  		}
   812 		}
   747 		if ( $current == 2 ) {
   813 		if ( $current == 2 ) {
   748 			$disable_first = true;
   814 			$disable_first = true;
   749 		}
   815 		}
   750  		if ( $current == $total_pages ) {
   816 		if ( $current == $total_pages ) {
   751 			$disable_last = true;
   817 			$disable_last = true;
   752 			$disable_next = true;
   818 			$disable_next = true;
   753  		}
   819 		}
   754 		if ( $current == $total_pages - 1 ) {
   820 		if ( $current == $total_pages - 1 ) {
   755 			$disable_last = true;
   821 			$disable_last = true;
   756 		}
   822 		}
   757 
   823 
   758 		if ( $disable_first ) {
   824 		if ( $disable_first ) {
   759 			$page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&laquo;</span>';
   825 			$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&laquo;</span>';
   760 		} else {
   826 		} else {
   761 			$page_links[] = sprintf( "<a class='first-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
   827 			$page_links[] = sprintf(
       
   828 				"<a class='first-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
   762 				esc_url( remove_query_arg( 'paged', $current_url ) ),
   829 				esc_url( remove_query_arg( 'paged', $current_url ) ),
   763 				__( 'First page' ),
   830 				__( 'First page' ),
   764 				'&laquo;'
   831 				'&laquo;'
   765 			);
   832 			);
   766 		}
   833 		}
   767 
   834 
   768 		if ( $disable_prev ) {
   835 		if ( $disable_prev ) {
   769 			$page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&lsaquo;</span>';
   836 			$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&lsaquo;</span>';
   770 		} else {
   837 		} else {
   771 			$page_links[] = sprintf( "<a class='prev-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
   838 			$page_links[] = sprintf(
   772 				esc_url( add_query_arg( 'paged', max( 1, $current-1 ), $current_url ) ),
   839 				"<a class='prev-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
       
   840 				esc_url( add_query_arg( 'paged', max( 1, $current - 1 ), $current_url ) ),
   773 				__( 'Previous page' ),
   841 				__( 'Previous page' ),
   774 				'&lsaquo;'
   842 				'&lsaquo;'
   775 			);
   843 			);
   776 		}
   844 		}
   777 
   845 
   778 		if ( 'bottom' === $which ) {
   846 		if ( 'bottom' === $which ) {
   779 			$html_current_page  = $current;
   847 			$html_current_page  = $current;
   780 			$total_pages_before = '<span class="screen-reader-text">' . __( 'Current Page' ) . '</span><span id="table-paging" class="paging-input"><span class="tablenav-paging-text">';
   848 			$total_pages_before = '<span class="screen-reader-text">' . __( 'Current Page' ) . '</span><span id="table-paging" class="paging-input"><span class="tablenav-paging-text">';
   781 		} else {
   849 		} else {
   782 			$html_current_page = sprintf( "%s<input class='current-page' id='current-page-selector' type='text' name='paged' value='%s' size='%d' aria-describedby='table-paging' /><span class='tablenav-paging-text'>",
   850 			$html_current_page = sprintf(
       
   851 				"%s<input class='current-page' id='current-page-selector' type='text' name='paged' value='%s' size='%d' aria-describedby='table-paging' /><span class='tablenav-paging-text'>",
   783 				'<label for="current-page-selector" class="screen-reader-text">' . __( 'Current Page' ) . '</label>',
   852 				'<label for="current-page-selector" class="screen-reader-text">' . __( 'Current Page' ) . '</label>',
   784 				$current,
   853 				$current,
   785 				strlen( $total_pages )
   854 				strlen( $total_pages )
   786 			);
   855 			);
   787 		}
   856 		}
   788 		$html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) );
   857 		$html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) );
   789 		$page_links[] = $total_pages_before . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . $total_pages_after;
   858 		$page_links[]     = $total_pages_before . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . $total_pages_after;
   790 
   859 
   791 		if ( $disable_next ) {
   860 		if ( $disable_next ) {
   792 			$page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&rsaquo;</span>';
   861 			$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&rsaquo;</span>';
   793 		} else {
   862 		} else {
   794 			$page_links[] = sprintf( "<a class='next-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
   863 			$page_links[] = sprintf(
   795 				esc_url( add_query_arg( 'paged', min( $total_pages, $current+1 ), $current_url ) ),
   864 				"<a class='next-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
       
   865 				esc_url( add_query_arg( 'paged', min( $total_pages, $current + 1 ), $current_url ) ),
   796 				__( 'Next page' ),
   866 				__( 'Next page' ),
   797 				'&rsaquo;'
   867 				'&rsaquo;'
   798 			);
   868 			);
   799 		}
   869 		}
   800 
   870 
   801 		if ( $disable_last ) {
   871 		if ( $disable_last ) {
   802 			$page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&raquo;</span>';
   872 			$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&raquo;</span>';
   803 		} else {
   873 		} else {
   804 			$page_links[] = sprintf( "<a class='last-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
   874 			$page_links[] = sprintf(
       
   875 				"<a class='last-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
   805 				esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ),
   876 				esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ),
   806 				__( 'Last page' ),
   877 				__( 'Last page' ),
   807 				'&raquo;'
   878 				'&raquo;'
   808 			);
   879 			);
   809 		}
   880 		}
   860 	 *
   931 	 *
   861 	 * @return string Name of the default primary column, in this case, an empty string.
   932 	 * @return string Name of the default primary column, in this case, an empty string.
   862 	 */
   933 	 */
   863 	protected function get_default_primary_column_name() {
   934 	protected function get_default_primary_column_name() {
   864 		$columns = $this->get_columns();
   935 		$columns = $this->get_columns();
   865 		$column = '';
   936 		$column  = '';
   866 
   937 
   867 		if ( empty( $columns ) ) {
   938 		if ( empty( $columns ) ) {
   868 			return $column;
   939 			return $column;
   869 		}
   940 		}
   870 
   941 
   916 		 * @since 4.3.0
   987 		 * @since 4.3.0
   917 		 *
   988 		 *
   918 		 * @param string $default Column name default for the specific list table, e.g. 'name'.
   989 		 * @param string $default Column name default for the specific list table, e.g. 'name'.
   919 		 * @param string $context Screen ID for specific list table, e.g. 'plugins'.
   990 		 * @param string $context Screen ID for specific list table, e.g. 'plugins'.
   920 		 */
   991 		 */
   921 		$column  = apply_filters( 'list_table_primary_column', $default, $this->screen->id );
   992 		$column = apply_filters( 'list_table_primary_column', $default, $this->screen->id );
   922 
   993 
   923 		if ( empty( $column ) || ! isset( $columns[ $column ] ) ) {
   994 		if ( empty( $column ) || ! isset( $columns[ $column ] ) ) {
   924 			$column = $default;
   995 			$column = $default;
   925 		}
   996 		}
   926 
   997 
   946 
  1017 
   947 			return $column_headers;
  1018 			return $column_headers;
   948 		}
  1019 		}
   949 
  1020 
   950 		$columns = get_column_headers( $this->screen );
  1021 		$columns = get_column_headers( $this->screen );
   951 		$hidden = get_hidden_columns( $this->screen );
  1022 		$hidden  = get_hidden_columns( $this->screen );
   952 
  1023 
   953 		$sortable_columns = $this->get_sortable_columns();
  1024 		$sortable_columns = $this->get_sortable_columns();
   954 		/**
  1025 		/**
   955 		 * Filters the list table sortable columns for a specific screen.
  1026 		 * Filters the list table sortable columns for a specific screen.
   956 		 *
  1027 		 *
   963 		 */
  1034 		 */
   964 		$_sortable = apply_filters( "manage_{$this->screen->id}_sortable_columns", $sortable_columns );
  1035 		$_sortable = apply_filters( "manage_{$this->screen->id}_sortable_columns", $sortable_columns );
   965 
  1036 
   966 		$sortable = array();
  1037 		$sortable = array();
   967 		foreach ( $_sortable as $id => $data ) {
  1038 		foreach ( $_sortable as $id => $data ) {
   968 			if ( empty( $data ) )
  1039 			if ( empty( $data ) ) {
   969 				continue;
  1040 				continue;
       
  1041 			}
   970 
  1042 
   971 			$data = (array) $data;
  1043 			$data = (array) $data;
   972 			if ( !isset( $data[1] ) )
  1044 			if ( ! isset( $data[1] ) ) {
   973 				$data[1] = false;
  1045 				$data[1] = false;
   974 
  1046 			}
   975 			$sortable[$id] = $data;
  1047 
   976 		}
  1048 			$sortable[ $id ] = $data;
   977 
  1049 		}
   978 		$primary = $this->get_primary_column_name();
  1050 
       
  1051 		$primary               = $this->get_primary_column_name();
   979 		$this->_column_headers = array( $columns, $hidden, $sortable, $primary );
  1052 		$this->_column_headers = array( $columns, $hidden, $sortable, $primary );
   980 
  1053 
   981 		return $this->_column_headers;
  1054 		return $this->_column_headers;
   982 	}
  1055 	}
   983 
  1056 
   988 	 *
  1061 	 *
   989 	 * @return int
  1062 	 * @return int
   990 	 */
  1063 	 */
   991 	public function get_column_count() {
  1064 	public function get_column_count() {
   992 		list ( $columns, $hidden ) = $this->get_column_info();
  1065 		list ( $columns, $hidden ) = $this->get_column_info();
   993 		$hidden = array_intersect( array_keys( $columns ), array_filter( $hidden ) );
  1066 		$hidden                    = array_intersect( array_keys( $columns ), array_filter( $hidden ) );
   994 		return count( $columns ) - count( $hidden );
  1067 		return count( $columns ) - count( $hidden );
   995 	}
  1068 	}
   996 
  1069 
   997 	/**
  1070 	/**
   998 	 * Print column headers, accounting for hidden and sortable columns.
  1071 	 * Print column headers, accounting for hidden and sortable columns.
  1021 			$current_order = 'asc';
  1094 			$current_order = 'asc';
  1022 		}
  1095 		}
  1023 
  1096 
  1024 		if ( ! empty( $columns['cb'] ) ) {
  1097 		if ( ! empty( $columns['cb'] ) ) {
  1025 			static $cb_counter = 1;
  1098 			static $cb_counter = 1;
  1026 			$columns['cb'] = '<label class="screen-reader-text" for="cb-select-all-' . $cb_counter . '">' . __( 'Select All' ) . '</label>'
  1099 			$columns['cb']     = '<label class="screen-reader-text" for="cb-select-all-' . $cb_counter . '">' . __( 'Select All' ) . '</label>'
  1027 				. '<input id="cb-select-all-' . $cb_counter . '" type="checkbox" />';
  1100 				. '<input id="cb-select-all-' . $cb_counter . '" type="checkbox" />';
  1028 			$cb_counter++;
  1101 			$cb_counter++;
  1029 		}
  1102 		}
  1030 
  1103 
  1031 		foreach ( $columns as $column_key => $column_display_name ) {
  1104 		foreach ( $columns as $column_key => $column_display_name ) {
  1033 
  1106 
  1034 			if ( in_array( $column_key, $hidden ) ) {
  1107 			if ( in_array( $column_key, $hidden ) ) {
  1035 				$class[] = 'hidden';
  1108 				$class[] = 'hidden';
  1036 			}
  1109 			}
  1037 
  1110 
  1038 			if ( 'cb' === $column_key )
  1111 			if ( 'cb' === $column_key ) {
  1039 				$class[] = 'check-column';
  1112 				$class[] = 'check-column';
  1040 			elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) )
  1113 			} elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) ) {
  1041 				$class[] = 'num';
  1114 				$class[] = 'num';
       
  1115 			}
  1042 
  1116 
  1043 			if ( $column_key === $primary ) {
  1117 			if ( $column_key === $primary ) {
  1044 				$class[] = 'column-primary';
  1118 				$class[] = 'column-primary';
  1045 			}
  1119 			}
  1046 
  1120 
  1047 			if ( isset( $sortable[$column_key] ) ) {
  1121 			if ( isset( $sortable[ $column_key ] ) ) {
  1048 				list( $orderby, $desc_first ) = $sortable[$column_key];
  1122 				list( $orderby, $desc_first ) = $sortable[ $column_key ];
  1049 
  1123 
  1050 				if ( $current_orderby === $orderby ) {
  1124 				if ( $current_orderby === $orderby ) {
  1051 					$order = 'asc' === $current_order ? 'desc' : 'asc';
  1125 					$order   = 'asc' === $current_order ? 'desc' : 'asc';
  1052 					$class[] = 'sorted';
  1126 					$class[] = 'sorted';
  1053 					$class[] = $current_order;
  1127 					$class[] = $current_order;
  1054 				} else {
  1128 				} else {
  1055 					$order = $desc_first ? 'desc' : 'asc';
  1129 					$order   = $desc_first ? 'desc' : 'asc';
  1056 					$class[] = 'sortable';
  1130 					$class[] = 'sortable';
  1057 					$class[] = $desc_first ? 'asc' : 'desc';
  1131 					$class[] = $desc_first ? 'asc' : 'desc';
  1058 				}
  1132 				}
  1059 
  1133 
  1060 				$column_display_name = '<a href="' . esc_url( add_query_arg( compact( 'orderby', 'order' ), $current_url ) ) . '"><span>' . $column_display_name . '</span><span class="sorting-indicator"></span></a>';
  1134 				$column_display_name = '<a href="' . esc_url( add_query_arg( compact( 'orderby', 'order' ), $current_url ) ) . '"><span>' . $column_display_name . '</span><span class="sorting-indicator"></span></a>';
  1061 			}
  1135 			}
  1062 
  1136 
  1063 			$tag = ( 'cb' === $column_key ) ? 'td' : 'th';
  1137 			$tag   = ( 'cb' === $column_key ) ? 'td' : 'th';
  1064 			$scope = ( 'th' === $tag ) ? 'scope="col"' : '';
  1138 			$scope = ( 'th' === $tag ) ? 'scope="col"' : '';
  1065 			$id = $with_id ? "id='$column_key'" : '';
  1139 			$id    = $with_id ? "id='$column_key'" : '';
  1066 
  1140 
  1067 			if ( !empty( $class ) )
  1141 			if ( ! empty( $class ) ) {
  1068 				$class = "class='" . join( ' ', $class ) . "'";
  1142 				$class = "class='" . join( ' ', $class ) . "'";
       
  1143 			}
  1069 
  1144 
  1070 			echo "<$tag $scope $id $class>$column_display_name</$tag>";
  1145 			echo "<$tag $scope $id $class>$column_display_name</$tag>";
  1071 		}
  1146 		}
  1072 	}
  1147 	}
  1073 
  1148 
  1080 		$singular = $this->_args['singular'];
  1155 		$singular = $this->_args['singular'];
  1081 
  1156 
  1082 		$this->display_tablenav( 'top' );
  1157 		$this->display_tablenav( 'top' );
  1083 
  1158 
  1084 		$this->screen->render_screen_reader_content( 'heading_list' );
  1159 		$this->screen->render_screen_reader_content( 'heading_list' );
  1085 ?>
  1160 		?>
  1086 <table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
  1161 <table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
  1087 	<thead>
  1162 	<thead>
  1088 	<tr>
  1163 	<tr>
  1089 		<?php $this->print_column_headers(); ?>
  1164 		<?php $this->print_column_headers(); ?>
  1090 	</tr>
  1165 	</tr>
  1091 	</thead>
  1166 	</thead>
  1092 
  1167 
  1093 	<tbody id="the-list"<?php
  1168 	<tbody id="the-list"
       
  1169 		<?php
  1094 		if ( $singular ) {
  1170 		if ( $singular ) {
  1095 			echo " data-wp-lists='list:$singular'";
  1171 			echo " data-wp-lists='list:$singular'";
  1096 		} ?>>
  1172 		}
       
  1173 		?>
       
  1174 		>
  1097 		<?php $this->display_rows_or_placeholder(); ?>
  1175 		<?php $this->display_rows_or_placeholder(); ?>
  1098 	</tbody>
  1176 	</tbody>
  1099 
  1177 
  1100 	<tfoot>
  1178 	<tfoot>
  1101 	<tr>
  1179 	<tr>
  1102 		<?php $this->print_column_headers( false ); ?>
  1180 		<?php $this->print_column_headers( false ); ?>
  1103 	</tr>
  1181 	</tr>
  1104 	</tfoot>
  1182 	</tfoot>
  1105 
  1183 
  1106 </table>
  1184 </table>
  1107 <?php
  1185 		<?php
  1108 		$this->display_tablenav( 'bottom' );
  1186 		$this->display_tablenav( 'bottom' );
  1109 	}
  1187 	}
  1110 
  1188 
  1111 	/**
  1189 	/**
  1112 	 * Get a list of CSS classes for the WP_List_Table table tag.
  1190 	 * Get a list of CSS classes for the WP_List_Table table tag.
  1130 			wp_nonce_field( 'bulk-' . $this->_args['plural'] );
  1208 			wp_nonce_field( 'bulk-' . $this->_args['plural'] );
  1131 		}
  1209 		}
  1132 		?>
  1210 		?>
  1133 	<div class="tablenav <?php echo esc_attr( $which ); ?>">
  1211 	<div class="tablenav <?php echo esc_attr( $which ); ?>">
  1134 
  1212 
  1135 		<?php if ( $this->has_items() ): ?>
  1213 		<?php if ( $this->has_items() ) : ?>
  1136 		<div class="alignleft actions bulkactions">
  1214 		<div class="alignleft actions bulkactions">
  1137 			<?php $this->bulk_actions( $which ); ?>
  1215 			<?php $this->bulk_actions( $which ); ?>
  1138 		</div>
  1216 		</div>
  1139 		<?php endif;
  1217 			<?php
       
  1218 		endif;
  1140 		$this->extra_tablenav( $which );
  1219 		$this->extra_tablenav( $which );
  1141 		$this->pagination( $which );
  1220 		$this->pagination( $which );
  1142 ?>
  1221 		?>
  1143 
  1222 
  1144 		<br class="clear" />
  1223 		<br class="clear" />
  1145 	</div>
  1224 	</div>
  1146 <?php
  1225 		<?php
  1147 	}
  1226 	}
  1148 
  1227 
  1149 	/**
  1228 	/**
  1150 	 * Extra controls to be displayed between bulk actions and pagination
  1229 	 * Extra controls to be displayed between bulk actions and pagination
  1151 	 *
  1230 	 *
  1174 	 * Generate the table rows
  1253 	 * Generate the table rows
  1175 	 *
  1254 	 *
  1176 	 * @since 3.1.0
  1255 	 * @since 3.1.0
  1177 	 */
  1256 	 */
  1178 	public function display_rows() {
  1257 	public function display_rows() {
  1179 		foreach ( $this->items as $item )
  1258 		foreach ( $this->items as $item ) {
  1180 			$this->single_row( $item );
  1259 			$this->single_row( $item );
       
  1260 		}
  1181 	}
  1261 	}
  1182 
  1262 
  1183 	/**
  1263 	/**
  1184 	 * Generates content for a single row of the table
  1264 	 * Generates content for a single row of the table
  1185 	 *
  1265 	 *
  1192 		$this->single_row_columns( $item );
  1272 		$this->single_row_columns( $item );
  1193 		echo '</tr>';
  1273 		echo '</tr>';
  1194 	}
  1274 	}
  1195 
  1275 
  1196 	/**
  1276 	/**
  1197 	 *
       
  1198 	 * @param object $item
  1277 	 * @param object $item
  1199 	 * @param string $column_name
  1278 	 * @param string $column_name
  1200 	 */
  1279 	 */
  1201 	protected function column_default( $item, $column_name ) {}
  1280 	protected function column_default( $item, $column_name ) {}
  1202 
  1281 
  1203 	/**
  1282 	/**
  1204 	 *
       
  1205 	 * @param object $item
  1283 	 * @param object $item
  1206 	 */
  1284 	 */
  1207 	protected function column_cb( $item ) {}
  1285 	protected function column_cb( $item ) {}
  1208 
  1286 
  1209 	/**
  1287 	/**
  1246 				);
  1324 				);
  1247 			} elseif ( method_exists( $this, 'column_' . $column_name ) ) {
  1325 			} elseif ( method_exists( $this, 'column_' . $column_name ) ) {
  1248 				echo "<td $attributes>";
  1326 				echo "<td $attributes>";
  1249 				echo call_user_func( array( $this, 'column_' . $column_name ), $item );
  1327 				echo call_user_func( array( $this, 'column_' . $column_name ), $item );
  1250 				echo $this->handle_row_actions( $item, $column_name, $primary );
  1328 				echo $this->handle_row_actions( $item, $column_name, $primary );
  1251 				echo "</td>";
  1329 				echo '</td>';
  1252 			} else {
  1330 			} else {
  1253 				echo "<td $attributes>";
  1331 				echo "<td $attributes>";
  1254 				echo $this->column_default( $item, $column_name );
  1332 				echo $this->column_default( $item, $column_name );
  1255 				echo $this->handle_row_actions( $item, $column_name, $primary );
  1333 				echo $this->handle_row_actions( $item, $column_name, $primary );
  1256 				echo "</td>";
  1334 				echo '</td>';
  1257 			}
  1335 			}
  1258 		}
  1336 		}
  1259 	}
  1337 	}
  1260 
  1338 
  1261 	/**
  1339 	/**
  1268 	 * @param string $primary     Primary column name.
  1346 	 * @param string $primary     Primary column name.
  1269 	 * @return string The row actions HTML, or an empty string if the current column is the primary column.
  1347 	 * @return string The row actions HTML, or an empty string if the current column is the primary column.
  1270 	 */
  1348 	 */
  1271 	protected function handle_row_actions( $item, $column_name, $primary ) {
  1349 	protected function handle_row_actions( $item, $column_name, $primary ) {
  1272 		return $column_name === $primary ? '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>' : '';
  1350 		return $column_name === $primary ? '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>' : '';
  1273  	}
  1351 	}
  1274 
  1352 
  1275 	/**
  1353 	/**
  1276 	 * Handle an incoming ajax request (called from admin-ajax.php)
  1354 	 * Handle an incoming ajax request (called from admin-ajax.php)
  1277 	 *
  1355 	 *
  1278 	 * @since 3.1.0
  1356 	 * @since 3.1.0
  1296 				_n( '%s item', '%s items', $this->_pagination_args['total_items'] ),
  1374 				_n( '%s item', '%s items', $this->_pagination_args['total_items'] ),
  1297 				number_format_i18n( $this->_pagination_args['total_items'] )
  1375 				number_format_i18n( $this->_pagination_args['total_items'] )
  1298 			);
  1376 			);
  1299 		}
  1377 		}
  1300 		if ( isset( $this->_pagination_args['total_pages'] ) ) {
  1378 		if ( isset( $this->_pagination_args['total_pages'] ) ) {
  1301 			$response['total_pages'] = $this->_pagination_args['total_pages'];
  1379 			$response['total_pages']      = $this->_pagination_args['total_pages'];
  1302 			$response['total_pages_i18n'] = number_format_i18n( $this->_pagination_args['total_pages'] );
  1380 			$response['total_pages_i18n'] = number_format_i18n( $this->_pagination_args['total_pages'] );
  1303 		}
  1381 		}
  1304 
  1382 
  1305 		die( wp_json_encode( $response ) );
  1383 		die( wp_json_encode( $response ) );
  1306 	}
  1384 	}
  1307 
  1385 
  1308 	/**
  1386 	/**
  1309 	 * Send required variables to JavaScript land
  1387 	 * Send required variables to JavaScript land
  1310 	 *
       
  1311 	 */
  1388 	 */
  1312 	public function _js_vars() {
  1389 	public function _js_vars() {
  1313 		$args = array(
  1390 		$args = array(
  1314 			'class'  => get_class( $this ),
  1391 			'class'  => get_class( $this ),
  1315 			'screen' => array(
  1392 			'screen' => array(
  1316 				'id'   => $this->screen->id,
  1393 				'id'   => $this->screen->id,
  1317 				'base' => $this->screen->base,
  1394 				'base' => $this->screen->base,
  1318 			)
  1395 			),
  1319 		);
  1396 		);
  1320 
  1397 
  1321 		printf( "<script type='text/javascript'>list_args = %s;</script>\n", wp_json_encode( $args ) );
  1398 		printf( "<script type='text/javascript'>list_args = %s;</script>\n", wp_json_encode( $args ) );
  1322 	}
  1399 	}
  1323 }
  1400 }