Skip to content

WPShout Newsletter

Sign up for news, tips, and insights to help you build better websites.

Newsletter - Top banner

How to Audit and Safely Clean Up WordPress Autoloaded Options

A WordPress site can feel slow for dozens of reasons. But when autoloaded options are the problem, the tempting fix is often the riskiest one: open the database and start deleting or disabling rows.

Don’t do that. A large autoload total is a useful clue, not a list of safe-to-remove data. The better path is to measure it, find the plugin or theme that owns the outlier, make one intentional change, test the feature, and measure again.

This guide explains that workflow for current WordPress, including the autoload changes introduced in 6.6, the built-in checks worth using, and the one lesson a very strange old migration taught a client site.

WPShout featured graphic for auditing and safely fixing WordPress autoloaded options

What autoload means in current WordPress

Options are sitewide settings stored in a site’s options table. Autoloaded options are loaded with every WordPress request, so they avoid an individual lookup later in the request. That can be sensible for small settings used nearly everywhere. It is wasteful for a large value used only on a narrow admin screen or an occasional task.

WordPress 6.6 made this more nuanced. Newer rows can store on, off, auto, auto-on, or auto-off; older yes and no rows still work. Core currently treats yes, on, auto-on, and auto as autoloaded. When code leaves the choice to Core, the default size heuristic avoids autoloading a newly saved option larger than 150,000 bytes. It does not retroactively clean up old rows. [1]

That detail matters when auditing a database. A legacy query that looks only for autoload = 'yes' can miss current rows that are still loaded automatically. It also means that a literal wp_options table name is not portable: WordPress installations can use a custom prefix, and Multisite has more than one options store.

Measure before changing anything

Start in Site Health, under Tools > Site Health > Status. Since WordPress 6.6, Core reports the count and combined size of autoloaded options. Its default critical threshold is 800,000 bytes. Treat that as a reason to investigate, not a magic line where every site suddenly breaks. [2]

WordPress Site Health result showing the autoloaded options count and size
Site Health reports the number and combined size of autoloaded options. This clean test site is below the warning threshold.

Keep Site Health as the baseline. The current WP-CLI wp option list --autoload=on filter is not a complete substitute: its implementation matches on and yes, but not auto or auto-on, and it excludes transients by default. That can make its total disagree with Site Health. [3]

For a complete, read-only list of the 20 largest candidates, save the following as audit-autoload.php. It asks wp_autoload_values_to_autoload() for the states the installed Core version actually loads, and it uses $wpdb->options instead of assuming a table prefix. [4]

<?php
global $wpdb;

$autoload_values = wp_autoload_values_to_autoload();
$placeholders    = implode(
    ', ',
    array_fill( 0, count( $autoload_values ), '%s' )
);

$query = $wpdb->prepare(
    "SELECT option_name, LENGTH(option_value) AS option_size, autoload
     FROM {$wpdb->options}
     WHERE autoload IN ($placeholders)
     ORDER BY option_size DESC
     LIMIT 20",
    $autoload_values
);

foreach ( $wpdb->get_results( $query ) as $row ) {
    printf(
        "%10d\t%-8s\t%s\n",
        $row->option_size,
        $row->autoload,
        $row->option_name
    );
}Code language: HTML, XML (xml)
wp eval-file audit-autoload.phpCode language: JavaScript (javascript)

The output is sorted by stored size, which makes it a candidate list rather than a deletion list. A large configuration array may be necessary; an old export log may not be. That distinction comes from the option’s owner and how the site uses it.

⚠️ Do not bulk-clean. Back up the database, reproduce the concern on staging where possible, and change one known option at a time. A smaller autoload total is not a win if it breaks checkout, a scheduled task, or an admin workflow.

Identify the owner before changing autoload

Take the largest candidate and search the active plugin, theme, and custom-code directories for its exact option name. Look for where it is added, updated, read, and cleaned up. Then answer three practical questions:

  • Who owns it? A Core setting, an active plugin, an inactive plugin’s leftover, or custom code?
  • When is it needed? Nearly every front-end request, a few admin pages, a background job, or only a migration that should already be retired?
  • What is the rollback? Can the team restore the database backup or turn autoload back on if the owner’s feature fails its test?

For general guidance on reading and writing options, see Mastering the WordPress Options API. This article deliberately stays narrower: the goal is to make a defensible performance change without treating the database like a junk drawer.

Change autoload safely with Core APIs

When the team has identified an existing option that is not needed on most requests, use wp_set_option_autoload(). It changes the autoload flag without changing the option value. This dedicated setter requires WordPress 6.4 or later:

wp_set_option_autoload( 'acme_old_report_cache', false );Code language: JavaScript (javascript)

For a short, already-reviewed list, use wp_set_option_autoload_values(). Core provides it specifically to change multiple autoload values without altering the stored option values, and it updates relevant option-cache data as part of the operation. Use booleans, not the legacy strings 'yes' and 'no'. [5]

wp_set_option_autoload_values(
    array(
        'acme_old_report_cache' => false,
        'acme_admin_notice_log' => false,
    )
);Code language: PHP (php)

For a new option, choose deliberately: use true when the small value is genuinely needed across most requests, and false when it is limited to specific paths. Leaving the choice as null lets current Core heuristics decide, including the large-value heuristic for newly saved options.

Choose an autoload value by access pattern

  • Use true for a small setting that the active feature reads on most requests, such as a compact configuration array used across the front end.
  • Use false for a known value that is read only in a limited context, such as an admin-only report, an occasional migration state, or a background workflow.
  • Use null when adding an option and you intentionally want current Core to make its default choice. Do not treat that as a substitute for understanding an existing large option.

Size helps prioritize an audit, but it does not make the decision. A larger value needed on every request may belong in the loaded set, while a smaller admin-only value may not. Ownership, access frequency, and a tested rollback decide the change.

One common trap is update_option(). It accepts an autoload argument, but on an existing option that argument can only change the autoload setting if the option value changes too. That makes it the wrong tool for a cleanup that should preserve the value exactly. [6]

Verify the change before calling it done

Test one known option at a time. That keeps the result attributable and gives you a clean rollback path. Use the same four-step loop for every candidate:

  1. Capture the before state. Save the Site Health total and the audit row with the exact option name, stored size, and autoload state.
  2. Change it on staging. Exercise the feature that owns the option, including its public page, admin screen, scheduled task, REST request, or checkout path where relevant. Check the PHP error log rather than relying on a page that merely looks normal.
  3. Repeat the measurements. Confirm the option is no longer in the loaded set and compare the same pages under the same cache conditions. A smaller autoload total is evidence that the database change worked; it is not, by itself, proof of a faster site.
  4. Roll back on the first regression. Turn autoload back on with the same Core setter or restore the database backup. Move the single reviewed change to production only after the owning workflow passes.

Manual inspection and Multisite caveats

A database interface can help inspect a specific suspect when there is no shell access. Keep that work read-only. In custom code, use $wpdb->options instead of assuming the table is called wp_options, and include the current Core autoload values when forming an audit query. Do not turn that inspection into a bulk UPDATE or DELETE.

WordPress database displayed in a database administration interface
Manual database views are useful for investigating a named suspect, not for blanket cleanup.

Multisite adds another boundary. Audit each site separately, for example with WP-CLI’s --url argument. Network options have their own storage and cache path, so a finding on one site does not justify changing every site or treating network settings like ordinary site options.

Also keep transients in their lane. They are not interchangeable with object caching, and a transient-looking row is not automatically a safe deletion candidate. Check what creates and reads it before acting.

The migration lesson still holds up

The original version of this article came from a client site that had accumulated a huge option during an old migration. The site’s host rejected a large cached object, which led the site to rebuild expensive option data more often than intended. The winning change was not “turn off the cache.” It was finding the option, confirming that the old migration code no longer needed it on ordinary requests, and turning off autoload for that specific value.

The host’s size limit was specific to that incident, so it should not become a rule for every WordPress site. The durable lesson is simpler: old migration code belongs in a disposable plugin or command, and unusually large data deserves an owner, a lifecycle, and an intentional autoload choice.

Bottom line

Autoloaded options are not automatically bad, and a smaller total is not automatically safer. Measure first, identify the owner, make the narrowest API-backed change, test what owns the data, and compare the result to the baseline. That is slower than a bulk database cleanup, but it is far less likely to create a new production incident.

References

  1. [1] Options API: Disabling autoload for large options, Make WordPress Core.
  2. [2] WP_Site_Health::get_test_autoloaded_options(), WordPress Developer Resources.
  3. [3] WP-CLI option-list implementation, official WP-CLI repository.
  4. [4] wp_autoload_values_to_autoload(), WordPress Developer Resources.
  5. [5] wp_set_option_autoload_values(), WordPress Developer Resources.
  6. [6] update_option(), WordPress Developer Resources.
Yay! 🎉 You made it to the end of the article!
WPShout Editorial
Share:

2 Comments
Most Voted
Newest Oldest
Jenn Webb
August 18, 2020 3:23 pm

Thank you for the great article. I was wondering if I can speed up my WordPress website by turning off some of the autoloads.

Petros
June 3, 2020 4:24 pm

Excellent write-up, thanks for sharing!