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=1Notes: 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-fpmStep 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.
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.