Storefront-JS
Guppy folgt dem Standard-Shopware-Storefront-JS-Pattern: PluginBase-Klassen mit Lifecycle, Registrierung im PluginManager, Selektor-basierte Aktivierung über data-*-Attribute. Diese Seite zeigt Architektur, mitgelieferte Plugins, Konfiguration und wie du eigene Plugins schreibst.
Plugin-Architektur
Registrierung
// Neue Plugins
PluginManager.register('SplideSliderPlugin', SplideSliderPlugin);
PluginManager.register('UspBannerPlugin', UspBannerPlugin);
PluginManager.register('ProductBoxClickPlugin', ProductBoxClickPlugin);
// Plugin-Overrides (Lazy-Imports möglich)
PluginManager.override('QuantitySelector', () => import('./js/quantity-selector.plugin'));Initialisierung via data-*-Attribute
<div data-splide-slider-plugin="true"
data-splide-slider-plugin-options='{...}'>Mitgelieferte Plugins
SplideSliderPlugin
Moderner Slider auf Basis von Splide.js: ersetzt Shopwares Standard-Tiny-Slider.
Features: bessere Performance, vollständige Keyboard-Navigation, Screen-Reader-Support, Touch-Gesten, Responsive.
export default class SplideSliderPlugin extends Plugin {
static options = {
splideSnippets: ""
}
init() {
this._mountSlider(this.el, this.options.splideSnippets);
}
_mountSlider(element, options) {
var splideSlider = new Splide(element, {
i18n: options
}).mount();
const splideOptions = Object.getPrototypeOf(splideSlider.options);
if (splideOptions.autoplay === "pause") {
splideSlider.Components.Autoplay.play();
}
}
}Verwendung:
<div class="splide" data-splide-slider-plugin="true">
<div class="splide__track">
<ul class="splide__list">
<li class="splide__slide">Slide 1</li>
<li class="splide__slide">Slide 2</li>
</ul>
</div>
</div>UspBannerPlugin
Interaktives USP-Banner mit Tooltip-Funktionalität und responsivem Verhalten.
Features: Tooltip-System, responsive Anzeige, Slider-Integration auf Mobile, konfigurierbare Layouts (Standard und Benefits).
{
"guppy-usp-active": true,
"guppy-usp-layout": "benefits",
"guppy-usp-layout-benefit1": "Kostenloser Versand",
"guppy-usp-layout-benefit2": "30 Tage Rückgabe",
"guppy-usp-layout-benefit3": "Schnelle Lieferung"
}Responsives Verhalten:
| Viewport | Anzahl USPs |
|---|---|
| Desktop | 1–4 statisch |
| Tablet | 1–2 als Slider mit Endlosschleife |
| Mobile | 1 als Slider mit Endlosschleife |
ProductBoxClickPlugin
Erweitert die Produktbox um vollständig klickbare Karten plus Keyboard-Support.
Features: ganze Box klickbar, Tastaturunterstützung, korrektes Focus-Management, Event-Delegation.
CustomCheckoutPlugin
Optimiert das Checkout-Erlebnis (Validierung, Progress-Tracking, Auto-Save, Error-Handling).
<div class="checkout-main" data-custom-checkout-plugin="true">QuantitySelectorPlugin (Override)
Erweitert Shopwares Mengenauswahl: Input-Validation, Pfeiltasten-Navigation, ARIA-Labels, smooth Animations.
Weitere Plugins
| Plugin | Zweck |
|---|---|
| RemoveExtraH1Plugin | SEO, entfernt redundante H1-Tags nach DOM-Load. |
| DeliveryInformationMarginPlugin | dynamische Margin-Anpassung für Lieferinformationen. |
| SplideSliderGalleryPlugin | erweiterte Galerie mit Thumbnail-Sync und Zoom. |
| CollapseFooterColumnsPlugin (Override) | Accordion-Footer auf Mobile. |
Splide-Konfiguration
Alle Splide.js-Optionen sind verfügbar.
<div class="splide"
data-splide-slider-plugin="true"
data-splide-slider-plugin-options='{
"type": "loop",
"perPage": 4,
"perMove": 1,
"gap": "1rem",
"pagination": false,
"arrows": true,
"autoplay": true,
"interval": 5000,
"pauseOnHover": true,
"breakpoints": {
"1024": { "perPage": 3 },
"768": { "perPage": 2 },
"576": { "perPage": 1 }
}
}'>| Option | Typ | Default | Beschreibung |
|---|---|---|---|
type | string | slide | slide, loop, fade |
perPage | number | 1 | sichtbare Slides |
perMove | number | 1 | Slides pro Bewegung |
gap | string | 0 | Abstand zwischen Slides |
arrows | boolean | true | Navigationspfeile |
pagination | boolean | true | Pagination-Dots |
autoplay | boolean | false | automatisches Abspielen |
interval | number | 5000 | Autoplay-Intervall (ms) |
pauseOnHover | boolean | true | Pause bei Hover |
rewind | boolean | false | Zurückspringen am Ende |
speed | number | 400 | Animationsgeschwindigkeit (ms) |
easing | string | cubic-bezier(0.25, 1, 0.5, 1) | Easing-Funktion |
Events
document.addEventListener('DOMContentLoaded', () => {
const splideEl = document.querySelector('.splide');
const splide = splideEl._splide;
if (splide) {
splide.on('move', (newIndex, prevIndex) => {
console.log(`Moved from ${prevIndex} to ${newIndex}`);
});
splide.on('mounted', () => console.log('Slider mounted'));
splide.on('autoplay:play', () => console.log('Autoplay started'));
splide.on('autoplay:pause', () => console.log('Autoplay paused'));
}
});ProductBoxClickPlugin
export default class ProductBoxClickPlugin extends Plugin {
static options = {
excludeSelectors: '.btn, .product-action, .wishlist-button, input, select',
linkSelector: '.product-name a, .product-image-link'
}
init() {
this.el.addEventListener('click', this._onClick.bind(this));
this.el.addEventListener('keydown', this._onKeydown.bind(this));
}
_onClick(event) {
if (event.target.closest(this.options.excludeSelectors)) {
return;
}
const link = this.el.querySelector(this.options.linkSelector);
if (link) {
link.click();
}
}
_onKeydown(event) {
if (event.key === 'Enter' || event.key === ' ') {
this._onClick(event);
}
}
}Eigene Plugins schreiben
Plugin-Template
import Plugin from 'src/plugin-system/plugin.class';
export default class MyCustomPlugin extends Plugin {
static options = {
myOption: 'default-value',
anotherOption: true
};
init() {
this._registerEvents();
}
_registerEvents() {
this.el.addEventListener('click', this._onClick.bind(this));
}
_onClick(event) {
console.log('Clicked!', this.options.myOption);
}
destroy() {
// Cleanup
}
}Plugin registrieren
// main.js
import MyCustomPlugin from './plugins/my-custom-plugin';
window.PluginManager.register('MyCustomPlugin', MyCustomPlugin, '[data-my-custom-plugin]');Plugin verwenden
<div data-my-custom-plugin="true"
data-my-custom-plugin-options='{"myOption": "custom-value"}'>
<!-- Inhalt -->
</div>Debugging
// Plugin-Instanz abrufen
const element = document.querySelector('[data-splide-slider-plugin]');
const pluginInstance = window.PluginManager.getPluginInstanceFromElement(element, 'SplideSliderPlugin');
// Optionen anzeigen
console.log(pluginInstance.options);
// Alle registrierten Plugins
console.log(window.PluginManager.getPluginList());Häufige Probleme
| Problem | Ursache | Lösung |
|---|---|---|
| Plugin lädt nicht | JS-Fehler | Browser-Konsole prüfen |
| Slider zeigt keine Slides | falsche HTML-Struktur | Splide-Klassen prüfen |
| Events feuern nicht | Plugin nicht initialisiert | DOMContentLoaded abwarten |
| Autoplay funktioniert nicht | autoplay: "pause" gesetzt | auf true ändern |
Verwandt
- Architektur: Plugin-Struktur und Build-Output (
dist/storefront/js/). - Twig-Overrides:
data-*-Attribute aus Templates korrekt setzen. - DmfSplideSlider: geteilte Slider-Komponente, von vielen Custom-Elements konsumiert.