Suspend WordPress Options Autoload
WordPress keeps its settings, and the settings of most plugins, in the options table in the database. Each setting is one row with a name and a value. The table is named wp_options by default, or wp_<site id>_options for each site on a multisite network. You can see all of them at /wp-admin/options.php.
One query for many settings#
A single page can need dozens of settings. Asking the database for each one would mean dozens of queries. To avoid that, each row has an autoload field. On every page, WordPress loads all the rows set to autoload with one query, and keeps them together in one big list called alloptions.
This makes WordPress faster, as long as the list stays small. The trouble is that the list is loaded on every single page, whether the page needs those settings or not.
Why alloptions grows too big#
Most plugins save their settings with get_option and update_option, and many set them to autoload. Without a persistent object cache, WordPress transients are saved in the options table too. Good plugins remove their data when they are uninstalled, and give their transients an expiry time. Not all plugins do, so the table fills up with old data that is still loaded on every page.
A large alloptions list causes three problems.
- uses more memory on every page, and can crash a site that runs out of memory
- takes longer to load from the database
- may not fit in the object cache. Memcached limits each item to 1MB unless it is set up otherwise, and Redis is slower with large items because they have to be serialized and unserialized.
The ideal size is 1MB or less. Since WordPress 6.6, Site Health warns you when autoloaded options add up to more than 800KB, and a new option larger than 150KB is no longer autoloaded unless the plugin asks for it.
A common tip that does not work#
Some people suggest setting autoload to "no" on every option to make alloptions smaller. It does not work the way they expect. If WordPress finds no rows set to autoload, it loads every row in the table instead.
This is the part of the WordPress wp_load_alloptions function that does it.
$alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE autoload IN ( '" . implode( "', '", esc_sql( wp_autoload_values_to_autoload() ) ) . "' )" );
if ( ! $alloptions_db ) {
$alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" );
}
$wpdb->suppress_errors( $suppress );
$alloptions = array();
foreach ( (array) $alloptions_db as $o ) {
$alloptions[ $o->option_name ] = $o->option_value;
}
- WordPress loads the rows set to autoload. Since WordPress 6.6, these are the rows with an
autoloadvalue ofyes,on,auto-onorauto. - If no row is found, it loads every row in the table, whatever its
autoloadvalue. - It then puts the rows into the
$alloptionslist.
So at least one row must stay set to autoload, and turning autoload off by hand for many rows can make things worse.
Our solution#
Docket Cache takes a different approach. It does not change anything in the database. Instead, it changes what is kept in the cached copy of alloptions.
With Suspend WP Options Autoload turned on, the cached alloptions keeps only the WordPress core options, about 100 of them, such as the site title, the site address and the date format. Options added by plugins are left out. When a page asks for one of them, it is loaded on its own and then kept in the cache like any other item. Pages that do not need it never load it.
The result is a small alloptions list that loads quickly on every page, while plugin settings are still cached and only loaded where they are used.
Turning it on#
Suspend WP Options Autoload is off by default. Turn it on under Optimisations on the Docket Cache Configuration screen, or add this line to wp-config.php.
define( 'DOCKET_CACHE_WPOPTALOAD', true );
When you turn it on or off from the Configuration screen, Docket Cache clears the cached options, so the change applies straight away. See DOCKET_CACHE_WPOPTALOAD.