wp/wp-admin/includes/class-wp-list-table.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
   164 			add_action( 'admin_footer', array( $this, '_js_vars' ) );
   164 			add_action( 'admin_footer', array( $this, '_js_vars' ) );
   165 		}
   165 		}
   166 
   166 
   167 		if ( empty( $this->modes ) ) {
   167 		if ( empty( $this->modes ) ) {
   168 			$this->modes = array(
   168 			$this->modes = array(
   169 				'list'    => __( 'List View' ),
   169 				'list'    => __( 'Compact view' ),
   170 				'excerpt' => __( 'Excerpt View' ),
   170 				'excerpt' => __( 'Extended view' ),
   171 			);
   171 			);
   172 		}
   172 		}
   173 	}
   173 	}
   174 
   174 
   175 	/**
   175 	/**
   179 	 *
   179 	 *
   180 	 * @param string $name Property to get.
   180 	 * @param string $name Property to get.
   181 	 * @return mixed Property.
   181 	 * @return mixed Property.
   182 	 */
   182 	 */
   183 	public function __get( $name ) {
   183 	public function __get( $name ) {
   184 		if ( in_array( $name, $this->compat_fields ) ) {
   184 		if ( in_array( $name, $this->compat_fields, true ) ) {
   185 			return $this->$name;
   185 			return $this->$name;
   186 		}
   186 		}
   187 	}
   187 	}
   188 
   188 
   189 	/**
   189 	/**
   194 	 * @param string $name  Property to check if set.
   194 	 * @param string $name  Property to check if set.
   195 	 * @param mixed  $value Property value.
   195 	 * @param mixed  $value Property value.
   196 	 * @return mixed Newly-set property.
   196 	 * @return mixed Newly-set property.
   197 	 */
   197 	 */
   198 	public function __set( $name, $value ) {
   198 	public function __set( $name, $value ) {
   199 		if ( in_array( $name, $this->compat_fields ) ) {
   199 		if ( in_array( $name, $this->compat_fields, true ) ) {
   200 			return $this->$name = $value;
   200 			return $this->$name = $value;
   201 		}
   201 		}
   202 	}
   202 	}
   203 
   203 
   204 	/**
   204 	/**
   208 	 *
   208 	 *
   209 	 * @param string $name Property to check if set.
   209 	 * @param string $name Property to check if set.
   210 	 * @return bool Whether the property is set.
   210 	 * @return bool Whether the property is set.
   211 	 */
   211 	 */
   212 	public function __isset( $name ) {
   212 	public function __isset( $name ) {
   213 		if ( in_array( $name, $this->compat_fields ) ) {
   213 		if ( in_array( $name, $this->compat_fields, true ) ) {
   214 			return isset( $this->$name );
   214 			return isset( $this->$name );
   215 		}
   215 		}
   216 	}
   216 	}
   217 
   217 
   218 	/**
   218 	/**
   221 	 * @since 4.0.0
   221 	 * @since 4.0.0
   222 	 *
   222 	 *
   223 	 * @param string $name Property to unset.
   223 	 * @param string $name Property to unset.
   224 	 */
   224 	 */
   225 	public function __unset( $name ) {
   225 	public function __unset( $name ) {
   226 		if ( in_array( $name, $this->compat_fields ) ) {
   226 		if ( in_array( $name, $this->compat_fields, true ) ) {
   227 			unset( $this->$name );
   227 			unset( $this->$name );
   228 		}
   228 		}
   229 	}
   229 	}
   230 
   230 
   231 	/**
   231 	/**
   232 	 * Make private/protected methods readable for backward compatibility.
   232 	 * Make private/protected methods readable for backward compatibility.
   233 	 *
   233 	 *
   234 	 * @since 4.0.0
   234 	 * @since 4.0.0
   235 	 *
   235 	 *
   236 	 * @param string   $name      Method to call.
   236 	 * @param string $name      Method to call.
   237 	 * @param array    $arguments Arguments to pass when calling.
   237 	 * @param array  $arguments Arguments to pass when calling.
   238 	 * @return mixed|bool Return value of the callback, false otherwise.
   238 	 * @return mixed|bool Return value of the callback, false otherwise.
   239 	 */
   239 	 */
   240 	public function __call( $name, $arguments ) {
   240 	public function __call( $name, $arguments ) {
   241 		if ( in_array( $name, $this->compat_methods ) ) {
   241 		if ( in_array( $name, $this->compat_methods, true ) ) {
   242 			return call_user_func_array( array( $this, $name ), $arguments );
   242 			return $this->$name( ...$arguments );
   243 		}
   243 		}
   244 		return false;
   244 		return false;
   245 	}
   245 	}
   246 
   246 
   247 	/**
   247 	/**
   249 	 *
   249 	 *
   250 	 * @since 3.1.0
   250 	 * @since 3.1.0
   251 	 * @abstract
   251 	 * @abstract
   252 	 */
   252 	 */
   253 	public function ajax_user_can() {
   253 	public function ajax_user_can() {
   254 		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 overridden in a subclass.' );
   255 	}
   255 	}
   256 
   256 
   257 	/**
   257 	/**
   258 	 * Prepares the list of items for displaying.
   258 	 * Prepares the list of items for displaying.
   259 	 *
   259 	 *
   261 	 *
   261 	 *
   262 	 * @since 3.1.0
   262 	 * @since 3.1.0
   263 	 * @abstract
   263 	 * @abstract
   264 	 */
   264 	 */
   265 	public function prepare_items() {
   265 	public function prepare_items() {
   266 		die( 'function WP_List_Table::prepare_items() must be over-ridden in a sub-class.' );
   266 		die( 'function WP_List_Table::prepare_items() must be overridden in a subclass.' );
   267 	}
   267 	}
   268 
   268 
   269 	/**
   269 	/**
   270 	 * An internal method that sets all the necessary pagination arguments
   270 	 * An internal method that sets all the necessary pagination arguments
   271 	 *
   271 	 *
   370 </p>
   370 </p>
   371 		<?php
   371 		<?php
   372 	}
   372 	}
   373 
   373 
   374 	/**
   374 	/**
   375 	 * Get an associative array ( id => link ) with the list
   375 	 * Gets the list of views available on this table.
   376 	 * of views available on this table.
   376 	 *
       
   377 	 * The format is an associative array:
       
   378 	 * - `'id' => 'link'`
   377 	 *
   379 	 *
   378 	 * @since 3.1.0
   380 	 * @since 3.1.0
   379 	 *
   381 	 *
   380 	 * @return array
   382 	 * @return array
   381 	 */
   383 	 */
   382 	protected function get_views() {
   384 	protected function get_views() {
   383 		return array();
   385 		return array();
   384 	}
   386 	}
   385 
   387 
   386 	/**
   388 	/**
   387 	 * Display the list of views available on this table.
   389 	 * Displays the list of views available on this table.
   388 	 *
   390 	 *
   389 	 * @since 3.1.0
   391 	 * @since 3.1.0
   390 	 */
   392 	 */
   391 	public function views() {
   393 	public function views() {
   392 		$views = $this->get_views();
   394 		$views = $this->get_views();
   394 		 * Filters the list of available list table views.
   396 		 * Filters the list of available list table views.
   395 		 *
   397 		 *
   396 		 * The dynamic portion of the hook name, `$this->screen->id`, refers
   398 		 * The dynamic portion of the hook name, `$this->screen->id`, refers
   397 		 * to the ID of the current screen, usually a string.
   399 		 * to the ID of the current screen, usually a string.
   398 		 *
   400 		 *
   399 		 * @since 3.5.0
   401 		 * @since 3.1.0
   400 		 *
   402 		 *
   401 		 * @param string[] $views An array of available list table views.
   403 		 * @param string[] $views An array of available list table views.
   402 		 */
   404 		 */
   403 		$views = apply_filters( "views_{$this->screen->id}", $views );
   405 		$views = apply_filters( "views_{$this->screen->id}", $views );
   404 
   406 
   415 		echo implode( " |</li>\n", $views ) . "</li>\n";
   417 		echo implode( " |</li>\n", $views ) . "</li>\n";
   416 		echo '</ul>';
   418 		echo '</ul>';
   417 	}
   419 	}
   418 
   420 
   419 	/**
   421 	/**
   420 	 * Get an associative array ( option_name => option_title ) with the list
   422 	 * Gets the list of bulk actions available on this table.
   421 	 * of bulk actions available on this table.
   423 	 *
       
   424 	 * The format is an associative array:
       
   425 	 * - `'option_name' => 'option_title'`
   422 	 *
   426 	 *
   423 	 * @since 3.1.0
   427 	 * @since 3.1.0
   424 	 *
   428 	 *
   425 	 * @return array
   429 	 * @return array
   426 	 */
   430 	 */
   427 	protected function get_bulk_actions() {
   431 	protected function get_bulk_actions() {
   428 		return array();
   432 		return array();
   429 	}
   433 	}
   430 
   434 
   431 	/**
   435 	/**
   432 	 * Display the bulk actions dropdown.
   436 	 * Displays the bulk actions dropdown.
   433 	 *
   437 	 *
   434 	 * @since 3.1.0
   438 	 * @since 3.1.0
   435 	 *
   439 	 *
   436 	 * @param string $which The location of the bulk actions: 'top' or 'bottom'.
   440 	 * @param string $which The location of the bulk actions: 'top' or 'bottom'.
   437 	 *                      This is designated as optional for backward compatibility.
   441 	 *                      This is designated as optional for backward compatibility.
   438 	 */
   442 	 */
   439 	protected function bulk_actions( $which = '' ) {
   443 	protected function bulk_actions( $which = '' ) {
   440 		if ( is_null( $this->_actions ) ) {
   444 		if ( is_null( $this->_actions ) ) {
   441 			$this->_actions = $this->get_bulk_actions();
   445 			$this->_actions = $this->get_bulk_actions();
       
   446 
   442 			/**
   447 			/**
   443 			 * Filters the list table Bulk Actions drop-down.
   448 			 * Filters the list table bulk actions drop-down.
   444 			 *
   449 			 *
   445 			 * The dynamic portion of the hook name, `$this->screen->id`, refers
   450 			 * The dynamic portion of the hook name, `$this->screen->id`, refers
   446 			 * to the ID of the current screen, usually a string.
   451 			 * to the ID of the current screen, usually a string.
   447 			 *
   452 			 *
   448 			 * This filter can currently only be used to remove bulk actions.
   453 			 * @since 3.1.0
   449 			 *
       
   450 			 * @since 3.5.0
       
   451 			 *
   454 			 *
   452 			 * @param string[] $actions An array of the available bulk actions.
   455 			 * @param string[] $actions An array of the available bulk actions.
   453 			 */
   456 			 */
   454 			$this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions );
   457 			$this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
   455 			$two            = '';
   458 
       
   459 			$two = '';
   456 		} else {
   460 		} else {
   457 			$two = '2';
   461 			$two = '2';
   458 		}
   462 		}
   459 
   463 
   460 		if ( empty( $this->_actions ) ) {
   464 		if ( empty( $this->_actions ) ) {
   461 			return;
   465 			return;
   462 		}
   466 		}
   463 
   467 
   464 		echo '<label for="bulk-action-selector-' . esc_attr( $which ) . '" class="screen-reader-text">' . __( 'Select bulk action' ) . '</label>';
   468 		echo '<label for="bulk-action-selector-' . esc_attr( $which ) . '" class="screen-reader-text">' . __( 'Select bulk action' ) . '</label>';
   465 		echo '<select name="action' . $two . '" id="bulk-action-selector-' . esc_attr( $which ) . "\">\n";
   469 		echo '<select name="action' . $two . '" id="bulk-action-selector-' . esc_attr( $which ) . "\">\n";
   466 		echo '<option value="-1">' . __( 'Bulk Actions' ) . "</option>\n";
   470 		echo '<option value="-1">' . __( 'Bulk actions' ) . "</option>\n";
   467 
   471 
   468 		foreach ( $this->_actions as $name => $title ) {
   472 		foreach ( $this->_actions as $name => $title ) {
   469 			$class = 'edit' === $name ? ' class="hide-if-no-js"' : '';
   473 			$class = 'edit' === $name ? ' class="hide-if-no-js"' : '';
   470 
   474 
   471 			echo "\t" . '<option value="' . $name . '"' . $class . '>' . $title . "</option>\n";
   475 			echo "\t" . '<option value="' . $name . '"' . $class . '>' . $title . "</option>\n";
   476 		submit_button( __( 'Apply' ), 'action', '', false, array( 'id' => "doaction$two" ) );
   480 		submit_button( __( 'Apply' ), 'action', '', false, array( 'id' => "doaction$two" ) );
   477 		echo "\n";
   481 		echo "\n";
   478 	}
   482 	}
   479 
   483 
   480 	/**
   484 	/**
   481 	 * Get the current action selected from the bulk actions dropdown.
   485 	 * Gets the current action selected from the bulk actions dropdown.
   482 	 *
   486 	 *
   483 	 * @since 3.1.0
   487 	 * @since 3.1.0
   484 	 *
   488 	 *
   485 	 * @return string|false The action name or False if no action was selected
   489 	 * @return string|false The action name. False if no action was selected.
   486 	 */
   490 	 */
   487 	public function current_action() {
   491 	public function current_action() {
   488 		if ( isset( $_REQUEST['filter_action'] ) && ! empty( $_REQUEST['filter_action'] ) ) {
   492 		if ( isset( $_REQUEST['filter_action'] ) && ! empty( $_REQUEST['filter_action'] ) ) {
   489 			return false;
   493 			return false;
   490 		}
   494 		}
   499 
   503 
   500 		return false;
   504 		return false;
   501 	}
   505 	}
   502 
   506 
   503 	/**
   507 	/**
   504 	 * Generate row actions div
   508 	 * Generates the required HTML for a list of row action links.
   505 	 *
   509 	 *
   506 	 * @since 3.1.0
   510 	 * @since 3.1.0
   507 	 *
   511 	 *
   508 	 * @param string[] $actions        An array of action links.
   512 	 * @param string[] $actions        An array of action links.
   509 	 * @param bool     $always_visible Whether the actions should be always visible.
   513 	 * @param bool     $always_visible Whether the actions should be always visible.
   510 	 * @return string
   514 	 * @return string The HTML for the row actions.
   511 	 */
   515 	 */
   512 	protected function row_actions( $actions, $always_visible = false ) {
   516 	protected function row_actions( $actions, $always_visible = false ) {
   513 		$action_count = count( $actions );
   517 		$action_count = count( $actions );
   514 		$i            = 0;
       
   515 
   518 
   516 		if ( ! $action_count ) {
   519 		if ( ! $action_count ) {
   517 			return '';
   520 			return '';
   518 		}
   521 		}
   519 
   522 
       
   523 		$mode = get_user_setting( 'posts_list_mode', 'list' );
       
   524 
       
   525 		if ( 'excerpt' === $mode ) {
       
   526 			$always_visible = true;
       
   527 		}
       
   528 
   520 		$out = '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">';
   529 		$out = '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">';
       
   530 
       
   531 		$i = 0;
       
   532 
   521 		foreach ( $actions as $action => $link ) {
   533 		foreach ( $actions as $action => $link ) {
   522 			++$i;
   534 			++$i;
   523 			( $i == $action_count ) ? $sep = '' : $sep = ' | ';
   535 
   524 			$out                          .= "<span class='$action'>$link$sep</span>";
   536 			$sep = ( $i < $action_count ) ? ' | ' : '';
   525 		}
   537 
       
   538 			$out .= "<span class='$action'>$link$sep</span>";
       
   539 		}
       
   540 
   526 		$out .= '</div>';
   541 		$out .= '</div>';
   527 
   542 
   528 		$out .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>';
   543 		$out .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>';
   529 
   544 
   530 		return $out;
   545 		return $out;
   531 	}
   546 	}
   532 
   547 
   533 	/**
   548 	/**
   534 	 * Display a monthly dropdown for filtering items
   549 	 * Displays a dropdown for filtering items in the list table by month.
   535 	 *
   550 	 *
   536 	 * @since 3.1.0
   551 	 * @since 3.1.0
   537 	 *
   552 	 *
   538 	 * @global wpdb      $wpdb
   553 	 * @global wpdb      $wpdb      WordPress database abstraction object.
   539 	 * @global WP_Locale $wp_locale
   554 	 * @global WP_Locale $wp_locale WordPress date and time locale object.
   540 	 *
   555 	 *
   541 	 * @param string $post_type
   556 	 * @param string $post_type The post type.
   542 	 */
   557 	 */
   543 	protected function months_dropdown( $post_type ) {
   558 	protected function months_dropdown( $post_type ) {
   544 		global $wpdb, $wp_locale;
   559 		global $wpdb, $wp_locale;
   545 
   560 
   546 		/**
   561 		/**
   578 		/**
   593 		/**
   579 		 * Filters the 'Months' drop-down results.
   594 		 * Filters the 'Months' drop-down results.
   580 		 *
   595 		 *
   581 		 * @since 3.7.0
   596 		 * @since 3.7.0
   582 		 *
   597 		 *
   583 		 * @param object $months    The months drop-down query results.
   598 		 * @param object[] $months    Array of the months drop-down query results.
   584 		 * @param string $post_type The post type.
   599 		 * @param string   $post_type The post type.
   585 		 */
   600 		 */
   586 		$months = apply_filters( 'months_dropdown_results', $months, $post_type );
   601 		$months = apply_filters( 'months_dropdown_results', $months, $post_type );
   587 
   602 
   588 		$month_count = count( $months );
   603 		$month_count = count( $months );
   589 
   604 
   607 
   622 
   608 			printf(
   623 			printf(
   609 				"<option %s value='%s'>%s</option>\n",
   624 				"<option %s value='%s'>%s</option>\n",
   610 				selected( $m, $year . $month, false ),
   625 				selected( $m, $year . $month, false ),
   611 				esc_attr( $arc_row->year . $month ),
   626 				esc_attr( $arc_row->year . $month ),
   612 				/* translators: 1: month name, 2: 4-digit year */
   627 				/* translators: 1: Month name, 2: 4-digit year. */
   613 				sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month ), $year )
   628 				sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month ), $year )
   614 			);
   629 			);
   615 		}
   630 		}
   616 		?>
   631 		?>
   617 		</select>
   632 		</select>
   618 		<?php
   633 		<?php
   619 	}
   634 	}
   620 
   635 
   621 	/**
   636 	/**
   622 	 * Display a view switcher
   637 	 * Displays a view switcher.
   623 	 *
   638 	 *
   624 	 * @since 3.1.0
   639 	 * @since 3.1.0
   625 	 *
   640 	 *
   626 	 * @param string $current_mode
   641 	 * @param string $current_mode
   627 	 */
   642 	 */
   629 		?>
   644 		?>
   630 		<input type="hidden" name="mode" value="<?php echo esc_attr( $current_mode ); ?>" />
   645 		<input type="hidden" name="mode" value="<?php echo esc_attr( $current_mode ); ?>" />
   631 		<div class="view-switch">
   646 		<div class="view-switch">
   632 		<?php
   647 		<?php
   633 		foreach ( $this->modes as $mode => $title ) {
   648 		foreach ( $this->modes as $mode => $title ) {
   634 			$classes = array( 'view-' . $mode );
   649 			$classes      = array( 'view-' . $mode );
       
   650 			$aria_current = '';
       
   651 
   635 			if ( $current_mode === $mode ) {
   652 			if ( $current_mode === $mode ) {
   636 				$classes[] = 'current';
   653 				$classes[]    = 'current';
       
   654 				$aria_current = ' aria-current="page"';
   637 			}
   655 			}
       
   656 
   638 			printf(
   657 			printf(
   639 				"<a href='%s' class='%s' id='view-switch-$mode'><span class='screen-reader-text'>%s</span></a>\n",
   658 				"<a href='%s' class='%s' id='view-switch-$mode'$aria_current><span class='screen-reader-text'>%s</span></a>\n",
   640 				esc_url( add_query_arg( 'mode', $mode ) ),
   659 				esc_url( remove_query_arg( 'attachment-filter', add_query_arg( 'mode', $mode ) ) ),
   641 				implode( ' ', $classes ),
   660 				implode( ' ', $classes ),
   642 				$title
   661 				$title
   643 			);
   662 			);
   644 		}
   663 		}
   645 		?>
   664 		?>
   646 		</div>
   665 		</div>
   647 		<?php
   666 		<?php
   648 	}
   667 	}
   649 
   668 
   650 	/**
   669 	/**
   651 	 * Display a comment count bubble
   670 	 * Displays a comment count bubble.
   652 	 *
   671 	 *
   653 	 * @since 3.1.0
   672 	 * @since 3.1.0
   654 	 *
   673 	 *
   655 	 * @param int $post_id          The post ID.
   674 	 * @param int $post_id          The post ID.
   656 	 * @param int $pending_comments Number of pending comments.
   675 	 * @param int $pending_comments Number of pending comments.
   659 		$approved_comments = get_comments_number();
   678 		$approved_comments = get_comments_number();
   660 
   679 
   661 		$approved_comments_number = number_format_i18n( $approved_comments );
   680 		$approved_comments_number = number_format_i18n( $approved_comments );
   662 		$pending_comments_number  = number_format_i18n( $pending_comments );
   681 		$pending_comments_number  = number_format_i18n( $pending_comments );
   663 
   682 
   664 		$approved_only_phrase = sprintf( _n( '%s comment', '%s comments', $approved_comments ), $approved_comments_number );
   683 		$approved_only_phrase = sprintf(
   665 		$approved_phrase      = sprintf( _n( '%s approved comment', '%s approved comments', $approved_comments ), $approved_comments_number );
   684 			/* translators: %s: Number of comments. */
   666 		$pending_phrase       = sprintf( _n( '%s pending comment', '%s pending comments', $pending_comments ), $pending_comments_number );
   685 			_n( '%s comment', '%s comments', $approved_comments ),
   667 
   686 			$approved_comments_number
   668 		// No comments at all.
   687 		);
       
   688 
       
   689 		$approved_phrase = sprintf(
       
   690 			/* translators: %s: Number of comments. */
       
   691 			_n( '%s approved comment', '%s approved comments', $approved_comments ),
       
   692 			$approved_comments_number
       
   693 		);
       
   694 
       
   695 		$pending_phrase = sprintf(
       
   696 			/* translators: %s: Number of comments. */
       
   697 			_n( '%s pending comment', '%s pending comments', $pending_comments ),
       
   698 			$pending_comments_number
       
   699 		);
       
   700 
   669 		if ( ! $approved_comments && ! $pending_comments ) {
   701 		if ( ! $approved_comments && ! $pending_comments ) {
       
   702 			// No comments at all.
   670 			printf(
   703 			printf(
   671 				'<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">%s</span>',
   704 				'<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">%s</span>',
   672 				__( 'No comments' )
   705 				__( 'No comments' )
   673 			);
   706 			);
   674 			// Approved comments have different display depending on some conditions.
   707 		} elseif ( $approved_comments && 'trash' === get_post_status( $post_id ) ) {
       
   708 			// Don't link the comment bubble for a trashed post.
       
   709 			printf(
       
   710 				'<span 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></span>',
       
   711 				$approved_comments_number,
       
   712 				$pending_comments ? $approved_phrase : $approved_only_phrase
       
   713 			);
   675 		} elseif ( $approved_comments ) {
   714 		} elseif ( $approved_comments ) {
       
   715 			// Link the comment bubble to approved comments.
   676 			printf(
   716 			printf(
   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>',
   717 				'<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(
   718 				esc_url(
   679 					add_query_arg(
   719 					add_query_arg(
   680 						array(
   720 						array(
   686 				),
   726 				),
   687 				$approved_comments_number,
   727 				$approved_comments_number,
   688 				$pending_comments ? $approved_phrase : $approved_only_phrase
   728 				$pending_comments ? $approved_phrase : $approved_only_phrase
   689 			);
   729 			);
   690 		} else {
   730 		} else {
       
   731 			// Don't link the comment bubble when there are no approved comments.
   691 			printf(
   732 			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>',
   733 				'<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>',
   693 				$approved_comments_number,
   734 				$approved_comments_number,
   694 				$pending_comments ? __( 'No approved comments' ) : __( 'No comments' )
   735 				$pending_comments ? __( 'No approved comments' ) : __( 'No comments' )
   695 			);
   736 			);
   718 			);
   759 			);
   719 		}
   760 		}
   720 	}
   761 	}
   721 
   762 
   722 	/**
   763 	/**
   723 	 * Get the current page number
   764 	 * Gets the current page number.
   724 	 *
   765 	 *
   725 	 * @since 3.1.0
   766 	 * @since 3.1.0
   726 	 *
   767 	 *
   727 	 * @return int
   768 	 * @return int
   728 	 */
   769 	 */
   735 
   776 
   736 		return max( 1, $pagenum );
   777 		return max( 1, $pagenum );
   737 	}
   778 	}
   738 
   779 
   739 	/**
   780 	/**
   740 	 * Get number of items to display on a single page
   781 	 * Gets the number of items to display on a single page.
   741 	 *
   782 	 *
   742 	 * @since 3.1.0
   783 	 * @since 3.1.0
   743 	 *
   784 	 *
   744 	 * @param string $option
   785 	 * @param string $option
   745 	 * @param int    $default
   786 	 * @param int    $default
   752 		}
   793 		}
   753 
   794 
   754 		/**
   795 		/**
   755 		 * Filters the number of items to be displayed on each page of the list table.
   796 		 * Filters the number of items to be displayed on each page of the list table.
   756 		 *
   797 		 *
   757 		 * The dynamic hook name, $option, refers to the `per_page` option depending
   798 		 * The dynamic hook name, `$option`, refers to the `per_page` option depending
   758 		 * on the type of list table in use. Possible values include: 'edit_comments_per_page',
   799 		 * on the type of list table in use. Possible filter names include:
   759 		 * 'sites_network_per_page', 'site_themes_network_per_page', 'themes_network_per_page',
   800 		 *
   760 		 * 'users_network_per_page', 'edit_post_per_page', 'edit_page_per_page',
   801 		 *  - `edit_comments_per_page`
   761 		 * 'edit_{$post_type}_per_page', etc.
   802 		 *  - `sites_network_per_page`
       
   803 		 *  - `site_themes_network_per_page`
       
   804 		 *  - `themes_network_per_page'`
       
   805 		 *  - `users_network_per_page`
       
   806 		 *  - `edit_post_per_page`
       
   807 		 *  - `edit_page_per_page'`
       
   808 		 *  - `edit_{$post_type}_per_page`
       
   809 		 *  - `edit_post_tag_per_page`
       
   810 		 *  - `edit_category_per_page`
       
   811 		 *  - `edit_{$taxonomy}_per_page`
       
   812 		 *  - `site_users_network_per_page`
       
   813 		 *  - `users_per_page`
   762 		 *
   814 		 *
   763 		 * @since 2.9.0
   815 		 * @since 2.9.0
   764 		 *
   816 		 *
   765 		 * @param int $per_page Number of items to be displayed. Default 20.
   817 		 * @param int $per_page Number of items to be displayed. Default 20.
   766 		 */
   818 		 */
   767 		return (int) apply_filters( "{$option}", $per_page );
   819 		return (int) apply_filters( "{$option}", $per_page );
   768 	}
   820 	}
   769 
   821 
   770 	/**
   822 	/**
   771 	 * Display the pagination.
   823 	 * Displays the pagination.
   772 	 *
   824 	 *
   773 	 * @since 3.1.0
   825 	 * @since 3.1.0
   774 	 *
   826 	 *
   775 	 * @param string $which
   827 	 * @param string $which
   776 	 */
   828 	 */
   788 
   840 
   789 		if ( 'top' === $which && $total_pages > 1 ) {
   841 		if ( 'top' === $which && $total_pages > 1 ) {
   790 			$this->screen->render_screen_reader_content( 'heading_pagination' );
   842 			$this->screen->render_screen_reader_content( 'heading_pagination' );
   791 		}
   843 		}
   792 
   844 
   793 		$output = '<span class="displaying-num">' . sprintf( _n( '%s item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . '</span>';
   845 		$output = '<span class="displaying-num">' . sprintf(
       
   846 			/* translators: %s: Number of items. */
       
   847 			_n( '%s item', '%s items', $total_items ),
       
   848 			number_format_i18n( $total_items )
       
   849 		) . '</span>';
   794 
   850 
   795 		$current              = $this->get_pagenum();
   851 		$current              = $this->get_pagenum();
   796 		$removable_query_args = wp_removable_query_args();
   852 		$removable_query_args = wp_removable_query_args();
   797 
   853 
   798 		$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
   854 		$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
   802 		$page_links = array();
   858 		$page_links = array();
   803 
   859 
   804 		$total_pages_before = '<span class="paging-input">';
   860 		$total_pages_before = '<span class="paging-input">';
   805 		$total_pages_after  = '</span></span>';
   861 		$total_pages_after  = '</span></span>';
   806 
   862 
   807 		$disable_first = $disable_last = $disable_prev = $disable_next = false;
   863 		$disable_first = false;
   808 
   864 		$disable_last  = false;
   809 		if ( $current == 1 ) {
   865 		$disable_prev  = false;
       
   866 		$disable_next  = false;
       
   867 
       
   868 		if ( 1 == $current ) {
   810 			$disable_first = true;
   869 			$disable_first = true;
   811 			$disable_prev  = true;
   870 			$disable_prev  = true;
   812 		}
   871 		}
   813 		if ( $current == 2 ) {
   872 		if ( 2 == $current ) {
   814 			$disable_first = true;
   873 			$disable_first = true;
   815 		}
   874 		}
   816 		if ( $current == $total_pages ) {
   875 		if ( $total_pages == $current ) {
   817 			$disable_last = true;
   876 			$disable_last = true;
   818 			$disable_next = true;
   877 			$disable_next = true;
   819 		}
   878 		}
   820 		if ( $current == $total_pages - 1 ) {
   879 		if ( $total_pages - 1 == $current ) {
   821 			$disable_last = true;
   880 			$disable_last = true;
   822 		}
   881 		}
   823 
   882 
   824 		if ( $disable_first ) {
   883 		if ( $disable_first ) {
   825 			$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&laquo;</span>';
   884 			$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&laquo;</span>';
   853 				$current,
   912 				$current,
   854 				strlen( $total_pages )
   913 				strlen( $total_pages )
   855 			);
   914 			);
   856 		}
   915 		}
   857 		$html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) );
   916 		$html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) );
   858 		$page_links[]     = $total_pages_before . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . $total_pages_after;
   917 		$page_links[]     = $total_pages_before . sprintf(
       
   918 			/* translators: 1: Current page, 2: Total pages. */
       
   919 			_x( '%1$s of %2$s', 'paging' ),
       
   920 			$html_current_page,
       
   921 			$html_total_pages
       
   922 		) . $total_pages_after;
   859 
   923 
   860 		if ( $disable_next ) {
   924 		if ( $disable_next ) {
   861 			$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&rsaquo;</span>';
   925 			$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&rsaquo;</span>';
   862 		} else {
   926 		} else {
   863 			$page_links[] = sprintf(
   927 			$page_links[] = sprintf(
   894 
   958 
   895 		echo $this->_pagination;
   959 		echo $this->_pagination;
   896 	}
   960 	}
   897 
   961 
   898 	/**
   962 	/**
   899 	 * Get a list of columns. The format is:
   963 	 * Gets a list of columns.
   900 	 * 'internal-name' => 'Title'
   964 	 *
       
   965 	 * The format is:
       
   966 	 * - `'internal-name' => 'Title'`
   901 	 *
   967 	 *
   902 	 * @since 3.1.0
   968 	 * @since 3.1.0
   903 	 * @abstract
   969 	 * @abstract
   904 	 *
   970 	 *
   905 	 * @return array
   971 	 * @return array
   906 	 */
   972 	 */
   907 	public function get_columns() {
   973 	public function get_columns() {
   908 		die( 'function WP_List_Table::get_columns() must be over-ridden in a sub-class.' );
   974 		die( 'function WP_List_Table::get_columns() must be overridden in a subclass.' );
   909 	}
   975 	}
   910 
   976 
   911 	/**
   977 	/**
   912 	 * Get a list of sortable columns. The format is:
   978 	 * Gets a list of sortable columns.
   913 	 * 'internal-name' => 'orderby'
   979 	 *
   914 	 * or
   980 	 * The format is:
   915 	 * 'internal-name' => array( 'orderby', true )
   981 	 * - `'internal-name' => 'orderby'`
   916 	 *
   982 	 * - `'internal-name' => array( 'orderby', 'asc' )` - The second element sets the initial sorting order.
   917 	 * The second format will make the initial sorting order be descending
   983 	 * - `'internal-name' => array( 'orderby', true )`  - The second element makes the initial order descending.
   918 	 *
   984 	 *
   919 	 * @since 3.1.0
   985 	 * @since 3.1.0
   920 	 *
   986 	 *
   921 	 * @return array
   987 	 * @return array
   922 	 */
   988 	 */
   973 	 */
  1039 	 */
   974 	protected function get_primary_column_name() {
  1040 	protected function get_primary_column_name() {
   975 		$columns = get_column_headers( $this->screen );
  1041 		$columns = get_column_headers( $this->screen );
   976 		$default = $this->get_default_primary_column_name();
  1042 		$default = $this->get_default_primary_column_name();
   977 
  1043 
   978 		// If the primary column doesn't exist fall back to the
  1044 		// If the primary column doesn't exist,
   979 		// first non-checkbox column.
  1045 		// fall back to the first non-checkbox column.
   980 		if ( ! isset( $columns[ $default ] ) ) {
  1046 		if ( ! isset( $columns[ $default ] ) ) {
   981 			$default = WP_List_Table::get_default_primary_column_name();
  1047 			$default = WP_List_Table::get_default_primary_column_name();
   982 		}
  1048 		}
   983 
  1049 
   984 		/**
  1050 		/**
   997 
  1063 
   998 		return $column;
  1064 		return $column;
   999 	}
  1065 	}
  1000 
  1066 
  1001 	/**
  1067 	/**
  1002 	 * Get a list of all, hidden and sortable columns, with filter applied
  1068 	 * Gets a list of all, hidden and sortable columns, with filter applied.
  1003 	 *
  1069 	 *
  1004 	 * @since 3.1.0
  1070 	 * @since 3.1.0
  1005 	 *
  1071 	 *
  1006 	 * @return array
  1072 	 * @return array
  1007 	 */
  1073 	 */
  1008 	protected function get_column_info() {
  1074 	protected function get_column_info() {
  1009 		// $_column_headers is already set / cached
  1075 		// $_column_headers is already set / cached.
  1010 		if ( isset( $this->_column_headers ) && is_array( $this->_column_headers ) ) {
  1076 		if ( isset( $this->_column_headers ) && is_array( $this->_column_headers ) ) {
  1011 			// Back-compat for list tables that have been manually setting $_column_headers for horse reasons.
  1077 			// Back-compat for list tables that have been manually setting $_column_headers for horse reasons.
  1012 			// In 4.3, we added a fourth argument for primary column.
  1078 			// In 4.3, we added a fourth argument for primary column.
  1013 			$column_headers = array( array(), array(), array(), $this->get_primary_column_name() );
  1079 			$column_headers = array( array(), array(), array(), $this->get_primary_column_name() );
  1014 			foreach ( $this->_column_headers as $key => $value ) {
  1080 			foreach ( $this->_column_headers as $key => $value ) {
  1026 		 * Filters the list table sortable columns for a specific screen.
  1092 		 * Filters the list table sortable columns for a specific screen.
  1027 		 *
  1093 		 *
  1028 		 * The dynamic portion of the hook name, `$this->screen->id`, refers
  1094 		 * The dynamic portion of the hook name, `$this->screen->id`, refers
  1029 		 * to the ID of the current screen, usually a string.
  1095 		 * to the ID of the current screen, usually a string.
  1030 		 *
  1096 		 *
  1031 		 * @since 3.5.0
  1097 		 * @since 3.1.0
  1032 		 *
  1098 		 *
  1033 		 * @param array $sortable_columns An array of sortable columns.
  1099 		 * @param array $sortable_columns An array of sortable columns.
  1034 		 */
  1100 		 */
  1035 		$_sortable = apply_filters( "manage_{$this->screen->id}_sortable_columns", $sortable_columns );
  1101 		$_sortable = apply_filters( "manage_{$this->screen->id}_sortable_columns", $sortable_columns );
  1036 
  1102 
  1053 
  1119 
  1054 		return $this->_column_headers;
  1120 		return $this->_column_headers;
  1055 	}
  1121 	}
  1056 
  1122 
  1057 	/**
  1123 	/**
  1058 	 * Return number of visible columns
  1124 	 * Returns the number of visible columns.
  1059 	 *
  1125 	 *
  1060 	 * @since 3.1.0
  1126 	 * @since 3.1.0
  1061 	 *
  1127 	 *
  1062 	 * @return int
  1128 	 * @return int
  1063 	 */
  1129 	 */
  1066 		$hidden                    = array_intersect( array_keys( $columns ), array_filter( $hidden ) );
  1132 		$hidden                    = array_intersect( array_keys( $columns ), array_filter( $hidden ) );
  1067 		return count( $columns ) - count( $hidden );
  1133 		return count( $columns ) - count( $hidden );
  1068 	}
  1134 	}
  1069 
  1135 
  1070 	/**
  1136 	/**
  1071 	 * Print column headers, accounting for hidden and sortable columns.
  1137 	 * Prints column headers, accounting for hidden and sortable columns.
  1072 	 *
  1138 	 *
  1073 	 * @since 3.1.0
  1139 	 * @since 3.1.0
  1074 	 *
  1140 	 *
  1075 	 * @staticvar int $cb_counter
  1141 	 * @param bool $with_id Whether to set the ID attribute or not
  1076 	 *
       
  1077 	 * @param bool $with_id Whether to set the id attribute or not
       
  1078 	 */
  1142 	 */
  1079 	public function print_column_headers( $with_id = true ) {
  1143 	public function print_column_headers( $with_id = true ) {
  1080 		list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
  1144 		list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
  1081 
  1145 
  1082 		$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
  1146 		$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
  1102 		}
  1166 		}
  1103 
  1167 
  1104 		foreach ( $columns as $column_key => $column_display_name ) {
  1168 		foreach ( $columns as $column_key => $column_display_name ) {
  1105 			$class = array( 'manage-column', "column-$column_key" );
  1169 			$class = array( 'manage-column', "column-$column_key" );
  1106 
  1170 
  1107 			if ( in_array( $column_key, $hidden ) ) {
  1171 			if ( in_array( $column_key, $hidden, true ) ) {
  1108 				$class[] = 'hidden';
  1172 				$class[] = 'hidden';
  1109 			}
  1173 			}
  1110 
  1174 
  1111 			if ( 'cb' === $column_key ) {
  1175 			if ( 'cb' === $column_key ) {
  1112 				$class[] = 'check-column';
  1176 				$class[] = 'check-column';
  1113 			} elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) ) {
  1177 			} elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ), true ) ) {
  1114 				$class[] = 'num';
  1178 				$class[] = 'num';
  1115 			}
  1179 			}
  1116 
  1180 
  1117 			if ( $column_key === $primary ) {
  1181 			if ( $column_key === $primary ) {
  1118 				$class[] = 'column-primary';
  1182 				$class[] = 'column-primary';
  1120 
  1184 
  1121 			if ( isset( $sortable[ $column_key ] ) ) {
  1185 			if ( isset( $sortable[ $column_key ] ) ) {
  1122 				list( $orderby, $desc_first ) = $sortable[ $column_key ];
  1186 				list( $orderby, $desc_first ) = $sortable[ $column_key ];
  1123 
  1187 
  1124 				if ( $current_orderby === $orderby ) {
  1188 				if ( $current_orderby === $orderby ) {
  1125 					$order   = 'asc' === $current_order ? 'desc' : 'asc';
  1189 					$order = 'asc' === $current_order ? 'desc' : 'asc';
       
  1190 
  1126 					$class[] = 'sorted';
  1191 					$class[] = 'sorted';
  1127 					$class[] = $current_order;
  1192 					$class[] = $current_order;
  1128 				} else {
  1193 				} else {
  1129 					$order   = $desc_first ? 'desc' : 'asc';
  1194 					$order = strtolower( $desc_first );
       
  1195 
       
  1196 					if ( ! in_array( $order, array( 'desc', 'asc' ), true ) ) {
       
  1197 						$order = $desc_first ? 'desc' : 'asc';
       
  1198 					}
       
  1199 
  1130 					$class[] = 'sortable';
  1200 					$class[] = 'sortable';
  1131 					$class[] = $desc_first ? 'asc' : 'desc';
  1201 					$class[] = 'desc' === $order ? 'asc' : 'desc';
  1132 				}
  1202 				}
  1133 
  1203 
  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>';
  1204 				$column_display_name = sprintf(
       
  1205 					'<a href="%s"><span>%s</span><span class="sorting-indicator"></span></a>',
       
  1206 					esc_url( add_query_arg( compact( 'orderby', 'order' ), $current_url ) ),
       
  1207 					$column_display_name
       
  1208 				);
  1135 			}
  1209 			}
  1136 
  1210 
  1137 			$tag   = ( 'cb' === $column_key ) ? 'td' : 'th';
  1211 			$tag   = ( 'cb' === $column_key ) ? 'td' : 'th';
  1138 			$scope = ( 'th' === $tag ) ? 'scope="col"' : '';
  1212 			$scope = ( 'th' === $tag ) ? 'scope="col"' : '';
  1139 			$id    = $with_id ? "id='$column_key'" : '';
  1213 			$id    = $with_id ? "id='$column_key'" : '';
  1145 			echo "<$tag $scope $id $class>$column_display_name</$tag>";
  1219 			echo "<$tag $scope $id $class>$column_display_name</$tag>";
  1146 		}
  1220 		}
  1147 	}
  1221 	}
  1148 
  1222 
  1149 	/**
  1223 	/**
  1150 	 * Display the table
  1224 	 * Displays the table.
  1151 	 *
  1225 	 *
  1152 	 * @since 3.1.0
  1226 	 * @since 3.1.0
  1153 	 */
  1227 	 */
  1154 	public function display() {
  1228 	public function display() {
  1155 		$singular = $this->_args['singular'];
  1229 		$singular = $this->_args['singular'];
  1185 		<?php
  1259 		<?php
  1186 		$this->display_tablenav( 'bottom' );
  1260 		$this->display_tablenav( 'bottom' );
  1187 	}
  1261 	}
  1188 
  1262 
  1189 	/**
  1263 	/**
  1190 	 * Get a list of CSS classes for the WP_List_Table table tag.
  1264 	 * Gets a list of CSS classes for the WP_List_Table table tag.
  1191 	 *
  1265 	 *
  1192 	 * @since 3.1.0
  1266 	 * @since 3.1.0
  1193 	 *
  1267 	 *
  1194 	 * @return array List of CSS classes for the table tag.
  1268 	 * @return string[] Array of CSS classes for the table tag.
  1195 	 */
  1269 	 */
  1196 	protected function get_table_classes() {
  1270 	protected function get_table_classes() {
  1197 		return array( 'widefat', 'fixed', 'striped', $this->_args['plural'] );
  1271 		$mode = get_user_setting( 'posts_list_mode', 'list' );
  1198 	}
  1272 
  1199 
  1273 		$mode_class = esc_attr( 'table-view-' . $mode );
  1200 	/**
  1274 
  1201 	 * Generate the table navigation above or below the table
  1275 		return array( 'widefat', 'fixed', 'striped', $mode_class, $this->_args['plural'] );
       
  1276 	}
       
  1277 
       
  1278 	/**
       
  1279 	 * Generates the table navigation above or below the table
  1202 	 *
  1280 	 *
  1203 	 * @since 3.1.0
  1281 	 * @since 3.1.0
  1204 	 * @param string $which
  1282 	 * @param string $which
  1205 	 */
  1283 	 */
  1206 	protected function display_tablenav( $which ) {
  1284 	protected function display_tablenav( $which ) {
  1224 	</div>
  1302 	</div>
  1225 		<?php
  1303 		<?php
  1226 	}
  1304 	}
  1227 
  1305 
  1228 	/**
  1306 	/**
  1229 	 * Extra controls to be displayed between bulk actions and pagination
  1307 	 * Extra controls to be displayed between bulk actions and pagination.
  1230 	 *
  1308 	 *
  1231 	 * @since 3.1.0
  1309 	 * @since 3.1.0
  1232 	 *
  1310 	 *
  1233 	 * @param string $which
  1311 	 * @param string $which
  1234 	 */
  1312 	 */
  1235 	protected function extra_tablenav( $which ) {}
  1313 	protected function extra_tablenav( $which ) {}
  1236 
  1314 
  1237 	/**
  1315 	/**
  1238 	 * Generate the tbody element for the list table.
  1316 	 * Generates the tbody element for the list table.
  1239 	 *
  1317 	 *
  1240 	 * @since 3.1.0
  1318 	 * @since 3.1.0
  1241 	 */
  1319 	 */
  1242 	public function display_rows_or_placeholder() {
  1320 	public function display_rows_or_placeholder() {
  1243 		if ( $this->has_items() ) {
  1321 		if ( $this->has_items() ) {
  1248 			echo '</td></tr>';
  1326 			echo '</td></tr>';
  1249 		}
  1327 		}
  1250 	}
  1328 	}
  1251 
  1329 
  1252 	/**
  1330 	/**
  1253 	 * Generate the table rows
  1331 	 * Generates the table rows.
  1254 	 *
  1332 	 *
  1255 	 * @since 3.1.0
  1333 	 * @since 3.1.0
  1256 	 */
  1334 	 */
  1257 	public function display_rows() {
  1335 	public function display_rows() {
  1258 		foreach ( $this->items as $item ) {
  1336 		foreach ( $this->items as $item ) {
  1259 			$this->single_row( $item );
  1337 			$this->single_row( $item );
  1260 		}
  1338 		}
  1261 	}
  1339 	}
  1262 
  1340 
  1263 	/**
  1341 	/**
  1264 	 * Generates content for a single row of the table
  1342 	 * Generates content for a single row of the table.
  1265 	 *
  1343 	 *
  1266 	 * @since 3.1.0
  1344 	 * @since 3.1.0
  1267 	 *
  1345 	 *
  1268 	 * @param object $item The current item
  1346 	 * @param object $item The current item
  1269 	 */
  1347 	 */
  1283 	 * @param object $item
  1361 	 * @param object $item
  1284 	 */
  1362 	 */
  1285 	protected function column_cb( $item ) {}
  1363 	protected function column_cb( $item ) {}
  1286 
  1364 
  1287 	/**
  1365 	/**
  1288 	 * Generates the columns for a single row of the table
  1366 	 * Generates the columns for a single row of the table.
  1289 	 *
  1367 	 *
  1290 	 * @since 3.1.0
  1368 	 * @since 3.1.0
  1291 	 *
  1369 	 *
  1292 	 * @param object $item The current item
  1370 	 * @param object $item The current item.
  1293 	 */
  1371 	 */
  1294 	protected function single_row_columns( $item ) {
  1372 	protected function single_row_columns( $item ) {
  1295 		list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
  1373 		list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
  1296 
  1374 
  1297 		foreach ( $columns as $column_name => $column_display_name ) {
  1375 		foreach ( $columns as $column_name => $column_display_name ) {
  1298 			$classes = "$column_name column-$column_name";
  1376 			$classes = "$column_name column-$column_name";
  1299 			if ( $primary === $column_name ) {
  1377 			if ( $primary === $column_name ) {
  1300 				$classes .= ' has-row-actions column-primary';
  1378 				$classes .= ' has-row-actions column-primary';
  1301 			}
  1379 			}
  1302 
  1380 
  1303 			if ( in_array( $column_name, $hidden ) ) {
  1381 			if ( in_array( $column_name, $hidden, true ) ) {
  1304 				$classes .= ' hidden';
  1382 				$classes .= ' hidden';
  1305 			}
  1383 			}
  1306 
  1384 
  1307 			// Comments column uses HTML in the display name with screen reader text.
  1385 			// Comments column uses HTML in the display name with screen reader text.
  1308 			// Instead of using esc_attr(), we strip tags to get closer to a user-friendly string.
  1386 			// Instead of using esc_attr(), we strip tags to get closer to a user-friendly string.
  1342 	 * @since 4.3.0
  1420 	 * @since 4.3.0
  1343 	 *
  1421 	 *
  1344 	 * @param object $item        The item being acted upon.
  1422 	 * @param object $item        The item being acted upon.
  1345 	 * @param string $column_name Current column name.
  1423 	 * @param string $column_name Current column name.
  1346 	 * @param string $primary     Primary column name.
  1424 	 * @param string $primary     Primary column name.
  1347 	 * @return string The row actions HTML, or an empty string if the current column is the primary column.
  1425 	 * @return string The row actions HTML, or an empty string
       
  1426 	 *                if the current column is not the primary column.
  1348 	 */
  1427 	 */
  1349 	protected function handle_row_actions( $item, $column_name, $primary ) {
  1428 	protected function handle_row_actions( $item, $column_name, $primary ) {
  1350 		return $column_name === $primary ? '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>' : '';
  1429 		return $column_name === $primary ? '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>' : '';
  1351 	}
  1430 	}
  1352 
  1431 
  1353 	/**
  1432 	/**
  1354 	 * Handle an incoming ajax request (called from admin-ajax.php)
  1433 	 * Handles an incoming ajax request (called from admin-ajax.php)
  1355 	 *
  1434 	 *
  1356 	 * @since 3.1.0
  1435 	 * @since 3.1.0
  1357 	 */
  1436 	 */
  1358 	public function ajax_response() {
  1437 	public function ajax_response() {
  1359 		$this->prepare_items();
  1438 		$this->prepare_items();
  1369 
  1448 
  1370 		$response = array( 'rows' => $rows );
  1449 		$response = array( 'rows' => $rows );
  1371 
  1450 
  1372 		if ( isset( $this->_pagination_args['total_items'] ) ) {
  1451 		if ( isset( $this->_pagination_args['total_items'] ) ) {
  1373 			$response['total_items_i18n'] = sprintf(
  1452 			$response['total_items_i18n'] = sprintf(
       
  1453 				/* translators: Number of items. */
  1374 				_n( '%s item', '%s items', $this->_pagination_args['total_items'] ),
  1454 				_n( '%s item', '%s items', $this->_pagination_args['total_items'] ),
  1375 				number_format_i18n( $this->_pagination_args['total_items'] )
  1455 				number_format_i18n( $this->_pagination_args['total_items'] )
  1376 			);
  1456 			);
  1377 		}
  1457 		}
  1378 		if ( isset( $this->_pagination_args['total_pages'] ) ) {
  1458 		if ( isset( $this->_pagination_args['total_pages'] ) ) {
  1382 
  1462 
  1383 		die( wp_json_encode( $response ) );
  1463 		die( wp_json_encode( $response ) );
  1384 	}
  1464 	}
  1385 
  1465 
  1386 	/**
  1466 	/**
  1387 	 * Send required variables to JavaScript land
  1467 	 * Sends required variables to JavaScript land.
       
  1468 	 *
       
  1469 	 * @since 3.1.0
  1388 	 */
  1470 	 */
  1389 	public function _js_vars() {
  1471 	public function _js_vars() {
  1390 		$args = array(
  1472 		$args = array(
  1391 			'class'  => get_class( $this ),
  1473 			'class'  => get_class( $this ),
  1392 			'screen' => array(
  1474 			'screen' => array(