acpl / flarum-lscache
LSCache implementation for Flarum.
Package info
github.com/android-com-pl/flarum-lscache
Type:flarum-extension
pkg:composer/acpl/flarum-lscache
Fund package maintenance!
Requires
- php: ^8.3
- flarum/core: ^2.0
Requires (Dev)
- flarum/approval: *
- flarum/likes: *
- flarum/phpstan: ^2.0
- flarum/tags: *
- flarum/testing: ^2.0
- fof/author-change: ^2.0
- fof/blog: ^2.0
- fof/masquerade: ^3.0
- fof/merge-discussions: ^2.0
- fof/move-posts: ^2.0
- rector/rector: ^2.3
Suggests
- fof/redis: This library allows using Redis as cache, session and for the queue. https://github.com/FriendsOfFlarum/redis?tab=readme-ov-file#set-up
Provides
None
Conflicts
None
Replaces
None
- 4.x-dev
- v4.0.0
- v4.0.0-beta.4
- v4.0.0-beta.3
- v4.0.0-beta.2
- v4.0.0-beta.1
- 3.x-dev
- v3.3.9
- v3.3.8
- v3.3.7
- v3.3.6
- v3.3.5
- v3.3.4
- v3.3.3
- v3.3.2
- v3.3.1
- v3.3.0
- v3.2.1
- v3.2.0
- v3.1.0
- v3.0.1
- v3.0.0
- 2.x-dev
- v2.3.1
- v2.3.0
- v2.2.1
- v2.2.0
- v2.1.0
- v2.0.1
- v2.0.0
- v1.0.2
- v1.0.1
- v1.0.0
- 0.4.1
- 0.4.0
- 0.3.0
- 0.2.2
- 0.2.1
- 0.1.5
- 0.1.4
- 0.1.3
- 0.1.2
- 0.1.1
- 0.1.0
- 0.0.5
- 0.0.4
- 0.0.3
- 0.0.1
- dev-fix/cache-fixes
- dev-v-1.0
This package is auto-updated.
Last update: 2026-10-14 18:02:53 UTC
README
Full-page LiteSpeed caching for Flarum.
If your forum runs on LiteSpeed, this is a must-have for heavy guest and bot traffic. The first request generates a response; LiteSpeed serves later requests for the same cached page directly, without running PHP or querying the database again. This can substantially reduce server load.
Requires LiteSpeed Web Server or OpenLiteSpeed with LSCache enabled.
π₯ Installation
Install with Composer:
composer require acpl/flarum-lscache
Back up your .htaccess before enabling the extension. It adds its cache rules to that file on activation.
π Updating
composer update acpl/flarum-lscache php flarum migrate php flarum cache:clear
π§Ή Cache Management
Changes invalidate the affected cache entries. For example, a new public post clears the cache for its discussion, tag pages, and the homepage.
Clearing Flarum's cache also clears LSCache, unless you disable this in the extension settings.
To clear only LSCache, use the admin panel's cache menu or the CLI:
php flarum lscache:clear php flarum lscache:clear --path=/tags --path=/d/1-test
β FAQ
Does it cache pages for logged-in users?
No. Forum pages are cached for guests only. Logged-in users can see different content, permissions, notifications, and read states. Sharing their cached pages would be unsafe.
A separate cache for each user would still need to generate each page on that user's first visit, then rebuild it whenever their content changes. That means fewer cache hits and more invalidation work. Guest caching lets many visitors reuse the same response.
Does it work on Apache or nginx?
No. It requires the LSCache engine in LiteSpeed Web Server or OpenLiteSpeed.
π§π»βπ» For Developers
Note
Cache tags are labels used to invalidate cached responses. They are separate from the discussion tags provided by flarum/tags.
π·οΈ How the Extension Tags Paths
Cache tags come from route names. For example, an extension could register these API routes:
(new Extend\Routes('api')) ->get('/examples', 'examples.index', ExamplesListController::class) ->get('/examples/{id}', 'examples.show', ExamplesShowController::class) ->post('/examples', 'examples.create', ExamplesCreateController::class);
For GET and HEAD responses:
.indexroutes get the resource tag:examples.indexβexamples.- Other routes get their full name:
examples.showβexamples.show. - An
idorslugroute parameter adds a tag using the singular resource name:example_1orexample_example-slug.
Tip
To see the cache tags added for a given request, check the value of the X-LiteSpeed-Tag header in the Network tab of DevTools.
ποΈ Purging Cache
Successful POST, PUT, PATCH, and DELETE requests to .create, .update, or .delete routes purge the resource's ID tag when an id route parameter is present. A collection's .create route usually has no id, so use events to invalidate its list cache.
For event-based purging, register the singular resource name in $resourcesSupportedByEvent to disable automatic ID purging. Keep this registration inside the condition so your extension also works when LSCache is disabled or absent:
// extend.php use Acpl\FlarumLSCache\Utility\LSCachePurger; use Flarum\Extend; return [ // ... your current extenders (new Extend\Conditional) ->whenExtensionEnabled('acpl-lscache', function () { LSCachePurger::$resourcesSupportedByEvent[] = 'example'; return [ (new Extend\Event)->listen(ExampleUpdated::class, ExampleUpdatedListener::class), ]; }), ];
// ExampleUpdatedListener.php use Acpl\FlarumLSCache\Listener\AbstractCachePurgeListener; /** @extends AbstractCachePurgeListener<ExampleUpdated> */ class ExampleUpdatedListener extends AbstractCachePurgeListener { protected function addPurgeData(object $event): void { $this->purger->addPurgeTags([ 'examples', "example_{$event->example->id}", ]); } }
Tip
Prefer tags: they also invalidate cached URL variants, including query strings.
For one tag, use addPurgeTag('examples'). To purge URLs directly, use addPurgePath('/api/examples') or addPurgePaths(['/api/examples', '/api/examples/1']).
To handle multiple events in one class, use a subscriber instead:
// extend.php use Acpl\FlarumLSCache\Utility\LSCachePurger; use Flarum\Extend; return [ // ... your current extenders (new Extend\Conditional) ->whenExtensionEnabled('acpl-lscache', function () { LSCachePurger::$resourcesSupportedByEvent[] = 'example'; return [ (new Extend\Event)->subscribe(ExampleEventSubscriber::class), ]; }), ];
// ExampleEventSubscriber.php use Acpl\FlarumLSCache\Listener\AbstractCachePurgeSubscriber; use Illuminate\Contracts\Events\Dispatcher; class ExampleEventSubscriber extends AbstractCachePurgeSubscriber { public function subscribe(Dispatcher $events): void { $this->addPurgeListener($events, ExampleUpdated::class, $this->handleExampleUpdated(...)); // ... rest of listeners } public function handleExampleUpdated(ExampleUpdated $event): void { $this->purger->addPurgeTags([ 'examples', "example_{$event->example->id}", ]); } // ... rest of methods }