# PWA Storefront Pack

> Volledige handleiding voor installatie, configuratie en gebruik van PWA Storefront Pack: de plugin die van uw WooCommerce-winkel een installeerbare Progressive Web App maakt, met offlinemodus en ingebouwde VAPID-pushmeldingen (zonder Firebase,…

- Pagina: <https://www.datafirefly.com/nl/documentation/pwa-storefront-pack/>
- Taal: nl
- Bijgewerkt op: 2026-08-31
- Andere talen: [fr](https://www.datafirefly.com/documentation/pwa-storefront-pack/index.md), [en](https://www.datafirefly.com/en/documentation/pwa-storefront-pack/index.md), [es](https://www.datafirefly.com/es/documentation/pwa-storefront-pack/index.md), [de](https://www.datafirefly.com/de/documentation/pwa-storefront-pack/index.md), [it](https://www.datafirefly.com/it/documentation/pwa-storefront-pack/index.md), [pl](https://www.datafirefly.com/pl/documentation/pwa-storefront-pack/index.md), [pt](https://www.datafirefly.com/pt/documentation/pwa-storefront-pack/index.md)
- Index: <https://www.datafirefly.com/nl/documentation/llms.txt>

Volledige handleiding voor installatie, configuratie en gebruik van **PWA Storefront Pack**: de plugin die van uw WooCommerce-winkel een installeerbare Progressive Web App maakt, met offlinemodus en ingebouwde VAPID-pushmeldingen (zonder Firebase, zonder OneSignal en zonder maandabonnement).

## Overzicht en werkingsprincipe

PWA Storefront Pack voegt aan uw WooCommerce drie zelfstandige maar elkaar aanvullende onderdelen toe:

- **Web App Manifest**: uw klanten kunnen uw winkel als een echte app op hun beginscherm installeren (pictogram, splash screen, standalone modus zonder adresbalk).
- **Service Worker**: slimme cache van pagina's en bronnen, een aanpasbare offlinepagina en automatische uitsluiting van gevoelige zones (winkelwagen, afrekenen, mijn account).
- **VAPID-pushmeldingen**: een volledige implementatie van het Web Push-protocol in pure PHP: ECDSA P-256, JWT ES256 en aes128gcm-versleuteling. Uw server praat rechtstreeks met de pushdiensten van de browsers.

**Geen enkele externe dienst.** Anders dan bij de meeste pushoplossingen voor WordPress gaat er geen enkel klantgegeven langs een tussenpartij. Uw VAPID-sleutels worden op uw eigen server aangemaakt en bewaard. U praat rechtstreeks met FCM (Google), Mozilla autopush, WNS (Microsoft) en de rest.

## Vereisten

- WordPress 6.2 of hoger
- WooCommerce 7.0 of hoger
- PHP 7.4 of hoger met de extensie `openssl` (bij alle hostingpartijen standaard ingeschakeld)
- **HTTPS verplicht**: browsers weigeren een Service Worker te registreren of pushmeldingen af te handelen over HTTP (behalve op localhost voor ontwikkeling)

Draait uw site nog niet op HTTPS, schakel dat dan in vóór u de plugin installeert. Alle PWA-functies worden stilzwijgend uitgeschakeld op HTTP.

## Installatie

1. Download het archief `pwa-storefront-pack.zip` vanuit uw DataFirefly-account.
2. Ga in WordPress naar **Plugins → Nieuwe plugin → Plugin uploaden**.
3. Selecteer de ZIP, klik op **Nu installeren** en daarna op **Activeren**.
4. Bij de activering maakt de plugin drie SQL-tabellen aan (`wp_pwasp_subscriptions`, `wp_pwasp_push_log`, `wp_pwasp_stock_waitlist`) en genereert ze automatisch uw VAPID-sleutelpaar.
5. Ga naar **WooCommerce → PWA Storefront** om alles in te stellen.

## Algemene configuratie

Het tabblad **General** bundelt de identiteit van uw applicatie:

- **Enable PWA**: de hoofdschakelaar. Zet die uit om het manifest en de Service Worker tijdelijk weg te halen zonder de plugin te verwijderen.
- **App name**: de volledige naam die bij de installatie en op het splash screen verschijnt (bijvoorbeeld "Mijn Officiële Winkel").
- **Short name**: het korte label onder het pictogram op het beginscherm, volgens de Android-conventie beperkt tot 12 tekens.
- **Theme color**: de kleur van de adresbalk en de takenkiezer (aanbevolen: uw belangrijkste merkkleur).
- **Background color**: de achtergrond van het splash screen tijdens het laden van de app (vaak wit of zeer licht).

### URL's van de endpoints

De plugin serveert twee cruciale endpoints:

- `https://uw-site.com/pwasp-manifest.json`: het Web App Manifest
- `https://uw-site.com/pwasp-service-worker.js`: de Service Worker

**Belangrijk voor cacheplugins:** deze twee URL's moeten altijd vers worden geserveerd. Voeg ze toe aan de uitsluitingen van WP Rocket, W3 Total Cache, LiteSpeed Cache of uw CDN. Anders bereiken configuratiewijzigingen de browsers nooit.

## Manifest

Het tabblad **Manifest** stuurt het gedrag van de geïnstalleerde app aan:

- **Display mode**: standaard `standalone` (aanbevolen, een app-achtige ervaring). Andere opties: `fullscreen`, `minimal-ui` en `browser`.
- **Orientation**: `any`, `portrait` of `landscape`. Op mobiel past `portrait` vaak het best bij webwinkels.
- **Start URL**: het pad waarop de app bij het starten opent. Standaard `/`. U kunt naar `/shop` wijzen om meteen de catalogus te openen.
- **Scope**: het bereik aan URL's dat de app beheert. Meestal `/`. Beperk dat alleen als u de PWA uitsluitend in een submap gebruikt.
- **Categories**: aanwijzingen voor de web-appstores (Chrome, Edge). Bijvoorbeeld `shopping,business`.
- **Shortcuts**: schakel dit in om snelkoppelingen naar Winkel, Winkelwagen en Mijn account te maken, bereikbaar door lang op het pictogram op het beginscherm te drukken.

## Pictogrammen van de applicatie

Op het tabblad **Icons** koppelt u uw pictogrammen uit de WordPress-mediabibliotheek. Er worden vijf formaten ondersteund:

- **Pictogram 192 bij 192 (any purpose)**: verplicht. Gebruikt op Android en in de zoekresultaten.
- **Pictogram 512 bij 512 (any purpose)**: verplicht. Het pictogram van het splash screen bij het starten.
- **Maskable 192 bij 192**: optioneel. Met een interne veiligheidsmarge van 10 procent voor de adaptieve pictogrammen van Android (rond, vierkant, druppelvormig).
- **Maskable 512 bij 512**: optioneel. Hetzelfde principe voor het splash screen.
- **Apple Touch Icon 180 bij 180**: voor iOS. Zonder afgeronde hoeken (iOS voegt die zelf toe).

**Tip voor maskable pictogrammen:** gebruik een hulpmiddel als `maskable.app` om uw maskable varianten met de juiste veilige zone te maken. Een logo zonder veiligheidsmarge wordt op sommige Android-toestellen afgesneden.

Zolang er geen pictogram is ingesteld, gebruikt de plugin de meegeleverde standaardpictogrammen (merk DataFirefly). Vervang die vóór u live gaat.

## Offlinemodus en cachestrategie

Het tabblad **Offline & Cache** regelt het gedrag van de Service Worker:

### Strategieën

- **Network first** (aanbevolen): de browser probeert eerst het netwerk en valt daarna terug op de cache als er geen verbinding is. Maximale actualiteit van prijzen en voorraad.
- **Cache first**: de cache antwoordt meteen en het netwerk werkt op de achtergrond bij. Sneller, maar kan licht verouderde prijzen tonen.

De strategieën gelden alleen voor **HTML-pagina's**. Andere bronnen hebben vaste, optimale strategieën:

- CSS, JS en lettertypen: _cache-first_ (die veranderen alleen bij een versie-update)
- Productafbeeldingen: _stale-while-revalidate_ (meteen uit de cache tonen, op de achtergrond verversen)

### Bereik van de cache

Met drie selectievakjes schakelt u de cache per type in of uit:

- **Cache HTML pages**: productpagina's, categorieën, startpagina en berichten
- **Cache CSS / JS / fonts**: het skelet van uw thema
- **Cache images**: productafbeeldingen en afbeeldingen bij blogberichten

**Altijd uitgesloten van de cache** (ongeacht de configuratie): `/wp-admin/`, `/wp-login.php`, `/cart`, `/checkout`, `/my-account` en alle AJAX-endpoints van WooCommerce. Die zones vereisen doorlopend een verse en geauthenticeerde toestand.

### Offlinepagina

Er zijn twee mogelijkheden:

- **Het standaardscherm gebruiken**: een minimalistisch scherm dat in de plugin zit (pictogram, boodschap, knop Opnieuw proberen), in uw merkkleuren.
- **Een eigen pagina gebruiken**: kies een bestaande WordPress-pagina. Die wordt bij de installatie van de Service Worker vooraf gecachet en getoond wanneer het netwerk uitvalt.

## Installatiebanner

Het tabblad **Install Banner** stuurt de promotie van de installatie aan:

- **Delay (page views)**: het aantal bekeken pagina's vóór de banner verschijnt. Standaard 3: de gebruiker heeft dan minimale interesse getoond zonder meteen bij het eerste bezoek te worden lastiggevallen.
- **Banner title / text / CTA / Dismiss**: volledig aanpasbare teksten, vertaalbaar via het `.pot`-bestand.

Gedrag:

- Op **Chrome, Edge, Opera en Samsung Internet**: de banner verschijnt zodra de browser meldt dat de site installeerbaar is (`beforeinstallprompt`). Een klik op de knop toont het ingebouwde installatievenster.
- Op **iOS Safari**: de banner toont automatisch de instructies "Tik op Deel en daarna op Zet op beginscherm" (Apple biedt geen API voor programmatische installatie).
- **Wegklikken 7 dagen onthouden**: sluit de gebruiker de banner, dan verschijnt die een week lang niet opnieuw.
- **Automatische herkenning**: is de app al geïnstalleerd (standalone modus herkend), dan verschijnt de banner niet meer.

## Pushmeldingen: de VAPID-sleutels

De pushmeldingen gebruiken het protocol **VAPID** (Voluntary Application Server Identification), een W3C-standaard. Bij de activering van de plugin wordt automatisch een ECDSA P-256-sleutelpaar aangemaakt:

- **Publieke sleutel**: gedeeld met de browsers van de abonnees (via JavaScript). 65 bytes, gecodeerd in base64url.
- **Privésleutel**: wordt nooit verstuurd en dient om elke verzending te ondertekenen. 32 bytes.

Het tabblad **Push Notifications** toont uw publieke sleutel in leesbare vorm en het aantal actieve abonnementen. U kunt die kopiëren voor eventuele externe tests.

### Sleutels opnieuw genereren

De knop **Regenerate keys** maakt een nieuw paar aan. Die handeling is **destructief**:

Het opnieuw genereren van de sleutels maakt **alle bestaande abonnementen** meteen ongeldig. De plugin maakt de abonnementstabel na bevestiging automatisch leeg. De browsers van de abonnees blijven de al ondertekende meldingen ontvangen, maar elke nieuwe melding mislukt stilzwijgend tot de gebruiker zich opnieuw abonneert.

Genereer de sleutels alleen opnieuw bij een vastgesteld lek of bij een migratie tussen omgevingen.

### VAPID subject

Het veld **VAPID subject**: een contactadres in de vorm `mailto:u@voorbeeld.nl` of `https://voorbeeld.nl/contact`. Sommige pushdiensten (met name Mozilla) gebruiken dat om u te bereiken als er misbruik vanaf uw server wordt vastgesteld. Het is vooraf ingevuld met het beheerdersadres van WordPress.

## Opt-in-prompt en AVG

Het onderdeel **Opt-in prompt** regelt de vooraankondiging die vóór het ingebouwde toestemmingsvenster verschijnt:

- **Show opt-in prompt**: schakelt de eigen vooraankondiging in. Aanbevolen: het ingebouwde venster alleen kent een hoog weigeringspercentage en blokkeert daarna 30 dagen lang elke nieuwe vraag.
- **GDPR consent required**: toont het ingebouwde venster nooit zonder een uitdrukkelijke klik van de gebruiker op uw knop. Vereist in Europa om AVG-conform te zijn.
- **Delay (seconds)**: de wachttijd vóór weergave. Standaard 10 seconden: laat de gebruiker eerst rondkijken voordat u om toestemming vraagt.
- **Prompt title / text / CTA / Dismiss**: volledig aanpasbare teksten.

**Goede gewoonten:** leg de meerwaarde voor de gebruiker uit ("Volg uw bestellingen in realtime"), niet die voor uzelf ("Blijf op de hoogte van onze aanbiedingen"). Het acceptatiepercentage ligt 3 tot 4 keer hoger.

## Automatische triggers

De plugin levert drie automatismen die rechtstreeks op WooCommerce-hooks aanhaken. Elk is afzonderlijk in te schakelen.

### Bestelstatus

Hook: `woocommerce_order_status_changed`.
De ingelogde klant (niet gasten) krijgt bij elke statuswijziging van zijn bestelling een melding. Titel: "Bestelling #1042 bijgewerkt". Tekst: "Status: Verzonden". Een klik leidt naar de volgpagina van de bestelling.

De melding gebruikt een unieke `tag` per bestelling (`order-1042`): opeenvolgende updates vervangen de vorige in plaats van zich op te stapelen.

### Nieuwe bestelling (beheerder)

Hook: `woocommerce_new_order`.
Alle gebruikers met de rol _administrator_ of _shop_manager_ die op push zijn geabonneerd, krijgen bij elke nieuwe bestelling een melding. Titel: "Nieuwe bestelling ontvangen". Tekst: "Bestelling #1042, 189,00 euro". Een klik leidt naar het bewerkscherm van de bestelling.

De beheerders-URL is **HPOS-bewust**: gebruikt uw WooCommerce de High-Performance Order Storage, dan wijst de link naar het nieuwe schema (`admin.php?page=wc-orders`). Anders naar het oude (`post.php?post=X`).

### Weer op voorraad

Hooks: `woocommerce_product_set_stock` en `woocommerce_variation_set_stock`.
Zodra een product van "uitverkocht" naar "op voorraad" gaat, stuurt de plugin een melding naar alle bezoekers die zich op de wachtlijst hadden gezet. Titel: "Weer op voorraad!". Tekst: "Premium leren sneakers, beperkte oplage is weer beschikbaar". Met een voorbeeldafbeelding van het product indien beschikbaar.

Elk item wordt na een geslaagde verzending gemarkeerd met `notified_at`, om dubbele meldingen te vermijden als de voorraad schommelt.

## Broadcast opstellen

Menu: **WooCommerce → PWA Broadcast**. Een interface om handmatig een melding naar alle actieve abonnees te sturen (marketingcampagnes, aankondigingen en dergelijke).

Velden:

- **Title**: de titel van de melding (aanbevolen maximaal 100 tekens)
- **Message**: de tekst van de melding (aanbevolen maximaal 200 tekens)
- **Open URL**: de pagina waar de gebruiker bij een klik terechtkomt (standaard de startpagina)
- **Image URL**: een grote afbeelding in de melding (alleen Android; iOS toont die niet)

Een voorbeeld in realtime toont rechts op het scherm bij benadering hoe de melding eruitziet.

Twee knoppen:

- **Send broadcast**: verzending naar alle actieve abonnees (bevestiging vereist)
- **Send test to me**: verzending alleen naar uw eigen abonnementen. Handig om de weergave te controleren vóór een grote broadcast.

**Timing:** vermijd broadcasts midden in de nacht, want op Android geven meldingen standaard geluid. Een verzending op vrijdagavond om 21 uur haalt een tweemaal hoger doorklikpercentage dan een verzending om 3 uur 's nachts.

## Wachtlijst voor terugkeer op voorraad (JavaScript-API)

Om bezoekers zich te laten inschrijven op de wachtlijst van een uitverkocht product, roept u vanuit uw thema het volgende aan:

```
window.PWASP.addToWaitlist(productId)
  .then(result => {
    if (result.success) {
      alert('U krijgt bericht zodra het product weer op voorraad is!');
    }
  });
```

Gedrag:

1. Is de gebruiker nog niet op push geabonneerd, dan opent het ingebouwde toestemmingsvenster.
2. Zodra het abonnement aan de serverzijde is vastgelegd, komt het item op de wachtlijst van het product.
3. Zodra de terugkeer op voorraad wordt herkend, gaat er automatisch een pushmelding uit.

U kunt deze API aanroepen vanaf elke eigen knop of via de hook `woocommerce_single_product_summary` in een mu-plugin.

### Andere beschikbare JS-API's

```
// Handmatig abonneren (bijvoorbeeld vanaf een eigen knop)
window.PWASP.subscribePush();

// Uitschrijven (knop "Uitschrijven")
window.PWASP.unsubscribePush();
```

## REST API

De plugin biedt zes endpoints onder de namespace `pwasp/v1`:

- `POST /wp-json/pwasp/v1/subscribe`: legt een abonnement vast. Body: het `PushSubscription`-object van de browser.
- `POST /wp-json/pwasp/v1/unsubscribe`: verwijdert een abonnement. Body: `{ endpoint: "..." }`.
- `POST /wp-json/pwasp/v1/test`: een testverzending naar de huidige gebruiker (authenticatie vereist, capability `manage_woocommerce`).
- `POST /wp-json/pwasp/v1/broadcast`: verzending naar alle abonnees (authenticatie vereist).
- `POST /wp-json/pwasp/v1/regenerate-vapid`: genereert de VAPID-sleutels opnieuw (authenticatie vereist).
- `POST /wp-json/pwasp/v1/waitlist`: voegt toe aan een wachtlijst. Body: `{ subscription_id, product_id }`.

Authenticatie: de WordPress-nonce `X-WP-Nonce` voor de publieke endpoints, en de capability `manage_woocommerce` voor de beheerdersendpoints.

## Compatibiliteit en bijzondere gevallen

### HPOS (High-Performance Order Storage)

De plugin verklaart haar HPOS-compatibiliteit uitdrukkelijk bij WooCommerce via `FeaturesUtil::declare_compatibility`. U ziet het vinkje in **WooCommerce → Instellingen → Geavanceerd → Functies**.

### Cacheplugins

Voeg de volgende uitsluitingen toe in uw cacheplugin:

- `/pwasp-manifest.json`
- `/pwasp-service-worker.js`

Sommige plugins (WP Rocket, LiteSpeed) bieden ook een optie om JavaScript-bestanden van een Service Worker _niet_ te cachen; schakel die in als ze beschikbaar is.

### iOS en Safari

Ondersteuning per versie:

- **iOS 16.4 en hoger**: installatie via "Zet op beginscherm" en pushmeldingen (alleen voor geïnstalleerde PWA's)
- **iOS 15 tot 16.3**: installatie mogelijk, pushmeldingen niet beschikbaar
- **iOS 14 en lager**: installatie mogelijk, geen meldingen

Op iOS werken pushmeldingen alleen als de gebruiker de PWA eerst op zijn beginscherm heeft geïnstalleerd. Dat is een beperking van Apple, niet van de plugin.

### Meertalig: WPML en Polylang

De plugin werkt met **WPML** (inclusief WooCommerce Multilingual) en **Polylang / Polylang Pro**, of de talen nu in submappen (`/en/`, `/it/`), subdomeinen of een taalparameter staan:

- **Service Worker**: altijd geregistreerd vanaf de hoofdmap van de site (`/pwasp-service-worker.js`) met scope `/`, zodat één worker alle talen dekt.
- **Manifest**: per taal geserveerd (`/en/pwasp-manifest.json`) met de naam, beschrijving en `start_url` van die taal. Het veld `id` is overal gelijk: de app die vanuit `/it/` en vanuit `/nl/` wordt geïnstalleerd, is dezelfde app.
- **Beheerteksten** (installatiebanner, push-voorvraag, offlinebericht, naam en korte naam van de app): automatisch geregistreerd in **WPML → String Translation** (domein "PWA Storefront Pack") en in **Talen → Stringvertalingen** voor Polylang. Voer ze in in de standaardtaal en vertaal ze daar.
- **Pushmeldingen**: verzonden in de taal van elke abonnee (locale opgeslagen bij het inschrijven). De melding bij terugkeer op voorraad gebruikt de naam en URL van het vertaalde product.
- **Offlinescherm**: vooraf gecachet voor elke taal en geserveerd in de taal van de gevraagde pagina.
- **Winkelwagen / Afrekenen / Mijn account**: uitgesloten van de cache, ongeacht de vertaalde slug (per taal opgelost aan de serverzijde).

**WooCommerce Multilingual met meerdere valuta's:** omdat de valuta via een cookie wordt gekozen, zien twee bezoekers verschillende prijzen op dezelfde URL. De plugin forceert de HTML-strategie daarom op _network-first_ en cachet nooit URL's voor valutawissel (`?currency=`). Het bedrag in de meldingen "nieuwe bestelling" is altijd dat van de bestelling, in haar valuta.

### Submappen en multisite

De plugin werkt op WordPress in de hoofdmap (`voorbeeld.nl`) of in een submap (`voorbeeld.nl/shop/`). De endpoints worden dynamisch bepaald via `home_url()`. Activeer de plugin bij multisite per site: elke site krijgt dan een eigen VAPID-sleutelpaar en een eigen abonneebestand.

## Probleemoplossing

### "De Service Worker wordt niet geregistreerd"

1. Controleer of uw site wel op HTTPS draait (`https://` en niet `http://`).
2. Open de browserconsole (F12, tabblad Application, daarna Service Workers). Staat daar een foutmelding?
3. Test de URL `https://uw-site.com/pwasp-service-worker.js` in een tabblad. Het bestand hoort JavaScript terug te geven, geen 404-pagina en niet de startpagina van WordPress.
4. Bij een 404: ga naar **Instellingen → Permalinks** en klik op **Wijzigingen opslaan** om de rewrite rules te verversen.

### "De meldingen komen niet aan"

1. Controleer in **WooCommerce → PWA Subscribers** of uw abonnement in de lijst staat met de status _active_.
2. Gebruik de knop **Send test to me** in de broadcastopsteller. Krijgt u de melding binnen?
3. Zo niet: mogelijk is het toestemmingsvenster geweigerd. In Chrome: open het slotje in de adresbalk, ga naar Meldingen en zet die op Toestaan.
4. Op Windows of macOS: controleer of Chrome of Firefox niet in de modus "Niet storen" staat.

### "Het opnieuw genereren van de VAPID-sleutels is mislukt"

Waarschijnlijke oorzaak: de PHP-extensie `openssl` is niet beschikbaar op uw hosting, of het aanmaken van ECDSA-sleutels wordt geblokkeerd. Controleer via een bestand `phpinfo.php` of het onderdeel `openssl` aanwezig is en of de curve `prime256v1` wordt ondersteund. Neem zo nodig contact op met uw hostingpartij.

## Verwijderen

Verwijderen via **Plugins → Geïnstalleerde plugins → Verwijderen**:

- de drie SQL-tabellen worden verwijderd;
- de opties van de plugin worden verwijderd;
- de geplande crontaken worden geannuleerd;
- de pictogrammen die u naar de mediabibliotheek hebt geüpload, **blijven staan** (die kunnen elders nog van pas komen).

## Support

Voor vragen of afwijkingen opent u een ticket vanuit uw [DataFirefly-account](https://www.datafirefly.com/my-account/). Antwoord binnen 24 werkuren.
