Skip to content

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

javascript
// 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

html
<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.

javascript
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:

html
<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).

json
{
    "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:

ViewportAnzahl USPs
Desktop1–4 statisch
Tablet1–2 als Slider mit Endlosschleife
Mobile1 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).

html
<div class="checkout-main" data-custom-checkout-plugin="true">

QuantitySelectorPlugin (Override)

Erweitert Shopwares Mengenauswahl: Input-Validation, Pfeiltasten-Navigation, ARIA-Labels, smooth Animations.

Weitere Plugins

PluginZweck
RemoveExtraH1PluginSEO, entfernt redundante H1-Tags nach DOM-Load.
DeliveryInformationMarginPlugindynamische Margin-Anpassung für Lieferinformationen.
SplideSliderGalleryPluginerweiterte Galerie mit Thumbnail-Sync und Zoom.
CollapseFooterColumnsPlugin (Override)Accordion-Footer auf Mobile.

Splide-Konfiguration

Alle Splide.js-Optionen sind verfügbar.

html
<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 }
       }
     }'>
OptionTypDefaultBeschreibung
typestringslideslide, loop, fade
perPagenumber1sichtbare Slides
perMovenumber1Slides pro Bewegung
gapstring0Abstand zwischen Slides
arrowsbooleantrueNavigationspfeile
paginationbooleantruePagination-Dots
autoplaybooleanfalseautomatisches Abspielen
intervalnumber5000Autoplay-Intervall (ms)
pauseOnHoverbooleantruePause bei Hover
rewindbooleanfalseZurückspringen am Ende
speednumber400Animationsgeschwindigkeit (ms)
easingstringcubic-bezier(0.25, 1, 0.5, 1)Easing-Funktion

Events

javascript
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

javascript
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

javascript
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

javascript
// main.js
import MyCustomPlugin from './plugins/my-custom-plugin';

window.PluginManager.register('MyCustomPlugin', MyCustomPlugin, '[data-my-custom-plugin]');

Plugin verwenden

html
<div data-my-custom-plugin="true"
     data-my-custom-plugin-options='{"myOption": "custom-value"}'>
    <!-- Inhalt -->
</div>

Debugging

javascript
// 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

ProblemUrsacheLösung
Plugin lädt nichtJS-FehlerBrowser-Konsole prüfen
Slider zeigt keine Slidesfalsche HTML-StrukturSplide-Klassen prüfen
Events feuern nichtPlugin nicht initialisiertDOMContentLoaded abwarten
Autoplay funktioniert nichtautoplay: "pause" gesetztauf 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.