wp/wp-admin/includes/class-wp-list-table.php
changeset 18 be944660c56a
parent 16 a86126ab1dd4
child 19 3d72ae0968f4
equal deleted inserted replaced
17:34716fd837a4 18:be944660c56a
    41 
    41 
    42 	/**
    42 	/**
    43 	 * The current screen.
    43 	 * The current screen.
    44 	 *
    44 	 *
    45 	 * @since 3.1.0
    45 	 * @since 3.1.0
    46 	 * @var object
    46 	 * @var WP_Screen
    47 	 */
    47 	 */
    48 	protected $screen;
    48 	protected $screen;
    49 
    49 
    50 	/**
    50 	/**
    51 	 * Cached bulk actions.
    51 	 * Cached bulk actions.
   394 		$views = $this->get_views();
   394 		$views = $this->get_views();
   395 		/**
   395 		/**
   396 		 * Filters the list of available list table views.
   396 		 * Filters the list of available list table views.
   397 		 *
   397 		 *
   398 		 * The dynamic portion of the hook name, `$this->screen->id`, refers
   398 		 * The dynamic portion of the hook name, `$this->screen->id`, refers
   399 		 * to the ID of the current screen, usually a string.
   399 		 * to the ID of the current screen.
   400 		 *
   400 		 *
   401 		 * @since 3.1.0
   401 		 * @since 3.1.0
   402 		 *
   402 		 *
   403 		 * @param string[] $views An array of available list table views.
   403 		 * @param string[] $views An array of available list table views.
   404 		 */
   404 		 */
   417 		echo implode( " |</li>\n", $views ) . "</li>\n";
   417 		echo implode( " |</li>\n", $views ) . "</li>\n";
   418 		echo '</ul>';
   418 		echo '</ul>';
   419 	}
   419 	}
   420 
   420 
   421 	/**
   421 	/**
   422 	 * Gets the list of bulk actions available on this table.
   422 	 * Retrieves the list of bulk actions available for this table.
   423 	 *
   423 	 *
   424 	 * The format is an associative array:
   424 	 * The format is an associative array where each element represents either a top level option value and label, or
   425 	 * - `'option_name' => 'option_title'`
   425 	 * an array representing an optgroup and its options.
   426 	 *
   426 	 *
   427 	 * @since 3.1.0
   427 	 * For a standard option, the array element key is the field value and the array element value is the field label.
       
   428 	 *
       
   429 	 * For an optgroup, the array element key is the label and the array element value is an associative array of
       
   430 	 * options as above.
       
   431 	 *
       
   432 	 * Example:
       
   433 	 *
       
   434 	 *     [
       
   435 	 *         'edit'         => 'Edit',
       
   436 	 *         'delete'       => 'Delete',
       
   437 	 *         'Change State' => [
       
   438 	 *             'feature' => 'Featured',
       
   439 	 *             'sale'    => 'On Sale',
       
   440 	 *         ]
       
   441 	 *     ]
       
   442 	 *
       
   443 	 * @since 3.1.0
       
   444 	 * @since 5.6.0 A bulk action can now contain an array of options in order to create an optgroup.
   428 	 *
   445 	 *
   429 	 * @return array
   446 	 * @return array
   430 	 */
   447 	 */
   431 	protected function get_bulk_actions() {
   448 	protected function get_bulk_actions() {
   432 		return array();
   449 		return array();
   443 	protected function bulk_actions( $which = '' ) {
   460 	protected function bulk_actions( $which = '' ) {
   444 		if ( is_null( $this->_actions ) ) {
   461 		if ( is_null( $this->_actions ) ) {
   445 			$this->_actions = $this->get_bulk_actions();
   462 			$this->_actions = $this->get_bulk_actions();
   446 
   463 
   447 			/**
   464 			/**
   448 			 * Filters the list table bulk actions drop-down.
   465 			 * Filters the items in the bulk actions menu of the list table.
   449 			 *
   466 			 *
   450 			 * The dynamic portion of the hook name, `$this->screen->id`, refers
   467 			 * The dynamic portion of the hook name, `$this->screen->id`, refers
   451 			 * to the ID of the current screen, usually a string.
   468 			 * to the ID of the current screen.
   452 			 *
   469 			 *
   453 			 * @since 3.1.0
   470 			 * @since 3.1.0
       
   471 			 * @since 5.6.0 A bulk action can now contain an array of options in order to create an optgroup.
   454 			 *
   472 			 *
   455 			 * @param string[] $actions An array of the available bulk actions.
   473 			 * @param array $actions An array of the available bulk actions.
   456 			 */
   474 			 */
   457 			$this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
   475 			$this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
   458 
   476 
   459 			$two = '';
   477 			$two = '';
   460 		} else {
   478 		} else {
   467 
   485 
   468 		echo '<label for="bulk-action-selector-' . esc_attr( $which ) . '" class="screen-reader-text">' . __( 'Select bulk action' ) . '</label>';
   486 		echo '<label for="bulk-action-selector-' . esc_attr( $which ) . '" class="screen-reader-text">' . __( 'Select bulk action' ) . '</label>';
   469 		echo '<select name="action' . $two . '" id="bulk-action-selector-' . esc_attr( $which ) . "\">\n";
   487 		echo '<select name="action' . $two . '" id="bulk-action-selector-' . esc_attr( $which ) . "\">\n";
   470 		echo '<option value="-1">' . __( 'Bulk actions' ) . "</option>\n";
   488 		echo '<option value="-1">' . __( 'Bulk actions' ) . "</option>\n";
   471 
   489 
   472 		foreach ( $this->_actions as $name => $title ) {
   490 		foreach ( $this->_actions as $key => $value ) {
   473 			$class = 'edit' === $name ? ' class="hide-if-no-js"' : '';
   491 			if ( is_array( $value ) ) {
   474 
   492 				echo "\t" . '<optgroup label="' . esc_attr( $key ) . '">' . "\n";
   475 			echo "\t" . '<option value="' . $name . '"' . $class . '>' . $title . "</option>\n";
   493 
       
   494 				foreach ( $value as $name => $title ) {
       
   495 					$class = ( 'edit' === $name ) ? ' class="hide-if-no-js"' : '';
       
   496 
       
   497 					echo "\t\t" . '<option value="' . esc_attr( $name ) . '"' . $class . '>' . $title . "</option>\n";
       
   498 				}
       
   499 				echo "\t" . "</optgroup>\n";
       
   500 			} else {
       
   501 				$class = ( 'edit' === $key ) ? ' class="hide-if-no-js"' : '';
       
   502 
       
   503 				echo "\t" . '<option value="' . esc_attr( $key ) . '"' . $class . '>' . $value . "</option>\n";
       
   504 			}
   476 		}
   505 		}
   477 
   506 
   478 		echo "</select>\n";
   507 		echo "</select>\n";
   479 
   508 
   480 		submit_button( __( 'Apply' ), 'action', '', false, array( 'id' => "doaction$two" ) );
   509 		submit_button( __( 'Apply' ), 'action', '', false, array( 'id' => "doaction$two" ) );
   493 			return false;
   522 			return false;
   494 		}
   523 		}
   495 
   524 
   496 		if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] ) {
   525 		if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] ) {
   497 			return $_REQUEST['action'];
   526 			return $_REQUEST['action'];
   498 		}
       
   499 
       
   500 		if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] ) {
       
   501 			return $_REQUEST['action2'];
       
   502 		}
   527 		}
   503 
   528 
   504 		return false;
   529 		return false;
   505 	}
   530 	}
   506 
   531 
   568 		 */
   593 		 */
   569 		if ( apply_filters( 'disable_months_dropdown', false, $post_type ) ) {
   594 		if ( apply_filters( 'disable_months_dropdown', false, $post_type ) ) {
   570 			return;
   595 			return;
   571 		}
   596 		}
   572 
   597 
   573 		$extra_checks = "AND post_status != 'auto-draft'";
   598 		/**
   574 		if ( ! isset( $_GET['post_status'] ) || 'trash' !== $_GET['post_status'] ) {
   599 		 * Filters to short-circuit performing the months dropdown query.
   575 			$extra_checks .= " AND post_status != 'trash'";
   600 		 *
   576 		} elseif ( isset( $_GET['post_status'] ) ) {
   601 		 * @since 5.7.0
   577 			$extra_checks = $wpdb->prepare( ' AND post_status = %s', $_GET['post_status'] );
   602 		 *
   578 		}
   603 		 * @param object[]|false $months   'Months' drop-down results. Default false.
   579 
   604 		 * @param string         $post_type The post type.
   580 		$months = $wpdb->get_results(
   605 		 */
   581 			$wpdb->prepare(
   606 		$months = apply_filters( 'pre_months_dropdown_query', false, $post_type );
   582 				"
   607 
   583 			SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
   608 		if ( ! is_array( $months ) ) {
   584 			FROM $wpdb->posts
   609 			$extra_checks = "AND post_status != 'auto-draft'";
   585 			WHERE post_type = %s
   610 			if ( ! isset( $_GET['post_status'] ) || 'trash' !== $_GET['post_status'] ) {
   586 			$extra_checks
   611 				$extra_checks .= " AND post_status != 'trash'";
   587 			ORDER BY post_date DESC
   612 			} elseif ( isset( $_GET['post_status'] ) ) {
   588 		",
   613 				$extra_checks = $wpdb->prepare( ' AND post_status = %s', $_GET['post_status'] );
   589 				$post_type
   614 			}
   590 			)
   615 
   591 		);
   616 			$months = $wpdb->get_results(
       
   617 				$wpdb->prepare(
       
   618 					"
       
   619 				SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
       
   620 				FROM $wpdb->posts
       
   621 				WHERE post_type = %s
       
   622 				$extra_checks
       
   623 				ORDER BY post_date DESC
       
   624 			",
       
   625 					$post_type
       
   626 				)
       
   627 			);
       
   628 		}
   592 
   629 
   593 		/**
   630 		/**
   594 		 * Filters the 'Months' drop-down results.
   631 		 * Filters the 'Months' drop-down results.
   595 		 *
   632 		 *
   596 		 * @since 3.7.0
   633 		 * @since 3.7.0
   606 			return;
   643 			return;
   607 		}
   644 		}
   608 
   645 
   609 		$m = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0;
   646 		$m = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0;
   610 		?>
   647 		?>
   611 		<label for="filter-by-date" class="screen-reader-text"><?php _e( 'Filter by date' ); ?></label>
   648 		<label for="filter-by-date" class="screen-reader-text"><?php echo get_post_type_object( $post_type )->labels->filter_by_date; ?></label>
   612 		<select name="m" id="filter-by-date">
   649 		<select name="m" id="filter-by-date">
   613 			<option<?php selected( $m, 0 ); ?> value="0"><?php _e( 'All dates' ); ?></option>
   650 			<option<?php selected( $m, 0 ); ?> value="0"><?php _e( 'All dates' ); ?></option>
   614 		<?php
   651 		<?php
   615 		foreach ( $months as $arc_row ) {
   652 		foreach ( $months as $arc_row ) {
   616 			if ( 0 == $arc_row->year ) {
   653 			if ( 0 == $arc_row->year ) {
   945 
   982 
   946 		$pagination_links_class = 'pagination-links';
   983 		$pagination_links_class = 'pagination-links';
   947 		if ( ! empty( $infinite_scroll ) ) {
   984 		if ( ! empty( $infinite_scroll ) ) {
   948 			$pagination_links_class .= ' hide-if-js';
   985 			$pagination_links_class .= ' hide-if-js';
   949 		}
   986 		}
   950 		$output .= "\n<span class='$pagination_links_class'>" . join( "\n", $page_links ) . '</span>';
   987 		$output .= "\n<span class='$pagination_links_class'>" . implode( "\n", $page_links ) . '</span>';
   951 
   988 
   952 		if ( $total_pages ) {
   989 		if ( $total_pages ) {
   953 			$page_class = $total_pages < 2 ? ' one-page' : '';
   990 			$page_class = $total_pages < 2 ? ' one-page' : '';
   954 		} else {
   991 		} else {
   955 			$page_class = ' no-pages';
   992 			$page_class = ' no-pages';
  1042 		$default = $this->get_default_primary_column_name();
  1079 		$default = $this->get_default_primary_column_name();
  1043 
  1080 
  1044 		// If the primary column doesn't exist,
  1081 		// If the primary column doesn't exist,
  1045 		// fall back to the first non-checkbox column.
  1082 		// fall back to the first non-checkbox column.
  1046 		if ( ! isset( $columns[ $default ] ) ) {
  1083 		if ( ! isset( $columns[ $default ] ) ) {
  1047 			$default = WP_List_Table::get_default_primary_column_name();
  1084 			$default = self::get_default_primary_column_name();
  1048 		}
  1085 		}
  1049 
  1086 
  1050 		/**
  1087 		/**
  1051 		 * Filters the name of the primary column for the current list table.
  1088 		 * Filters the name of the primary column for the current list table.
  1052 		 *
  1089 		 *
  1063 
  1100 
  1064 		return $column;
  1101 		return $column;
  1065 	}
  1102 	}
  1066 
  1103 
  1067 	/**
  1104 	/**
  1068 	 * Gets a list of all, hidden and sortable columns, with filter applied.
  1105 	 * Gets a list of all, hidden, and sortable columns, with filter applied.
  1069 	 *
  1106 	 *
  1070 	 * @since 3.1.0
  1107 	 * @since 3.1.0
  1071 	 *
  1108 	 *
  1072 	 * @return array
  1109 	 * @return array
  1073 	 */
  1110 	 */
  1074 	protected function get_column_info() {
  1111 	protected function get_column_info() {
  1075 		// $_column_headers is already set / cached.
  1112 		// $_column_headers is already set / cached.
  1076 		if ( isset( $this->_column_headers ) && is_array( $this->_column_headers ) ) {
  1113 		if ( isset( $this->_column_headers ) && is_array( $this->_column_headers ) ) {
  1077 			// Back-compat for list tables that have been manually setting $_column_headers for horse reasons.
  1114 			/*
  1078 			// In 4.3, we added a fourth argument for primary column.
  1115 			 * Backward compatibility for `$_column_headers` format prior to WordPress 4.3.
       
  1116 			 *
       
  1117 			 * In WordPress 4.3 the primary column name was added as a fourth item in the
       
  1118 			 * column headers property. This ensures the primary column name is included
       
  1119 			 * in plugins setting the property directly in the three item format.
       
  1120 			 */
  1079 			$column_headers = array( array(), array(), array(), $this->get_primary_column_name() );
  1121 			$column_headers = array( array(), array(), array(), $this->get_primary_column_name() );
  1080 			foreach ( $this->_column_headers as $key => $value ) {
  1122 			foreach ( $this->_column_headers as $key => $value ) {
  1081 				$column_headers[ $key ] = $value;
  1123 				$column_headers[ $key ] = $value;
  1082 			}
  1124 			}
  1083 
  1125 
  1090 		$sortable_columns = $this->get_sortable_columns();
  1132 		$sortable_columns = $this->get_sortable_columns();
  1091 		/**
  1133 		/**
  1092 		 * Filters the list table sortable columns for a specific screen.
  1134 		 * Filters the list table sortable columns for a specific screen.
  1093 		 *
  1135 		 *
  1094 		 * The dynamic portion of the hook name, `$this->screen->id`, refers
  1136 		 * The dynamic portion of the hook name, `$this->screen->id`, refers
  1095 		 * to the ID of the current screen, usually a string.
  1137 		 * to the ID of the current screen.
  1096 		 *
  1138 		 *
  1097 		 * @since 3.1.0
  1139 		 * @since 3.1.0
  1098 		 *
  1140 		 *
  1099 		 * @param array $sortable_columns An array of sortable columns.
  1141 		 * @param array $sortable_columns An array of sortable columns.
  1100 		 */
  1142 		 */
  1211 			$tag   = ( 'cb' === $column_key ) ? 'td' : 'th';
  1253 			$tag   = ( 'cb' === $column_key ) ? 'td' : 'th';
  1212 			$scope = ( 'th' === $tag ) ? 'scope="col"' : '';
  1254 			$scope = ( 'th' === $tag ) ? 'scope="col"' : '';
  1213 			$id    = $with_id ? "id='$column_key'" : '';
  1255 			$id    = $with_id ? "id='$column_key'" : '';
  1214 
  1256 
  1215 			if ( ! empty( $class ) ) {
  1257 			if ( ! empty( $class ) ) {
  1216 				$class = "class='" . join( ' ', $class ) . "'";
  1258 				$class = "class='" . implode( ' ', $class ) . "'";
  1217 			}
  1259 			}
  1218 
  1260 
  1219 			echo "<$tag $scope $id $class>$column_display_name</$tag>";
  1261 			echo "<$tag $scope $id $class>$column_display_name</$tag>";
  1220 		}
  1262 		}
  1221 	}
  1263 	}
  1341 	/**
  1383 	/**
  1342 	 * Generates content for a single row of the table.
  1384 	 * Generates content for a single row of the table.
  1343 	 *
  1385 	 *
  1344 	 * @since 3.1.0
  1386 	 * @since 3.1.0
  1345 	 *
  1387 	 *
  1346 	 * @param object $item The current item
  1388 	 * @param object|array $item The current item
  1347 	 */
  1389 	 */
  1348 	public function single_row( $item ) {
  1390 	public function single_row( $item ) {
  1349 		echo '<tr>';
  1391 		echo '<tr>';
  1350 		$this->single_row_columns( $item );
  1392 		$this->single_row_columns( $item );
  1351 		echo '</tr>';
  1393 		echo '</tr>';
  1352 	}
  1394 	}
  1353 
  1395 
  1354 	/**
  1396 	/**
  1355 	 * @param object $item
  1397 	 * @param object|array $item
  1356 	 * @param string $column_name
  1398 	 * @param string $column_name
  1357 	 */
  1399 	 */
  1358 	protected function column_default( $item, $column_name ) {}
  1400 	protected function column_default( $item, $column_name ) {}
  1359 
  1401 
  1360 	/**
  1402 	/**
  1361 	 * @param object $item
  1403 	 * @param object|array $item
  1362 	 */
  1404 	 */
  1363 	protected function column_cb( $item ) {}
  1405 	protected function column_cb( $item ) {}
  1364 
  1406 
  1365 	/**
  1407 	/**
  1366 	 * Generates the columns for a single row of the table.
  1408 	 * Generates the columns for a single row of the table.
  1367 	 *
  1409 	 *
  1368 	 * @since 3.1.0
  1410 	 * @since 3.1.0
  1369 	 *
  1411 	 *
  1370 	 * @param object $item The current item.
  1412 	 * @param object|array $item The current item.
  1371 	 */
  1413 	 */
  1372 	protected function single_row_columns( $item ) {
  1414 	protected function single_row_columns( $item ) {
  1373 		list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
  1415 		list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
  1374 
  1416 
  1375 		foreach ( $columns as $column_name => $column_display_name ) {
  1417 		foreach ( $columns as $column_name => $column_display_name ) {
  1381 			if ( in_array( $column_name, $hidden, true ) ) {
  1423 			if ( in_array( $column_name, $hidden, true ) ) {
  1382 				$classes .= ' hidden';
  1424 				$classes .= ' hidden';
  1383 			}
  1425 			}
  1384 
  1426 
  1385 			// Comments column uses HTML in the display name with screen reader text.
  1427 			// Comments column uses HTML in the display name with screen reader text.
  1386 			// Instead of using esc_attr(), we strip tags to get closer to a user-friendly string.
  1428 			// Strip tags to get closer to a user-friendly string.
  1387 			$data = 'data-colname="' . wp_strip_all_tags( $column_display_name ) . '"';
  1429 			$data = 'data-colname="' . esc_attr( wp_strip_all_tags( $column_display_name ) ) . '"';
  1388 
  1430 
  1389 			$attributes = "class='$classes' $data";
  1431 			$attributes = "class='$classes' $data";
  1390 
  1432 
  1391 			if ( 'cb' === $column_name ) {
  1433 			if ( 'cb' === $column_name ) {
  1392 				echo '<th scope="row" class="check-column">';
  1434 				echo '<th scope="row" class="check-column">';
  1417 	/**
  1459 	/**
  1418 	 * Generates and display row actions links for the list table.
  1460 	 * Generates and display row actions links for the list table.
  1419 	 *
  1461 	 *
  1420 	 * @since 4.3.0
  1462 	 * @since 4.3.0
  1421 	 *
  1463 	 *
  1422 	 * @param object $item        The item being acted upon.
  1464 	 * @param object|array $item        The item being acted upon.
  1423 	 * @param string $column_name Current column name.
  1465 	 * @param string       $column_name Current column name.
  1424 	 * @param string $primary     Primary column name.
  1466 	 * @param string       $primary     Primary column name.
  1425 	 * @return string The row actions HTML, or an empty string
  1467 	 * @return string The row actions HTML, or an empty string
  1426 	 *                if the current column is not the primary column.
  1468 	 *                if the current column is not the primary column.
  1427 	 */
  1469 	 */
  1428 	protected function handle_row_actions( $item, $column_name, $primary ) {
  1470 	protected function handle_row_actions( $item, $column_name, $primary ) {
  1429 		return $column_name === $primary ? '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>' : '';
  1471 		return $column_name === $primary ? '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>' : '';