I got a call about a site that was crawling. Especially in the wp-admin dashboard. The client was convinced they needed a bigger server, but I’ve seen this movie before. Nine times out of ten, it’s not the hardware. It’s a rogue plugin or a theme doing something dumb in the database. Sure enough, I fired up Query Monitor and the `wp_options` table was getting absolutely hammered on every single page load. This is a classic case of someone misunderstanding the WordPress Options API.
The Options API is how WordPress stores and retrieves all sorts of data, mostly settings for themes and plugins. It’s basically a big key-value store right in your database. Super useful. But it has one feature that can either be your best friend or your worst enemy: the `autoload` flag.
The Autoload Trap in the WordPress Options API
When an option is set to `autoload`, WordPress loads it into memory on every single page. For small bits of data you need everywhere, that’s great. It saves a database query. But the plugin I was debugging had stored a massive 2MB of log data in a single, autoloaded option. Total nightmare. Every page load was dragging this huge, useless weight with it.
My first thought was to just switch it off. A quick and dirty fix. You can do this with the third parameter in `update_option`.
// The quick fix: just disable autoload
update_option( 'the_problem_plugin_option', $huge_data, false );And yeah, the site immediately got faster. Problem solved, right? Nope. A few minutes later, the client reported that a frontend widget from that same plugin had stopped working. Turns out, the widget actually needed a tiny piece of that data to function. By turning off autoload, I’d fixed the performance but broken the functionality. Classic rookie mistake. The real fix had to be more nuanced.
The right way to handle this is to split the option in two. As I learned from a great breakdown over at carlalexander.ca, you need to think about how the data is accessed. Store the small, essential data in one option that gets autoloaded, and keep the big, clunky stuff in a second option that you only load when you actually need it.
// The RIGHT way to fix it
$all_options = get_option( 'the_problem_plugin_option' );
// 1. Create a smaller array with just the essential data
$essential_data = [
'api_key' => $all_options['api_key'],
'widget_title' => $all_options['widget_title'],
];
// 2. Create another array for the non-essential stuff
$non_essential_data = [
'historical_logs' => $all_options['historical_logs'],
// ... other large data
];
// 3. Save the small array with autoload ON
update_option( 'the_problem_plugin_essentials', $essential_data, true );
// 4. Save the big array with autoload OFF
update_option( 'the_problem_plugin_logs', $non_essential_data, false );So, What’s the Real Takeaway?
The lesson here isn’t just about the `autoload` flag. It’s about being intentional. Before you save anything to the database, ask yourself a few questions:
- How often do I really need this data?
- Does it need to be available on every single request?
- Could I split it into smaller, more manageable chunks?
Thinking through those questions is what separates a junior dev from a senior one. You stop causing problems and start building things that are stable and scalable. It’s the difference between a quick patch and a real solution.
Look, this stuff gets complicated fast. If you’re tired of debugging someone else’s mess and just want your site to work, drop my team a line. We’ve probably seen it before.
Leave a Reply