PWA Push
Notifications
Premium Progressive Web App push notifications for WordPress — with rich images, install detection, six admin themes, and seamless WooCommerce integration.
01 Overview
PWA Push Notifications by XaniaCode turns any WordPress installation into an installable Progressive Web App capable of sending rich, image-based push notifications to subscribers — even when the browser is closed.
The plugin implements the Web Push Protocol (RFC 8292) with VAPID authentication entirely server-side, requiring no third-party push service or external API account. Subscribers are stored locally in your database, and all cryptography is handled by the bundled xania-webpush library.
| Area | Capability | Notes |
|---|---|---|
| Push Notifications | Title, body, icon, badge, hero image, click URL | Core |
| PWA Manifest | Dynamic, site-aware manifest served via rewrite rule | Core |
| Install Banner | Smart banner with 7-day dismissal memory, iOS instructions | Core |
| Subscriber Segmentation | All / PWA-installed only / Browser-only | Core |
| VAPID | P-256 ECDSA key generation and rotation | Core |
| Admin Themes | 6 presets including fully custom color picker | UI |
| WooCommerce | Order and stock event notifications per-customer and admin | Add-on |
| Diagnostic | 40+ environment, conflict and live HTTP checks | Tools |
| Dead Endpoint GC | Automatic removal of expired/invalid push endpoints | Core |
| i18n / RTL | Translation-ready, RTL-aware admin UI | UI |
02 Requirements
Verify your hosting environment meets all of the following before installing:
Service workers won't load over HTTP
openssl, gmp or bcmathfcm.googleapis.com, updates.push.services.mozilla.com) and to xaniacode.com for license validation.
03 Installation
Manual Upload (Recommended)
-
1Upload the plugin folder
Extract the ZIP and upload the
pwa-push-notificationsfolder to your server at:/wp-content/plugins/pwa-push-notifications/ -
2Activate through WordPress admin
Go to Plugins → Installed Plugins, locate PWA Push Notifications, and click Activate. The plugin creates its subscriber database table automatically on activation.
-
3Navigate to PWA Push in the sidebar
A new top-level menu item — PWA Push — will appear in the WordPress admin sidebar.
-
4Generate VAPID keys
On the Dashboard screen, click Generate VAPID Keys. This is required before any subscription or notification will work. See Section 04 for details.
-
5Activate your license (or start the trial)
The 14-day trial starts automatically the first time you open the plugin's admin pages — no key required. For an active license, see Section 07.
-
6Visit your site over HTTPS
Front-end visitors will now see the install/subscribe banner. The service worker is registered and the PWA manifest is served automatically.
What the Plugin Installs
The activation routine creates:
{prefix}xc_pwa_subscribers) with columns for endpoint, auth, p256dh keys, user_id, is_pwa (install detection), and timestamps.
/pwa-manifest.json dynamically — no static file is created or overwritten on your server.
xc_pwa_daily_license) for license validation. Transient failures do not deactivate the plugin.
Uninstalling
Deleting the plugin via Plugins → Delete triggers the bundled uninstall.php script, which removes the subscribers table and all plugin options from the database, leaving no orphan data behind.
04 VAPID Keys
VAPID (Voluntary Application Server Identification) is the authentication mechanism that proves to browser push services that push requests originate from your server. The plugin implements VAPID per RFC 8292 using P-256 / prime256v1 ECDSA key pairs.
Generating Keys
-
1Go to PWA Push → Dashboard
The VAPID status panel at the top of the dashboard shows whether keys are currently set.
-
2Click "Generate VAPID Keys"
The plugin generates a new P-256 ECDSA key pair using PHP's
opensslextension and stores both the public key (base64url) and private PEM securely in the WordPress options table. -
3Set the VAPID subject
The subject should be either a
mailto:address or anhttps:URL identifying your organisation. This is embedded in VAPID JWT tokens and is visible to browser push services.Example subjectsmailto:admin@example.com https://example.com
How Keys Are Used
The public key is embedded in the front-end JavaScript (pwaPush.publicKey) and passed to the browser's PushManager.subscribe() call as the applicationServerKey. The private key PEM is used server-side to sign JWT tokens attached to each push request.
05 General Settings
Navigate to PWA Push → Settings to configure all plugin options. Settings are grouped into tabs.
Frontend Behaviour
theme_color and background_color injected into the dynamic PWA manifest and the <meta name="theme-color"> tag in <head>.
WooCommerce Integration
admin-post.php with action pwa_push_save_settings. All input is sanitised with WordPress helpers (sanitize_text_field, esc_url_raw, etc.) before being stored.
06 Appearance
The plugin ships with six admin theme presets selectable under Settings → Appearance. Themes are applied only to the plugin's own admin pages and do not affect the rest of the WordPress admin or the front end.
Custom Colour Variables
When the Custom theme is selected, you can set six CSS variables independently via the WordPress colour picker:
xc_pwa_save_appearance, allowing you to update colours without touching functional settings.
07 License
The plugin includes a license manager that gates the notification-sending functionality. VAPID key management and subscriber collection work regardless of license status.
Trial Period
A 14-day local trial starts automatically the first time you open any plugin admin page — no license key is required. During the trial you can send notifications and test all features.
Activating a License
-
1Go to PWA Push → License
The license screen shows current status, expiry, and trial remaining time.
-
2Enter your license key and click Activate
The plugin contacts
xaniacode.com/api/v1/license/activatewith your key and the current site URL to register the activation. -
3Confirmation
On success the license status updates to Active and the notification composer becomes fully available.
Background Validation
A WP-Cron job runs daily to re-validate the license against the XaniaCode server. Transient server failures do not deactivate the plugin — the last known valid state is preserved until a definitive invalid response is received.
Deactivating a License
Click Deactivate on the License screen. This contacts xaniacode.com/api/v1/license/deactivate and frees the activation slot so you can move the license to another site.
08 Sending Notifications
Notifications can be sent manually from the Dashboard or programmatically via the PHP API. An active license or trial is required to send.
Manual Send (Dashboard)
The notification composer on the Dashboard page accepts the following fields:
| Field | Required | Description |
|---|---|---|
| Title | Yes | Notification title displayed by the OS notification system |
| Body | Yes | Main notification message text |
| Click URL | No | URL opened when the user clicks the notification. Defaults to home_url() |
| Icon URL | No | Small icon shown alongside the notification. Defaults to the site icon |
| Hero Image URL | No | Large image displayed below the notification body (Chrome/Android) |
| Badge URL | No | Monochrome icon used by Android to replace the browser icon in the status bar |
| Target | No | Audience segment: all, pwa (installed app), or browser |
Subscriber Segmentation
The Target field lets you send to subsets of your subscriber list:
Dead Endpoint Cleanup
When the push service returns HTTP 404 or 410 for a subscriber endpoint (meaning the subscription has expired or been revoked), the plugin automatically removes that subscriber from the database. This keeps your subscriber list clean without any manual intervention.
09 Subscribers
Navigate to PWA Push → Subscribers to view and manage all active push subscriptions.
Subscriber Data
| Column | Description |
|---|---|
| Endpoint | The push service URL unique to this subscription (partial, truncated for display) |
| Is PWA | Whether the subscriber subscribed from an installed PWA (standalone mode) |
| User ID | Linked WordPress user ID, if the visitor was logged in when subscribing |
| Created At | Timestamp of when the subscription was created |
Front-End Opt-In Flow
The plugin follows browser best-practice for permission requests:
-
1Install banner appears
A non-intrusive banner slides in offering to install the app and/or subscribe to notifications. The banner is dismissed and not shown again for 7 days if the user clicks "Not now".
-
2User gesture triggers permission request
Clicking "Install" or "Subscribe" counts as a user gesture, satisfying Chrome's requirement that permission prompts be triggered by user interaction.
-
3Browser shows the native permission prompt
If the user grants permission, the endpoint and keys are sent to the server via an AJAX call secured with a WordPress nonce.
10 WooCommerce Integration
When WooCommerce (≥ 8.0) is active and you enable the integration under Settings → WooCommerce, the plugin hooks into order lifecycle and stock events to dispatch push notifications automatically.
Supported Events
woocommerce_new_order and woocommerce_checkout_order_processed fire together.Guest Checkout Auto-Linking
When a guest completes checkout, the plugin checks whether their billing email matches a registered WordPress user. If a match is found within a 60-minute window and the IP addresses align, the subscription is automatically linked to that user account — ensuring customer-targeted notifications reach returning guests who then log in.
Admin Capability
Admin notifications are dispatched to all subscribers who have the capability set in wc_admin_capability. The default is manage_woocommerce, but you can change this to manage_options or edit_shop_orders depending on who should receive store alerts.
get_edit_order_url, get_view_order_url) so notification click URLs work correctly whether or not High Performance Order Storage is enabled.
11 Diagnostic
Navigate to PWA Push → Diagnostic to run a comprehensive suite of environment and health checks. This page is essential for troubleshooting why push notifications may not be working.
Check Groups
/sw.js checking Content-Type and response integrity/pwa-manifest.json for correct MIME type (application/manifest+json)Caching Conflicts
The diagnostic also detects common caching and optimisation plugins that might cache sw.js with the wrong headers or an incorrect Cache-Control value. Detected plugins include: WP Rocket, LiteSpeed Cache, W3 Total Cache, WP Super Cache, and others.
Exporting a Diagnostic Report
Click Export Diagnostic Report on the Diagnostic page to download a plain-text summary of all check results. Include this file when submitting a support ticket to XaniaCode.
=== XaniaCode PWA Push Notifications — Diagnostic Report ===
Generated: 2026-04-29 14:32:01
Plugin version: 1.0.0
--- ENVIRONMENT ---
✅ PHP version — 8.2.12
✅ OpenSSL extension — loaded
✅ HTTPS — secure context detected
⚠️ GMP extension — not loaded (bcmath fallback active)
--- CONFLICTS ---
✅ No competing PWA plugins detected
⚠️ WP Rocket active — ensure sw.js is excluded from caching
12 Developer API
The plugin exposes a clean PHP API on the XC_PWA_Notifications class for sending notifications from custom code — themes, other plugins, or WP-CLI scripts.
Accessing the Instance
$plugin = XC_PWA_Plugin::instance();
$notifications = $plugin->notifications;
$subscribers = $plugin->subscribers;
dispatch() — Send to a list of subscribers
The lowest-level dispatch method. Pass an array of subscriber rows from the database and a payload array:
$result = $notifications->dispatch(
$subscribers, // array of subscriber rows
[
'title' => 'Hello from my plugin',
'body' => 'Something interesting happened.',
'icon' => 'https://example.com/icon.png',
'url' => 'https://example.com/event/',
'image' => 'https://example.com/hero.jpg', // optional
'badge' => 'https://example.com/badge.png', // optional
]
);
// $result shape:
// [
// 'sent' => int,
// 'failed' => int,
// 'failures' => [ ['id'=>int, 'status'=>int, 'error'=>string], ... ],
// 'skipped' => bool, // true when license is inactive
// ]
send_to_user() — Send to a specific WordPress user
$notifications->send_to_user( $user_id, [
'title' => 'Your report is ready',
'body' => 'Click to download.',
'url' => admin_url( 'admin.php?page=my-reports' ),
] );
send_to_capability() — Send to all users with a capability
$notifications->send_to_capability( 'manage_options', [
'title' => 'Admin alert',
'body' => 'Disk usage has exceeded 90%.',
'url' => admin_url(),
] );
dispatch() returns skipped: true and no network requests are made.
Custom WP-CLI Integration Example
// Send a notification from a custom WP-CLI command.
WP_CLI::add_command( 'pwa notify', function( $args ) {
$plugin = XC_PWA_Plugin::instance();
$subs = $plugin->subscribers->get_by_target( 'all' );
$result = $plugin->notifications->dispatch( $subs, [
'title' => $args[0] ?? 'Test',
'body' => $args[1] ?? 'Hello from CLI',
'url' => home_url(),
] );
WP_CLI::success( "Sent: {$result['sent']} Failed: {$result['failed']}" );
} );
13 FAQ
Does the plugin work without HTTPS?
Why don't notifications work in trial mode?
Will visitors be automatically prompted for permission?
I regenerated VAPID keys — why did all my subscribers disappear?
Why is sw.js being cached incorrectly?
sw.js with a long Cache-Control max-age, which means browsers won't pick up service worker updates. You should exclude /wp-content/plugins/pwa-push-notifications/sw.js from any page or file caching rules. The Diagnostic page will flag known offending caching plugins.Can I send notifications from my own plugin or theme code?
XC_PWA_Plugin::instance()->notifications. See Section 12 — Developer API for usage examples including dispatch(), send_to_user(), and send_to_capability().Does the plugin work with Cloudflare or other reverse proxies?
sw.js and /pwa-manifest.json are excluded from Cloudflare's edge caching. Set a Page Rule to Cache Level: Bypass for those paths. Also verify that Cloudflare's Rocket Loader does not defer the pwa-push.js script (add the data-cfasync="false" attribute via a filter if needed).Does this plugin replace or conflict with other PWA plugins?
14 Security
The plugin was designed with security as a first-class concern. Key measures:
| Measure | Implementation |
|---|---|
| License storage | AES-256-CBC encryption + HMAC-SHA256 message authentication (encrypt-then-MAC). Keys derived from WordPress secret salts. |
| AJAX nonce protection | All AJAX endpoints verified with check_ajax_referer() using separate nonces for admin (pwa_admin_nonce) and frontend (pwa_push_nonce). |
| Input sanitisation | All $_POST values sanitised with WordPress helpers: sanitize_text_field, sanitize_textarea_field, esc_url_raw. |
| Capability checks | Every admin AJAX action and POST handler verifies current_user_can('manage_options') before proceeding. |
| VAPID subject validation | The VAPID subject is validated against a mailto: or https: pattern before being stored. |
| License resilience | Transient failures reaching the license server do not deactivate the plugin, preventing false invalidation from temporary network issues. |
| No external CDN | All assets (JS, CSS, vendor library) are self-hosted within the plugin. No external CDN connections are made during page load. |
xaniacode.com.