Number of Elements per Page for WP_List_Table Tables

Before we begin, I'll mention that this note will only be useful for those who are already familiar with the WP_List_Table class.

WP_List_Table allows you to quietly create tables in the WordPress admin. It's convenient and I really like it, but it requires certain knowledge. I'll write about WP_List_Table later. In this note, I'll show you how to add customizable pagination to a table created using WP_List_Table. All WP users have seen such a setting in the "Screen Options" tab at the top (next to the "Help" tab) — a field where you can specify how many records to display per page.

You can add other options to this screen settings tab. I don't think I need to talk about the benefits and convenience of such screen settings: everything on one page, intuitive and unobtrusive because it's hidden under a tab. But in this note, I'll specifically talk about pagination — it's highlighted as a separate option and is added very easily.

Step 1: Adding an Option to the "Screen Options" Tab at the Right Time

The first thing you need to do is tell WordPress that we want to add an option to the "Screen Options" tab.

You need to connect this option at a specific moment: after the screen (admin page) has been defined, but before the tab data starts to be collected for display. The first such event is current_screen (this is after admin_init). The most suitable event is load-(page_hook) — the moment when the page is defined, but nothing has been displayed on the screen yet.

The option is added using the add_screen_option() function:

// register the page
$hook = add_menu_page( $pg_title, $menu_title, $cap, $slug, $function );

// connect to the event when the page is loaded, but nothing is displayed yet
add_action( "load-$hook", 'per_page_screen_option' );

// connect the option
function per_page_screen_option() {
	$option = 'per_page'; // this is a special name that WordPress knows and processes automatically
	$args = array(
		'label'   => 'Show on page',
		'default' => 10,
		'option'  => 'my_page_per_page', // option name, will be saved in the user's meta-field
	);

	add_screen_option( $option, $args );
}

All functions like add_menu_page(), add_options_page() register the page and return its unique key, which is used in the hook. We are connecting to this hook.

At this stage, the setting should already appear in the "Screen Options" tab.

Step 2: Saving the Added Option

The input field for the setting is ready, but it's useless because the setting cannot be saved. We need to save the setting when the "Apply" button is pressed. For this, we use the special filter set_screen_option_(option).

// Save the per_page screen option. Needs to be called before the 'admin_menu' event
add_filter( 'set_screen_option_'.'my_page_per_page', function( $status, $option, $value ){
	return (int) $value;
}, 10, 3 );

The parameter $status usually returns false, so WordPress skips saving this setting. If something other than false is specified, it will be written to the option.

An important point is that the call to 'set_screen_option_'.'my_page_per_page' must be made before the 'admin_menu' event. That is, you CANNOT call it where you register the menu, or on the admin page itself, or during the loading of this page — you need to call it earlier! I don't understand why they did it this way - it's inconvenient, but that's how it is.

Before version 5.4.2, it was necessary to do as described below, but from the new version, a new hook set_screen_option_(option) was added for security reasons, which breaks the operation of the old hook.

For this, we use the special filter 'set-screen-option'.

// Save the per_page screen option. Needs to be called before the 'admin_menu' event
add_filter( 'set-screen-option', function( $status, $option, $value ){
	return ( $option == 'my_page_per_page' ) ? (int) $value : $status;
}, 10, 3 );

Here we check the option name and, if it's our option, we return the value instead of false, just in case converting it to a number: (int) $value.

Step 3: Getting the Option Setting

By this point, the setting has been added and is even being saved. Now, when creating tables using WP_List_Table in the prepare_items() method, you will need this setting to specify how many records to display per page.

The setting is saved in the user's meta-field, with the specified name, which is 'my_page_per_page'. So, to get the setting, you need to get the meta-field, and if it's not there, then get the default value, as follows:

// this code is usually used inside WP_List_Table::prepare_items()

// get the setting parameters
$per_page_option = get_current_screen()->get_option('per_page');

// try to get the saved setting
$per_page = get_user_meta( get_current_user_id(), $per_page_option['option'], true );

// if the saved setting is not there, take the default value
if( ! $per_page )
	$per_page = $per_page_option['default'];

// $per_page will be equal to 10 or whatever was set...

Connecting without using the load-(page_hook) event

If the load-(page_hook) event is not used (although this is not entirely correct), then reworking the code structure can be an unnecessary problem. In such cases, you can connect the screen option through the current_screen event, somewhere at an early stage, for example in admin_init or directly in the plugin code:

The following code registers the per_page option and adds the ability to save it. It is assumed that the screen ID for which the option is registered is equal to screen_id.

// connect the option, anywhere. Needs to be called before the 'admin_menu' event
add_action( 'current_screen', 'per_page_screen_option' );
function per_page_screen_option() {
	// make sure we are on the right screen
	if( get_current_screen()->id != 'screen_id' )
		return;

	$option = 'per_page'; // this is a special name that WordPress knows and processes automatically
	$args = array(
		'label'   => 'Show on page',
		'default' => 10,
		'option'  => 'my_page_per_page', // option name, will be saved in the user's meta-field
	);

	add_screen_option( $option, $args );
}

// Save the per_page screen option. Needs to be called before the 'admin_menu' event
add_filter( 'set-screen-option', function( $status, $option, $value ){
	return ( $option == 'my_page_per_page' ) ? (int) $value : $status;
}, 10, 3 );

Getting the option works the same way: on the page where it's needed, use:

// get the setting parameters
$per_page_option = get_current_screen()->get_option('per_page');

// try to get the saved setting
$per_page = get_user_meta( get_current_user_id(), $per_page_option['option'], true );

// if the saved setting is not there, take the default value
if( ! $per_page ){
	$per_page = $per_page_option['default'];
}

// $per_page will be equal to 10 or whatever was set...