Clerk (JTL-Shop 5)
- 1 Einleitung
- 2 Installation und Update
- 3 Konfiguration (Shop)
- 4 Konfiguration Shop bei Clerk.io (Allgemein)
- 5 Hinzufügen der Live-Suche
- 5.1 Design:
- 5.1.1 HTML Datei:
- 5.1.2 CSS Datei:
- 5.2 Content:
- 5.1 Design:
- 6 Hinzufügen der Facetten
- 7 Hinzufügen der Suchergebnisse
- 8 Eigene zusätzliche Slider hinzufügen
- 8.1 EasyTemplate
- 8.2 OnPage Composer
- 9 PHP Events
- 10 Individualisierung
- 11 Formatierungen
- 12 Troubleshooting
- 12.1 Logs prüfen
- 12.1.1 Browser-Log
- 12.1.2 Shop-Log
- 12.1.3 Webserver-Log
- 12.1 Logs prüfen
- 13 FAQ
- 14 Changelog
- 15 Support und Kontakt
Einleitung
Dieses Plugin integriert den Clerk.io Service in Ihren JTL-Shop.
Somit sind personalisierte Produktempfehlungen, eine erweiterte Suche, individualisierte Slider und vieles weitere möglich.
Installation und Update
Systemvoraussetzungen
JTL-Shop 5.1+ (und die beinhalteten Bibliotheken)
JTL-Wawi 1.5
MySQL 5.7
Linux mit Apache 2 / Litespeed (andere Konstellationen sind möglich, aber nicht per se unterstützt)
PHP Version 8.0
Benötigte folgende PHP Erweiterungen:
cURL
GD
ImageMagick
JSON-Support
mbstring
MySQLi
Socket-Support
SPL
eingesetztes Template
NOVA
easyTemplate
andere Templates müssen ggf. mit Servicepartner geprüft werden
Weitere Voraussetzungen
Sie müssen bei Clerk.io registriert sein, um einen API Schlüssel zu erhalten.
Plugin-Installation
Die Installation des Plugins erfolgt im Standardverfahren für JTL-Shop 5, wie es hier beschrieben ist.
Plugin-Update
Für ein Update laden Sie das Plugin wie bei einer Installation in der neuesten Version hoch (und überschreiben ggf. alle vorhandenen Plugin Dateien) oder folgen Sie den Hinweisen des Extension Stores.
Gehen Sie dann in die Plugin Verwaltung und betätigen Sie den Update-Button.
Konfiguration (Shop)
Einstellungen des Plugins
Die Einstellungen des Plugins erreichen Sie über Plugins → Installierte Plugins → S360 Clerk → Einstellung
Bereich | Option | Bedeutung |
|---|---|---|
Allgemein | Cookieless Tracking nutzen | Tracking ohne Cookie Nutzung |
| Warenkorb Tracking nutzen? | Informiert Clerk über Änderungen am Warenkorb (allg. Tracking des Warenkorbs) |
| Kindartikel im Warenkorb Tracking berücksichtigen? | Wenn diese Option aktiviert ist, werden bei Variationskombinationen Kindartikel anstatt der Vaterartikel im Warenkorb Tracking genutzt. Benötigt Plugin Version 1.0.7 |
| E-Mails anonymisieren | E-Mail Adressen werden anonymisiert (als Hash) an Clerk übertragen |
| Clerk JS Name | Falls gesetzt wird das Clerk Javascript nicht von Benötigt Plugin Version 1.0.6 |
|
|
|
Omni-Suche Benötigt Plugin Version 1.0.6 |
|
|
| In Webseite einfügen | Gibt an, ob die Omni-Suche über das Plugin eingebunden werden soll oder ob sie direkt über Clerk.js eingebunden werden soll. In letzterem Fall haben die Plugin-Einstellungen für die Omni-Suche keine Auswirkung → die Einstellungen müssen in diesem Fall im Clerk Backend vorgenommen werden! |
| Omni-Suche aktivieren | Falls deaktiviert wird im Frontend die Clerk Omni-Suche nicht ausgespielt. Falls aktiviert, haben die Einstellungen der Live-Suche und Suche (Ergebnisseite) keine Auswirkungen! |
| Selektor Omni-Suche | Selektor für die Omni-Suche unabhängig von Clerk |
| Clerk templateName Omni-Suche | Template für die Omni-Suche (Clerk Backend → Search → Content → Omnisuche → Insert into website → Im Code den Wert aus “data-template=”@WERT'“) |
|
|
|
Live Suche (Header) | Live Suche aktivieren? | Falls deaktiviert wird im Frontend die Clerk Live Suche nicht ausgespielt. |
| Selektor Livesuche | Selektor für die Live-Suche unabhängig von Clerk |
| Clerk TemplateName Livesuche | Template für die Live-Suche (Clerk Backend → Search → Content → Livesuche → Insert into website → Im Code den Wert aus “data-template=”@WERT'“) |
| Anzahl Suchvorschläge in der Livesuche | Anzahl der Suchvorschläge die angezeigt werden soll |
| Anzahl Kategorievorschläge | Anzahl der Kategorie Vorschläge die angezeigt werden soll |
| Anzahl Seitenvorschläge | Anzahl der Seitenvorschläge die angezeigt werden soll |
| Position | Position des Live-Suche Ergebnisses in Bezug auf den Selektor |
|
|
|
Suche (Ergebnisseite) | Ergebnisseite aktivieren? | Falls deaktiviert wird im Frontend die Clerk Ergebnisseite nicht ausgespielt. |
| Clerk TemplateName Suche | Template für die Live-Suche (Clerk Backend → Search → Content → Suche → Insert into website → Im Code den Wert aus “data-template=”@WERT'“) |
| Position Facetten | Position der Facetten |
| Facetten in URL anzeigen | Facetten in URL anzeigen |
| Clerk Facetten Attribute | Kommagetrennte Liste der verfügbaren Facetten (JTL Merkmale) |
| Clerk Facetten Attribute Multiple Werte | Kommagetrennte Liste der verfügbaren Facetten mit multiplen Werten (JTL Merkmale für ODER Filterung) |
Bereich | Option | Bedeutung |
|---|---|---|
Data Feed | Cronverarbeitung | Art und Weise wie der Cron zur Generierung des Daten Feeds angestoßen werden soll (Im Abschnitt Möglichkeiten der Daten Feed Erstellung genauer erklärt) |
| Stapelgröße | Stapelgröße der Produkte des Feeds (Im Abschnitt Stapelgröße genauer erklärt) |
|
|
|
Produkt Seite | Produktseiten Slider aktivieren? | Falls deaktiviert wird im Frontend der Slider auf der Produktseite nicht ausgespielt. |
| Artikel Selektor Slider | Selektor für den Artikel Slider unabhängig von Clerk |
| Clerk TemplateName Artikel | Namen der Slider Templates die ausgegeben werden sollen. Mehrere Template Namen können als komma-separierte Liste angegeben werden. |
| Slider | Einfügemethode, wie der Slider zum Selektor hinzugefügt werden soll (After, Append, Before, Prepand, ReplaceWith) |
| Duplikate filtern | Verhindert, dass nachfolgende Slider Produkte aus vorherigen Slidern enthalten (Standard: Ja) |
|
|
|
Warenkorb Seite | Warenkorb Slider aktivieren? | Falls deaktiviert wird im Frontend der Slider auf der Warenkorbseite nicht ausgespielt. |
| Warenkorb Selektor Slider | Selektor für den Warenkorb Slider unabhängig von Clerk |
| Clerk TemplateName Warenkorb | Namen der Slider Templates die ausgegeben werden sollen. Mehrere Template Namen können als komma-separierte Liste angegeben werden. |
| Slider | Einfügemethode, wie der Slider zum Selektor hinzugefügt werden soll (After, Append, Before, Prepand, ReplaceWith) |
| Duplikate filtern | Verhindert, dass nachfolgende Slider Produkte aus vorherigen Slidern enthalten (Standard: Ja) |
|
|
|
Powerstep | Powerstep Slider aktivieren? | Falls deaktiviert wird im Frontend der Slider im Powerstep nicht ausgespielt. |
| Powerstep Selektor | Selektor für den Powerstep Slider unabhängig von Clerk |
| Clerk TemplateName Powerstep | Namen der Slider Templates die ausgegeben werden sollen. Mehrere Template Namen können als komma-separierte Liste angegeben werden. |
| Powerstep Einfügemethode | Einfügemethode, wie der Slider zum Selektor hinzugefügt werden soll (After, Append, Before, Prepand, ReplaceWith) |
| Duplikate filtern | Verhindert, dass nachfolgende Slider Produkte aus vorherigen Slidern enthalten (Standard: Ja) |
Bereich | Option | Bedeutung |
|---|---|---|
Kategorie Seite | Kategorieseiten Slider aktivieren? | Falls deaktiviert wird im Frontend der Slider auf der Kategorieseite nicht ausgespielt. |
| Kategorie Selektor Slider | Selektor für den Kategorie Slider unabhängig von Clerk |
| Clerk TemplateName Warenkorb | Namen der Slider Templates die ausgegeben werden sollen. Mehrere Template Namen können als komma-separierte Liste angegeben werden. |
| Slider | Einfügemethode, wie der Slider zum Selektor hinzugefügt werden soll (After, Append, Before, Prepand, ReplaceWith) |
| Duplikate filtern | Verhindert, dass nachfolgende Slider Produkte aus vorherigen Slidern enthalten (Standard: Ja) |
|
|
|
Exit Intent (Ausstiegsabsicht) | Exit Intent Slider aktivieren? | Falls deaktiviert wird im Frontend der Exit Intent nicht ausgespielt. |
| Clerk TemplateName Exit Intent | Template für den Exit Intent |
Erstellung von Datenfeeds
Einstellungen:
Die Einstellungen des Datenfeeds erreichen Sie über Plugins → Installierte Plugins → S360 Clerk → klick auf Zahnrad (siehe Bild)
Hier kann genau ausgewählt werden, welche Daten dem Feed hinzugefügt werden bzw. welche für Sie relevant sind.
Option | Bedeutung |
|---|---|
API Key | Ihr von Clerk erhaltener API Schlüssel |
Private Key | Ihr von Clerk bereitgestellter Legacy private API Key. Wird für die Zugriffsbeschränkung auf den Daten-Feed benötigt. Ab Plugin Version 1.05 wird dieser nicht mehr benötigt und kann leer gelassen. Falls Sie diesen Key doch benötigen, weist Sie Clerk.io darauf hin. |
Sprache | Sprache des Daten Feeds |
Kundengruppe | Preise für die Kundengruppe |
Währung | Währung im Daten Feed |
Facetten Design | Design der Facetten |
Weitere Informationen sind aus der jeweiligen Reihe zu entnehmen (i-Icon).
Weitere Daten Feed Einstellungen
Option | Bedeutung |
|---|---|
Produktauswahl für Feed | Welche Produkte sollen im Feed enthalten sein?
Benötigt Plugin Version 1.0.7 |
Möglichkeiten der Daten Feed Erstellung
Es gibt 3 Möglichkeiten die Generierung der Cron-Jobs anzustoßen:
CLI → Bei CLI wird der Cronjob über den Shop CLI Befehl php cli s360_clerk_shop5:cron aufgerufen
Wawi Abgleich → Cronjob wird beim Wawi Abgleich mit ausgeführt
Aufgabenplaner → Der Cronjob wird zusammen mit anderen Cronjobs z.B Exporte über den Aufruf der cron_inc.php angestoßen. (Standard JTL Cron → JTL5-Shop Backend -> System-> Cron)
Gesamtablauf zur Erstellung des Feeds
Feed im Shop Backend einstellen (Plugins → Installierte Plugins → S360 Clerk → klick auf Zahnrad (siehe Bild))
Nach den Einstellungen, den Feed erstellen (Plugins → Installierte Plugins → S360 Clerk → klick auf Doppelpfeil)
Nach erfolgreichem erstellen muss der Feed im Clerk.io Backend hinterlegt werden:
Stapelgröße
Anstatt alle Produkte auf einmal aus der Datenbank auszulesen, wird immer nur ein Stapel von Produkten auf einmal ausgelesen .
Bei einer großen Anzahl an Produkten, kann so der Speicherverbrauch stark reduziert werden., erhöht dabei allerdings die Laufzeit.
Ist der Wert auf 0 gesetzt, werden ALLE Produkte ausgegeben.
Konfiguration Shop bei Clerk.io (Allgemein)
Das Standardisierte Vorgehen zum hinzufügen neuer Elemente ist:
Öffnen des Clerk.io Backends
Design erstellen
Content hinzufügen
Einstellungen im Plugin Backend
Hinzufügen des Warenkorb-Sliders
Neue Slider können via Clerk Backend erzeugt und hinzugefügt werden.
Anlegen des Design erfolgt im Clerk.io Backend unter Recommendations → Designs.
Hier kann via HTML und CSS das Grund-Design angepasst werden.
Wichtig: Lieferstatus wird momentan nur vom EasyTemplate Slider unterstützt.
Vorlage Design Nova:
{% if products.length != 0 %}
<div class="slick-slider-other is-not-opc">
<div class="hr-sect h2">
{{ headline }}
</div>
<div id="slick-slider-{{ snippets.settings.slider.id }}" class="carousel-arrows-inside carousel slick-smooth-loading slider-no-preview slick-type-product slick-lazy" data-slick-type="product-slider">
{% for product in products %}
<div class="product-wrapper col">
<div id="result-wrapper_buy_form_{{ product.id }}" data-wrapper="true" class="productbox productbox-column">
<div class="productbox-inner">
<div class="row">
<div class="col col-12">
<div class="productbox-image">
<div class="productbox-images">
<a href="{{ product.url }}" title="{{ product.name }}">
<div class="productbox-image square square-image">
<div class="inner">
<picture>
<img src="{{ product.image }}" class="img-fluid" loading="lazy" alt="{{ product.name }}" />
</picture>
</div>
</div>
{% if product.top_article and product.top_article != false %}
<div class="ribbon ribbon-4 productbox-ribbon">
{{ snippets.ribbons.4 }}
</div>
{% endif %}
{% if product.on_sale and product.on_sale != false %}
<div class="ribbon ribbon-2 productbox-ribbon">
{{ snippets.ribbons.2 }}
</div>
{% endif %}
{% if product.in_stock and product.in_stock != false %}
<div class="ribbon ribbon-8 productbox-ribbon">
{{ snippets.ribbons.8 }}
</div>
{% endif %}
{% if product.in_stock and product.in_stock <= 0 %}
<div class="ribbon ribbon-7 productbox-ribbon">
{{ snippets.ribbons.7 }}
</div>
{% endif %}
{% if product.age and product.age <= snippets.settings.newProductmaxDays %}
<div class="ribbon ribbon-3 productbox-ribbon">
{{ snippets.ribbons.3 }}
</div>
{% endif %}
{% if product.average_rating and product.average_rating <= snippets.settings.topProductMinStars %}
<div class="ribbon ribbon-6 productbox-ribbon">
{{ snippets.ribbons.6 }}
</div>
{% endif %}
{% if product.age and product.age < 0 %}
<div class="ribbon ribbon-5 productbox-ribbon">
{{ snippets.ribbons.5 }}
</div>
{% endif %}
{% if product.vorbestellbardate and product.vorbestellbardate > 0 %}
<div class="ribbon ribbon-9 productbox-ribbon">
{{ snippets.ribbons.9 }}
</div>
{% endif %}
{% if product.age and product.age > 0 and product.stock <= 0 %}
<div class="ribbon ribbon-5 productbox-ribbon">
{{ snippets.ribbons.5 }}
</div>
{% endif %}
</a>
</div>
</div>
</div>
<div class="col col-12">
<div class="productbox-title">
<a href="{{ product.url }}" title="{{ product.name }}" class="text-clamp-2">
{{ product.name }}
</a>
</div>
{% if product.reviews_avg > 0 %}
<a class="rating" href="{{ product.url }}#tab-votes" title="{{ snippets.productRating }}: {{ product.reviews_avg }}/5">
{% if product.reviews_avg >= 5 %}
<i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i>
{% else %}
{% if product.reviews_avg >= 4 %}
<i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i>{% if product.reviews_avg > 4 %}<i class="{{ snippets.icons.ratingHalf }}"></i>{% else %}<i class="{{ snippets.icons.ratingEmpty }}"></i>{% endif %}
{% else %}
{% if product.reviews_avg >= 3 %}
<i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i>{% if product.reviews_avg > 3 %}<i class="{{ snippets.icons.ratingHalf }}"></i>{% else %}<i class="{{ snippets.icons.ratingEmpty }}"></i>{% endif %}<i class="{{ snippets.icons.ratingEmpty }}"></i>
{% else %}
{% if product.reviews_avg >= 2 %}
<i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i>{% if product.reviews_avg > 2 %}<i class="{{ snippets.icons.ratingHalf }}"></i>{% else %}<i class="{{ snippets.icons.ratingEmpty }}"></i>{% endif %}<i class="{{ snippets.icons.ratingEmpty }}"></i><i class="{{ snippets.icons.ratingEmpty }}"></i>
{% else %}
{% if product.reviews_avg >= 1 %}
<i class="{{ snippets.icons.rating }}"></i>{% if product.reviews_avg > 1 %}<i class="{{ snippets.icons.ratingHalf }}"></i>{% else %}<i class="{{ snippets.icons.ratingEmpty }}"></i>{% endif %}<i class="{{ snippets.icons.ratingEmpty }}"></i><i class="{{ snippets.icons.ratingEmpty }}"></i><i class="{{ snippets.icons.ratingEmpty }}"></i>
{% else %}
{% if product.reviews_avg > 0 %}
<i class="{{ snippets.icons.ratingHalf }}"></i><i class="{{ snippets.icons.ratingEmpty }}"></i><i class="{{ snippets.icons.ratingEmpty }}"></i><i class="{{ snippets.icons.ratingEmpty }}"></i><i class="{{ snippets.icons.ratingEmpty }}"></i>
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
</a>
{% else %}
<div class="rating productbox-rating-empty"></div>
{% endif %}
<div>
<div class="price_wrapper">
{% if product.has_variations or product.bulk_prices != 0 %}
<span class="price_label pricestarting">
{{ snippets.priceStarting }}
</span>
{% endif %}
<div class="price productbox-price {% if product.on_sale %} special-price{% endif %}">
<span>{{ product.price | money_eu }} {{ globals.currency_symbol }} <span class="footnote-reference">*</span></span>
</div>
{% if product.on_sale %}
<div class="price-note">
<div class="instead-of old-price">
<small class="text-muted-util">
<del class="value">{{ product.original_price | money_eu }} {{ globals.currency_symbol }}</del>
</small>
</div>
</div>
{% endif %}
{% if product.base_price > 0 %}
<div class="price-note">
<span class="value">{{ product.base_price | money_eu }} {{ globals.currency_symbol }} {{ snippets.vpePer }} {{ product.base_price_unit }}</span>
</div>
{% else %}
<div class="price-note"> </div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<script>
$(function() {
$.evo.generateSlickSlider();
$.evo.popover();
});
</script>
{% endif %}
Vorlage Design EasyTemplate:
{% if products.length != 0 %}
<div class="et-widget-clerkslider-headline">
<div class="et-product-slider-headline">
<div class="et-textfield text-align-default et-widget-headline h2">{{ headline }}</div>
</div>
</div>
<div class="et-product-slider-wrapper row">
<div class="col p-0">
<div class="slick-slider-other is-not-opc">
<div id="et-clerk-slider-{{ snippets.settings.slider.id }}" class="et-product-slider-slider et-slider carousel slick-smooth-loading slider-no-preview slick-type-product">
{% for product in products %}
<div class="product-wrapper col">
<div id="result-wrapper_buy_form_{{ product.id }}" data-wrapper="true" class="productbox productbox-show-variations et-item-box productbox-column">
<div class="productbox-inner">
<div class="row">
<div class="col col-12">
<div class="productbox-image">
{% if product.top_article and product.top_article != false %}
<div class="ribbon ribbon-4 productbox-ribbon">
{{ snippets.ribbons.4 }}
</div>
{% endif %}
{% if product.on_sale and product.on_sale != false %}
<div class="ribbon ribbon-2 productbox-ribbon">
{{ snippets.ribbons.2 }}
</div>
{% endif %}
{% if product.in_stock and product.in_stock != false %}
<div class="ribbon ribbon-8 productbox-ribbon">
{{ snippets.ribbons.8 }}
</div>
{% endif %}
{% if product.in_stock and product.in_stock <= 0 %}
<div class="ribbon ribbon-7 productbox-ribbon">
{{ snippets.ribbons.7 }}
</div>
{% endif %}
{% if product.age and product.age <= snippets.settings.newProductmaxDays %}
<div class="ribbon ribbon-3 productbox-ribbon">
{{ snippets.ribbons.3 }}
</div>
{% endif %}
{% if product.average_rating and product.average_rating <= snippets.settings.topProductMinStars %}
<div class="ribbon ribbon-6 productbox-ribbon">
{{ snippets.ribbons.6 }}
</div>
{% endif %}
{% if product.age and product.age < 0 %}
<div class="ribbon ribbon-5 productbox-ribbon">
{{ snippets.ribbons.5 }}
</div>
{% endif %}
{% if product.vorbestellbardate and product.vorbestellbardate > 0 %}
<div class="ribbon ribbon-9 productbox-ribbon">
{{ snippets.ribbons.9 }}
</div>
{% endif %}
{% if product.age and product.age > 0 and product.stock <= 0 %}
<div class="ribbon ribbon-5 productbox-ribbon">
{{ snippets.ribbons.5 }}
</div>
{% endif %}
<div class="productbox-images list-gallery">
<a href="{{ product.url }}" title="{{ product.name }}">
<div class="productbox-image square square-image">
<div class="inner">
<picture>
<img src="{{ product.image }}" class="img-fluid" loading="lazy" alt="{{ product.name }}" />
</picture>
</div>
</div>
</a>
</div>
</div>
</div>
<div class="col col-12">
<div class="productbox-caption">
<div class="et-item-box-manufacturer productbox-manufacturer">
<span>{% if snippets.settings.showBrand %}{{ product.brand }}{% endif %}</span>
</div>
<div class="et-item-box-title productbox-title">
<a href="{{ product.url }}" class="text-clamp-2 link-discreet">
{{ product.name }}
</a>
</div>
<div class="et-item-box-rating productbox-rating">
{% if product.average_rating > 0 %}
<a class="rating" href="{{ product.url }}#tab-votes" title="{{ snippets.productRating }}: {{ product.average_rating }}/5">
{% if product.average_rating >= 5 %}
<i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i>
{% else %}
{% if product.average_rating >= 4 %}
<i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i>{% if product.average_rating > 4 %}<i class="{{ snippets.icons.ratingHalf }}"></i>{% else %}<i class="{{ snippets.icons.ratingEmpty }}"></i>{% endif %}
{% else %}
{% if product.average_rating >= 3 %}
<i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i>{% if product.average_rating > 3 %}<i class="{{ snippets.icons.ratingHalf }}"></i>{% else %}<i class="{{ snippets.icons.ratingEmpty }}"></i>{% endif %}<i class="{{ snippets.icons.ratingEmpty }}"></i>
{% else %}
{% if product.average_rating >= 2 %}
<i class="{{ snippets.icons.rating }}"></i><i class="{{ snippets.icons.rating }}"></i>{% if product.average_rating > 2 %}<i class="{{ snippets.icons.ratingHalf }}"></i>{% else %}<i class="{{ snippets.icons.ratingEmpty }}"></i>{% endif %}<i class="{{ snippets.icons.ratingEmpty }}"></i><i class="{{ snippets.icons.ratingEmpty }}"></i>
{% else %}
{% if product.average_rating >= 1 %}
<i class="{{ snippets.icons.rating }}"></i>{% if product.average_rating > 1 %}<i class="{{ snippets.icons.ratingHalf }}"></i>{% else %}<i class="{{ snippets.icons.ratingEmpty }}"></i>{% endif %}<i class="{{ snippets.icons.ratingEmpty }}"></i><i class="{{ snippets.icons.ratingEmpty }}"></i><i class="{{ snippets.icons.ratingEmpty }}"></i>
{% else %}
{% if product.average_rating > 0 %}
<i class="{{ snippets.icons.ratingHalf }}"></i><i class="{{ snippets.icons.ratingEmpty }}"></i><i class="{{ snippets.icons.ratingEmpty }}"></i><i class="{{ snippets.icons.ratingEmpty }}"></i><i class="{{ snippets.icons.ratingEmpty }}"></i>
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
</a>
{% endif %}
</div>
{% if product.in_stock %}
{% if product.stock >= snippets.settings.storageLightsGreen%}
<div class="delivery-status">
<ul class="list-unstyled">
<li>
<span class="status status-2">
<span class="{{snippets.settings.storageLightIcon}} status-icon"> </span>
<span class="status-text">{{snippets.settings.storageLightTextGreen}}</span>
</span>
</li>
</ul>
</div>
{% endif %}
{% if product.stock > snippets.settings.storageLightsRed and product.stock < snippets.settings.storageLightsGreen %}
<div class="delivery-status">
<ul class="list-unstyled">
<li>
<span class="status status-1">
<span class="{{snippets.settings.storageLightIcon}} status-icon"> </span>
<span class="status-text">{{snippets.settings.storageLightTextYellow}}</span>
</span>
</li>
</ul>
</div>
{% endif %}
{% if product.stock == snippets.settings.storageLightsRed%}
<div class="delivery-status">
<ul class="list-unstyled">
<li>
<span class="status status-0">
<span class="{{snippets.settings.storageLightIcon}} status-icon"> </span>
<span class="status-text">{{snippets.settings.storageLightTextRed}}</span>
</span>
</li>
</ul>
</div>
{% endif %}
{% endif %}
<div class="et-item-box-price">
<div class="price_wrapper">
{% if product.has_variations or product.bulk_prices != 0 %}
<span class="price_label pricestarting">
{{ snippets.priceStarting }}
</span>
{% endif %}
<div class="price productbox-price {% if product.on_sale %} special-price{% endif %}">
<span>{{ product.price | money }} {{ globals.currency_symbol }} <span class="footnote-reference">*</span></span>
</div>
{% if product.on_sale %}
<div class="price-note et-old-price">
<div class="instead-of old-price">
<small class="text-muted-util">
<del class="value">{{ product.original_price | money }} {{ globals.currency_symbol }}</del>
</small>
</div>
</div>
{% endif %}
{% if product.base_price > 0 %}
<div class="price-note">
<span class="value">{{ product.base_price | money }} {{ globals.currency_symbol }} {{ snippets.vpePer }} {{ product.base_price_unit }}</span>
</div>
{% else %}
<div class="price-note"> </div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<div class="et-slider-nav" id="clerk-slider-nav-{{ snippets.settings.slider.id }}">
<div class="et-slider-nav-prev enabled slick-arrow slick-hidden" id="clerk-slider-prev-{{ snippets.settings.slider.id }}">
<i class="{{ snippets.icons.sliderPrevious }}"></i>
</div>
<div class="et-slider-nav-next enabled slick-arrow slick-hidden" id="clerk-slider-next-{{ snippets.settings.slider.id }}">
<i class="{{ snippets.icons.sliderNext }}"></i>
</div>
</div>
</div>
</div>
</div>
<script>
$(function() {
$("#et-clerk-slider-{{ snippets.settings.slider.id }}").slick({{ snippets.settings.slider.settings }});
$.evo.popover();
});
</script>
{% endif %}
Content hinzufügen
Unter Clerk.io → Recommendations → Content , kann der Content für den neuen Warenkorb-Slider erzeugt werden (Button New Content)
Die nun folgende Seite beinhaltet 4 wichtige Abschnitte:
Name your content → Hier wird der Name festgelegt
Choose product logic → Hier kann die Produktlogik ausgewählt werden, unter anderem “Best Sellers” / “Hot Products” und vieles mehr
Select design → Welches Design soll verwendet werden / wie soll die Überschrift lauten und wie viele Produkte sollen angezeigt werden (Wichtig: wird durch das Plugin festgelegt, auch wenn hier eine “Anzahl” hinterlegt werden kann)
Insert into website → Hier wird der Name ausgegeben, den wir in unserem JTL5-Shop Backend unter Clerk TemplateName Warenkorb eingeben müssen
Nachdem alles eingestellt und befüllt wurde, muss nun ins JTL5-Shop Backend gewechselt werden und dort wird nun der Name der Komponente (aus Insert into website) hinterlegt.
Einstellung Plugin Backend
Hinzufügen des Artikel Sliders
Das Hinzufügen des Artikel Sliders verläuft äquivalent zum Warenkorb Slider.
Es werden im Standardfall, die selben Design Dateien verwendet (Slider NOVA / Slider ET), lediglich der Name/Produktlogik im Clerk.io Backend wird verändert und im Plugin Backend wird ein anderer Selektor gewählt.
Hinzufügen der Live-Suche
Verläuft äquivalent zu den Slidern:
Design erstellen
Content hinzufügen
Einstellungen im Plugin Backend
Anlegen des Design erfolgt im Clerk.io Backend unter Search → Designs.
Unterschiede zu den Slidern:
Hier wird auch der CSS Abschnitt befüllt.
Kein Unterschied zwischen Nova und EasyTemplate Design
Design:
HTML Datei:
<div id="clerk-template-live-search" style="background: white">
<div class="clerk-live-search">
<div class="row">
<div class="col-12 col-sm-8 clerk-live-search-products">
{% if products.length != 0 %}
<div class="h4 headline-style">{{ snippets.headlineProducts }}</div>
{% for product in products %}
<div class="product clerk-instant-search-key-selectable">
<a href="{{ product.url }}" class="d-block product-link link-discreet">
<div class="row align-items-center">
<div class="col-2 text-center product-image-wrapper">
<img src="{{ product.image }}" class="product-image img-fluid" />
</div>
<div class="col-7">
<div class="product-name productbox-title et-mb-0">{{ product.name }}</div>
</div>
<div class="col-3">
<div class="price_wrapper text-right">
{% if product.has_variations or product.bulk_prices != 0 %}
<span class="price_label pricestarting">
{{ snippets.priceStarting }}
</span>
{% endif %}
{% if product.on_sale %}
<span class="instead-of old-price">
<small class="text-muted-util">
<del class="value">{{ product.original_price | money_eu }} {{ globals.currency_symbol }}</del>
</small>
</span>
{% endif %}
<span class="price productbox-price {% if product.on_sale %} special-price{% endif %}">
<span>{{ product.price | money_eu }} {{ globals.currency_symbol }} <span class="footnote-reference">*</span></span>
</span>
{% if product.base_price > 0 %}
<div class="price-note">
<span class="value">{{ product.base_price | money_eu }} {{ globals.currency_symbol }} {{ snippets.vpePer }} {{ product.base_price_unit }}</span>
</div>
{% endif %}
</div>
</div>
</div>
</a>
</div>
{% endfor %}
<div class="text-center">
<a href="{{ snippets.searchUrl }}?query={{ query }}" class="btn btn-secondary btn-lg">
{{ snippets.showAllResults }}
</a>
</div>
{% else %}
<div class="text-center">
{{ snippets.textNoResults | replace '###QUERY###' query | highlight query 'clerk-live-search-highlight' }}
</div>
{% endif %}
</div>
<div class="col col-sm-4 clerk-live-search-others">
{% if suggestions.length != 0 %}
<div class="h4 headline-style">{{ snippets.headlineSuggestions }}</div>
<div class="clerk-live-search-others-wrapper clerk-suggestion">
{% for suggestion in suggestions %}
<a href="{{ snippets.searchUrl }}?query={{ suggestion }}">
{{ suggestion }}
</a>
{% endfor %}
</div>
{% endif %}
{% if categories.length != 0 %}
<div class="h4 headline-style">{{ snippets.headlineCategories }}</div>
<div class="clerk-live-search-others-wrapper clerk-category">
{% for category in categories %}
<a href="{{ category.url }}">
{{ category.name }}
</a>
{% endfor %}
</div>
{% endif %}
{% if pages.length != 0 %}
<div class="h4 headline-style">{{ snippets.headlinePages }}</div>
<div class="clerk-live-search-others-wrapper clerk-pages">
{% for page in pages %}
<a href="{{ page.url }}">
{{ page.title }}
</a>
{% endfor %}
</div>
{% endif %}
</div>
</div>
</div>
</div>CSS Datei:
#clerk-template-live-search {
background: var(--white);
padding: 1rem;
box-shadow: 0 0 1.5rem rgba(0, 0, 0, 0.2);
}
#clerk-template-live-search .product {
margin-bottom: 1rem;
}
.clerk-live-search-container .clerk-live-search-others a {
text-decoration: none;
display: block;
margin-bottom: 0.3125rem;
}
.clerk-live-search-others-wrapper .clerk-category {
display: flex;
flex-wrap: wrap;
}Content:
Hinzufügen der Facetten
Design erstellen in Clerk (Clerk.io Backend unter Search → Designs)
Nach der Erstellung wird eine ID, diese muss im Plugin Backend(Plugins → Installierte Plugins → S360 Clerk → klick auf Zahnrad → Einstellungen → Facetten Design) hinterlegt werden
Vorlage Design Nova:
<div class="row">
<aside class="sidepanel-left d-print-none col-12 dropdown-full-width">
<div class="box box-normal">
<div id="clerk-facets-headline-count" class="productlist-filter-headline d-none d-md-flex">
Filter und Sortierung <span class="value"></span>
</div>
<!-- Reset Filter Button -->
{% assign isActive = 0 %}
{% for facet_group in facets %}
{% for facet in facet_group.facets %}
{% if facet.selected %}
{% assign isActive = 1 %}
{% endif %}
{% endfor %}
{% endfor %}
{% if isActive %}
<div title="Alle Filter zurücksetzen" class="snippets-filter-item-all btn btn-danger btn-sm">
<span class="et-active-filter-name">Alle Filter zurücksetzen</span><i class="fas fa-times snippets-filter-item-icon-left"></i>
</div>
{% endif %}
</div>
<!-- Sorting -->
<div class="box box-filter word-break">
<div class="nav-panel">
<ul class="nav flex-column">
<li class="nav-item dropdown facet-sort">
<span class="nav-link dropdown-toggle" role="button" data-toggle="collapse" data-target="#facet-group-sort" aria-expanded="false">
Sortierung
</span>
<div class="collapse snippets-categories-collapse " id="facet-group-sort">
<div id="clerk-sort">
<div class="link-discreet filter-item js-clerk-sort" data-sort="asc_price" title="Preis aufsteigend">
<span class="et-filter-option-name filter-item-value">Preis aufsteigend</span>
</div>
<div class="link-discreet filter-item js-clerk-sort" data-sort="desc_price" title="Preis absteigend">
<span class="et-filter-option-name filter-item-value">Preis absteigend</span>
</div>
<div class="link-discreet filter-item js-clerk-sort" data-sort="asc_age" title="Neueste zuerst">
<span class="et-filter-option-name filter-item-value">Neueste zuerst</span>
</div>
<div class="link-discreet filter-item js-clerk-sort" data-sort="asc_name" title="Artikelname von A bis Z">
<span class="et-filter-option-name filter-item-value">Artikelname von A bis Z</span>
</div>
<div class="link-discreet filter-item js-clerk-sort" data-sort="desc_name" title="Artikelname von Z bis A">
<span class="et-filter-option-name filter-item-value">Artikelname von Z bis A</span>
</div>
</div>
</div>
</li>
</ul>
</div>
<hr class="box-filter-hr">
</div>
<!-- Facet Groups -->
{% for facet_group in facets %}
<div class="box box-filter word-break">
<div class="nav-panel">
<ul class="nav flex-column">
{% assign activeGroup = 0 %}
{% for facet in facet_group.facets %}
{% if facet.selected %}
{% assign activeGroup = 1 %}
{% endif %}
{% endfor %}
<!-- Facet Group -->
<li class="nav-item dropdown facet-{{ facet_group.group }}">
<span class="nav-link dropdown-toggle" role="button" data-toggle="collapse" data-target="#facet-group-{{ facet_group.title }}" aria-expanded="{% if activeGroup == 1}true{% else %}false{% endif %}">
{{ facet_group.title }}
</span>
<!-- Facets -->
<div class="snippets-categories-collapse {% if activeGroup == 1}collapsed show{% else %}collapse{% endif %}" id="facet-group-{{ facet_group.title }}">
{% if facet_group.type == "range" %}
<div class="filter-item clerk-range stagio_range"
data-group="{{ facet_group.group}}"
data-min="{{ facet_group.min }}"
data-max="{{ facet_group.max }}"
data-start="{{ facet_group.start }}"
data-end="{{ facet_group.end }}"
data-step="auto">
</div>
{% endif %}
{% for facet in facet_group.facets %}
<div class="filter-item clerk-facet {% if facet.selected %} active clerk-facet-selected {% endif %}"
data-facet="{{ facet_group.group }}"
data-value="{{ facet.value }}"
data-min="{{ facet.min }}"
data-max="{{ facet.max }}"
title="{{ facet.name }}"
>
<div class="box-link-wrapper">
{% if facet.selected %}
<i class="far fa-check-square snippets-filter-item-icon-right"></i>
{% else %}
<i class="far fa-square snippets-filter-item-icon-right"></i>
{% endif %}
<span class="word-break">{{ facet.name }}</span>
<span class="badge badge-outline-secondary">{{ facet.count }}</span>
</div>
</div>
{% endfor %}
</div>
</li>
</ul>
</div>
<hr class="box-filter-hr">
</div>
{% endfor %}
</aside>
</div>
<script>
if (!window.s360_clerk) {
window.s360_clerk = {};
}
Clerk('on', 'rendered', '#clerk-search', function(content, data) {
window.s360_clerk.query = data.query;
// add product count to facet headline
$("#clerk-facets-headline-count .value").html(data.count);
// register sort layers
$("#clerk-sort .js-clerk-sort").on('click', function() {
let val = $(this).data('sort');
let or = (val.split('_')[0] == 'null') ? eval(val.split('_')[0]) : val.split('_')[0];
let orb = (val.split('_')[1] == 'null') ? eval(val.split('_')[1]) : val.split('_')[1];
window.s360_clerk.sort = val;
Clerk('content', '[data-target][data-query][data-template][data-clerk-content-id]', 'param', {
orderby: orb,
order: or
});
});
// function for remove all filter button
$('.snippets-filter-item-all').on('click', function (e) {
e.preventDefault();
window.location.href = window.location.href.split('?')[0] + "?query=" + window.s360_clerk.query;
});
// set sort layer active
if (window.s360_clerk.sort) {
let sortActive = $('#clerk-sort .js-clerk-sort[data-sort=' + window.s360_clerk.sort + ']');
if (sortActive.hasClass("active") === false) {
sortActive.addClass("active");
sortActive.append('<i class="fas fa-check ml-auto pl-1"></i>');
sortActive.data("sort", "null_null");
}
}
});
</script>
Vorlage Design EasyTemplate:
<div class="row">
<div class="col-12 et-product-list-filter-wrapper">
<div class="et-product-list-filter-top-wrapper">
<div class="bg-gray-lighter et-pt-10 et-pt-md-30 et-pb-15 et-mb-30">
<div class="headline-style h2 d-none d-md-block">
Filter und Sortierung
</div>
<div class="d-flex flex-wrap justify-content-center justify-content-md-start et-product-list-filter-top et-filters-active" data-more-filters-limit="{"xs":0,"sm":0,"md":0,"lg":0,"xl":0}">
<div class="col-6 col-sm-auto d-lg-none et-product-list-filter-mobile text-right">
<div id="et-product-list-filter-collapse-trigger-mobile" class="et-product-list-filter-collapse-trigger-mobile et-collapse btn btn-filter" data-toggle="collapse" aria-expanded="true" data-target="#et-product-list-filter-collapse-content-mobile" aria-controls="et-product-list-filter-collapse-content-mobile">
<i class="fas fa-filter"></i> Filtern
</div>
</div>
<div id="et-product-list-filter-collapse-content-mobile" class="col-12 et-product-list-filter-collapse-content-mobile collapse">
<div class="row">
<div class="col w-100 et-product-list-filter-filters">
<div class="row row-cols-1 row-cols-sm-2 row-cols-md-4 row-cols-lg-4 row-cols-xl-6">
<!-- Sorting -->
<div class="col et-product-list-filter-item">
<div class="dropdown et-product-list-filter-sort">
<button class="btn btn-filter dropdown-toggle et-dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-display="static">
Sortieren
<i class="fas fa-angle-up et-dropdown-open"></i>
<i class="fas fa-angle-down et-dropdown-closed"></i>
</button>
<div class="dropdown-menu" id="clerk-sort">
<div class="link-discreet dropdown-item js-clerk-sort" data-sort="asc_price" title="Preis aufsteigend">
<span class="et-filter-option-name filter-item-value">Preis aufsteigend</span>
</div>
<div class="link-discreet dropdown-item js-clerk-sort" data-sort="desc_price" title="Preis absteigend">
<span class="et-filter-option-name filter-item-value">Preis absteigend</span>
</div>
<div class="link-discreet dropdown-item js-clerk-sort" data-sort="asc_age" title="Neueste zuerst">
<span class="et-filter-option-name filter-item-value">Neueste zuerst</span>
</div>
<div class="link-discreet dropdown-item js-clerk-sort" data-sort="asc_name" title="Artikelname von A bis Z">
<span class="et-filter-option-name filter-item-value">Artikelname von A bis Z</span>
</div>
<div class="link-discreet dropdown-item js-clerk-sort" data-sort="desc_name" title="Artikelname von Z bis A">
<span class="et-filter-option-name filter-item-value">Artikelname von Z bis A</span>
</div>
</div>
</div>
</div>
<!-- Facet Groups -->
{% for facet_group in facets %}
{% assign activeGroup = '' %}
{% for facet in facet_group.facets %}
{% if facet.selected %}
{% assign activeGroup = ' active ' %}
{% endif %}
{% endfor %}
<div class="col et-product-list-filter-item">
<div class="dropdown et-product-list-filter-{{ facet_group.group }}">
<button class="btn btn-filter dropdown-toggle et-dropdown-toggle{{ activeGroup }}" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-display="static">
<span class="text-truncate">{{ facet_group.title }}</span>
<i class="fas fa-angle-up et-dropdown-open"></i>
<i class="fas fa-angle-down et-dropdown-closed"></i>
</button>
<div class="dropdown-menu">
{% if facet_group.type == "range" %}
<div class="clerk-range stagio_range"
data-group="{{ facet_group.group}}"
data-min="{{ facet_group.min }}"
data-max="{{ facet_group.max }}"
data-start="{{ facet_group.start }}"
data-end="{{ facet_group.end }}"
data-step="auto"></div>
{% endif %}
{% for facet in facet_group.facets %}
<div class="clerk-facet
{% if facet.selected %}
clerk-facet-selected
{% endif %} nav-link filter-item d-flex align-items-center"
data-facet="{{ facet_group.group }}"
data-value="{{ facet.value }}"
data-min="{{ facet.min }}"
data-max="{{ facet.max }}"
title="{{ facet.name }}"
rel="nofollow">
<i class="far fa{% if facet.selected %}-check{% endif %}-square snippets-filter-item-icon-right"></i>
<span class="et-filter-option-name filter-item-value">{{ facet.name }}</span>
<span class="badge badge-outline-secondary">{{ facet.count }}</span>
</div>
{% endfor %}
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<!-- Active Filters -->
{% assign isActive = 0 %}
{% for facet_group in facets %}
{% for facet in facet_group.facets %}
{% if facet.selected %}
{% assign isActive = 1 %}
{% endif %}
{% endfor %}
{% endfor %}
{% if isActive %}
<div class="col-12 et-product-list-filter-actions">
<div id="active-filters" class="active-filters">
{% for facet_group in facets %}
{% for facet in facet_group.facets %}
{% if facet.selected %}
<div class="clerk-facet clerk-facet-selected filter-type-{{ facet_group.group }} snippets-filter-item et-active-filter btn btn-xs btn-secondary"
data-facet="{{ facet_group.group }}"
data-value="{{ facet.value }}"
data-min="{{ facet.min }}"
data-max="{{ facet.max }}"
title="Diesen Filter entfernen"
rel="nofollow">
<span class="et-active-filter-value">{{ facet.name }}</span> <i class="fas fa-times snippets-filter-item-icon-left"></i>
</div>
{% endif %}
{% endfor %}
{% endfor %}
<div title="Alle Filter zurücksetzen" class="snippets-filter-item-all et-active-filter-clear btn btn-danger btn-xs">
<span class="et-active-filter-name">Alle Filter zurücksetzen</span><i class="fas fa-times snippets-filter-item-icon-left"></i>
</div>
</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<div class="et-product-list-filter-total" id="clerk-facets-headline-count" >
<span class="value"></span> Artikel
</div>
</div>
</div>
<script>
if (!window.s360_clerk) {
window.s360_clerk = {};
}
Clerk('on', 'rendered', '#clerk-search', function(content, data) {
window.s360_clerk.query = data.query;
// add product count to facet headline
$("#clerk-facets-headline-count .value").html(data.count);
// register sort layers
$("#clerk-sort .js-clerk-sort").on('click', function() {
let val = $(this).data('sort');
let or = (val.split('_')[0] == 'null') ? eval(val.split('_')[0]) : val.split('_')[0];
let orb = (val.split('_')[1] == 'null') ? eval(val.split('_')[1]) : val.split('_')[1];
window.s360_clerk.sort = val;
Clerk('content', '[data-target][data-query][data-template][data-clerk-content-id]', 'param', {
orderby: orb,
order: or
});
});
// function for remove all filter button
$('.snippets-filter-item-all').on('click', function (e) {
e.preventDefault();
window.location.href = window.location.href.split('?')[0] + "?query=" + window.s360_clerk.query;
});
// set sort layer active
if (window.s360_clerk.sort) {
let sortActive = $('#clerk-sort .js-clerk-sort[data-sort=' + window.s360_clerk.sort + ']');
if (sortActive.hasClass("active") === false) {
sortActive.addClass("active");
sortActive.append('<i class="fas fa-check ml-auto pl-1"></i>');
sortActive.data("sort", "null_null");
}
}
});
</script>Hinzufügen der Suchergebnisse
Verläuft äquivalent zu den Slidern:
Design erstellen
Content hinzufügen
Einstellungen im Plugin Backend
Anlegen des Design erfolgt im Clerk.io Backend unter Search → Designs.