philippoehrlein/kirby-push-notifications

Web Push for Kirby: channel-based subscriptions, Panel UI, frontend dialog, hooks and API

Maintainers

Package info

github.com/philippoehrlein/Kirby-Push-Notifications

Type:kirby-plugin

pkg:composer/philippoehrlein/kirby-push-notifications

Statistics

Installs: 5

Dependents: 0

Suggesters: 0

Stars: 11

Open Issues: 0

1.1.0 2026-03-16 16:40 UTC

This package is auto-updated.

Last update: 2026-03-18 09:54:12 UTC


README

License Version

Kirby Push Notifications is a plugin for Kirby CMS that adds Web Push support. Visitors can subscribe to channels (e.g. “Notes”, “News”), and you can send notifications from the Panel or via hooks. Subscriptions are stored in SQLite; sending is powered by the minishlink/web-push library with VAPID authentication.

Cover Kirby Push Notifications

Features

  • 🔔 Visitors subscribe to channels
  • 👨‍💻 Editors send notifications from the Panel
  • 🚀 Developers automate via hooks

Requirements

  • Kirby 5.x
  • PHP 8.2+
  • HTTPS (required for Web Push)

Installation

Composer (recommended)

In your site root:

composer require philippoehrlein/kirby-push-notifications

Manual installation

  1. Download or clone the repo.
  2. Copy the kirby-push-notifications folder into site/plugins/.

The plugin ships with its own vendor/, so no composer install in the plugin folder is needed.

Configuration

In site/config/config.php (or a separate config file):

return [
    'philippoehrlein.push-notifications' => [
        'vapid' => [
            'publicKey'  => 'your-vapid-public-key',
            'privateKey' => 'your-vapid-private-key',
            'subject'    => 'https://yourdomain.com',
        ],
        'channels' => [
            'panel' => [
                [
                    'value' => 'note-approval',
                    'text' => 'Note Approval',
                    'info' => 'Get informed when a note is waiting for approval',
                ]
            ],
            'website' => [
                [
                    'value' => 'notes',
                    'text'  => 'Notes',
                    'info'  => 'Receive new notes',
                ],
                [
                    'value' => 'photos',
                    'text'  => 'Photography',
                    'info'  => 'Receive the latest Photo series',
                ],
            ]
        ],
        // optional: change DB location
        // 'db' => [
        //     'name' => 'push_notifications',
        //     'dir'  => 'site/push-notifications',
        // ],
        // optional: Web Push default options (TTL, contentType, batchSize, etc.)
        // 'webPush' => [
        //     'contentType' => 'application/json',
        //     'TTL' => 3600,
        //     'urgency' => null,
        //     'topic' => null,
        //     'batchSize' => 1000,
        //     'requestConcurrency' => 100,
        // ],
    ],
];

Note Defining channels in the plugin options is optional. It is only required if you want to use the built‑in subscription UIs that read channels from the config (like kpn-dialog). If you use the helper script (helper.js), panel buttons or your own custom UI, you can pass channel names directly in your code without configuring them in channels.

Alternative: flat channels (no panel/website groups)

By default, you can configure channels in two groups (panel and website) so the Panel groups them visually. Channels in the website group are exposed to the frontend snippet, while panel channels are only available inside the Panel. If you don’t need this distinction, you can also use a flat list of channels.

// site/config/config.php
return [
  'philippoehrlein.push-notifications' => [
    'channels' => [
      [
        'value' => 'news',
        'text'  => 'News',
        'info'  => 'General website updates',
      ],
      [
        'value' => 'notes',
        'text'  => 'Notes',
        'info'  => 'New notes and articles',
      ],
    ],
  ],
];

VAPID keys

Web Push requires a VAPID key pair. Set vapid.publicKey, vapid.privateKey and vapid.subject (your site URL, e.g. https://yourdomain.com). Keep the private key secret.

Generating keys: Use the Create VAPID keys section in the web-push-php README (OpenSSL in bash or VAPID::createVapidKeys() in PHP).

Option webPush

Optional: Set global defaults for all push sends with the webPush option. Keys: contentType (e.g. application/json), TTL (seconds, e.g. 3600), urgency, topic, batchSize, requestConcurrency. Usually urgency and topic are left null here and set per send via the hook payload (see Payload for send hooks). You can still set global defaults if needed.

Usage

There are two main use cases: website (visitors subscribe) and panel (editors manage or send notifications). Each can be used in a simple way (ready-made UI) or a custom way (your own UI with the same APIs).

Website

Simple: Dialog snippet

Dialog for subscriptions

Use the kpn-dialog snippet for a button that opens a subscribe/unsubscribe dialog with channel checkboxes. No custom JS needed.

In a template or snippet:

<?php snippet('kpn-dialog', slots: true) ?>
🔔 Notifications
<?php endsnippet() ?>

Optional: pass data to override defaults or translations:

<?php snippet('kpn-dialog', [
    'headline'    => 'Your Headline',
    'description' => 'Choose the channels you want to receive.',
    // 'channels'   => [['value' => 'news', 'text' => 'News', 'info' => '…']],
], slots: true) ?>
🔔 Notifications
<?php endsnippet() ?>

Custom: helper.js

If you don’t want the dialog (e.g. a single button with fixed channels, or your own UI), use the helper script. Set window.KPN_CONFIG (vapidPublicKey, subscribeUrl, unsubscribeUrl, swPath), load /assets/kpn/helper.js, then call window.KPN.subscribe(channels) and window.KPN.unsubscribe(). You stay in control of markup and flow; the helper only handles the Web Push API and the plugin routes.

Panel

Simple: View buttons, button components, dialog

Panel dialog for subscriptions

The plugin ships with two view buttons (kpn-subscribe, kpn-notification), two button components (kpn-subscribe-button, kpn-notification-button) and one dialog (kpn-subscribe-dialog). Register and place them in your Panel blueprints or views where needed. That’s enough to let logged-in users subscribe/unsubscribe and to send a notification (channel, title, body) without building your own UI. See src/index.js and src/components/ for how they’re wired.

Panel dialog for sending notifications

Custom: Your own UI with hooks and API

Build your own Panel UI and call the hooks (subscribe, unsubscribe, send-to-one, send-to-many) and the Panel API (e.g. get-channels, get-keys, status, subscribe, unsubscribe). Same backend, full control over the interface.

Example: send a push when a note is published:

// site/config/config.php
'hooks' => [
    'page.changeStatus:after' => function ($newPage, $oldPage) {
        if ($newPage->intendedTemplate() === 'note' && $newPage->status() === 'listed') {
            kirby()->trigger('philippoehrlein.push-notifications.send-to-many', [
                'payload' => [
                    'message' => [
                        'title' => kirby()->site()->title()->value(),
                        'body'  => 'New note: ' . $newPage->title()->value(),
                        'data'  => ['url' => $newPage->url()],
                    ],
                    'channel' => 'notes',
                    'options' => ['urgency' => 'normal'],
                ],
            ]);
        }
    },
],

Hooks

Hook Use case
philippoehrlein.push-notifications.subscribe After a subscription is created (payload: endpoint, keys, channel, user_id).
philippoehrlein.push-notifications.unsubscribe After unsubscription (payload: endpoint and/or user_id, channel).
philippoehrlein.push-notifications.send-to-one Send to one user (payload: user_id, message, channel, language?, options?).
philippoehrlein.push-notifications.send-to-many Send to many users or to a full channel (payload: message, user_ids?, channel?, language?, options?).

Payload for send hooks

For send-to-one and send-to-many, the payload can include an optional options array with Web Push options for that send:

  • urgency: Delivery priority – 'very-low', 'low', 'normal', 'high'. Affects delivery timing and presentation (e.g. sound, vibration).
  • topic: Optional. When set, push services may replace older notifications with the same topic by newer ones (collapse). Whether and when to use e.g. the channel as topic is up to you (e.g. 'topic' => $channel for one notification per channel).
  • TTL: Optional, time-to-live in seconds for this message.

Example: 'options' => ['urgency' => 'high', 'TTL' => 600].

Routes and API

  • Frontend (public):
    • POST /push-notifications/subscribe — Body: endpoint, keys, channel. Param: lang (optional).
    • POST /push-notifications/unsubscribe
    • GET /push-notifications-sw.js (service worker)
    • GET /assets/kpn/helper.js
  • Panel API: philippoehrlein/push-notifications/* (subscribe, unsubscribe, get-channels, get-keys, status, etc.).

License

MIT. See LICENSE for details.

Support