Technology

PHP OPcache Settings for WordPress, Laravel and WooCommerce

PHP OPcache can reduce repeated compilation work for WordPress, Laravel and WooCommerce. It is worth reviewing alongside PHP-FPM and basic PHP limits. The resulting CPU and request-latency improvements depend on the workload. In this guide we will explain OPcache directives for WordPress, Laravel and WooCommerce and provide configuration examples to evaluate against your PHP version and deployment process. Whether you are on shared hosting, an NVMe VPS or a dedicated server, you will leave with a framework for selecting OPcache settings to match your deployment workflow.

What PHP OPcache Really Does for Your PHP Apps

Without OPcache, PHP needs to read, parse and compile source code into opcodes for each request. OPcache stores compiled opcodes in memory so later requests can reuse them instead of recompiling. That means:

  • Less CPU time spent compiling cached PHP files.
  • Potentially lower request latency; measure the effect under the actual workload.
  • Potentially more capacity from the same hardware, subject to other bottlenecks.

For WordPress and WooCommerce, this mostly accelerates core, plugin and theme PHP files. For Laravel, it speeds up framework classes, your application code and vendor libraries. OPcache is not a replacement for object cache (Redis/Memcached) or full‑page caching, but it is the base layer. Evaluate it alongside the techniques we covered in our server‑side optimization guide for WordPress (PHP‑FPM, OPcache, Redis and MySQL tuning).

OPcache Baseline Settings: The Short Version

Before diving deep, here is an illustrative baseline to evaluate on supported PHP 8.3+ versions for WordPress, WooCommerce and Laravel on a typical VPS (2–4 vCPU, 4–8 GB RAM):

; Enable OPcache
opcache.enable=1
opcache.enable_cli=0

; Memory and file capacity
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.max_wasted_percentage=5

; File change detection (for shared hosting / simple setups)
opcache.validate_timestamps=1
opcache.revalidate_freq=60

; Preserve doc comments; leave file-check overrides disabled
opcache.save_comments=1
opcache.enable_file_override=0

; JIT (optional, usually OFF for classic WordPress/WooCommerce)
opcache.jit=0
opcache.jit_buffer_size=0

Prerequisite: OPcache must already be installed and loaded for the PHP SAPI serving the site. Check the existing extension configuration rather than adding a duplicate loader; package names and loader paths vary by deployment.

You will tune these numbers depending on:

  • PHP version and the directives it supports
  • Project size (number of PHP files, plugins, Composer packages)
  • Server RAM
  • Deployment workflow (manual FTP vs automated CI/CD)

Next, we will go directive by directive and then build tailored configs for WordPress, Laravel and WooCommerce. After configuration changes, use deployment tooling for a controlled reload of the actual PHP‑FPM master serving the site, or the corresponding web SAPI. An FPM reload affects all workers under that master, not just one pool.

Understanding Key OPcache Directives One by One

opcache.enable and opcache.enable_cli

opcache.enable turns OPcache on for web SAPI (PHP‑FPM, mod_php, etc.). This should almost always be 1 on production servers.

opcache.enable_cli controls OPcache for command-line PHP. With file caching disabled, ordinary separately launched CLI commands do not share a warm in-memory cache across invocations. A long-running process may reuse compiled scripts, but gains depend on repeated compilation and workload, not duration alone.

  • Shared hosting / small VPS: opcache.enable_cli=0
  • Long-running CLI workloads: evaluate opcache.enable_cli=1 against measured compilation work

opcache.memory_consumption

This sets how much shared memory (in MB) OPcache can use to store compiled PHP code. If shared memory is exhausted, new cache misses may run uncached or use a separately configured file cache. OPcache does not evict old scripts to make room; exhaustion can schedule a restart subject to the wasted-memory threshold. Monitor memory usage, misses and restart counts before resizing.

  • Small WordPress sites (few plugins): 64–128 MB
  • WooCommerce / multiple plugins: 192–256 MB
  • Medium Laravel apps with many Composer deps: 256–512 MB
  • Very large multi‑tenant or monorepo apps: 512 MB+

On a server with 4–8 GB RAM, allocating 256 MB to OPcache is a starting point to evaluate alongside the memory needed by PHP‑FPM, the database and other services. Review memory usage alongside hit rate and deployment-related changes before deciding whether to increase the allocation.

opcache.interned_strings_buffer

PHP can “intern” strings – store a single copy in memory and reuse it – which reduces memory usage and speeds comparisons. opcache.interned_strings_buffer controls how many megabytes are available for those interned strings.

  • Do not assume the default is insufficient; assess observed buffer usage.
  • For modern frameworks and plugin‑heavy WordPress, 16–32 MB is a range to evaluate if the current buffer is insufficient.

An example starting value:

opcache.interned_strings_buffer=16

Consider 32 MB if observed buffer usage warrants a larger allocation.

opcache.max_accelerated_files

This sets the maximum key capacity of OPcache’s script hash table. The effective capacity is rounded up to the first supported prime at least as large as the configured value: for example, 20000 becomes 32531. Monitor key usage as well as cached script count. If the table fills, new scripts cannot enter shared memory; misses may run uncached or use the configured file cache, and a restart may be scheduled conditionally rather than dropping older entries.

Illustrative starting values; verify the required key capacity in the actual application:

  • Small WordPress sites: 8000–10000
  • WooCommerce + many plugins: 20000
  • Medium–large Laravel apps: 20000–40000

Choose capacity based on the PHP files the application uses, leaving room for growth rather than raising the limit solely because the hardware is newer.

validate_timestamps and revalidate_freq

These two settings control how OPcache notices file changes:

  • opcache.validate_timestamps – 1 enables periodic timestamp validation on requests; 0 disables it, so changed code requires an explicit cache refresh. Compile-time timestamp checks can still occur when opcache.file_update_protection or opcache.max_file_size is nonzero.
  • opcache.revalidate_freq – the interval in seconds when validation is enabled; 0 checks on every request. It is ignored when validation is disabled. This is request-driven checking, not a wall-clock deployment guarantee.

On shared hosting or any environment where files can change at random times (manual FTP, plugin uploads via dashboard), you should keep opcache.validate_timestamps=1.

Patterns to evaluate: intervals of 30–60 seconds trade fewer timestamp checks for delayed change detection, so updates may not become visible immediately.

  • Shared hosting WordPress: opcache.validate_timestamps=1, opcache.revalidate_freq=60
  • VPS with simple manual deploys: opcache.validate_timestamps=1, with an illustrative opcache.revalidate_freq=30
  • CI/CD with atomic releases: consider opcache.validate_timestamps=0 only with a verified cache-refresh workflow on every deployment and rollback. Run opcache_reset() in a restricted context sharing the site’s serving cache, or perform a controlled reload of the actual serving PHP‑FPM master. An ordinary standalone CLI reset does not clear the web cache. Reset affects subsequent script loads, not already executing code or the separate file cache.

If you are moving towards zero‑downtime deployments, the patterns in our guides on zero‑downtime CI/CD to a VPS with rsync + symlinks and deploying Laravel on a VPS with Nginx, PHP-FPM and Horizon are relevant deployment reading. Using opcache.validate_timestamps=0 still requires a reliable cache-refresh step for deployments and rollbacks.

opcache.max_wasted_percentage

Invalidated cached scripts can leave wasted shared memory. opcache.max_wasted_percentage is the wasted-memory threshold used in conditional restart scheduling when memory or hash capacity is exhausted. Crossing the threshold alone does not trigger periodic defragmentation.

Values such as 5 or 10 are examples to evaluate; the next snippet uses 5:

opcache.max_wasted_percentage=5

Lower values can make a restart eligible at a smaller wasted-memory percentage when exhaustion conditions apply; they do not independently keep fragmentation under control. Treat 5% as a starting point to evaluate, not an optimum for every WordPress or Laravel application.

opcache.save_comments

Some tools parse PHP doc comments for annotations. opcache.save_comments controls whether OPcache preserves those comments. Native PHP attributes are structured metadata, and type declarations are language syntax; neither is a doc comment.

  • 1 (recommended): keep doc comments available to tools that inspect them
  • 0: slightly less memory usage, but can break frameworks or tools that inspect docblocks

To preserve compatibility with tools that parse doc-comment annotations, use this baseline:

opcache.save_comments=1

opcache.file_update_protection

This setting prevents caching files younger than the configured number of seconds, protecting against incompletely updated files. Use opcache.file_update_protection=0 only when every file update is verified to publish complete files atomically. Local SSD/NVMe storage alone is not sufficient; the atomic-update requirement applies to both local and remote filesystems.

  • Verified atomic file updates: opcache.file_update_protection=0 can be considered when every updated file becomes visible only after it is complete.
  • Other deployments, on local or remote storage: retain the default opcache.file_update_protection=2 and verify the update procedure. A file-age delay does not repair a corrupted cache or make a multi-file release atomic.

opcache.restrict_api

This optional setting restricts OPcache API functions (opcache_reset, opcache_invalidate, etc.) by the executing script’s path prefix. It is not user authentication or an HTTP access rule. For a directory-specific prefix, include the trailing slash so a similarly named sibling directory does not also match; keep the deployment directory and its access separately controlled.

Example:

opcache.restrict_api="/var/www/deploy-scripts/"

JIT: opcache.jit and opcache.jit_buffer_size

PHP 8 introduced JIT (Just‑In‑Time compilation) as part of OPcache. JIT can speed up CPU‑heavy numeric or algorithmic workloads, but for typical WordPress and WooCommerce sites it often brings little benefit and sometimes complicates debugging.

  • Classic WordPress / WooCommerce: safe to keep JIT disabled:
opcache.jit=0
opcache.jit_buffer_size=0
  • Laravel APIs with CPU-heavy PHP loops or calculations: JIT might help, but benchmark the real workload before enabling it. Work already performed inside native image-processing extensions is not automatically accelerated by PHP JIT.

If you plan a broader PHP 8.x tuning project, our article on the PHP 8.x upgrade checklist (OPcache preload and FPM pool tuning) gives a wider context.

Recommended OPcache Configurations by Stack

1) WordPress & WooCommerce on Shared Hosting

On shared hosting, global php.ini changes usually require the hosting administrator. CGI/FastCGI deployments may allow selected overrides through .user.ini or a control panel; INI_SYSTEM directives such as OPcache memory size and CLI enablement cannot be set in .user.ini. Available RAM and PHP process isolation depend on the hosting plan.

In this environment, ask the hosting administrator which settings are available before using this example:

; Administrator-managed php.ini example, not a .user.ini file
; Enable OPcache for web only
opcache.enable=1
opcache.enable_cli=0

; Modest memory for many small sites
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.max_wasted_percentage=10

; Check timestamps on requests, subject to revalidate_freq
opcache.validate_timestamps=1
opcache.revalidate_freq=60
opcache.file_update_protection=2

; Safer defaults
opcache.save_comments=1
opcache.enable_file_override=0

; JIT off
opcache.jit=0
opcache.jit_buffer_size=0

You will not have full control over all values on most shared plans, but understanding these directives helps you read the hosting provider’s defaults and decide when it is time to move resource‑hungry stores to a VPS. If you frequently hit “Resource Limit Reached” or see high TTFB during campaigns, combine OPcache tuning with the strategies in our guide on moving from shared hosting to a VPS without downtime.

2) WordPress & WooCommerce on a VPS or Dedicated Server

Once you control your own PHP‑FPM pools and php.ini, you can allocate more memory to OPcache and tighten timestamp checks. For a typical 2–4 vCPU, 4–8 GB RAM NVMe VPS hosting a few WordPress and WooCommerce sites, an example starting point to evaluate is:

opcache.enable=1
opcache.enable_cli=0

; More generous memory
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.max_wasted_percentage=5

; File change detection
; Select the request-time check interval for the deployment workflow
opcache.validate_timestamps=1
opcache.revalidate_freq=30
opcache.file_update_protection=2

opcache.save_comments=1
opcache.enable_file_override=0

; JIT disabled for typical WooCommerce
opcache.jit=0
opcache.jit_buffer_size=0

On multi‑tenant VPS setups where each site has its own PHP‑FPM pool, budget for OPcache shared memory alongside PHP worker memory and FPM process counts so that the total fits into available RAM. For more server-tuning topics, visit the DCHost blog.

3) Laravel on a VPS or Dedicated Server

Laravel applications can contain many PHP files (framework + vendor + app code). For a large codebase, consider higher max_accelerated_files and memory_consumption values based on measured cache usage.

opcache.enable=1
; Decide per project whether CLI caching is useful
opcache.enable_cli=0

opcache.memory_consumption=256 ; or 512 for large apps
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=40000
opcache.max_wasted_percentage=5

; Advanced: requires a tested correct-runtime cache update on deployment
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.file_update_protection=2

opcache.save_comments=1
opcache.enable_file_override=0

; JIT off unless you tested and measured benefits
opcache.jit=0
opcache.jit_buffer_size=0

With opcache.validate_timestamps=0, periodic timestamp revalidation is disabled and opcache.revalidate_freq is ignored. Compile-time checks can still occur when file-update protection or maximum-file-size settings require them. The deployment must deliberately update the correct application cache and restart long-lived application processes as needed; a symlink switch alone does not prove every process uses the new release.

  • Identify the PHP-FPM master and actual service name serving the application, then use its tested graceful reload procedure. FPM documents reloading all workers of that master; there is no generic pool-specific reload. Account for other applications sharing it.
  • If deployment tooling uses opcache_reset(), run it in the correct serving cache context behind administrator-only access. A separate CLI invocation does not reset the web cache. Coordinate resolved-path caches and long-lived workers, then verify the new release through application requests; do not publish a reset endpoint.

This aligns nicely with the production tune‑up we describe in our Laravel production optimization guide (PHP‑FPM pools, OPcache, Octane, queues and Redis).

How OPcache Interacts with PHP‑FPM, JIT and Application Caches

OPcache and PHP‑FPM Pools

On most Linux servers, OPcache runs in shared memory per PHP‑FPM master process. Each pool shares the same OPcache instance by default. That means:

  • Raising opcache.memory_consumption increases shared memory for all pools
  • A graceful reload affects the workers of the selected FPM master. Verify the resulting in-memory cache and new release; a separately configured file cache means a blanket “every script recompiles on first use” promise is inappropriate.

When designing multi‑tenant hosting (many sites, one server), combine OPcache sizing with PHP‑FPM limits and PHP memory_limit. If a WooCommerce site uses 512 MB of PHP memory per request and you allow many FPM children, OPcache memory becomes relatively small in that picture. The balance across OPcache, memory_limit and process counts is often more impactful than any single directive.

OPcache vs Object Cache (Redis/Memcached)

OPcache stores compiled PHP code. Object caches store application data (e.g. query results and options). Both are important but solve different problems. A Redis or Memcached object-cache integration does not automatically configure application session storage.

  • OPcache reduces CPU time spent parsing and compiling PHP
  • Object cache reduces database queries and expensive computations

For serious WooCommerce or Laravel apps, you usually want both. To understand the data‑side caching piece better, you can read our guide on choosing PHP session and cache storage (files vs Redis vs Memcached) and our detailed WordPress object cache setup with Redis or Memcached.

OPcache and JIT in Real Projects

Use profiling to distinguish CPU‑heavy PHP execution from disk I/O, database delays, slow plugins and network latency. Do not treat enabling JIT as a substitute for finding the bottleneck. For e‑commerce and content sites, a conservative starting point is:

opcache.jit=0
opcache.jit_buffer_size=0

For compute‑heavy Laravel workloads, test JIT in a staging environment with realistic load tests (for example, using the techniques described in our article about load testing hosting with k6, JMeter and Locust). If you see a clear, reproducible gain and stable behavior, you can enable it selectively.

Monitoring and Debugging OPcache in Production

Checking OPcache Configuration and Status

Use the command below as an initial configuration check; do not treat its output alone as proof that the web application uses the expected settings. The php command inspects the CLI SAPI, which may load different configuration and has a separate cache from PHP-FPM.

php -i | grep -i opcache

For a status check, use a small script only behind administrator-only access, then remove it when finished. For the web application, run it in the serving PHP context; an ordinary CLI run inspects only that CLI process and requires OPcache to be loaded with CLI caching enabled. The examples above leave CLI caching disabled.

<?php
$status = function_exists('opcache_get_status')
    ? opcache_get_status(false)
    : false;
if ($status === false) {
    echo "OPcache status is unavailable in this runtime.\n";
} else {
    print_r($status);
}

Useful fields to watch:

  • memory_usage – how much of OPcache memory is used/free
  • interned_strings_usage – interned string memory usage
  • opcache_statistics – hit rate, number of cached scripts, misses

Assess hit rate against the application’s normal workload and warm-up state; there is no universal 99% target. Diagnose byte capacity and key capacity separately: compare memory_usage used/free/wasted bytes and oom_restarts when considering opcache.memory_consumption. Compare num_cached_keys with max_cached_keys, alongside hash_restarts, when considering opcache.max_accelerated_files. Increase only the constrained resource with enough host RAM; raising the key limit does not add OPcache memory bytes.

Common OPcache‑Related Issues

  • Code changes not visible: With opcache.validate_timestamps=0, use the tested deployment procedure for the serving PHP cache. A separate CLI opcache_reset() does not reset PHP-FPM’s cache; identify the actual FPM master and controlled reload or restricted in-context reset mechanism.
  • Mixed versions after a failed deploy: Do not expose partially uploaded files. Prepare a complete release and validate the switch, path-cache behavior and long-lived process lifecycle. Keep opcache.file_update_protection=2 unless every file update is verified atomic; local storage alone does not justify 0, and the delay does not make a whole release atomic.
  • High CPU spikes despite OPcache: Profile the application and examine database work, object-cache behavior and PHP-FPM capacity alongside OPcache metrics.

Small OPcache Status Dashboard

For teams that prefer a visual overview, you can adapt a small, password‑protected dashboard page that calls opcache_get_status() and renders key metrics. Run it in the intended serving PHP context, handle unavailable status, and keep it inaccessible to the public because it can expose path and environment information.

Safe Deployment Workflow with OPcache Enabled

Misaligned deployment and OPcache settings are a common source of “it works on some requests but not others” problems. A robust workflow usually follows these principles:

  1. Build/compile assets elsewhere (CI, local) so production only receives ready‑to‑run PHP and static files.
  2. Deploy to a new release directory, e.g. /var/www/myapp/releases/2025-01-01-120000.
  3. Update a symlink, e.g. /var/www/myapp/current → new release, atomically.
  4. Update the correct serving runtime: use the verified FPM master/service lifecycle, or restricted opcache_reset() execution in that cache context. Cover resolved-path caches and long-lived workers separately, and verify the intended release through application requests. Apply the same procedure on rollback.

Before using validate_timestamps=0, verify that deployment and rollback activate the intended release consistently across all serving instances. Validate request handling during release transitions before describing the workflow as zero‑downtime. We use a similar pattern in our guides on zero‑downtime CI/CD to a VPS and Laravel deployments with Nginx, PHP‑FPM and Horizon.

Putting It All Together: Practical Checklists

Checklist for WordPress / WooCommerce

  • Verify opcache.enable=1 in the PHP runtime actually serving each site.
  • Treat opcache.memory_consumption values such as 128 or 256 MB as examples to evaluate against measured byte usage and available RAM.
  • Choose opcache.max_accelerated_files from measured key usage and the effective prime-rounded limit, not an assumed plugin count.
  • Keep opcache.save_comments=1 for packages relying on doc-comment annotations.
  • Where files can change through plugins, themes, panels or other paths outside a controlled release workflow, retain opcache.validate_timestamps=1 and choose opcache.revalidate_freq with the administrator.
  • Consider disabling periodic validation only if every production code-change path and rollback uses a tested release and correct-cache update procedure. A standalone CLI reset does not satisfy this.
  • Keep JIT off unless realistic profiling and tests justify enabling it.

Checklist for Laravel

  • Size opcache.max_accelerated_files using actual framework, vendor and application key usage; check the effective capacity.
  • Evaluate illustrative 256–512 MB opcache.memory_consumption values against byte usage and host memory.
  • Disable periodic timestamp validation only when all production code changes and rollbacks use a tested complete-release workflow that updates the correct serving cache, resolved-path state and long-lived workers. CI/CD availability alone is insufficient.
  • Keep opcache.save_comments=1 for packages using doc-comment annotations.
  • Measure whether opcache.enable_cli=1 benefits the actual long-running workload; independent fresh Artisan invocations do not share a warm in-memory cache by default.
  • Benchmark JIT for CPU-heavy PHP execution; native extension work is not automatically accelerated.

Final Thoughts and Next Steps

OPcache tuning should be guided by measurements from your workload. For WordPress, WooCommerce and Laravel, the right configuration can shave precious milliseconds from each request, reduce CPU load during peak campaigns and give you more breathing room before you need to scale up hardware. The key is to treat OPcache as part of a broader stack: aligned with PHP‑FPM pools, PHP memory limits, database tuning and, when needed, Redis or Memcached caches.

Treat these OPcache patterns as starting points, adapting values to each project’s size and traffic profile. If you are unsure where your current bottleneck is – OPcache, PHP‑FPM, MySQL, or storage – you can always start by measuring, then adjust one layer at a time. Use the baselines in this guide, watch OPcache stats under real traffic, and refine. If you need help with low‑level tuning, establish who is responsible for PHP configuration and deployment support under your hosting agreement.

Frequently Asked Questions

Verify that OPcache is installed, loaded and enabled in the PHP runtime serving the site. Evaluate memory values such as 128–256 MB against actual usage, and size opcache.max_accelerated_files using measured key usage and its effective prime-rounded capacity. Keep opcache.save_comments=1. For dashboard or manual updates, retain opcache.validate_timestamps=1; the guide's 30–60-second intervals are examples that delay change detection, not immediate-update guarantees. Leave JIT disabled unless workload tests justify it. Shared-hosting administrators control system-level settings.

Consider opcache.validate_timestamps=0 only when every code change and rollback uses a tested release workflow that refreshes the correct serving cache, handles resolved-path caches and restarts long-lived workers as needed. A symlink switch alone is insufficient. Use a controlled reload of the actual serving PHP-FPM master or an administrator-only opcache_reset() call in the same cache context. A standalone CLI reset does not clear the web cache. Reset does not replace already executing code or clear a separate file cache. Otherwise, keep timestamp validation enabled.

JIT may help CPU-heavy PHP loops or calculations, but typical WooCommerce workloads often gain little. The guide keeps opcache.jit=0 and opcache.jit_buffer_size=0 as a conservative baseline. Profile the actual Laravel or WooCommerce workload, then benchmark JIT under realistic staging load before enabling it. Work already performed inside native extensions is not automatically accelerated by PHP JIT.

The guide uses 256 MB as an illustrative starting point for a 4–8 GB VPS, not a requirement. Smaller WordPress sites may need less; larger Laravel applications may need more. Check used, free and wasted bytes plus oom_restarts before changing opcache.memory_consumption. Diagnose key capacity separately using num_cached_keys, max_cached_keys and hash_restarts. Budget shared OPcache memory alongside PHP-FPM workers, the database and other services; pools under one FPM master normally share the cache.

Use php -i | grep -i opcache only as an initial CLI configuration check; it does not prove that PHP-FPM uses the same settings. Inspect opcache_get_status(false) in the site's serving PHP context behind administrator-only access, handle unavailable status, and remove temporary diagnostics afterward. Review memory_usage, interned_strings_usage and opcache_statistics, distinguishing memory exhaustion from key-capacity limits. Evaluate hit rate against normal traffic and warm-up state rather than a universal 99% target.
↑