Search by

acpl / flarum-lscache

rafaucau

LSCache implementation for Flarum.

Package info

github.com/android-com-pl/flarum-lscache

Forum

Type:flarum-extension

pkg:composer/acpl/flarum-lscache

Statistics

Installs: 4 984

Dependents: 0

Suggesters: 0

Stars: 7

Open Issues: 0

v4.0.0 2026-10-14 17:55 UTC

README

Latest Stable Version Total Downloads GitHub Sponsors

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:

  • .index routes get the resource tag: examples.index β†’ examples.
  • Other routes get their full name: examples.show β†’ examples.show.
  • An id or slug route parameter adds a tag using the singular resource name: example_1 or example_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
}

πŸ”— Links