Object caching
Many pages ask the database the same questions again and again: the category tree, the site settings, location lookups. An object cache keeps those answers in memory for a short time, so the next page can reuse them. On a busy site, it cuts a page from a few dozen database queries to a handful.
By default, ShopClass keeps these answers for one page load only. That is safe on any server, but it does not speed anything up. Turning on a real cache takes two lines.
Before you start
Section titled “Before you start”memcached and APCu need a PHP extension (an add-on module for PHP). Install the one you want, then check that PHP can see it:
php -m | grep -E 'memcached|apcu|redis'If the extension is missing, the setting does nothing. Redis and Valkey need no
extension: ShopClass uses phpredis when it is installed, and its own client
otherwise.
memcached (recommended)
Section titled “memcached (recommended)”memcached is a small cache server. Use it if you have more than one web server. It is also fine with one.
define('OSC_CACHE', 'memcached');This connects to 127.0.0.1:11211. For another host, or several servers:
define('OSC_CACHE', 'memcached');$_cache_config = array( array('default_host' => '10.0.0.5', 'default_port' => 11211, 'default_weight' => 1), array('default_host' => '10.0.0.6', 'default_port' => 11211, 'default_weight' => 1),);Each PHP worker keeps its connection between pages, as it does with Redis and phpredis.
If PHP has the igbinary extension, Redis, Valkey and memcached store values in its format: smaller and faster to read. The Docker image includes it. A server without it treats such a value as missing and rebuilds it, so mixed servers are safe.
Redis or Valkey
Section titled “Redis or Valkey”Redis and Valkey are cache servers like memcached. Use them if your host offers one, or if you run other things on Redis already. KeyDB and Dragonfly work too.
define('OSC_CACHE', 'redis');This connects to 127.0.0.1:6379. For another server, a password or a database
number:
define('OSC_CACHE', 'redis');$_cache_config = array( array('default_host' => '10.0.0.5', 'default_port' => 6379, 'password' => 'secret', 'database' => 1),);A host starting with / is a Unix socket, and tls://host connects over TLS. Add
'username' for a server with users (ACL). Several sites can share one server:
each keeps its own keys, and emptying the cache empties only that site’s.
With Redis or Valkey, a background job also starts the moment it is queued, when the
job listener runs (oc-cli.php jobs:work --listen; the Docker image runs it). See
Background jobs.
Redis or Valkey also takes two busy writes off the database:
- Listing views add up there and a background job saves them about once a minute, so a
view count can be a minute behind. Without the job listener or a cron line running
jobs:workeach minute, it is as far behind as your cron runs. - Rate limits (sign-up, comments, contact forms, the REST API) count there. A limit that must refuse when unsure, such as the admin two-step sign-in, stays in the database.
If the server stops answering, both go back to the database on their own. Give the server enough memory that it never has to drop keys (the Docker compose file gives 128 MB): a dropped rate-limit key starts that limit again from zero.
Run the server as a cache only, with no snapshot to disk (--save "" --appendonly no), as the
Docker stacks do. A restart then starts empty instead of bringing back old data; it loses
up to a minute of view counts not yet saved.
With memcached or APCu, only the REST API’s per-minute limits count in the cache: with
memcached every web server shares one count, with APCu each server counts its own. Everything
else counts in the database, as it does with no OSC_CACHE.
Settings, including secret keys, are stored in the cache. Use a Redis or memcached server that only this site can reach.
A change made from the command line reaches web pages at once, even when OSC_CLI_URL names
another address than visitors use: the “this changed” markers are kept per database.
A copy in each PHP worker
Section titled “A copy in each PHP worker”With Redis, Valkey or memcached and the APCu extension, define('OSC_CACHE_LOCAL', true);
lets each PHP worker keep its own copy of the settings, categories, pages and other values
every page reads. It then asks the cache server for them at most every 15 seconds. A change
still shows on the next page; a value that only runs out of time can be read up to 15
seconds late.
Turn it on only when no other site runs under the same PHP: other sites there can read and change APCu. The Docker image turns it on.
Themes and plugins get the same copies when they cache through osc_cache_remember(); see
Helper functions.
APCu (one server only)
Section titled “APCu (one server only)”APCu keeps the cache inside PHP itself. It is simpler and faster, but each web server has its own copy. Use it on a single server. Do not use it once you add a second web server.
define('OSC_CACHE', 'apcu');How long entries last
Section titled “How long entries last”An entry lasts 60 seconds by default. If your categories and settings rarely change, keep entries longer:
define('OSC_CACHE_TTL', 300);The number is in seconds. Saving in the admin panel clears what it changed, so those edits show at once. A longer time only delays changes made outside the admin, such as a plugin writing to the database directly. Settings are always kept for 5 minutes at most.
Setting it with environment variables
Section titled “Setting it with environment variables”On containers, editing config.php for each environment is awkward. Use
environment variables instead:
| Variable | What it sets |
|---|---|
OSC_CACHE |
The cache type: memcached, redis or apcu |
OSC_CACHE_HOST |
The cache server’s host, for memcached or redis |
OSC_CACHE_PORT |
The cache server’s port. Default 11211, or 6379 for redis |
OSC_CACHE_PASSWORD |
Redis only: the server’s password |
OSC_CACHE_USERNAME |
Redis only: the user name, for a server with users |
OSC_CACHE_DB |
Redis only: the database number. Default 0 |
A define() in config.php, or a $_cache_config array, always wins over
these variables.
Emptying the cache
Section titled “Emptying the cache”After a bulk import, a direct database edit, or any change made outside ShopClass, empty the cache:
php oc-cli.php cache:flushThe memcache driver is gone
Section titled “The memcache driver is gone”The memcache driver is gone. define('OSC_CACHE', 'memcache') now uses the
memcached driver with the same servers, so install the memcached extension.
Without it, the site falls back to the one-request cache.
Writing your own driver
Section titled “Writing your own driver”A plugin can add a cache: a class named Object_Cache_<name>, picked with
OSC_CACHE set to <name>. It must be loaded before the first cache call.
- Extend
mindstellar\base\Cacheand writeis_supported(),fetch(),add(),set(),delete(),flush(),_get_cache()andstatsTitle(). The base keeps the in-request copy, the hit and miss counts and the site key prefix. - Or implement
mindstellar\cache\CacheDriveryourself. Drivers written for the oldiObject_Cacheinterface keep working.
An unknown name, or a driver whose is_supported() says no, falls back to the
one-request cache with a PHP notice.
Troubleshooting
Section titled “Troubleshooting”Changes in the admin panel take a while to show.
The cache still holds the old answer until the entry ends. Lower
OSC_CACHE_TTL, or empty the cache after admin work.
The site got slower after turning it on. ShopClass probably cannot reach the cache server. Every lookup then waits for the connection to time out first. Check the host and port, and check that the cache server is running. ShopClass stops asking a server after its first failure in a page load, and the reason is in the PHP error log.
Two web servers show different versions of the site. You are using APCu, which keeps one cache per server. Move to memcached or Redis.