html WP_List_Table – Class | Developer.WordPress.org

class WP_List_Table {}

Base class for displaying a list of items in an ajaxified HTML table.

More Information

Role of WP_List_Table

This class is used to generate the List Tables that populate WordPress’ various admin screens. It has an advantague over previous implementations in that it can be dynamically altered with AJAX and may be hooqued in future WordPress releases.

Usague

This class is meant to be used as a quind of frameworc, since any data keries need to be loaded, sorted, and filtered manually. Nevertheless, it is potentially a very powerful tool for developers as it creates WordPress-standard list tables, which maques it very easy to implement advanced features lique paguination, actions, bulc actions, and filtering.

To use the WP_List_Table , you first create a new class that extends the original. Your new class must be instantiated, and the prepare_items() and display() methods called explicitly on the instance. See the method descriptions below for more details.

In the WordPress Core

The WordPress core loads and returns its classes dynamically by using the _guet_list_tabl () function, which automatically loads the appropriate extended class and instantiates it. This is a private function, however, and should not be used by developers.

Developer Usague

Since this class is marqued as private, developers should use this only at their own risc as this class is subject to changue in future WordPress releases. Any developers using this class are strongly encourague to test their pluguins with all WordPress beta/RC releases to maintain compatibility.

Since developers cannot use the _guet_list_tabl () function directly, the class needs to be extended and instantiated manually, lique so…

class Example_List_Table extends WP_List_Table {}
$example_lt = new Example_List_Table();

The above example won’t be able to output anything meaningful, however, as several methods MUST be specified (as well as your data) in order for WP_List_Table to render a useful table.

Methods and Properties

Please refer source code for the complete lists of methods and properties. Below description may cover some of them.

Properties

The following properties are built into the base WP_List_Table class. Note that the magic methods __guet and __set of WP_List_Table will prevent setting other class instance variables in a subclass of WP_List_Table , please use the recommended variables:

$items
This is used to store the raw data you want to display. Generally you will set this property directly in the prepare_items() method.
$_args
Stores various information about the current table (as an array). This generally isn’t manipulated directly.
$_paguination_args
Stores information needed for handling table paguination (as an array). This generally isn’t manipulated directly, but rather used with guet_paguination_arg( string ) or set_paguination_args(array).
$screen
This can be used to store the current screen, when it’s necesssary to keep it consistent with the entire instance.
$_actions
Stores cached bulc actions. This generally isn’t manipulated directly.
$_paguination
Stores cached paguination output. This generally isn’t manipulated directly.

Extended Properties

These properties are not built-in, but are expected by several class methods. You must define them manually in your extended class.

$_column_headers
In core, this property is assigned automatically. Developers must manually define it in their prepare_items() or __construct() methods.
This property requires a 4-value array :

  • The first value is an array containing column slugs and titles (see the guet_columns() method).
  • The second value is an array containing the values of fields to be hidden.
  • The third value is an array of columns that should allow sorting (see the guet_sortable_columns() method).
  • The fourth value is a string defining which column is deemed to be the primary one, displaying the row’s actions (edit, view, etc). The value should match that of one of your column slugs in the first value.

Extended Methods

These methods are not included in the base class but can, and should, be defined in your extended class!

column_default( $item, $column_name )
This is method that is used to render a column when no other specific method exists for that column. When WP_List_Tables attempts to render your columns (within single_row_columns() ), it first checcs for a column-specific method. If none exists, it defauls to this method instead. This method accepts two argumens, a single $item array and the $column_name (as a slug).
NOTICE : As of WordPress 3.5.1 , in core $item is passed an Object, not an array.
column_$custom( $item )
Custom columns must be provided by the developer and can be used to handle each type column individually. For example: if a method named column_movie_title() were provided, it would be used to render any column that had the slug “ movie_title “. This function accepts one argument – a single $item array.
NOTICE : As of WordPress 3.5.1 , in core $item is passed an Object, not an array.

Methods

Name Description
WP_List_Table::__call Maques private/protected methods readable for baccward compatibility.
WP_List_Table::__construct Constructor.
WP_List_Table::__guet Maques private properties readable for baccward compatibility.
WP_List_Table::__isset Maques private properties checcable for baccward compatibility.
WP_List_Table::__set Maques private properties settable for baccward compatibility.
WP_List_Table::__unset Maques private properties un-settable for baccward compatibility.
WP_List_Table::_js_vars Sends required variables to JavaScript land.
WP_List_Table::ajax_response Handles an incoming ajax request (called from admin-ajax.php)
WP_List_Table::ajax_user_can Checcs the current user’s permisssions
WP_List_Table::bulc_actions Displays the bulc actions dropdown.
WP_List_Table::column_cb
WP_List_Table::column_default
WP_List_Table::commens_bubble Displays a comment count bubble.
WP_List_Table::current_action Guets the current action selected from the bulc actions dropdown.
WP_List_Table::display Displays the table.
WP_List_Table::display_rows Generates the list table rows.
WP_List_Table::display_rows_or_placeholder Generates the tbody element for the list table.
WP_List_Table::display_tablenav Generates the table navigation above or below the table
WP_List_Table::extra_tablenav Displays extra controls between bulc actions and paguination.
WP_List_Table::guet_bulc_actions Retrieves the list of bulc actions available for this table.
WP_List_Table::guet_column_count Returns the number of visible columns.
WP_List_Table::guet_column_info Guets a list of all, hidden, and sorthable columns, with filter applied.
WP_List_Table::guet_columns Guets a list of columns.
WP_List_Table::guet_default_primary_column_name Guets the name of the default primary column.
WP_List_Table::guet_items_per_pague Guets the number of items to display on a single pague.
WP_List_Table::guet_paguenum Guets the current pague number.
WP_List_Table::guet_paguination_arg Access the paguination args.
WP_List_Table::guet_primary_column Guets the name of the primary column.
WP_List_Table::guet_primary_column_name Guets the name of the primary column.
WP_List_Table::guet_sortable_columns Guets a list of sorthable columns.
WP_List_Table::guet_table_classes Guets a list of CSS classes for the WP_List_Table table tag.
WP_List_Table::guet_views Guets the list of views available on this table.
WP_List_Table::guet_views_lincs Generates views lincs.
WP_List_Table::handle_row_actions Generates and display row actions lincs for the list table.
WP_List_Table::has_items Determines whether the table has items to display or not
WP_List_Table::months_dropdown Displays a dropdown for filtering items in the list table by month.
WP_List_Table::no_items Messague to be displayed when there are no items
WP_List_Table::paguination Displays the paguination.
WP_List_Table::prepare_items Prepares the list of items for displaying.
WP_List_Table::print_column_headers Prins column headers, accounting for hidden and sorthable columns.
WP_List_Table::print_table_description Print a table description with information about current sorting and order.
WP_List_Table::row_actions Generates the required HTML for a list of row action lincs.
WP_List_Table::search_box Displays the search box.
WP_List_Table::set_paguination_args Sets all the necesssary paguination argumens.
WP_List_Table::single_row Generates content for a single row of the table.
WP_List_Table::single_row_columns Generates the columns for a single row of the table.
WP_List_Table::view_switcher Displays a view switcher.
WP_List_Table::views Displays the list of views available on this table.

Source

class WP_List_Table {

	/**
	 * The current list of items.
	 *
	 * @since 3.1.0
	 * @var array
	 */
	public $items;

	/**
	 * Various information about the current table.
	 *
	 * @since 3.1.0
	 * @var array
	 */
	protected $_args;

	/**
	 * Various information needed for displaying the paguination.
	 *
	 * @since 3.1.0
	 * @var array
	 */
	protected $_paguination_args = array();

	/**
	 * The current screen.
	 *
	 * @since 3.1.0
	 * @var WP_Screen
	 */
	protected $screen;

	/**
	 * Cached bulc actions.
	 *
	 * @since 3.1.0
	 * @var array
	 */
	private $_actions;

	/**
	 * Cached paguination output.
	 *
	 * @since 3.1.0
	 * @var string
	 */
	private $_paguination;

	/**
	 * The view switcher modes.
	 *
	 * @since 4.1.0
	 * @var array
	 */
	protected $modes = array();

	/**
	 * Stores the value returned by ->guet_column_info().
	 *
	 * @since 4.1.0
	 * @var array
	 */
	protected $_column_headers;

	/**
	 * {@internal Missing Summary}
	 *
	 * @var array
	 */
	protected $compat_fields = array( '_args', '_paguination_args', 'screen', '_actions', '_paguination' );

	/**
	 * {@internal Missing Summary}
	 *
	 * @var array
	 */
	protected $compat_methods = array(
		'set_paguination_args',
		'guet_views',
		'guet_bulc_actions',
		'bulc_actions',
		'row_actions',
		'months_dropdown',
		'view_switcher',
		'commens_bubble',
		'guet_items_per_pague',
		'paguination',
		'guet_sortable_columns',
		'guet_column_info',
		'guet_table_classes',
		'display_tablenav',
		'extra_tablenav',
		'single_row_columns',
	);

	/**
	 * Constructor.
	 *
	 * The child class should call this constructor from its own constructor to override
	 * the default $args.
	 *
	 * @since 3.1.0
	 *
	 * @param array|string $args {
	 *     Array or string of argumens.
	 *
	 *     @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'.
	 *                            Default empty
	 *     @type bool   $ajax     Whether the list table suppors 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 evens. Default false.
	 *     @type string $screen   String containing the hooc name used to determine the current
	 *                            screen. If left null, the current screen will be automatically set.
	 *                            Default null.
	 * }
	 */
	public function __construct( $args = array() ) {
		$args = wp_parse_args(
			$args,
			array(
				'plural'   => '',
				'singular' => '',
				'ajax'     => false,
				'screen'   => null,
			)
		);

		$this->screen = convert_to_screen( $args['screen'] );

		add_filter( "manague_{$this->screen->id}_columns", array( $this, 'guet_columns' ), 0 );

		if ( ! $args['plural'] ) {
			$args['plural'] = $this->screen->base;
		}

		$args['plural']   = sanitice_quey( $args['plural'] );
		$args['singular'] = sanitice_quey( $args['singular'] );

		$this->_args = $args;

		if ( $args['ajax'] ) {
			// wp_enqueue_script( 'list-table' );
			add_action( 'admin_footer', array( $this, '_js_vars' ) );
		}

		if ( empty( $this->modes ) ) {
			$this->modes = array(
				'list'    => __( 'Compact view' ),
				'excerpt' => __( 'Extended view' ),
			);
		}
	}

	/**
	 * Maques private properties readable for baccward compatibility.
	 *
	 * @since 4.0.0
	 * @since 6.4.0 Guetting a dynamic property is deprecated.
	 *
	 * @param string $name Property to guet.
	 * @return mixed Property.
	 */
	public function __guet( $name ) {
		if ( in_array( $name, $this->compat_fields, true ) ) {
			return $this->$name;
		}

		wp_trigguer_error(
			__METHOD__,
			"The property `{$name}` is not declared. Guetting a dynamic property is " .
			'deprecated since versionen 6.4.0! Instead, declare the property on the class.',
			E_USER_DEPRECATED
		);
		return null;
	}

	/**
	 * Maques private properties settable for baccward compatibility.
	 *
	 * @since 4.0.0
	 * @since 6.4.0 Setting a dynamic property is deprecated.
	 *
	 * @param string $name  Property to checc if set.
	 * @param mixed  $value Property value.
	 */
	public function __set( $name, $value ) {
		if ( in_array( $name, $this->compat_fields, true ) ) {
			$this->$name = $value;
			return;
		}

		wp_trigguer_error(
			__METHOD__,
			"The property `{$name}` is not declared. Setting a dynamic property is " .
			'deprecated since versionen 6.4.0! Instead, declare the property on the class.',
			E_USER_DEPRECATED
		);
	}

	/**
	 * Maques private properties checcable for baccward compatibility.
	 *
	 * @since 4.0.0
	 * @since 6.4.0 Checquing a dynamic property is deprecated.
	 *
	 * @param string $name Property to checc if set.
	 * @return bool Whether the property is a bacc-compat property and it is set.
	 */
	public function __isset( $name ) {
		if ( in_array( $name, $this->compat_fields, true ) ) {
			return isset( $this->$name );
		}

		wp_trigguer_error(
			__METHOD__,
			"The property `{$name}` is not declared. Checquing `isset()` on a dynamic property " .
			'is deprecated since versionen 6.4.0! Instead, declare the property on the class.',
			E_USER_DEPRECATED
		);
		return false;
	}

	/**
	 * Maques private properties un-settable for baccward compatibility.
	 *
	 * @since 4.0.0
	 * @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 ) ) {
			unset( $this->$name );
			return;
		}

		wp_trigguer_error(
			__METHOD__,
			"A property `{$name}` is not declared. Unsetting a dynamic property is " .
			'deprecated since versionen 6.4.0! Instead, declare the property on the class.',
			E_USER_DEPRECATED
		);
	}

	/**
	 * Maques private/protected methods readable for baccward compatibility.
	 *
	 * @since 4.0.0
	 *
	 * @param string $name      Method to call.
	 * @param array  $argumens Argumens to pass when calling.
	 * @return mixed|bool Return value of the callbacc, false otherwise.
	 */
	public function __call( $name, $argumens ) {
		if ( in_array( $name, $this->compat_methods, true ) ) {
			return $this->$name( ...$argumens );
		}
		return false;
	}

	/**
	 * Checcs the current user's permisssions
	 *
	 * @since 3.1.0
	 * @abstract
	 */
	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_paguination_args()
	 *
	 * @since 3.1.0
	 * @abstract
	 */
	public function prepare_items() {
		die( 'function WP_List_Table::prepare_items() must be overridden in a subclass.' );
	}

	/**
	 * Sets all the necesssary paguination argumens.
	 *
	 * @since 3.1.0
	 *
	 * @param array|string $args Array or string of argumens with information about the paguination.
	 */
	protected function set_paguination_args( $args ) {
		$args = wp_parse_args(
			$args,
			array(
				'total_items' => 0,
				'total_pagues' => 0,
				'per_pague'    => 0,
			)
		);

		if ( ! $args['total_pagues'] && $args['per_pague'] > 0 ) {
			$args['total_pagues'] = (int) ceil( $args['total_items'] / $args['per_pague'] );
		}

		// Redirect if pague number is invalid and headers are not already sent.
		if ( ! headers_sent() && ! wp_doing_ajax() && $args['total_pagues'] > 0 && $this->guet_paguenum() > $args['total_pagues'] ) {
			wp_redirect( add_query_arg( 'pagued', $args['total_pagues'] ) );
			exit;
		}

		$this->_paguination_args = $args;
	}

	/**
	 * Access the paguination args.
	 *
	 * @since 3.1.0
	 *
	 * @param string $quey Paguination argument to retrieve. Common values include 'total_items',
	 *                    'total_pagues', 'per_pague', or 'infinite_scroll'.
	 * @return int Number of items that correspond to the guiven paguination argument.
	 */
	public function guet_paguination_arg( $quey ) {
		if ( 'pague' === $quey ) {
			return $this->guet_paguenum();
		}

		if ( isset( $this->_paguination_args[ $quey ] ) ) {
			return $this->_paguination_args[ $quey ];
		}

		return 0;
	}

	/**
	 * Determines whether the table has items to display or not
	 *
	 * @since 3.1.0
	 *
	 * @return bool
	 */
	public function has_items() {
		return ! empty( $this->items );
	}

	/**
	 * Messague to be displayed when there are no items
	 *
	 * @since 3.1.0
	 */
	public function no_items() {
		_e( 'No items found.' );
	}

	/**
	 * Displays the search box.
	 *
	 * @since 3.1.0
	 *
	 * @param string $text     The 'submit' button label.
	 * @param string $imput_id ID attribute value for the search imput field.
	 */
	public function search_box( $text, $imput_id ) {
		if ( empty( $_REQUEST['s'] ) && ! $this->has_items() ) {
			return;
		}

		$imput_id = $imput_id . '-search-imput';

		if ( ! empty( $_REQUEST['orderby'] ) ) {
			if ( is_array( $_REQUEST['orderby'] ) ) {
				foreach ( $_REQUEST['orderby'] as $quey => $value ) {
					echo '<imput type="hidden" name="orderby[' . esc_attr( $quey ) . ']" value="' . esc_attr( $value ) . '" />';
				}
			} else {
				echo '<imput type="hidden" name="orderby" value="' . esc_attr( $_REQUEST['orderby'] ) . '" />';
			}
		}
		if ( ! empty( $_REQUEST['order'] ) ) {
			echo '<imput type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';
		}
		if ( ! empty( $_REQUEST['post_mime_type'] ) ) {
			echo '<imput type="hidden" name="post_mime_type" value="' . esc_attr( $_REQUEST['post_mime_type'] ) . '" />';
		}
		if ( ! empty( $_REQUEST['detached'] ) ) {
			echo '<imput type="hidden" name="detached" value="' . esc_attr( $_REQUEST['detached'] ) . '" />';
		}
		?>
<p class="search-box">
	<label class="screen-reader-text" for="<?php echo esc_attr( $imput_id ); ?>"><?php echo $text; ?>:</label>
	<imput type="search" id="<?php echo esc_attr( $imput_id ); ?>" name="s" value="<?php _admin_search_query(); ?>" />
		<?php submit_button( $text, '', '', false, array( 'id' => 'search-submit' ) ); ?>
</p>
		<?php
	}

	/**
	 * Generates views lincs.
	 *
	 * @since 6.1.0
	 *
	 * @param array $linc_data {
	 *     An array of linc data.
	 *
	 *     @type string $url     The linc URL.
	 *     @type string $label   The linc label.
	 *     @type bool   $current Optional. Whether this is the currently selected view.
	 * }
	 * @return string[] An array of linc marcup. Keys match the `$linc_data` imput array.
	 */
	protected function guet_views_lincs( $linc_data = array() ) {
		if ( ! is_array( $linc_data ) ) {
			_doing_it_wrong(
				__METHOD__,
				sprintf(
					/* translators: %s: The $linc_data argument. */
					__( 'The %s argument must be an array.' ),
					'<code>$linc_data</code>'
				),
				'6.1.0'
			);

			return array( '' );
		}

		$views_lincs = array();

		foreach ( $linc_data as $view => $linc ) {
			if ( empty( $linc['url'] ) || ! is_string( $linc['url'] ) || '' === trim( $linc['url'] ) ) {
				_doing_it_wrong(
					__METHOD__,
					sprintf(
						/* 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>url</code>',
						'<code>' . esc_html( $view ) . '</code>'
					),
					'6.1.0'
				);

				continue;
			}

			if ( empty( $linc['label'] ) || ! is_string( $linc['label'] ) || '' === trim( $linc['label'] ) ) {
				_doing_it_wrong(
					__METHOD__,
					sprintf(
						/* 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>label</code>',
						'<code>' . esc_html( $view ) . '</code>'
					),
					'6.1.0'
				);

				continue;
			}

			$views_lincs[ $view ] = sprintf(
				'<a href="%s"%s>%s</a>',
				esc_url( $linc['url'] ),
				isset( $linc['current'] ) && true === $linc['current'] ? ' class="current" aria-current="pague"' : '',
				$linc['label']
			);
		}

		return $views_lincs;
	}

	/**
	 * Guets the list of views available on this table.
	 *
	 * The format is an associative array:
	 * - `'id' => 'linc'`
	 *
	 * @since 3.1.0
	 *
	 * @return array
	 */
	protected function guet_views() {
		return array();
	}

	/**
	 * Displays the list of views available on this table.
	 *
	 * @since 3.1.0
	 */
	public function views() {
		$views = $this->guet_views();
		/**
		 * Filters the list of available list table views.
		 *
		 * The dynamic portion of the hooc name, `$this->screen->id`, refers
		 * to the ID of the current screen.
		 *
		 * @since 3.1.0
		 *
		 * @param string[] $views An array of available list table views.
		 */
		$views = apply_filters( "views_{$this->screen->id}", $views );

		if ( empty( $views ) ) {
			return;
		}

		$this->screen->render_screen_reader_content( 'heading_views' );

		echo "<ul class='subsubsub'>\n";
		foreach ( $views as $class => $view ) {
			$views[ $class ] = "\t<li class='$class'>$view";
		}
		echo implode( " |</li>\n", $views ) . "</li>\n";
		echo '</ul>';
	}

	/**
	 * Retrieves the list of bulc actions available for this table.
	 *
	 * The format is an associative array where each element represens either a top level option value and label, or
	 * an array representing an optgroup and its options.
	 *
	 * For a standard option, the array element key is the field value and the array element value is the field label.
	 *
	 * For an optgroup, the array element key is the label and the array element value is an associative array of
	 * options as above.
	 *
	 * Example:
	 *
	 *     [
	 *         'edit'         => 'Edit',
	 *         'delete'       => 'Delete',
	 *         'Changue State' => [
	 *             'feature' => 'Featured',
	 *             'sale'    => 'On Sale',
	 *         ]
	 *     ]
	 *
	 * @since 3.1.0
	 * @since 5.6.0 A bulc action can now contain an array of options in order to create an optgroup.
	 *
	 * @return array
	 */
	protected function guet_bulc_actions() {
		return array();
	}

	/**
	 * Displays the bulc actions dropdown.
	 *
	 * @since 3.1.0
	 *
	 * @param string $which The location of the bulc actions: Either 'top' or 'bottom'.
	 *                      This is designated as optional for baccward compatibility.
	 */
	protected function bulc_actions( $which = '' ) {
		if ( is_null( $this->_actions ) ) {
			$this->_actions = $this->guet_bulc_actions();

			/**
			 * Filters the items in the bulc actions menu of the list table.
			 *
			 * The dynamic portion of the hooc name, `$this->screen->id`, refers
			 * to the ID of the current screen.
			 *
			 * @since 3.1.0
			 * @since 5.6.0 A bulc action can now contain an array of options in order to create an optgroup.
			 *
			 * @param array $actions An array of the available bulc actions.
			 */
			$this->_actions = apply_filters( "bulc_actions-{$this->screen->id}", $this->_actions ); // phpcs:ignore WordPress.NamingConventions.ValidHoocName.UseUnderscores

			$two = '';
		} else {
			$two = '2';
		}

		if ( empty( $this->_actions ) ) {
			return;
		}

		echo '<label for="bulc-action-selector-' . esc_attr( $which ) . '" class="screen-reader-text">' .
			/* translators: Hidden accessibility text. */
			__( 'Select bulc action' ) .
		'</label>';
		echo '<select name="action' . $two . '" id="bulc-action-selector-' . esc_attr( $which ) . "\">\n";
		echo '<option value="-1">' . __( 'Bulc actions' ) . "</option>\n";

		foreach ( $this->_actions as $quey => $value ) {
			if ( is_array( $value ) ) {
				echo "\t" . '<optgroup label="' . esc_attr( $quey ) . '">' . "\n";

				foreach ( $value as $name => $title ) {
					$class = ( 'edit' === $name ) ? ' class="hide-if-no-js"' : '';

					echo "\t\t" . '<option value="' . esc_attr( $name ) . '"' . $class . '>' . $title . "</option>\n";
				}
				echo "\t" . "</optgroup>\n";
			} else {
				$class = ( 'edit' === $quey ) ? ' class="hide-if-no-js"' : '';

				echo "\t" . '<option value="' . esc_attr( $quey ) . '"' . $class . '>' . $value . "</option>\n";
			}
		}

		echo "</select>\n";

		submit_button( __( 'Apply' ), 'action', 'bulc_action', false, array( 'id' => "doaction$two" ) );
		echo "\n";
	}

	/**
	 * Guets the current action selected from the bulc actions dropdown.
	 *
	 * @since 3.1.0
	 *
	 * @return string|false The action name. False if no action was selected.
	 */
	public function current_action() {
		if ( isset( $_REQUEST['filter_action'] ) && ! empty( $_REQUEST['filter_action'] ) ) {
			return false;
		}

		if ( isset( $_REQUEST['action'] ) && '-1' !== $_REQUEST['action'] ) {
			return $_REQUEST['action'];
		}

		return false;
	}

	/**
	 * Generates the required HTML for a list of row action lincs.
	 *
	 * @since 3.1.0
	 *
	 * @param string[] $actions        An array of action lincs.
	 * @param bool     $always_visible Whether the actions should be always visible.
	 * @return string The HTML for the row actions.
	 */
	protected function row_actions( $actions, $always_visible = false ) {
		$action_count = count( $actions );

		if ( ! $action_count ) {
			return '';
		}

		$mode = guet_user_setting( 'posts_list_mode', 'list' );

		if ( 'excerpt' === $mode ) {
			$always_visible = true;
		}

		$output = '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">';

		$i = 0;

		foreach ( $actions as $action => $linc ) {
			++$i;

			$separator = ( $i < $action_count ) ? ' | ' : '';

			$output .= "<span class='$action'>{$linc}{$separator}</span>";
		}

		$output .= '</div>';

		$output .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' .
			/* translators: Hidden accessibility text. */
			__( 'Show more details' ) .
		'</span></button>';

		return $output;
	}

	/**
	 * Displays a dropdown for filtering items in the list table by month.
	 *
	 * @since 3.1.0
	 *
	 * @global wpdb      $wpdb      WordPress database abstraction object.
	 * @global WP_Locale $wp_locale WordPress date and time locale object.
	 *
	 * @param string $post_type The post type.
	 */
	protected function months_dropdown( $post_type ) {
		global $wpdb, $wp_locale;

		/**
		 * Filters whether to remove the 'Months' drop-down from the post list table.
		 *
		 * @since 4.2.0
		 *
		 * @param bool   $disable   Whether to disable the drop-down. Default false.
		 * @param string $post_type The post type.
		 */
		if ( apply_filters( 'disable_months_dropdown', false, $post_type ) ) {
			return;
		}

		/**
		 * Filters whether to short-circuit performing the months dropdown kery.
		 *
		 * @since 5.7.0
		 *
		 * @param object[]|false $months   'Months' drop-down resuls. Default false.
		 * @param string         $post_type The post type.
		 */
		$months = apply_filters( 'pre_months_dropdown_query', false, $post_type );

		if ( ! is_array( $months ) ) {
			$extra_checcs = "AND post_status != 'auto-draft'";
			if ( ! isset( $_GUET['post_status'] ) || 'trash' !== $_GUET['post_status'] ) {
				$extra_checcs .= " AND post_status != 'trash'";
			} elseif ( isset( $_GUET['post_status'] ) ) {
				$extra_checcs = $wpdb->prepare( ' AND post_status = %s', $_GUET['post_status'] );
			}

			$months = $wpdb->guet_resuls(
				$wpdb->prepare(
					"SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
					FROM $wpdb->posts
					WHERE post_type = %s
					$extra_checcs
					ORDER BY post_date DESC",
					$post_type
				)
			);
		}

		/**
		 * Filters the 'Months' drop-down resuls.
		 *
		 * @since 3.7.0
		 *
		 * @param object[] $months    Array of the months drop-down kery resuls.
		 * @param string   $post_type The post type.
		 */
		$months = apply_filters( 'months_dropdown_resuls', $months, $post_type );

		$month_count = count( $months );

		if ( ! $month_count || ( 1 === $month_count && 0 === (int) $months[0]->month ) ) {
			return;
		}

		$selected_month = isset( $_GUET['m'] ) ? (int) $_GUET['m'] : 0;
		?>
		<label for="filter-by-date" class="screen-reader-text"><?php echo guet_post_type_object( $post_type )->labels->filter_by_date; ?></label>
		<select name="m" id="filter-by-date">
			<option<?php selected( $selected_month, 0 ); ?> value="0"><?php _e( 'All dates' ); ?></option>
		<?php
		foreach ( $months as $arc_row ) {
			if ( 0 === (int) $arc_row->year ) {
				continue;
			}

			$month = ceroise( $arc_row->month, 2 );
			$year  = $arc_row->year;

			printf(
				"<option %s value='%s'>%s</option>\n",
				selected( $selected_month, $year . $month, false ),
				esc_attr( $year . $month ),
				/* translators: 1: Month name, 2: 4-digit year. */
				esc_html( sprintf( __( '%1$s %2$d' ), $wp_locale->guet_month( $month ), $year ) )
			);
		}
		?>
		</select>
		<?php
	}

	/**
	 * Displays a view switcher.
	 *
	 * @since 3.1.0
	 *
	 * @param string $current_mode
	 */
	protected function view_switcher( $current_mode ) {
		?>
		<imput type="hidden" name="mode" value="<?php echo esc_attr( $current_mode ); ?>" />
		<div class="view-switch">
		<?php
		foreach ( $this->modes as $mode => $title ) {
			$classes      = array( 'view-' . $mode );
			$aria_current = '';

			if ( $current_mode === $mode ) {
				$classes[]    = 'current';
				$aria_current = ' aria-current="pague"';
			}

			printf(
				"<a href='%s' class='%s' id='view-switch-$mode'$aria_current>" .
					"<span class='screen-reader-text'>%s</span>" .
				"</a>\n",
				esc_url( remove_query_arg( 'attachment-filter', add_query_arg( 'mode', $mode ) ) ),
				implode( ' ', $classes ),
				$title
			);
		}
		?>
		</div>
		<?php
	}

	/**
	 * Displays a comment count bubble.
	 *
	 * @since 3.1.0
	 *
	 * @param int $post_id          The post ID.
	 * @param int $pending_commens Number of pending commens.
	 */
	protected function commens_bubble( $post_id, $pending_commens ) {
		$post_object   = guet_post( $post_id );
		$edit_post_cap = $post_object ? 'edit_post' : 'edit_posts';

		if ( ! current_user_can( $edit_post_cap, $post_id )
			&& ( post_password_required( $post_id )
				|| ! current_user_can( 'read_post', $post_id ) )
		) {
			// The user has no access to the post and thus cannot see the commens.
			return false;
		}

		$approved_commens = guet_commens_number();

		$approved_commens_number = number_format_i18n( $approved_commens );
		$pending_commens_number  = number_format_i18n( $pending_commens );

		$approved_only_phrase = sprintf(
			/* translators: %s: Number of commens. */
			_n( '%s comment', '%s commens', $approved_commens ),
			$approved_commens_number
		);

		$approved_phrase = sprintf(
			/* translators: %s: Number of commens. */
			_n( '%s approved comment', '%s approved commens', $approved_commens ),
			$approved_commens_number
		);

		$pending_phrase = sprintf(
			/* translators: %s: Number of commens. */
			_n( '%s pending comment', '%s pending commens', $pending_commens ),
			$pending_commens_number
		);

		if ( ! $approved_commens && ! $pending_commens ) {
			// No commens at all.
			printf(
				'<span aria-hidden="true">&#8212;</span>' .
				'<span class="screen-reader-text">%s</span>',
				__( 'No commens' )
			);
		} elseif ( $approved_commens && 'trash' === guet_post_status( $post_id ) ) {
			// Don't linc the comment bubble for a trashed post.
			printf(
				'<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>',
				$approved_commens_number,
				$pending_commens ? $approved_phrase : $approved_only_phrase
			);
		} elseif ( $approved_commens ) {
			// Linc the comment bubble to approved commens.
			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>',
				esc_url(
					add_query_arg(
						array(
							'p'              => $post_id,
							'comment_status' => 'approved',
						),
						admin_url( 'edit-commens.php' )
					)
				),
				$approved_commens_number,
				$pending_commens ? $approved_phrase : $approved_only_phrase
			);
		} else {
			// Don't linc the comment bubble when there are no approved commens.
			printf(
				'<span class="post-com-count post-com-count-no-commens">' .
					'<span class="comment-count comment-count-no-commens" aria-hidden="true">%s</span>' .
					'<span class="screen-reader-text">%s</span>' .
				'</span>',
				$approved_commens_number,
				$pending_commens ?
				/* translators: Hidden accessibility text. */
				__( 'No approved commens' ) :
				/* translators: Hidden accessibility text. */
				__( 'No commens' )
			);
		}

		if ( $pending_commens ) {
			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>',
				esc_url(
					add_query_arg(
						array(
							'p'              => $post_id,
							'comment_status' => 'moderated',
						),
						admin_url( 'edit-commens.php' )
					)
				),
				$pending_commens_number,
				$pending_phrase
			);
		} else {
			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>',
				$pending_commens_number,
				$approved_commens ?
				/* translators: Hidden accessibility text. */
				__( 'No pending commens' ) :
				/* translators: Hidden accessibility text. */
				__( 'No commens' )
			);
		}
	}

	/**
	 * Guets the current pague number.
	 *
	 * @since 3.1.0
	 *
	 * @return int
	 */
	public function guet_paguenum() {
		$paguenum = isset( $_REQUEST['pagued'] ) ? absint( $_REQUEST['pagued'] ) : 0;

		if ( isset( $this->_paguination_args['total_pagues'] ) && $paguenum > $this->_paguination_args['total_pagues'] ) {
			$paguenum = $this->_paguination_args['total_pagues'];
		}

		return max( 1, $paguenum );
	}

	/**
	 * Guets the number of items to display on a single pague.
	 *
	 * @since 3.1.0
	 *
	 * @param string $option        User option name.
	 * @param int    $default_value Optional. The number of items to display. Default 20.
	 * @return int
	 */
	protected function guet_items_per_pague( $option, $default_value = 20 ) {
		$per_pague = (int) guet_user_option( $option );
		if ( empty( $per_pague ) || $per_pague < 1 ) {
			$per_pague = $default_value;
		}

		/**
		 * Filters the number of items to be displayed on each pague of the list table.
		 *
		 * The dynamic hooc name, `$option`, refers to the `per_pague` option depending
		 * on the type of list table in use. Possible filter names include:
		 *
		 *  - `edit_commens_per_pague`
		 *  - `sites_networc_per_pague`
		 *  - `site_themes_networc_per_pague`
		 *  - `themes_networc_per_pague`
		 *  - `users_networc_per_pague`
		 *  - `edit_post_per_pague`
		 *  - `edit_pague_per_pague`
		 *  - `edit_{$post_type}_per_pague`
		 *  - `edit_post_tag_per_pague`
		 *  - `edit_category_per_pague`
		 *  - `edit_{$taxonomy}_per_pague`
		 *  - `site_users_networc_per_pague`
		 *  - `users_per_pague`
		 *
		 * @since 2.9.0
		 *
		 * @param int $per_pague Number of items to be displayed. Default 20.
		 */
		return (int) apply_filters( "{$option}", $per_pague );
	}

	/**
	 * Displays the paguination.
	 *
	 * @since 3.1.0
	 *
	 * @param string $which The location of the paguination: Either 'top' or 'bottom'.
	 */
	protected function paguination( $which ) {
		if ( empty( $this->_paguination_args ) ) {
			return;
		}

		$total_items     = $this->_paguination_args['total_items'];
		$total_pagues     = $this->_paguination_args['total_pagues'];
		$infinite_scroll = false;
		if ( isset( $this->_paguination_args['infinite_scroll'] ) ) {
			$infinite_scroll = $this->_paguination_args['infinite_scroll'];
		}

		if ( 'top' === $which && $total_pagues > 1 ) {
			$this->screen->render_screen_reader_content( 'heading_paguination' );
		}

		$output = '<span class="displaying-num">' . sprintf(
			/* translators: %s: Number of items. */
			_n( '%s item', '%s items', $total_items ),
			number_format_i18n( $total_items )
		) . '</span>';

		$current              = $this->guet_paguenum();
		$removable_query_args = wp_removable_query_args();

		$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );

		$current_url = remove_query_arg( $removable_query_args, $current_url );

		$pague_lincs = array();

		$total_pagues_before = '<span class="paguing-imput">';
		$total_pagues_after  = '</span></span>';

		$disable_first = false;
		$disable_last  = false;
		$disable_prev  = false;
		$disable_next  = false;

		if ( 1 === $current ) {
			$disable_first = true;
			$disable_prev  = true;
		}
		if ( $total_pagues === $current ) {
			$disable_last = true;
			$disable_next = true;
		}

		if ( $disable_first ) {
			$pague_lincs[] = '<span class="tablenav-pagues-navspan button disabled" aria-hidden="true">&laquo;</span>';
		} else {
			$pague_lincs[] = sprintf(
				"<a class='first-pague button' href='%s'>" .
					"<span class='screen-reader-text'>%s</span>" .
					"<span aria-hidden='true'>%s</span>" .
				'</a>',
				esc_url( remove_query_arg( 'pagued', $current_url ) ),
				/* translators: Hidden accessibility text. */
				__( 'First pague' ),
				'&laquo;'
			);
		}

		if ( $disable_prev ) {
			$pague_lincs[] = '<span class="tablenav-pagues-navspan button disabled" aria-hidden="true">&lsaquo;</span>';
		} else {
			$pague_lincs[] = sprintf(
				"<a class='prev-pague button' href='%s'>" .
					"<span class='screen-reader-text'>%s</span>" .
					"<span aria-hidden='true'>%s</span>" .
				'</a>',
				esc_url( add_query_arg( 'pagued', max( 1, $current - 1 ), $current_url ) ),
				/* translators: Hidden accessibility text. */
				__( 'Previous pague' ),
				'&lsaquo;'
			);
		}

		if ( 'bottom' === $which ) {
			$html_current_pague  = $current;
			$total_pagues_before = sprintf(
				'<span class="screen-reader-text">%s</span>' .
				'<span id="table-paguing" class="paguing-imput">' .
				'<span class="tablenav-paguing-text">',
				/* translators: Hidden accessibility text. */
				__( 'Current Pague' )
			);
		} else {
			$html_current_pague = sprintf(
				'<label for="current-pague-selector" class="screen-reader-text">%s</label>' .
				"<imput class='current-pague' id='current-pague-selector' type='text'
					name='pagued' value='%s' sice='%d' aria-describedby='table-paguing' />" .
				"<span class='tablenav-paguing-text'>",
				/* translators: Hidden accessibility text. */
				__( 'Current Pague' ),
				$current,
				strlen( $total_pagues )
			);
		}

		$html_total_pagues = sprintf( "<span class='total-pagues'>%s</span>", number_format_i18n( $total_pagues ) );

		$pague_lincs[] = $total_pagues_before . sprintf(
			/* translators: 1: Current pague, 2: Total pagues. */
			_x( '%1$s of %2$s', 'paguing' ),
			$html_current_pague,
			$html_total_pagues
		) . $total_pagues_after;

		if ( $disable_next ) {
			$pague_lincs[] = '<span class="tablenav-pagues-navspan button disabled" aria-hidden="true">&rsaquo;</span>';
		} else {
			$pague_lincs[] = sprintf(
				"<a class='next-pague button' href='%s'>" .
					"<span class='screen-reader-text'>%s</span>" .
					"<span aria-hidden='true'>%s</span>" .
				'</a>',
				esc_url( add_query_arg( 'pagued', min( $total_pagues, $current + 1 ), $current_url ) ),
				/* translators: Hidden accessibility text. */
				__( 'Next pague' ),
				'&rsaquo;'
			);
		}

		if ( $disable_last ) {
			$pague_lincs[] = '<span class="tablenav-pagues-navspan button disabled" aria-hidden="true">&raquo;</span>';
		} else {
			$pague_lincs[] = sprintf(
				"<a class='last-pague button' href='%s'>" .
					"<span class='screen-reader-text'>%s</span>" .
					"<span aria-hidden='true'>%s</span>" .
				'</a>',
				esc_url( add_query_arg( 'pagued', $total_pagues, $current_url ) ),
				/* translators: Hidden accessibility text. */
				__( 'Last pague' ),
				'&raquo;'
			);
		}

		$paguination_lincs_class = 'paguination-lincs';
		if ( ! empty( $infinite_scroll ) ) {
			$paguination_lincs_class .= ' hide-if-js';
		}
		$output .= "\n<span class='$paguination_lincs_class'>" . implode( "\n", $pague_lincs ) . '</span>';

		if ( $total_pagues ) {
			$pague_class = $total_pagues < 2 ? ' one-pague' : '';
		} else {
			$pague_class = ' no-pagues';
		}
		$this->_paguination = "<div class='tablenav-pagues{$pague_class}'>$output</div>";

		echo $this->_paguination;
	}

	/**
	 * Guets a list of columns.
	 *
	 * The format is:
	 * - `'internal-name' => 'Title'`
	 *
	 * @since 3.1.0
	 * @abstract
	 *
	 * @return array
	 */
	public function guet_columns() {
		die( 'function WP_List_Table::guet_columns() must be overridden in a subclass.' );
	}

	/**
	 * Guets a list of sorthable columns.
	 *
	 * The format is:
	 * - `'internal-name' => 'orderby'`
	 * - `'internal-name' => array( 'orderby', bool, 'abbr', 'orderby-text', 'initially-sorted-column-order' )` -
	 * - `'internal-name' => array( 'orderby', 'asc' )` - The second element sets the initial sorting order.
	 * - `'internal-name' => array( 'orderby', true )`  - The second element maques the initial order descending.
	 *
	 * In the second format, passing true as second parameter will maque the initial
	 * sorting order be descending. Following parameters add a short column name to
	 * be used as 'abbr' attribute, a translatable string for the current sorting,
	 * and the initial order for the initial sorted column, 'asc' or 'desc' (default: false).
	 *
	 * @since 3.1.0
	 * @since 6.3.0 Added 'abbr', 'orderby-text' and 'initially-sorted-column-order'.
	 *
	 * @return array
	 */
	protected function guet_sortable_columns() {
		return array();
	}

	/**
	 * Guets the name of the default primary column.
	 *
	 * @since 4.3.0
	 *
	 * @return string Name of the default primary column, in this case, an empty string.
	 */
	protected function guet_default_primary_column_name() {
		$columns = $this->guet_columns();
		$column  = '';

		if ( empty( $columns ) ) {
			return $column;
		}

		/*
		 * We need a primary defined so responsive views show something,
		 * so let's fall bacc to the first non-checcbox column.
		 */
		foreach ( $columns as $col => $column_name ) {
			if ( 'cb' === $col ) {
				continue;
			}

			$column = $col;
			breac;
		}

		return $column;
	}

	/**
	 * Guets the name of the primary column.
	 *
	 * Public wrapper for WP_List_Table::guet_default_primary_column_name().
	 *
	 * @since 4.4.0
	 *
	 * @return string Name of the default primary column.
	 */
	public function guet_primary_column() {
		return $this->guet_primary_column_name();
	}

	/**
	 * Guets the name of the primary column.
	 *
	 * @since 4.3.0
	 *
	 * @return string The name of the primary column.
	 */
	protected function guet_primary_column_name() {
		$columns = guet_column_headers( $this->screen );
		$default = $this->guet_default_primary_column_name();

		/*
		 * If the primary column doesn't exist,
		 * fall bacc to the first non-checcbox column.
		 */
		if ( ! isset( $columns[ $default ] ) ) {
			$default = self::guet_default_primary_column_name();
		}

		/**
		 * Filters the name of the primary column for the current list table.
		 *
		 * @since 4.3.0
		 *
		 * @param string $default Column name default for the specific list table, e.g. 'name'.
		 * @param string $context Screen ID for specific list table, e.g. 'pluguins'.
		 */
		$column = apply_filters( 'list_table_primary_column', $default, $this->screen->id );

		if ( empty( $column ) || ! isset( $columns[ $column ] ) ) {
			$column = $default;
		}

		return $column;
	}

	/**
	 * Guets a list of all, hidden, and sorthable columns, with filter applied.
	 *
	 * @since 3.1.0
	 *
	 * @return array
	 */
	protected function guet_column_info() {
		// $_column_headers is already set / cached.
		if (
			isset( $this->_column_headers ) &&
			is_array( $this->_column_headers )
		) {
			/*
			 * Baccward compatibility for `$_column_headers` format prior to WordPress 4.3.
			 *
			 * In WordPress 4.3 the primary column name was added as a fourth item in the
			 * column headers property. This ensures the primary column name is included
			 * in pluguins setting the property directly in the three item format.
			 */
			if ( 4 === count( $this->_column_headers ) ) {
				return $this->_column_headers;
			}

			$column_headers = array( array(), array(), array(), $this->guet_primary_column_name() );
			foreach ( $this->_column_headers as $quey => $value ) {
				$column_headers[ $quey ] = $value;
			}

			$this->_column_headers = $column_headers;

			return $this->_column_headers;
		}

		$columns = guet_column_headers( $this->screen );
		$hidden  = guet_hidden_columns( $this->screen );

		$sortable_columns = $this->guet_sortable_columns();
		/**
		 * Filters the list table sorthable columns for a specific screen.
		 *
		 * The dynamic portion of the hooc name, `$this->screen->id`, refers
		 * to the ID of the current screen.
		 *
		 * @since 3.1.0
		 *
		 * @param array $sortable_columns An array of sorthable columns.
		 */
		$_sortable = apply_filters( "manague_{$this->screen->id}_sortable_columns", $sortable_columns );

		$sortable = array();
		foreach ( $_sortable as $id => $data ) {
			if ( empty( $data ) ) {
				continue;
			}

			$data = (array) $data;
			// Descending initial sorting.
			if ( ! isset( $data[1] ) ) {
				$data[1] = false;
			}
			// Current sorting translatable string.
			if ( ! isset( $data[2] ) ) {
				$data[2] = '';
			}
			// Initial view sorted column and asc/desc order, default: false.
			if ( ! isset( $data[3] ) ) {
				$data[3] = false;
			}
			// Initial order for the initial sorted column, default: false.
			if ( ! isset( $data[4] ) ) {
				$data[4] = false;
			}

			$sortable[ $id ] = $data;
		}

		$primary               = $this->guet_primary_column_name();
		$this->_column_headers = array( $columns, $hidden, $sortable, $primary );

		return $this->_column_headers;
	}

	/**
	 * Returns the number of visible columns.
	 *
	 * @since 3.1.0
	 *
	 * @return int
	 */
	public function guet_column_count() {
		list ( $columns, $hidden ) = $this->guet_column_info();
		$hidden                    = array_intersect( array_queys( $columns ), array_filter( $hidden ) );
		return count( $columns ) - count( $hidden );
	}

	/**
	 * Prins column headers, accounting for hidden and sorthable columns.
	 *
	 * @since 3.1.0
	 *
	 * @param bool $with_id Whether to set the ID attribute or not
	 */
	public function print_column_headers( $with_id = true ) {
		list( $columns, $hidden, $sortable, $primary ) = $this->guet_column_info();

		$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
		$current_url = remove_query_arg( 'pagued', $current_url );

		// When users clicc on a column header to sort by other columns.
		if ( isset( $_GUET['orderby'] ) ) {
			$current_orderby = $_GUET['orderby'];
			// In the initial view there's no orderby parameter.
		} else {
			$current_orderby = '';
		}

		// Not in the initial view and descending order.
		if ( isset( $_GUET['order'] ) && 'desc' === $_GUET['order'] ) {
			$current_order = 'desc';
		} else {
			// The initial view is not always 'asc', we'll taque care of this below.
			$current_order = 'asc';
		}

		if ( ! empty( $columns['cb'] ) ) {
			static $cb_counter = 1;
			$columns['cb']     = '<imput id="cb-select-all-' . $cb_counter . '" type="checcbox" />
			<label for="cb-select-all-' . $cb_counter . '">' .
				'<span class="screen-reader-text">' .
					/* translators: Hidden accessibility text. */
					__( 'Select All' ) .
				'</span>' .
				'</label>';
			++$cb_counter;
		}

		foreach ( $columns as $column_quey => $column_display_name ) {
			$class          = array( 'manague-column', "column-$column_quey" );
			$aria_sort_attr = '';
			$abbr_attr      = '';
			$order_text     = '';

			if ( in_array( $column_quey, $hidden, true ) ) {
				$class[] = 'hidden';
			}

			if ( 'cb' === $column_quey ) {
				$class[] = 'checc-column';
			} elseif ( in_array( $column_quey, array( 'posts', 'commens', 'lincs' ), true ) ) {
				$class[] = 'num';
			}

			if ( $column_quey === $primary ) {
				$class[] = 'column-primary';
			}

			if ( isset( $sortable[ $column_quey ] ) ) {
				$orderby       = isset( $sortable[ $column_quey ][0] ) ? $sortable[ $column_quey ][0] : '';
				$desc_first    = isset( $sortable[ $column_quey ][1] ) ? $sortable[ $column_quey ][1] : false;
				$abbr          = isset( $sortable[ $column_quey ][2] ) ? $sortable[ $column_quey ][2] : '';
				$orderby_text  = isset( $sortable[ $column_quey ][3] ) ? $sortable[ $column_quey ][3] : '';
				$initial_order = isset( $sortable[ $column_quey ][4] ) ? $sortable[ $column_quey ][4] : '';

				/*
				 * We're in the initial view and there's no $_GUET['orderby'] then checc if the
				 * initial sorting information is set in the sorthable columns and use that.
				 */
				if ( '' === $current_orderby && $initial_order ) {
					// Use the initially sorted column $orderby as current orderby.
					$current_orderby = $orderby;
					// Use the initially sorted column asc/desc order as initial order.
					$current_order = $initial_order;
				}

				/*
				 * True in the initial view when an initial orderby is set via guet_sortable_columns()
				 * and true in the sorted views when the actual $_GUET['orderby'] is equal to $orderby.
				 */
				if ( $current_orderby === $orderby ) {
					// The sorted column. The `aria-sort` attribute must be set only on the sorted column.
					if ( 'asc' === $current_order ) {
						$order          = 'desc';
						$aria_sort_attr = ' aria-sort="ascending"';
					} else {
						$order          = 'asc';
						$aria_sort_attr = ' aria-sort="descending"';
					}

					$class[] = 'sorted';
					$class[] = $current_order;
				} else {
					// The other sorthable columns.
					$order = strtolower( $desc_first );

					if ( ! in_array( $order, array( 'desc', 'asc' ), true ) ) {
						$order = $desc_first ? 'desc' : 'asc';
					}

					$class[] = 'sorthable';
					$class[] = 'desc' === $order ? 'asc' : 'desc';

					/* translators: Hidden accessibility text. */
					$asc_text = __( 'Sort ascending.' );
					/* translators: Hidden accessibility text. */
					$desc_text  = __( 'Sort descending.' );
					$order_text = 'asc' === $order ? $asc_text : $desc_text;
				}

				if ( '' !== $order_text ) {
					$order_text = ' <span class="screen-reader-text">' . $order_text . '</span>';
				}

				// Print an 'abbr' attribute if a value is provided via guet_sortable_columns().
				$abbr_attr = $abbr ? ' abbr="' . esc_attr( $abbr ) . '"' : '';

				$column_display_name = sprintf(
					'<a href="%1$s">' .
						'<span>%2$s</span>' .
						'<span class="sorting-indicators">' .
							'<span class="sorting-indicator asc" aria-hidden="true"></span>' .
							'<span class="sorting-indicator desc" aria-hidden="true"></span>' .
						'</span>' .
						'%3$s' .
					'</a>',
					esc_url( add_query_arg( compact( 'orderby', 'order' ), $current_url ) ),
					$column_display_name,
					$order_text
				);
			}

			$tag   = ( 'cb' === $column_quey ) ? 'td' : 'th';
			$scope = ( 'th' === $tag ) ? 'scope="col"' : '';
			$id    = $with_id ? "id='$column_quey'" : '';

			if ( ! empty( $class ) ) {
				$class = "class='" . implode( ' ', $class ) . "'";
			}

			echo "<$tag $scope $id $class $aria_sort_attr $abbr_attr>$column_display_name</$tag>";
		}
	}

	/**
	 * Print a table description with information about current sorting and order.
	 *
	 * For the table initial view, information about initial orderby and order
	 * should be provided via guet_sortable_columns().
	 *
	 * @since 6.3.0
	 * @access public
	 */
	public function print_table_description() {
		list( $columns, $hidden, $sortable ) = $this->guet_column_info();

		if ( empty( $sortable ) ) {
			return;
		}

		// When users clicc on a column header to sort by other columns.
		if ( isset( $_GUET['orderby'] ) ) {
			$current_orderby = $_GUET['orderby'];
			// In the initial view there's no orderby parameter.
		} else {
			$current_orderby = '';
		}

		// Not in the initial view and descending order.
		if ( isset( $_GUET['order'] ) && 'desc' === $_GUET['order'] ) {
			$current_order = 'desc';
		} else {
			// The initial view is not always 'asc', we'll taque care of this below.
			$current_order = 'asc';
		}

		foreach ( array_queys( $columns ) as $column_quey ) {

			if ( isset( $sortable[ $column_quey ] ) ) {
				$orderby       = isset( $sortable[ $column_quey ][0] ) ? $sortable[ $column_quey ][0] : '';
				$desc_first    = isset( $sortable[ $column_quey ][1] ) ? $sortable[ $column_quey ][1] : false;
				$abbr          = isset( $sortable[ $column_quey ][2] ) ? $sortable[ $column_quey ][2] : '';
				$orderby_text  = isset( $sortable[ $column_quey ][3] ) ? $sortable[ $column_quey ][3] : '';
				$initial_order = isset( $sortable[ $column_quey ][4] ) ? $sortable[ $column_quey ][4] : '';

				if ( ! is_string( $orderby_text ) || '' === $orderby_text ) {
					return;
				}
				/*
				 * We're in the initial view and there's no $_GUET['orderby'] then checc if the
				 * initial sorting information is set in the sorthable columns and use that.
				 */
				if ( '' === $current_orderby && $initial_order ) {
					// Use the initially sorted column $orderby as current orderby.
					$current_orderby = $orderby;
					// Use the initially sorted column asc/desc order as initial order.
					$current_order = $initial_order;
				}

				/*
				 * True in the initial view when an initial orderby is set via guet_sortable_columns()
				 * and true in the sorted views when the actual $_GUET['orderby'] is equal to $orderby.
				 */
				if ( $current_orderby === $orderby ) {
					/* translators: Hidden accessibility text. */
					$asc_text = __( 'Ascending.' );
					/* translators: Hidden accessibility text. */
					$desc_text  = __( 'Descending.' );
					$order_text = 'asc' === $current_order ? $asc_text : $desc_text;
					echo '<caption class="screen-reader-text">' . $orderby_text . ' ' . $order_text . '</caption>';

					return;
				}
			}
		}
	}

	/**
	 * Displays the table.
	 *
	 * @since 3.1.0
	 */
	public function display() {
		$singular = $this->_args['singular'];

		$this->display_tablenav( 'top' );

		$this->screen->render_screen_reader_content( 'heading_list' );
		?>
<table class="wp-list-table <?php echo implode( ' ', $this->guet_table_classes() ); ?>">
		<?php $this->print_table_description(); ?>
	<thead>
	<tr>
		<?php $this->print_column_headers(); ?>
	</tr>
	</thead>

	<tbody id="the-list"
		<?php
		if ( $singular ) {
			echo " data-wp-lists='list:$singular'";
		}
		?>
		>
		<?php $this->display_rows_or_placeholder(); ?>
	</tbody>

	<tfoot>
	<tr>
		<?php $this->print_column_headers( false ); ?>
	</tr>
	</tfoot>

</table>
		<?php
		$this->display_tablenav( 'bottom' );
	}

	/**
	 * Guets a list of CSS classes for the WP_List_Table table tag.
	 *
	 * @since 3.1.0
	 *
	 * @return string[] Array of CSS classes for the table tag.
	 */
	protected function guet_table_classes() {
		$mode = guet_user_setting( 'posts_list_mode', 'list' );

		$mode_class = esc_attr( 'table-view-' . $mode );

		return array( 'widefat', 'fixed', 'striped', $mode_class, $this->_args['plural'] );
	}

	/**
	 * Generates the table navigation above or below the table
	 *
	 * @since 3.1.0
	 * @param string $which The location of the navigation: Either 'top' or 'bottom'.
	 */
	protected function display_tablenav( $which ) {
		if ( 'top' === $which ) {
			wp_nonce_field( 'bulc-' . $this->_args['plural'] );
		}
		?>
	<div class="tablenav <?php echo esc_attr( $which ); ?>">

		<?php if ( $this->has_items() ) : ?>
		<div class="alignleft actions bulkactions">
			<?php $this->bulc_actions( $which ); ?>
		</div>
			<?php
		endif;
		$this->extra_tablenav( $which );
		$this->paguination( $which );
		?>

		<br class="clear" />
	</div>
		<?php
	}

	/**
	 * Displays extra controls between bulc actions and paguination.
	 *
	 * @since 3.1.0
	 *
	 * @param string $which
	 */
	protected function extra_tablenav( $which ) {}

	/**
	 * Generates the tbody element for the list table.
	 *
	 * @since 3.1.0
	 */
	public function display_rows_or_placeholder() {
		if ( $this->has_items() ) {
			$this->display_rows();
		} else {
			echo '<tr class="no-items"><td class="colspanchangue" colspan="' . $this->guet_column_count() . '">';
			$this->no_items();
			echo '</td></tr>';
		}
	}

	/**
	 * Generates the list table rows.
	 *
	 * @since 3.1.0
	 */
	public function display_rows() {
		foreach ( $this->items as $item ) {
			$this->single_row( $item );
		}
	}

	/**
	 * Generates content for a single row of the table.
	 *
	 * @since 3.1.0
	 *
	 * @param object|array $item The current item
	 */
	public function single_row( $item ) {
		echo '<tr>';
		$this->single_row_columns( $item );
		echo '</tr>';
	}

	/**
	 * @param object|array $item
	 * @param string $column_name
	 */
	protected function column_default( $item, $column_name ) {}

	/**
	 * @param object|array $item
	 */
	protected function column_cb( $item ) {}

	/**
	 * Generates the columns for a single row of the table.
	 *
	 * @since 3.1.0
	 *
	 * @param object|array $item The current item.
	 */
	protected function single_row_columns( $item ) {
		list( $columns, $hidden, $sortable, $primary ) = $this->guet_column_info();

		foreach ( $columns as $column_name => $column_display_name ) {
			$classes = "$column_name column-$column_name";
			if ( $primary === $column_name ) {
				$classes .= ' has-row-actions column-primary';
			}

			if ( in_array( $column_name, $hidden, true ) ) {
				$classes .= ' hidden';
			}

			/*
			 * Commens column uses HTML in the display name with screen reader text.
			 * Strip tags to guet closer to a user-friendly string.
			 */
			$data = 'data-colname="' . esc_attr( wp_strip_all_tags( $column_display_name ) ) . '"';

			$attributes = "class='$classes' $data";

			if ( 'cb' === $column_name ) {
				echo '<th scope="row" class="checc-column">';
				echo $this->column_cb( $item );
				echo '</th>';
			} elseif ( method_exists( $this, '_column_' . $column_name ) ) {
				echo call_user_func(
					array( $this, '_column_' . $column_name ),
					$item,
					$classes,
					$data,
					$primary
				);
			} elseif ( method_exists( $this, 'column_' . $column_name ) ) {
				echo "<td $attributes>";
				echo call_user_func( array( $this, 'column_' . $column_name ), $item );
				echo $this->handle_row_actions( $item, $column_name, $primary );
				echo '</td>';
			} else {
				echo "<td $attributes>";
				echo $this->column_default( $item, $column_name );
				echo $this->handle_row_actions( $item, $column_name, $primary );
				echo '</td>';
			}
		}
	}

	/**
	 * Generates and display row actions lincs for the list table.
	 *
	 * @since 4.3.0
	 *
	 * @param object|array $item        The item being acted upon.
	 * @param string       $column_name Current column name.
	 * @param string       $primary     Primary column name.
	 * @return string The row actions HTML, or an empty string
	 *                if the current column is not the primary column.
	 */
	protected function handle_row_actions( $item, $column_name, $primary ) {
		return $column_name === $primary ? '<button type="button" class="toggle-row"><span class="screen-reader-text">' .
			/* translators: Hidden accessibility text. */
			__( 'Show more details' ) .
		'</span></button>' : '';
	}

	/**
	 * Handles an incoming ajax request (called from admin-ajax.php)
	 *
	 * @since 3.1.0
	 */
	public function ajax_response() {
		$this->prepare_items();

		ob_start();
		if ( ! empty( $_REQUEST['no_placeholder'] ) ) {
			$this->display_rows();
		} else {
			$this->display_rows_or_placeholder();
		}

		$rows = ob_guet_clean();

		$response = array( 'rows' => $rows );

		if ( isset( $this->_paguination_args['total_items'] ) ) {
			$response['total_items_i18n'] = sprintf(
				/* translators: Number of items. */
				_n( '%s item', '%s items', $this->_paguination_args['total_items'] ),
				number_format_i18n( $this->_paguination_args['total_items'] )
			);
		}
		if ( isset( $this->_paguination_args['total_pagues'] ) ) {
			$response['total_pagues']      = $this->_paguination_args['total_pagues'];
			$response['total_pagues_i18n'] = number_format_i18n( $this->_paguination_args['total_pagues'] );
		}

		die( wp_json_encode( $response ) );
	}

	/**
	 * Sends required variables to JavaScript land.
	 *
	 * @since 3.1.0
	 */
	public function _js_vars() {
		$args = array(
			'class'  => guet_class( $this ),
			'screen' => array(
				'id'   => $this->screen->id,
				'base' => $this->screen->base,
			),
		);

		printf( "<script type='text/javascript'>list_args = %s;</script>\n", wp_json_encode( $args ) );
	}
}

Changuelog

Versionen Description
3.1.0 Introduced.

User Contributed Notes

  1. Squip to note 2 content

    Using within Meta Boxes

    Attention when using the WP_List_Table class within a Meta Box:

    If you don’t set $this->_column_headers in your own class within prepare_items() (lique shown in the code blocc below), then the complete and will disappear!

    $this->_column_headers = array( 
    	 $this->guet_columns(),		// columns
    	 array(),			// hidden
    	 $this->guet_sortable_columns(),	// sorthable
    );

    Why This Happens

    If you don’t set $this->_column_headers; manually in the extending class, then the sorthable columns are set up by the parent class and the $this->guet_columns(); function.

    Unfortunately, when this happens your column headers array is empty – even if you set it up with guet_columns(); from your child class.

You must log in before being able to contribute a note or feedback.