PHP OPcache: Why It Is Mandatory on Every WordPress Site and How to Tune It

OPcache stores PHP bytecode in memory and shaves 30-60% off every request's compile time. Set it up correctly.

OPcache is a built-in PHP extension (since 5.5) that stores compiled PHP bytecode in shared memory. Without OPcache, every WordPress request runs lex + parse + compile against hundreds of PHP files from scratch - 30-60% of PHP processing time wasted. With OPcache, only the first request after deploy pays the cost; every subsequent one pulls opcode straight from RAM.

Why this matters

WordPress core alone is 1,500+ PHP files. Yoast adds 400; WooCommerce 800; Elementor 600. A typical front-end request loads 100-200 files. Without OPcache, each one parses and compiles from zero - 200-500ms of CPU work. With OPcache active, that work disappears entirely; files arrive from memory in microseconds.

In production OPcache is a prerequisite for every other optimization. PageSpeed Insights will keep reporting high TTFB even after page cache, object cache, and a CDN - if OPcache is off. In wp-admin (not page-cached), the difference is immediate: navigation that took 800ms drops to 200ms.

OPcache is unrelated to W3 Total Cache or any content cache. It sits one layer lower - saving the cost of compiling the code itself.

How to detect

Drop a temporary phpinfo.php at the site root containing:

<?php phpinfo(); ?>

Open it and search for "Zend OPcache". "Opcode Caching: Up and Running" means active. Missing or "Disabled" means off. Delete phpinfo.php immediately after the check - it leaks server details.

Alternative via WP-CLI:

wp eval 'var_dump(opcache_get_status() !== false);'

Returning bool(true) means active.

How to fix

Step 1: confirm the extension is loaded. Almost every modern host ships it, but not always loaded. Check with php -m | grep -i opcache.

Step 2: enable it. cPanel: "Select PHP Version" or "PHP Selector" > Extensions > tick opcache. Plesk: Domain > PHP Settings > Extensions.

Step 3: tune php.ini:

opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.revalidate_freq=2
opcache.fast_shutdown=1
opcache.validate_timestamps=1
opcache.save_comments=1

Notes: memory_consumption=256 covers a typical 50-plugin WordPress; if logs show "out of memory", raise to 512. max_accelerated_files=20000 matters for big sites - each PHP file takes a slot. revalidate_freq=2 means OPcache rechecks file timestamps every two seconds (balanced between speed and pickup of new code).

Step 4: restart PHP-FPM:

systemctl restart php8.2-fpm

Step 5: confirm the cache is filling. Install opcache-gui, or add to functions.php:

if (current_user_can('manage_options') && isset($_GET['opcache_status'])) {
    var_dump(opcache_get_status());
    exit;
}

Visit ?opcache_status=1. opcache_statistics->opcache_hit_rate should be above 95%.

Common mistakes

Mistake one: leaving memory_consumption at the 64MB default. Heavy WordPress installs cannot fit, so OPcache evicts and re-caches the same files endlessly - that actually slows the site. Mistake two: setting opcache.validate_timestamps=0 without a deploy strategy. Performance is great until the next code change, which OPcache stubbornly ignores. Mistake three: skipping a reset after PHP upgrade, WordPress upgrade, or plugin deploy - sometimes the residual cache holds class definitions incompatible with the new code and triggers fatal errors. Run opcache_reset() or reload PHP-FPM.

Verifying the fix

Run Lighthouse on the homepage - TTFB should drop 100-300ms. wp-admin (uncached) shows the change most clearly. Inspect opcache_get_status() - opcache_hit_rate should land between 95-99%. Below 90% means you need more memory_consumption. oom_restarts above 0 means OPcache is thrashing.

Tip: After deploying a plugin or theme, run opcache_reset() or systemctl reload php8.2-fpm. Otherwise OPcache may serve stale bytecode for a couple of seconds - or worse, throw fatal errors from old class definitions that no longer match the new ones.