You've put the site on the server, you change the code, you refresh the page, and nothing happens. You save the file again, and still the same old output. Then you restart the PHP service once and everything works. This is exactly where you should look at OPcache, not the browser cache and not the CDN.
OPcache keeps the compiled bytecode of PHP files in shared memory so that every request doesn't have to read and parse the file from disk again. On a typical WordPress site, this single layer alone can bring script execution time from around 80 milliseconds down to 25 milliseconds. The exact number depends on the number of plugins and the size of the code, but the direction of change is always the same.
Why code changes don't take effect
The key parameter here is: opcache.validate_timestamps. When its value is 1, OPcache checks the file modification time every few seconds (based on opcache.revalidate_freq) and if the file is newer, it discards the cached version. When its value is 0, this check is completely disabled and the same old bytecode is served until PHP is restarted or the cache is cleared.
On a production server, setting it to 0 is tempting because it saves a few milliseconds. But the cost is that every deploy must be accompanied by an explicit cache-clearing step, otherwise half of the users see the old version of the site and half see the new version. If your deploy process isn't automated and reliable, keep 1 and set opcache.revalidate_freq to 2. The performance difference is negligible in practice; the difference in hassle is not.
This is where they make a mistake
The common mistake is that a developer sets validate_timestamps=0 on the development server too, then spends hours hunting for a bug that doesn't exist. The sign is this: you change the code with var_dump, the output doesn't change, but when you copy the file to a new name and call it, it works correctly. That moment means the cache, not the application logic, is the culprit. On the development environment, always set validate_timestamps=1 and revalidate_freq=0 so that every change is seen immediately.
How much OPcache memory should we set
The default value of opcache.memory_consumption in many builds is 128 megabytes, and it's not enough for a WordPress site with several plugins. When this memory fills up, OPcache starts discarding scripts and recompiling them; the result is a performance drop while you see no error in the log.
To see the actual status, run the opcache_get_status() script or start with the output of php -i | grep opcache. If opcache_get_status()['opcache_statistics']['oom_restarts'] is greater than zero, it means you've run out of memory. The number 256 is a reasonable starting point for most sites; heavy sites with large frameworks reach 512 as well.
Two other parameters are also important. opcache.max_accelerated_files is the ceiling on the number of cached files and its default is 10000. A WordPress installation with heavy plugins easily exceeds this number. Set the value to 20000 or 30000. And opcache.interned_strings_buffer, whose default is 8 megabytes; set it to 16 or 32 so that duplicate strings between files are shared.
Configuration example
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=2
opcache.save_comments=1
opcache.fast_shutdown=1
Don't underestimate that save_comments=1. If you set it to 0, annotations and DocBlock comments are removed from the bytecode and anything that relies on them breaks; from annotation-based ORMs to some WordPress plugins. The memory savings are small, the cost of breakage is large.
OPcache or APCu or Redis?
These don't replace each other and confusing them wastes your time.
| Layer | What it caches | Where it's used |
|---|---|---|
| OPcache | Bytecode of PHP files | Everywhere, without exception |
| APCu | Application data in the memory of the same server | Single-server object cache |
| Redis / Memcached | Application data on a separate service | Multiple servers, shared sessions |
If the site is on a single server, APCu works more simply and faster than Redis because it has no network round-trip. If you're on multiple servers behind a load balancer, APCu is useless because each server has its own cache and the user may go to another server after each request. There, Redis is the right choice. For setting up on a single-server Linux hosting, the combination of OPcache along with APCu is almost always enough.
When you should turn off OPcache
On the development environment, as we said. Also when you use opcache.file_cache and the cache files on disk are shared between different PHP versions; this mode can return incompatible bytecode and give a strange error that has nothing to do with your code. If you see such an error, first clear opcache.file_cache.
And one practical point: after every deploy, if you have validate_timestamps=0, don't forget to clear the cache. The simplest way is to call opcache_reset() from a CLI script, or restart php-fpm with systemctl reload php8.2-fpm. Note that reload is enough and there's no need for a full restart; reload doesn't drop active connections.
If after these settings you still see slowness, the problem is elsewhere. Start by reading the server error log and see if there's a recurring error that redoes part of the work each time. And if the site sometimes goes completely down, the right path is diagnosing intermittent downtime, not touching cache settings.
Frequently asked questions
Why don't changes take effect after modifying a PHP file?
Because OPcache has kept the previous compiled version in memory and the file modification time check is disabled. Check the value of opcache.validate_timestamps; if it's 0, either set it to 1 or clear the cache with opcache_reset() after every change.
What is the appropriate value for opcache.memory_consumption?
For most WordPress sites, 256 megabytes is a good starting point. If in the output of opcache_get_status() the value of oom_restarts is greater than zero, memory is low and you should raise it. Heavy sites with large frameworks go up to 512 megabytes as well.
Is OPcache also enabled on shared hosting?
On most Linux hostings OPcache is enabled by default, but you usually can't change its values from within the panel because the settings are applied at the server level. If you need precise configuration, you should go for a server that has full control over php.ini.
What's the difference between OPcache and WordPress cache?
OPcache works at a lower level and independently of WordPress and only caches the bytecode of PHP files. WordPress cache keeps the output of queries and HTML fragments. These two aren't rivals; both should be enabled and each covers a different layer.
If right now you have access to php.ini on your server, first check the value of max_accelerated_files. This parameter affects WordPress sites more than you think and gets the least attention.
Comments 0
No comments yet — be the first!