kdjfs/user-presence

Shows who is currently working in the Kirby Panel, right in the users view

Maintainers

Package info

github.com/kdjfs-design/kirby-user-presence

Type:kirby-plugin

pkg:composer/kdjfs/user-presence

Transparency log

Fund package maintenance!

Buymeacoffee

paypal.me/kdjfs

Statistics

Installs: 4

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.1 2026-07-30 17:42 UTC

This package is auto-updated.

Last update: 2026-07-31 00:12:40 UTC


README

Shows who is currently working in the Kirby Panel, right in the users view — the users list with a green dot for an active admin and a blue dot for an idle editor

Deutsche Fassung

Latest version Tests License

Shows who is currently working in the Kirby Panel, right in the users view.

Dot Meaning
green active in the Panel within the last few minutes
blue signed in, but idle for a while
no dot not signed in

Green means worked in the Panel: opened a view, edited a page, saved a field. An open tab on its own is not activity, so a forgotten browser window turns blue like everyone else.

Three tabs filter the list, and they combine with the role filter (/users?role=editor&presence=active):

Tab Query Shows
Active presence=active the green dots
Idle presence=idle the blue dots
Signed in presence=signedin both, everyone with a session

Signed in is the union of the other two, so someone working right now appears under Active and under Signed in, but never under Idle.

A presence tab always shows every role: Active means every active user, never a subset. To combine, pick the presence first and the role second — the role tabs keep an active presence filter. Kirby's own All tab clears both at once and is the way back to the unfiltered list.

The active dot pulses. Anyone who has asked for less motion in their system settings (prefers-reduced-motion) gets it at rest — colour and meaning stay the same.

Requirements

Kirby 5.2 or newer, PHP 8.2 or newer. No build step and no npm.

Installation

With Composer

composer require kdjfs/user-presence

The getkirby/composer-installer places the plugin in site/plugins/.

Without Composer

Copy the directory to site/plugins/user-presence/. The plugin loads its own classes, so no autoloader is required.

Options

In site/config/config.php, all values in seconds:

'kdjfs.user-presence' => [
    'activeWithin'   => 300,   // green up to here, blue after
    'sessionTimeout' => 1800,  // no dot beyond this
    'throttle'       => 60,    // minimum gap between writes
    'staleAfter'     => 120,   // when the stale notice appears
],

Presence is kept in the plugin cache, which is enabled by default (kdjfs.user-presence.cache). A different cache type can be configured as for any Kirby plugin.

If the cache is unavailable, the plugin follows Kirby's own convention: with debug enabled the request fails with the original error message, so a misconfigured cache is fixed rather than worked around. In production the message goes to the error log, every user counts as offline, and the Panel keeps working. Nothing is swallowed silently either way.

Which cache type. The default file cache is fine for a few hundred users. Beyond that a shared in-memory cache is noticeably quicker, because filtering by presence reads one entry per user:

'kdjfs.user-presence' => [
    'cache' => ['type' => 'apcu'],
],

Kirby's memory type is not the one you want: it lives for a single request only, so every user would always appear offline. apcu needs no extra service; use memcached or redis when several web servers have to share the data. Losing it on a restart is harmless — everyone shows offline until their next click.

Language

The Panel labels ship in English and German and follow the Panel language of the signed-in user. Any other language falls back to English.

A language is added in site/config/config.php, no plugin required:

'extensions' => [
    'translations' => [
        'fr' => [
            'kdjfs.user-presence.tab.active'   => 'Actif',
            'kdjfs.user-presence.tab.idle'     => 'Inactif',
            'kdjfs.user-presence.tab.signedin' => 'Connecté',
            'kdjfs.user-presence.stale'        => 'État d’il y a {{ minutes }} minutes.',
            'kdjfs.user-presence.refresh'      => 'Actualiser',
        ],
    ],
],

The extensions wrapper is what makes it work: only api, routes and hooks are read straight from the options, everything else has to sit below that key. A translations key at the top level of the config has no effect.

The same route renames single labels, because config extensions are registered after the plugins and merged recursively — so this changes one word and leaves the rest of the German set alone:

'extensions' => [
    'translations' => [
        'de' => ['kdjfs.user-presence.tab.idle' => 'Abwesend'],
    ],
],

A language that others should get too is welcome as a pull request; it then ships with the plugin instead of living in one project's config.

Privacy

The plugin stores one timestamp per user — when they were last seen in the Panel — and shows everyone with access to the users view who is currently working.

It is built to keep as little as possible:

  • No history. Only the latest timestamp is held, never a trail.
  • Automatic deletion. Entries live in the cache with sessionTimeout as their lifetime, 30 minutes by default, and expire on their own.
  • Removed on sign-out, immediately.
  • No export, no API, no third party. The data never leaves the site.

Even so, in an employment context a display of colleagues' activity is a technical facility capable of monitoring conduct and performance. Under German law that can require the works council's agreement (§ 87 (1) no. 6 BetrVG), and comparable rules exist in other jurisdictions — being capable of it is enough, an intention to monitor is not required. This is not legal advice: please check it before rolling the plugin out to a team.

Limitations

The list shows the state at the time it was loaded. If it stays open, a notice appears offering to refresh it. There is deliberately no automatic refresh in the background: it would put constant load on the server for information that is rarely urgent.

Closing the browser without signing out leaves a user marked as signed in until sessionTimeout expires. They turn blue after activeWithin, so the display never claims presence that isn't there.

Your own account is always green and never appears under Idle — not as a matter of principle, but because the display only changes when you act: loading the list is activity, and so is the refresh from the notice. Watching your own entry grow old would take a refresh in the background, and that refresh would have to be excluded from activity itself — the way the keep-alive ping is. There deliberately is no such refresh, see the paragraph above.

With a role and a presence filter set at once, only the presence tab is underlined. Both filters still apply — the tab bar can mark just one of them.

Support the work

This plugin is free and stays that way. If it saves you some time, you are welcome to buy me a coffee or chip in directly:

Buy Me A Coffee   Donate via PayPal

Internals

How the plugin is put together, and which Panel behaviour it relies on, is described in ARCHITECTURE.md.

Licence

MIT — see LICENSE.

Eine deutsche Fassung dieser Datei liegt unter README.de.md.