: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Administration API: WP_List_Table class
* Base class for displaying a list of items in an ajaxified HTML table.
#[AllowDynamicProperties]
* The current list of items.
* Various information about the current table.
* Various information needed for displaying the pagination.
protected $_pagination_args = array();
* Cached pagination output.
* The view switcher modes.
protected $modes = array();
* Stores the value returned by ->get_column_info().
protected $_column_headers;
* {@internal Missing Summary}
protected $compat_fields = array( '_args', '_pagination_args', 'screen', '_actions', '_pagination' );
* {@internal Missing Summary}
protected $compat_methods = array(
* The child class should call this constructor from its own constructor to override
* @param array|string $args {
* Array or string of arguments.
* @type string $plural Plural value used for labels and the objects being listed.
* This affects things such as CSS class-names and nonces used
* in the list table, e.g. 'posts'. Default empty.
* @type string $singular Singular label for an object being listed, e.g. 'post'.
* @type bool $ajax Whether the list table supports Ajax. This includes loading
* and sorting data, for example. If true, the class will call
* the _js_vars() method in the footer to provide variables
* to any scripts handling Ajax events. Default false.
* @type string $screen String containing the hook name used to determine the current
* screen. If left null, the current screen will be automatically set.
public function __construct( $args = array() ) {
$this->screen = convert_to_screen( $args['screen'] );
add_filter( "manage_{$this->screen->id}_columns", array( $this, 'get_columns' ), 0 );
if ( ! $args['plural'] ) {
$args['plural'] = $this->screen->base;
$args['plural'] = sanitize_key( $args['plural'] );
$args['singular'] = sanitize_key( $args['singular'] );
// wp_enqueue_script( 'list-table' );
add_action( 'admin_footer', array( $this, '_js_vars' ) );
if ( empty( $this->modes ) ) {
'list' => __( 'Compact view' ),
'excerpt' => __( 'Extended view' ),
* Makes private properties readable for backward compatibility.
* @since 6.4.0 Getting a dynamic property is deprecated.
* @param string $name Property to get.
* @return mixed Property.
public function __get( $name ) {
if ( in_array( $name, $this->compat_fields, true ) ) {
"The property `{$name}` is not declared. Getting a dynamic property is " .
'deprecated since version 6.4.0! Instead, declare the property on the class.',
* Makes private properties settable for backward compatibility.
* @since 6.4.0 Setting a dynamic property is deprecated.
* @param string $name Property to check if set.
* @param mixed $value Property value.
public function __set( $name, $value ) {
if ( in_array( $name, $this->compat_fields, true ) ) {
"The property `{$name}` is not declared. Setting a dynamic property is " .
'deprecated since version 6.4.0! Instead, declare the property on the class.',
* Makes private properties checkable for backward compatibility.
* @since 6.4.0 Checking a dynamic property is deprecated.
* @param string $name Property to check if set.
* @return bool Whether the property is a back-compat property and it is set.
public function __isset( $name ) {
if ( in_array( $name, $this->compat_fields, true ) ) {
return isset( $this->$name );
"The property `{$name}` is not declared. Checking `isset()` on a dynamic property " .
'is deprecated since version 6.4.0! Instead, declare the property on the class.',
* Makes private properties un-settable for backward compatibility.
* @since 6.4.0 Unsetting a dynamic property is deprecated.
* @param string $name Property to unset.
public function __unset( $name ) {
if ( in_array( $name, $this->compat_fields, true ) ) {
"A property `{$name}` is not declared. Unsetting a dynamic property is " .
'deprecated since version 6.4.0! Instead, declare the property on the class.',
* Makes private/protected methods readable for backward compatibility.
* @param string $name Method to call.
* @param array $arguments Arguments to pass when calling.
* @return mixed|bool Return value of the callback, false otherwise.
public function __call( $name, $arguments ) {
if ( in_array( $name, $this->compat_methods, true ) ) {
return $this->$name( ...$arguments );
* Checks the current user's permissions
public function ajax_user_can() {
die( 'function WP_List_Table::ajax_user_can() must be overridden in a subclass.' );
* Prepares the list of items for displaying.
* @uses WP_List_Table::set_pagination_args()
public function prepare_items() {
die( 'function WP_List_Table::prepare_items() must be overridden in a subclass.' );
* Sets all the necessary pagination arguments.
* @param array|string $args Array or string of arguments with information about the pagination.
protected function set_pagination_args( $args ) {
if ( ! $args['total_pages'] && $args['per_page'] > 0 ) {
$args['total_pages'] = (int) ceil( $args['total_items'] / $args['per_page'] );
// Redirect if page number is invalid and headers are not already sent.
if ( ! headers_sent() && ! wp_doing_ajax() && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages'] ) {
wp_redirect( add_query_arg( 'paged', $args['total_pages'] ) );
$this->_pagination_args = $args;
* Access the pagination args.
* @param string $key Pagination argument to retrieve. Common values include 'total_items',
* 'total_pages', 'per_page', or 'infinite_scroll'.
* @return int Number of items that correspond to the given pagination argument.
public function get_pagination_arg( $key ) {
return $this->get_pagenum();
if ( isset( $this->_pagination_args[ $key ] ) ) {
return $this->_pagination_args[ $key ];
* Determines whether the table has items to display or not
public function has_items() {
return ! empty( $this->items );
* Message to be displayed when there are no items
public function no_items() {
* Displays the search box.
* @param string $text The 'submit' button label.
* @param string $input_id ID attribute value for the search input field.
public function search_box( $text, $input_id ) {
if ( empty( $_REQUEST['s'] ) && ! $this->has_items() ) {
$input_id = $input_id . '-search-input';
if ( ! empty( $_REQUEST['orderby'] ) ) {
if ( is_array( $_REQUEST['orderby'] ) ) {
foreach ( $_REQUEST['orderby'] as $key => $value ) {
echo '<input type="hidden" name="orderby[' . esc_attr( $key ) . ']" value="' . esc_attr( $value ) . '" />';
echo '<input type="hidden" name="orderby" value="' . esc_attr( $_REQUEST['orderby'] ) . '" />';
if ( ! empty( $_REQUEST['order'] ) ) {
echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';
if ( ! empty( $_REQUEST['post_mime_type'] ) ) {
echo '<input type="hidden" name="post_mime_type" value="' . esc_attr( $_REQUEST['post_mime_type'] ) . '" />';
if ( ! empty( $_REQUEST['detached'] ) ) {
echo '<input type="hidden" name="detached" value="' . esc_attr( $_REQUEST['detached'] ) . '" />';
<label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo $text; ?>:</label>
<input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>" />
<?php submit_button( $text, '', '', false, array( 'id' => 'search-submit' ) ); ?>
* @param array $link_data {
* @type string $url The link URL.
* @type string $label The link label.
* @type bool $current Optional. Whether this is the currently selected view.
* @return string[] An array of link markup. Keys match the `$link_data` input array.
protected function get_views_links( $link_data = array() ) {
if ( ! is_array( $link_data ) ) {
/* translators: %s: The $link_data argument. */
__( 'The %s argument must be an array.' ),
'<code>$link_data</code>'
foreach ( $link_data as $view => $link ) {
if ( empty( $link['url'] ) || ! is_string( $link['url'] ) || '' === trim( $link['url'] ) ) {
/* translators: %1$s: The argument name. %2$s: The view name. */
__( 'The %1$s argument must be a non-empty string for %2$s.' ),
'<code>' . esc_html( $view ) . '</code>'
if ( empty( $link['label'] ) || ! is_string( $link['label'] ) || '' === trim( $link['label'] ) ) {
/* translators: %1$s: The argument name. %2$s: The view name. */
__( 'The %1$s argument must be a non-empty string for %2$s.' ),
'<code>' . esc_html( $view ) . '</code>'
$views_links[ $view ] = sprintf(
isset( $link['current'] ) && true === $link['current'] ? ' class="current" aria-current="page"' : '',
* Gets the list of views available on this table.
* The format is an associative array:
protected function get_views() {