Rückblick auf das 3. e-Spirit Usergroup Treffen

Einblick in die CMS-Zukunft durch e-Spirit

In der vergangenen Woche nahmen vier unserer FirstSpirit-Entwickler_innen am dritten Treffen der e-Spirit Usergroup statt. Die Veranstaltung fand hervorragenden Zulauf: Rund 50 Teilnehmer_innen, bestehend aus e-Spirit Lösungs- und Implementierungspartnern sowie Kollegen von e-Spirit und dem DAM-Hersteller CELUM, fanden sich am 7. Februar im Sheraton Airport Conference Center in Frankfurt ein.

Begrüßung und Agenda

Dirk Langenheim von Intentive, Mitgründer und Vorstandsmitglied der e-Spirit Usergroup, eröffnete die Veranstaltung mit einer Begrüßung und einem “Warm-up”Auftakt, in dem er anhand einiger Kundenaussagen die allgemeine Situation in Kundenprojekten umriss. Die bestehenden und oft nicht so flexiblen Infrastrukturen bei vielen Kunden beschrieb er bspw. als eine Hürde für den Wechsel auf ein neues Content Management System. CMS-Projekte auf der “grünen Wiese” sind eben so gut wie ausgestorben.

Im Folgenden standen dann diese Vorträge auf der Agenda:

  • TranslationStudio bzw. Übersetzungsmanagement – Dr. Patrick Sandmann von ID-Media
  • Vorstellung CELUM und CELUM Connect – Gerd Laski von CELUM
  • MondayWebforms & Pinuts Universal Messenger – von Monday Consulting und Pinuts
  • Zukünftige Rolle eines CMS – Lars Onasch von e-Spirit
  • CaaS Case Studies – Lars Onasch / Sebastian Glock von e-Spirit
  • Role Specific View Architecture – Sebastian Glock von e-Spirit

Übersetzungsprozesse optimieren mit dem TranslationStudio

Dr. Patrick Sandmann, CEO von ID-Media, stellte das FirstSpirit Modul “TranslationStudio” vor. Das Übersetzungsmanagement-System organisiert einen effizienten und kostenoptimierten Übersetzungsprozess für Website-Inhalte, indem es das FirstSpirit CMS über einen Connector mit dem verwendeten Translation Management Systemen wie Across oder Trados verbindet.

Der Redakteur wählt die zu übersetzenden Inhalte oder auch ganze Projekte im FirstSpirit aus, exportiert sie und übergibt sie dem TranslationStudio. Der Content wird dort in die vorgegebene Zielsprache übersetzt, automatisiert wieder ins FirstSpirit importiert und kann dann publiziert werden.    

Damit bietet das Modul besonders für Website-Projekte mit vielen Länder- und Sprachvarianten eine deutliche Vereinfachung und Zeitersparnis.

Vorstellung CELUM DAM und Integration in FirstSpirit

Der Vortrag von Gerd Laski, Partnermanager der CELUM GmbH, startete mit der Vorstellung des CELUM DAM. Das professionelle Digital Asset Management System verwaltet und organisiert alle Mediendateien eines Unternehmens unter Berücksichtigung von Rollen- und Berechtigungskonzepten und verteilt diese aktuell und im passenden Format aufbereitet in die verschiedenen Marketing- und Vertriebskanäle.

Vorstellung CELUM DAM
Vorstellung des CELUM DAM

Gerd Laski stellte außerdem das CELUM Ökosystem vor, dass eine Reihe von CELUM Produktvarianten umfasst, die komplette Inhaltssysteme wie Social Media Management, Markenportale und Content Integration optimieren.

Der anschließende Video-Einblick in den von uns entwickelten CELUM Connector, der das CELUM DAM in das FirstSpirit CMS integriert, stieß auf breites Interesse. Die Anbindung von CELUM an das CMS ermöglicht den Redakteuren den direkten Zugriff auf die im DAM abgelegten Mediendateien, ohne die FirstSpirit-Benutzeroberfläche verlassen zu müssen. Dies reduziert u.a. den Arbeitsaufwand und die Fehleranfälligkeit bei der Website-Pflege.    

Was haben MondayWebforms und der Universal Messenger miteinander zu tun?

Monday Consulting und Pinuts gaben in ihrer gemeinsamen Live-Demo einen Überblick über MondayWebforms, einem mächtigen Formularmanager von Monday Consulting, und dessen enges Zusammenspiel mit dem Universal Messenger von Pinuts, einem Tool für den optimierten Kundendialog bspw. via E-Mail-Marketing.

Webforms integriert eine neue Eingabekomponente in FirstSpirit, mit der Redakteure jede Art von Formularen, auch mit komplexen Anforderungen, einfach und intuitiv erstellen können.

Der Universal Messenger von Pinuts, der an das FirstSpirit CMS angebunden wird, verarbeitet Anfragen, die über solche Formulare generiert werden und wertet diese aus.

Zwischen Webforms und dem Universal Messenger gibt es jetzt eine Schnittstelle, welche das Mapping der Benutzer-Eingabe zu der dahinterliegenden Datenbank möglich macht. Diese Schnittstelle erlaubt dem Redakteur auch ein automatisches Mapping, sowie Einbindung von Vorgabewerten wie z.B. Werte für Anrede oder Abteilung.

Quo vadis CMS?

Nach einer Mittagspause mit Zeit zum Austauschen und Netzwerken leitete Lars Onasch von e-Spirit mit ein paar Überlegungen zur Zukunft des CMS das Nachmittagsprogramm ein.

Einblick in die CMS-Zukunft durch e-Spirit
Einblick in die CMS-Zukunft durch Sebastian Glock von e-Spirit

Welche Rolle wird ein CMS in den nächsten Jahren spielen und wie wandeln sich seine Aufgaben und Funktionen? Als mögliches Szenario wurde skizziert, dass ein CMS nur noch der reinen Bereitstellung von Content für verschiedene Endgeräte dienen wird, ohne ein konkretes Layout zu definieren. Die Inhalte werden dann von den Devices, zu denen zunehmend smarte Geräte zählen werden, abgerufen, User-individuell konfiguriert und ausgespielt.  

Case Studies zur Content-as-a-Service-Lösung (CaaS)

Zu diesen Gedanken passte der nächste Beitrag von Sebastian Glock und Lars Onasch gut: Sie stellten anhand einiger Case Studies den Einsatz der e-Spirit Content-as-a-Service-Lösung (CaaS) vor. Diese wurde auf der dmexco 2016 erstmals präsentiert und trägt der zunehmenden Digitalisierung und der stetig größeren Zahl an Touchpoints Rechnung. Diese müssen mit entsprechenden Mengen Content “gefüttert” werden. Mit der Content-Everywhere-Lösung können Inhalte CMS-unabhängig über eine API von verschiedenen Geräten abgerufen werden. Dazu müssen die Ausgabekanäle nicht vorher im Backend programmiert werden.  

Die unterschiedlichen Case Studies zeigten, dass die CaaS-Lösung sehr vielseitig und flexibel zu nutzen ist: Sie wurde bisher von jedem Kunden auf eine andere Weise und für andere Anforderungen, aber jedes Mal erfolgreich eingesetzt.

Role Specific View Architecture

In einem letzten Beitrag stellte Sebastian Glock die e-Spirit-Pläne zum Umbau des FirstSpirit Serversystems vor. Vorgesehen ist ein Baukasten-System für einzelne Komponenten, so dass es zukünftig viele kleine Microservices statt eines großen Servers geben soll. Außerdem ist ein separater Delivery Server für die Ausgabe der Webseiten geplant. Diese Änderungen sollen es Administratoren ermöglichen, einen Client zielgerichteter nach ihren Bedürfnissen zusammen zu stecken. Die Redaktion bekommt dann nur die Funktionen angezeigt, die auch wirklich benötigt werden.

Diskussionsrunden

Im Anschluss an die Vorträge gab es verschiedene Diskussionsrunden zu den bisher gehörten Themen, die mehr oder weniger gut besucht waren.

Mit den Vertretern von e-Spirit wurden u.a. Lizenzthemen diskutiert. Außerdem regten die Teilnehmer an, die Möglichkeiten für ein Distributed Development besser zu optimieren. Immer das Ziel im Blick, dass mehrere Entwickler effizienter zeitgleich an einem Projekt arbeiten können.

Enablement war ein weiteres wichtiges Thema. Um seine Partner-Agenturen noch besser im Projektgeschäft zu unterstützen, sind für die Zukunft mehr Webinare, WebEx-Meetings und Techinare speziell für Entwickler geplant. Einige haben in den letzten 4 Monaten schon stattgefunden, wie z.B. eins zum Thema “Neue Eingabekomponenten und DataAccessPlugins“. Einer unserer Themenwünsche in dem Zusammenhang ist die Vorschau eines hybris-Fensters bei der Integration der E-Commerce-Shopsoftware in FirstSpirit.

In einer Diskussionsrunde zum Projekt- und Modul-Entwicklungsprozess, die unsere FirstSpirit-Entwicklerin Mareike angestoßen und moderiert hat, fand ein gelungener Austausch zu den eingesetzten Technologien und Vorgehensweisen statt. Der Agentur-übergreifende Austausch wurde als sehr positiv empfunden.

Unser Fazit

Für uns war dieses Usergroup Treffen ein sehr interessanter Tag mit viel wertvollem Input und neuen Bekanntschaften. Selten haben wir sonst die Gelegenheit zu einem solch intensiven Austausch mit anderen FirstSpirit-Entwicklern.

Die nächste e-Spirit Usergroup ist bereits in Planung und das ist gut so, denn das Interesse an einem regelmäßigen Austausch ist groß. Unser Wunsch für zukünftige Treffen ist, dass die Beiträge noch stärker und konkreter in die Tiefen technischer Themen gehen. Wir freuen uns auf die nächsten Veranstaltungen!

Übrigens: Nähere Informationen zur e-Spirit Usergroup, seiner Gründung und seinen Zielen finden Sie auch hier:

1 Jahr e-Spirit Usergroup – ein Rückblick
Mitgründer Andreas Kämmer im Interview: Die wichtigsten Erkenntnisse aus einem Jahr e-Spirit Usergroup

Best Practice: Umzug dynamischer Websites in die Cloud

Webinar Umzug von Websites in die Cloud

Der Umzug einer Website in die Cloud kann für Unternehmen eine sinnvolle Alternative zum Server-Hosting sein: Vorteile wie flexible Skalierbarkeit, weltweite Content-Verteilung, geringere Kosten und die Steigerung der Geschwindigkeit im Deployment machen die Cloud vor allem für Unternehmen interessant, die an weltweit verteilten Standorte arbeiten.

Unser Webinar: Umzug in die Cloud am Beispiel des Dornbracht-Händlerportals 

Für unseren Kunden Aloys F. Dornbracht haben wir das Händlerportal beste-badstudios.de, das auf dem Sitecore CMS basiert, in die Microsoft Azure Cloud gebracht. Welche Vorüberlegungen wir dabei angestellt haben und wie sich der Umzug vollzogen hat, haben wir in Kooperation mit unserem CMS-Partner Sitecore in einem Webinar mit dem Thema “Umzug in die Cloud: Flexible, dynamische Websites und Digital Marketing am Beispiel beste-badstudios.de” gezeigt.

In dem Webinar in der vergangenen Woche hat unser Head of Account Management Johannes Tappmeier die verschiedenen Cloud-Möglichkeiten und die Vorteile der Microsoft Azure Cloud im Zusammenspiel mit Sitecore vorgestellt. Außerdem zeigt er, welche konkreten Schritte für den Umzug unseres Kundenprojekts beste-badstudio.de in die Azure Cloud nötig waren.

Dies sind die Webinar-Inhalte im Überblick:

  • Vorstellung des Händlerportals und Projekts “beste-badstudios.de”
  • Vom dedizierten Server zur Cloud: Wir stellen die Cloud-Arten Infrastruktur-as-a-Service (IaaS), Platform-as-a-Service (PaaS) und Software-as-a-Service (SaaS) und die damit einhergehenden unterschiedlichen Verantwortlichkeiten für den Anwender vor.
  • Sitecore on Azure: Wie bekommt man Sitecore in die Azure Cloud? Hier gibt es zwei Möglichkeiten: Zum einen die Standard Sitecore-Installation über den Marketplace ohne die Notwendigkeit technischer Kenntnisse, zum anderen die Nutzung des Azure Resource Manager (ARM) Templates & Web Deploy Packages, die eine flexiblere Installation und Konfiguration erlauben, aber auch mehr technische Fähigkeiten voraussetzen. 
  • Vorteile der Microsoft Azure Cloud wie Skalierbarkeit, hochperformante Bereitstellung von Mediadaten, Benutzerverwaltung, Multi-Plattform Support und Datenschutz nach deutschen Standards.
  • Was macht die Kombination der Microsoft Azure Cloud mit Sitecore interessant?
  • Umzug des Händerportals beste-badstudios.de in die Azure Cloud: Sie erfahren konkret die einzelnen Schritte auf dem Weg in die Cloud. U.a. wird erläutert, welche Cloud-Art wir für welche Anwendung genutzt haben.
  • Zum Schluss steht die Evaluierung der Lösung und ein Ausblick in die Zukunft der Azure Cloud.

Hier können Sie sich die komplette Webinar-Aufzeichnung anschauen:

Über das Portal beste-badstudios.de

Das Händlerportal DIE BESTEN BADSTUDIOS ist eine vom führenden Armaturenhersteller Dornbracht betriebene Website, auf der sich Badstudios präsentieren können. Momentan sind rund 660 Badstudios auf der Plattform vertreten. Die Verwaltung der Plattform wird von den Partnern und Dornbracht gemeinsam vorgenommen. Das Portal, das wir auf Sitecore-Basis realisiert haben, wird in der Azure Cloud betrieben.

Über die Microsoft Azure Cloud als Alternative zum Server-Hosting

Für dynamische und flexible Webseiten ist die Cloud eine echte Alternative zu dedizierten oder virtuellen Servern. Die Microsoft Azure Cloud ist eine der größten Cloud-Plattformen und stellt alle nötigen Services zur Verfügung, die das Hosting einer Corporate Website unterstützt. Aufgrund der gemeinsamen Windows-Basis ist die Azure Cloud besonders für Sitecore-basierte Websites eine interessante Lösung.

Der Google Tag Manager im Überblick

Einführung Google Tag Manager

Was ist der Google Tag Manager?

Im Oktober 2012 hat Google den Tag Manager veröffentlicht, der das Tracking auf Webseiten vereinfachen und unterstützen soll –  daher benötigt der Anwender für die Basisfunktionen keine speziellen Programmierkenntnisse.

Der Google Tag Manager ermöglicht die Messung und Identifizierung des Nutzerverhalten auf der Webseite und verbindet über Tracking-Codes gängige Web-Analyse und Marketing-Tools. Durch den Google Tag Manager kann so das Nutzerverhalten im Hintergrund verfolgt werden. Diese gewonnenen Daten können genutzt werden um Ihre Webseite zu verbessern und zu optimieren.

Wie funktioniert der Google Tag Manager?

Wurden bis dato auf jeder Webseite und Unterseite die Tracking-Codeschnipsel manuell durch Web-Entwickler hinzugefügt, reduziert der Tag Manager nun diese Arbeit um ein Vielfaches und öffnet diese Thematik damit einer breiteren Masse. Statt mehrere einzelne Codes zu implementieren, erfordert der Tag Manager nur noch eine einmalige Änderung am Quellcode.

Der Code macht den Unterschied

Der Google Tag Manager trennt die Implementierung des Tracking von HTML und JavaScript und beschleunigt so die internen Prozesse, da viele Tätigkeiten ohne umfangreiche Programmierkenntnisse durchgeführt werden können.

Der Code lässt sich wie folgt implementieren:

Dieses JS-Code-Snippet  gehört in den <head>

<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXX');</script>
<!-- End Google Tag Manager -->

Und das ist der <noscript>Teil mit iframe

<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->

Weitere technische Informationen erhalten Sie auch hier:
https://developers.google.com/tag-manager/quickstart

Der Aufbau des Google Tag Manager

Anschließende Änderungen kann der Seitenbetreiber nun ohne aufwändige Anpassungen selbst erledigen. Ein weiteres Plus ist die Google-typische, nutzerfreundliche Oberfläche, auf der alles zentral verwaltet und gesteuert werden kann. Schnell & Effizient.

Die Verflechtung der wenigen Elemente im Google Tag Manager werden anhand der Grafik deutlich. Der Nutzer kann je nach Rechteverwaltung auf gesamte Accounts oder einzelne Container zugreifen. Ein Container ist bspw. einer Webseite zugeordnet und regelt in sich geschlossen Tags, Trigger (Regeln) und Variablen (Makros).

Aufbau des Google Tag Manager
© http://www.fourthsource.com/web-development/google-tag-manager-series-2-overview-15816

Was ist ein Tag?

Ein Tag ist ein Code-Schnipsel, der Informationen an Dienste von Dritten übermitteln kann.
Tags können genutzt werden um Informationen zu senden, sie definieren also WAS gemessen wird (z.B. “Formular gesendet”). Der Tag Manager integriert die Code-Schnipsel in die Webseite.

Was steuert ein Trigger im Google Tag Manager?

Eigentlich ganz einfach: die Regel legt fest, unter welchen Bedingungen ein Tag ausgelöst wird. Dies kann ein Seitenaufruf, ein Klick oder eine definierte Zeitspanne sein. Die Regel wird auch Trigger genannt.

Was sind Makros?

Makros – auch Variablen genannt – beschreiben die Daten innerhalb der Tags und Regeln genauer. Und ermöglichen auf einer gesonderten Ebene Variablen zu definieren. Dafür gibt es schon Vorlagen oder man kann sie frei definieren. Beispielsweise lässt sich die Google-Analytics-ID als Makro anlegen und so auf mehrere Seiten übertragen.

Was ist ein Container im Google Tag Manager?

Alle Tags im Tag Manager bilden zusammen einen Container. Dieser Container erhält eine eindeutige ID und wird über ein bereitgestelltes Container-Snippet auf allen Seiten Ihrer Webseite eingefügt. Durch das komfortable Tag-Management im Dashboard können bestehende Tags und Container einfach kopiert und auf andere Webseiten übertragen werden. Dies ist hilfreich wenn Sie z.B. mehrsprachige Länder-Webseiten verwalten.
Dabei kann der Tag Manager sein Hauptvorteil ausspielen – die Zeitersparnis bei der Pflege von großen Webseiten. Wurde der Container einmalig implementiert, werden die Inhalte (also die Tags) durch den Webseitenbetreiber beliebig verändert und gesteuert ohne dabei auf tiefgreifende technische Kenntnisse zurückgreifen zu müssen.

Welche Dienste werden vom Google Tag Manager unterstützt?

Kurz gesagt: viele – Tendenz steigend.
Nach der Installation hat man sofort Zugriff auf eine gute Auswahl fertiger Tag-Vorlagen. Die Bandbreite deckt gängige Lösungen bereits ab: Ob Tags zu Webanalyse-Werkzeugen, Heatmaps, Social Media, Konversion und natürlich ist auch das Google-Portfolio verfügbar.
Eine Liste der Vorlagen bzw. der unterstützten Tags gibt es hier.

Welche Vorteile bietet der Google Tag Manager?

  • Zentrale Verwaltung von Codes
    • Entlastung der IT + Webmaster
    • übersichtliche Struktur und sauberer Quellcode der Webseite
    • Durch die Nutzung der Container verbessert sich die Ladezeit der Webseite
    • Benutzerfreundliche Oberfläche
  • Große Anzahl vorkonfigurierter Codes
    • Regel und Trigger wählen – fertig
  • Umfangreiche Konfigurierbarkeit
    • individuelle Erstellung eigener Codes
    • Tags, Regeln und Variablen sind beliebig kombinierbar
    • Hierarchien lassen sich anlegen (zB Vorrang für Google Analytics-Tag)
  • Vorschaumodus
    • Möglichkeit der Funktionsprüfung und Debugging von Tags
    • Simulation der aktuellen Container-Konfiguration auf der Seite durch den Tag Manager
    • automatische Überprüfung der Tag-Einbindung
  • Versionsbasierte Dokumentation
    • Versionshistorie der Container und Tags wird transparent gespeichert
    • Welches Teammitglied einen Tag erstellt hat oder Änderungen vorgenommen hat, ist in der Übersichtsdarstellung sofort ersichtlich
    • Wiederherstellung einer früheren Version ist möglich

Grenzen des Google Tag Managers

  • Die Anzahl der sofort nutzbaren Tags ist überschaubar. Die Erstellung eigener Tags setzt Grundkenntnisse in HTML voraus und je nach Komplexität auch JavaScript.
  • Besondere Anforderungen an Tags und die Einbindung von weiteren Diensten erreichen schnell die Grenzen des Marketers und erfordern weitergehende Programmierfähigkeiten.
  • Die Möglichkeiten Änderungen in den Tags selbst umzusetzen, umgeht möglicherweise Qualitätssicherungs-Prozesse der IT und bergen Fehlerpotenzial.
  • Nutzen Sie andere Tools abseits des Google-Portfolios, z.B. zur Webanalyse oder Monitoring, müssen Sie entscheiden ob es für Sie nicht zu aufwändig ist, die Tags im Google Tag Manager zu pflegen. Gerade im Bereich der Marketing-Plattformen gibt es hier Lösungen, die bereits einen integrierten Tag Manager besitzen.
  • Die Anbindung an “Nicht-Google”-Analytics-Produkte ist standardmäßig nicht gewährleistet und muss individuell programmiert werden möchte man bspw. Sitecore Analytics oder Adobe Analytics mit den gewonnen Datensätzen versorgen.
  • Eine rollenbasierte Rechtevergabe ist nicht vorhanden, um bspw. der Marketing-Abteilung das publizieren auf einer Testseite zu ermöglichen – die letztendliche Veröffentlichung aber einer übergeordneten Hierarchieebene zuzuweisen.

Fazit

Dieser erste Überblick soll nur einen ersten Eindruck von den Nutzungsmöglichkeiten des Google Tag Manager geben. Zusammenfassend macht der Tag Manager vor allem Sinn, wenn auf den eigenen Webseiten ein umfassendes Tracking eingesetzt werden soll und dabei auf Tools von Google oder Drittanbieter zurückgegriffen werden soll.
Die wesentlichen Stärken sind dabei die Benutzerfreundlichkeit, keine erforderlichen Programmierkenntnisse und die Ressourcenersparnis.

In diesem Einführungsvideo von Google können Sie sich eine Zusammenfassung der Anwendung und Funktionen des Tag Manager anschauen: Zum Video

SEO: Paginierung für Onlineshops und inhaltsreiche Seiten

Paginierung mit rel="next" und rel="prev"

Onlineshop-Betreiber kennen das Problem: Produktkategorieseiten beinhalten oftmals viele Produkte, die über mehrere Seiten verteilt dargestellt werden.

Ohne weiteres Zutun indexieren die Suchmaschinen diese Seiten separat und erkennen hier doppelten Inhalt (“duplicate content”).
Mit ein paar Handgriffen zeigen wir, wie dieses Problem vermieden werden kann.

 

Alles auf einer Seite: Bietet sich eine Gesamtansicht an?

Zuallererst sollten Sie sich die Frage stellen, ob Sie Ihren Besuchern eine “view-all”-Seite anbieten möchten, d. h. alle Produkte – oder besser: alle Elemente, die normalerweise über mehrere Seiten verteilt dargestellt werden – finden Sie dann auf einer Gesamtseite wieder.

Paginierung Gesamtseite

Vorteil: Die paginierten Seiten 1 bis n verweisen über den sogenannten canonical-Tag auf die Seite, auf der die Inhalte zusammengeführt werden. Über einen canonical-Tag teilen Sie den Suchmaschinen mit, wie diese mit (weitgehend) identischen Inhalten verschiedener Seiten umgehen soll. Durch die Angabe verweisen Sie auf eine Orginalressource bzw. URL .

Nachteil: Was bei einem mehrere Seiten langen News-Artikel, der vorzugsweise aus textlichem Inhalt besteht, charmant klingt, stößt bei der Produktkategorieseite eines Onlineshops mit hunderten Artikeln samt Produktbildern auf das Problem langer Ladezeiten. Da Latenzen ein Rankingfaktor sind, hört bei Google der Spaß bei Ladezeiten jenseits von drei Sekunden schnell auf.

 

Ohne Gesamtansicht: Inhalte auf mehrere Seiten verteilt

In solchen Fällen ist eine “view-all”-Page nicht sinnvoll. Hier empfiehlt es sich, alle Folgeseiten, also die Seiten 2 bis n (n=letzte Seite) als ergänzende oder weiterführende Seiten zu kennzeichnen. Sie teilen der Suchmaschine mit, dass die Seiten 1 bis n zusammengehören, also im Grunde als „Kapitel“ in das Inhaltsverzeichnis aufgenommen werden sollen.

Paginierung mit rel="next" und rel="prev"

Die Auszeichnungen erfolgen im <head> Bereich des Markup. Auf der ersten Seite teilen Sie der Suchmaschine über ein <link> Element mit, dass es weitere, ergänzende Seiten gibt:
<link rel=”next” href=”seite-2.html”>

Auf der zweiten bis vorletzten Seite (Kompontentenseiten) definieren Sie die vorige und die nachfolgende Seite:
<link rel=”prev” href=”seite-1.html”>
<link rel=”next” href=”seite-3.html”>

Auf der letzten Seite reicht der Hinweis auf die vorige Seite (eine nächste Seite gibt es ja nicht):
<link rel=”prev” href=”seite-n-1.html”>

Ergänzend soll verhindert werden, dass die Seiten 2 bis n in den Index der Suchmaschinen aufgenommen werden (die Linkkraft der Produkte hingegen soll behalten werden). Dazu bedienen Sie sich folgenden Elements:
<meta name=”robots” content=”noindex, follow”>

Bitte achten Sie darauf, dass die erste Seite ganz regulär indexiert werden darf:
<meta name=”robots” content=”index, follow”>

Zusätzlich zu rel=”prev” und rel=”next” lässt beispielsweise Zalando die Komponentenseiten (Folgeseiten) via canonical-Tag auf die kanonische URL zeigen. Das sieht dann in etwa so aus:
<link rel="canonical" href="seite-1">
Im href-Attribut sind übrigens relative und absolute Pfadangaben erlaubt.

Viele Wege führen nach Rom

Wie oftmals im Online-Marketing gibt es auch in Sachen Paginierung unterschiedliche Herangehensweisen.
So verzichten einige Online Shops auf den Einsatz von rel=”prev” und rel=”next” und verweigern den Suchmaschinen über die Meta-Robots die Indexierung der Komponentenseiten.

Welche Variante Sie auch bevorzugen: Das Hauptaugenmerk sollte darauf liegen, doppelten Inhalt zu vermeiden. Ob Sie dies nun mit einer „view all“ Seite oder über die Angaben im <head> Bereich Ihrer Seite lösen, hängt nicht zuletzt auch vom Kontext ab: Verteilen sich vorwiegend textliche Inhalte über mehrere Seiten, kann eine Gesamtseite – auch unter Usabilty-Gesichtspunkten – ideal sein. Bei bildlastigen Produktkategorieseiten sind rel="prev" und rel="next" sicherlich die bessere Wahl.

Hier sei noch angemerkt, dass nicht sicher ist, ob andere Suchmaschinen wie bpsw. Bing die Attributswerte „next“ und „prev“ in gleicher Weise interpretieren wie Google. Google selbst hat bereits im September 2011 erklärt, die Paginierung von Seiten mit rel=“next“ und rel=“prev“ zu unterstüzen.

 

E-Spirit Usergroup: Perfekter Auftakt im Unperfekthaus

ESUG Gründungsveranstaltung

Unter dem Motto “Real-Life Community für FirstSpirit-Anwender” nahmen rund 40 Teilnehmer an der Auftaktveranstaltung zur Gründung der e-Spirit Usergroup – kurz ESUG – teil.
Das Unperfekthaus in Essen ist Anlaufstelle für Kreative, Co-Worker und bietet neben den Seminarräumen auch Ausstellungsflächen, eine Bühne, eine riesige Dachterrasse und mehrere “WG-Zimmer”.

Aufgrund des zahlreichen und positiven Feedbacks war der Wunsch einer Community für Anwender, Nutzer und Dienstleister schon im Vorfeld der Planungen spürbar gewesen.

Die Teilnehmer-Erwartungen reichten vom konkurrenzfreien Netzwerken, dem Austausch von Erfahrungen und Best-Practices bis hin zum konkreten Vorantreiben von speziellen Anforderungen/ Optimierungen.

Was ist also der Kerngedanke der ESUG?

Die Usergroup möchte den Anwendern, Kunden und Partnern eine unabhängige Plattform bieten, um gegenüber e-Spirit als Hersteller eine Interessenvertretung zu bilden. Durch intensiven Austausch von Wissen und Erfahrungen werden außerdem Synergien zwischen den Partnern geschaffen.

ESUG Gründungsveranstaltung

Die Gründungsveranstaltung

Die Veranstaltung begann mit einem Meet&Greet für die Dienstleister, Freiberufler, Agenturen, Modulhersteller und Kunden. So konnten die Teilnehmer direkt neue Kontakte knüpfen, bestehende auffrischen und vorab die ersten informellen Gespräche führen.

Jörn Bodemann ließ es sich als CEO der e-Spirit AG nicht nehmen, dem gesamten Projekt seine Unterstützung zuzusichern und kündigte den bevorstehenden e-Spirit Partnertag im Phantasialand Brühl an.

Michael Bartz von der USU AG veranschaulichte, wie man Herausforderungen üblicher Anwender-Szenarien durch die Vereinigung der Stärken von CMS und Portalen am Beispiel von Liferay begegnen kann.

Warum gründet man eine Usergroup?

Es gibt viele Gründe sich in einer Interessengruppe zu organiseren – die ausschlaggebendsten sind wohl die gleichen Ziele:

  • Steigerung der Kundenorientierung und -zufriedenheit.
  • Alle erhalten gemeinsam eine gewichtige Stimme gegenüber dem Hersteller.
  • Gemeinsam kann man voneinander lernen und Erfahrungen aus erster Hand austauschen.
  • Miteinander kann man die gängigen Painpoints beim Hersteller anmerken.
  • Zusammen können eigene Module, Features und Lösungen erarbeitet werden.
  • Eine Verbesserung der Entwickler- und Anwenderorientierung.

Außerdem soll über Kooperationen der Nachwuchs aktiv gefordert und gefördert werden und damit auch ein wichtiger, gemeinnütziger Beitrag geleistet werden.

Vortrag von Andreas Kämmer, comspace bei der ESUG Gründungsveranstaltung

Vereinsgründung mit (e-)Spirit

Nach der Mittagspause ging es im zweiten Teil um die Gründung des Vereins mit allen organisatorischen Facetten:

  • Welche Voraussetzungen sollen künftige Mitglieder mitbringen?
  • Wie kann sich der Verein seine Hersteller-Unabhängigkeit bewahren?
  • Was soll zukünftig Inhalt kommender Veranstaltungen sein?
  • Welche Veranstaltungsarten, wie z.B. Roundtables, Barcamps, Workhops sind seitens der Mitglieder gewünscht?
  • Wie soll der fachliche Austausch stattfinden
  • Wie werden gemeinsam erarbeitete Produkte, Projekte, Konzepte & Techniken zukünftig gehandhabt?

Die beschlossenen Details zur Usergroup, können in Kürze in der aktuellen Satzung eingesehen werden.

Der Vorstand:

Im Rahmen der ersten Gründungssitzung wurde der Verein gegen 17.05 Uhr gegründet und der Vorstand wie folgt gewählt:
1. Vorsitzender – Andreas Kämmer, comspace GmbH & Co.KG
2. Vorsitzender – Dirk Langenheim, Intentive GmbH
3. Vorsitzender – Andreas Gromadecki, Pinuts media + science GmbH

Zukunftsausblick

Als erste, kurzfristige Maßnahmen wurden beschlossen die Mitgliederwerbung und die thematische Schwerpunktsetzung für die kommenden Veranstaltungen in den Vordergrund zu stellen. Daneben wurde die erste Kooperation mit dem anstehenden e-Spirit Barcamp angeregt, die Bildung von technisch ausgerichteten Arbeitskreisen oder Kooperationen mit Hochschulen.

Die Erwartungen an kommende Veranstaltungen sind hoch. So könnten Teilnehmer Ihre eigenen Erfahrungen in Form von Usecases und Workarounds teilen, wie es hier zum Beispiel Arithnea und Publicis Pixelpark vormachen.
Wer sich nun von den Vorteilen der Usergroup angesprochen fühlt und mitmachen möchte, kann sich auf www.e-spirit-usergroup.de gleich anmelden oder auf Twitter unter dem Hashtag #esug auf dem Laufenden bleiben.

Sitecore Commerce Connect – Teil 5: Warenkorb verwalten

Bisher ging es in dieser Serie um die Verwaltung und Darstellung von Produkten und Preisen aus Hybris. Das Ziel dieses Artikels ist es auch erste Prozesse rund um den Warenkorb mittels Sitecore Commerce Connect abbilden zu können.

Warenkorb

Die zentrale Überlegung am Anfang eines Projektes ist, welches System zu welcher Zeit die Zuständigkeit für den Warenkorb hat. Wird der Warenkorb immer auf beiden Seiten synchron gehalten, das heißt jede Änderung am Warenkorb wird unmittelbar an das externe Shopsystem (kurz ECS) gemeldet, oder wird der Warenkorb im ECS nur zu definierten Zeitpunkten synchronisiert, also z.B. beim Checkout? Letzteres bedingt weniger Requests an das ECS, aber Sitecore-seitig ist dann z.B. eine Warenkorbwertermittlung erforderlich, die im schlechtesten Fall nicht mit der im ECS synchron ist.

Warenkorb-Verwaltung

Im Rahmen unserer Evaluierung ist das ECS für den Warenkorb zuständig und Sitecore meldet alle Änderungen unmittelbar an das ECS. Für die Darstellung auf der Webseite werden die Daten rund um den Warenkorb wiederum immer online vom ECS abgefragt.
Außerdem haben wir uns entschieden, den mitgelieferten Engagement Plan ‘Abandoned Carts’ gleich mit zu nutzen, zumal dafür scheinbar keine weitere Implementierung erforderlich ist.

Warenkorb anlegen/ abfragen

Für alle Funktionen rund um den Warenkorb ist der Service Provider ‚CartServiceProvider‘ des Cart Service Layers zuständig.

Beispiel Verwendung CartServiceProvider.CreateOrResumeCart

[csharp]
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Comspace.Sitecore.CommerceConnect.Services.Prices;
using Sitecore;
using Sitecore.Analytics;
using Sitecore.Commerce.Entities.Carts;
using Sitecore.Commerce.Services.Carts;
using Sitecore.Commerce.Services.Prices;
using Sitecore.Data;

namespace Comspace.Sitecore.CommerceConnect.Services.Carts
{
/// <summary>
/// Sitecore.Commerce.Carts.config
/// </summary>
public class CartManager
{
public const string TrackerAttachmentKeyCart = "Comspace.Sitecore.CommerceConnect_Cart";

public static Cart GetCart()
{
if (!Tracker.Current.Contact.Attachments.ContainsKey(TrackerAttachmentKeyCart))
{
//create cart
var createOrResumeCartRequest = new CreateOrResumeCartRequest(
"Website",
Context.User.Profile.Email,
"Default",
Context.User.Profile.Email); //NOTE FindCartInEaState: c.CustomerId == request.CustomerId
var cart = new CartServiceProvider().CreateOrResumeCart(createOrResumeCartRequest).Cart;

//persist cart
Tracker.Current.Contact.Attachments[TrackerAttachmentKeyCart] = cart;
}
return Tracker.Current.Contact.Attachments[TrackerAttachmentKeyCart] as Cart;
}
}

//…
}
[/csharp]

Pipeline loadCart

Die Anbindung des ECS erfolgt mittels Erweiterung der Pipeline ‚loadCart‘ der Sitecore.Commerce.Carts.config.
.config

[xml]
<!– LOAD CART
Gets the cart object that matches the specified criteria.
This pipeline is responsible for reading data for a specific cart that is managed by the commerce system.
This pipeline reads the cart data from the commerce system and converts that data into the Commerce format.
–>
<commerce.carts.loadCart>
<processor type="Comspace.Sitecore.CommerceConnect.Hybris.Pipelines.Carts.LoadCart, Comspace.Sitecore.CommerceConnect.Hybris" patch:after="processor[@type=’Sitecore.Commerce.Pipelines.Carts.LoadCart.LoadCartFromEaState, Sitecore.Commerce‘]"/>
</commerce.carts.loadCart>
[/xml]

Processor LoadCart

[csharp]
using Comspace.Sitecore.CommerceConnect.Hybris.Connector;
using Comspace.Sitecore.CommerceConnect.Hybris.Connector.Model.Cart;
using Comspace.Sitecore.CommerceConnect.Services.Carts;
using Sitecore.Commerce.Entities.Carts;
using Sitecore.Commerce.Pipelines;
using Sitecore.Commerce.Pipelines.Carts.Common;
using Sitecore.Commerce.Services.Carts;

namespace Comspace.Sitecore.CommerceConnect.Hybris.Pipelines.Carts
{
/// <summary>
/// commerce.carts.loadCart
/// </summary>
public class LoadCart : CartPipelineProcessor
{
public override void Process(ServicePipelineArgs args)
{
var loadCartRequest = args.Request as LoadCartRequest;

//get from ECS
ExternalCart externalCart = CartConnector.Load(global::Sitecore.Context.Language.Name, loadCartRequest.UserId);

//convert to commerce connect cart
Cart cart = new Cart();
cart.ExternalId = externalCart.Code;
cart.ShopName = loadCartRequest.ShopName;
cart.UserId = loadCartRequest.UserId;

//init totals
cart = CartManager.UpdateCartTotals(cart); //NOTE prevent multiple request

//persist for next processor
((CartResult) args.Result).Cart = cart;
}
}
}
[/csharp]

Produkt zum Warenkorb hinzufügen

Beispiel Verwendung CartServiceProvider.AddCartLines

[csharp]
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Comspace.Sitecore.CommerceConnect.Services.Prices;
using Sitecore;
using Sitecore.Analytics;
using Sitecore.Commerce.Entities.Carts;
using Sitecore.Commerce.Services.Carts;
using Sitecore.Commerce.Services.Prices;
using Sitecore.Data;

namespace Comspace.Sitecore.CommerceConnect.Services.Carts
{
/// <summary>
/// Sitecore.Commerce.Carts.config
/// </summary>
public class CartManager
{
//…

public static Cart AddLine(string externalId, string sitecoreItemId, uint quantitiy)
{
Cart cart = GetCart();

//create cartlines
List<CartLine> lines = new List<CartLine>
{
new CartLine
{
Product = new CartProduct
{
ProductId = externalId,
SitecoreProductItemId = new ID(sitecoreItemId),
Price = PriceManager.GetPrice(externalId, Context.Language)
},
Quantity = quantitiy,
LineNumber = (uint) (cart.Lines.Count + 1)
}
};

//add cart lines
AddCartLinesRequest addCartLinerequest = new AddCartLinesRequest(cart, new ReadOnlyCollection<CartLine>(lines));
CartResult cartResult = new CartServiceProvider().AddCartLines(addCartLinerequest);

return cartResult.Cart; //result contains the updated cart
}
}
}
[/csharp]

Pipeline addCartLines

.config

[xml]
<!– ADD CART LINES
This pipeline is responsible for adding a new line to the shopping cart and recording a corresponding page event in DMS.
This happens when a product is added to the cart.
–>
<commerce.carts.addCartLines>
<processor type="Comspace.Sitecore.CommerceConnect.Hybris.Pipelines.Carts.AddLineToCart, Comspace.Sitecore.CommerceConnect.Hybris" patch:after="processor[@type=’Sitecore.Commerce.Pipelines.Carts.AddCartLines.AddLinesToCart, Sitecore.Commerce‘]"/>
</commerce.carts.addCartLines>
[/xml]

Processor AddCartLines

[csharp]
using System.Linq;
using Comspace.Sitecore.CommerceConnect.Hybris.Connector;
using Sitecore.Commerce.Entities.Carts;
using Sitecore.Commerce.Pipelines;
using Sitecore.Commerce.Services.Carts;

namespace Comspace.Sitecore.CommerceConnect.Hybris.Pipelines.Carts
{
/// <summary>
/// commerce.carts.addCartLines
/// </summary>
public class AddLineToCart : PipelineProcessor<ServicePipelineArgs>
{
public override void Process(ServicePipelineArgs args)
{
var cartLinesRequest = args.Request as CartLinesRequest;

//add to ECS
Cart cart = cartLinesRequest.Cart;
CartLine cartline = cartLinesRequest.Lines.First();
CartConnector.AddLineToCard(global::Sitecore.Context.Language.Name, cart, cartline);
}
}
}
[/csharp]

Warenkorb Summen

Damit die Summen im Warenkorb immer korrekt sind und keine Sitecore-seitige Berechnung stattfinden muss, werden auch die Warenkorb Summen immer online aus dem ECS geholt. Dafür muss die Pipeline ‘saveCart’ erweitert werden:

Pipeline saveCart

.config

[xml]
<!– SAVE CART
Saves the cart object to the external system and in Sitecore EA state.
–>
<commerce.carts.saveCart>
<processor type="Comspace.Sitecore.CommerceConnect.Pipelines.Carts.UpdateCartTotals, Comspace.Sitecore.CommerceConnect" patch:after="processor[@type=’Sitecore.Commerce.Pipelines.Carts.Common.SaveCartToEaState, Sitecore.Commerce‘]"/>
</commerce.carts.saveCart>
[/xml]

Processor UpdateCartTotals

[csharp]
using Comspace.Sitecore.CommerceConnect.Services.Carts;
using Sitecore.Commerce.Entities.Carts;
using Sitecore.Commerce.Pipelines;
using Sitecore.Commerce.Services.Carts;

namespace Comspace.Sitecore.CommerceConnect.Pipelines.Carts
{
/// <summary>
/// commerce.carts.saveCart
/// </summary>
public class UpdateCartTotals : PipelineProcessor<ServicePipelineArgs>
{
public override void Process(ServicePipelineArgs args)
{
var cartRequest = (CartRequestWithCart) args.Request;

//get from ECS
Cart cart = CartManager.UpdateCartTotals(cartRequest.Cart);

//persist for next processor
((CartResult) args.Result).Cart = cart;
}
}
}
[/csharp]

Beispiel Verwendung PricingServiceProvider.GetCartTotal

[csharp]
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Comspace.Sitecore.CommerceConnect.Services.Prices;
using Sitecore;
using Sitecore.Analytics;
using Sitecore.Commerce.Entities.Carts;
using Sitecore.Commerce.Services.Carts;
using Sitecore.Commerce.Services.Prices;
using Sitecore.Data;

namespace Comspace.Sitecore.CommerceConnect.Services.Carts
{
/// <summary>
/// Sitecore.Commerce.Carts.config
/// </summary>
public class CartManager
{
//…

public static Cart UpdateCartTotals(Cart cart)
{
var request = new GetCartTotalRequest();
request.Cart = cart;

//get from ECS
var cartTotalResult = new PricingServiceProvider().GetCartTotal(request); //result contains the updated cart

Tracker.Current.Contact.Attachments[TrackerAttachmentKeyCart] = cartTotalResult.Cart; //refresh cache
return cartTotalResult.Cart;
}
}
}
[/csharp]

Stolpersteine

Der Processor ‘FindCartInEaState’ benötigt eine CustomerId, damit der Contact ermittelt werden kann. Dafür muss die eigentlich optionale CustomerId mit an den ‘CreateOrResumeCartRequest’ übergeben werden (siehe oben). Anderenfalls wird immer wieder ein neuer Warenkorb angelegt, obwohl für den Contact bereits einer existiert.

Resumé

Und auch diesen letzten Beitrag möchte ich mit ein paar Eindrücken und Erkenntnissen abschließen:

  • Der Cart Sercice Layer ist sehr umfangreich und im Rahmen der Evaluierung konnte nur ein sehr kleiner Ausschnitt evaluiert werden.
  • Eine Herausforderung in einem echten Projekt sind die Zuständigkeit und Synchronisation zwischen dem Sitecore Shop und dem ECS. Was wird wo zwischengespeichert und wann an wen gemeldet?
  • Wie auch schon unter Stolpersteine beschrieben, war der Zugriff auf die Contacts im Engangement Plan (automatisch im Hintergrund) immer wieder holprig. Eine der Ursachen war sicherlich die Entwicklungsumgebung: wechselnde Browser, plötzliche Neustarts etc.  Hier müsste in einem echten Projekt eine kritische Analyse erfolgen.
  • Auch dem Umgang mit Fehlern in der Verarbeitung muss in einem echten Projekt eine hohe Aufmerksamkeit gewidmet werden – Stichwort Transaktionssicherheit.

So, das war’s erstmal von meiner Seite zum Thema Commerce Connect. Ich freue mich über euer Feedback 🙂

Alle voran gegangenen Artikel dieser Serie findet ihr hier:
Teil 1: Ein Überblick
Teil 2: Produkte synchronisieren
Teil 3: Klassifizierungen synchronisieren
Teil 4: Preise darstellen

Sitecore Commerce Connect – Teil 3: Klassifizierungen synchronisieren

Im letzten Teil dieser Serie ging es um die Synchronisation von Produkten. Das Ziel dieses Blog-Artikels ist es auch Klassifizierungen unidirektional aus dem Sitecore heraus mit dem externen Commerce System (kurz ECS, in unserem Fall Hybris) zu synchronisieren und den Produkten zuzuordnen.

Klassifizierungen sind im Projekt individuell definierbare Spezifikationen zur Beschreibung von Produkten. Die sog. Classifications in Sitecore können über eine Parent-Verknüpfung (ExternalParentID) beliebig geschachtelt werden, die erste Ebene ist aber immer eine Gruppe, eine sog. ClassificationGroup.
ClassificationRepo

Synchronisation Klassifizierungen

Um Klassifizierungen zu synchronisieren muss zunächst die Pipeline ’synchronizeClassifications‘ der Sitecore.Commerce.Products.config erweitert werden:

Pipeline synchronizeClassifications

.config

[xml]
<!– SYNCHRONIZE CLASSIFICATIONS –>
<commerce.synchronizeProducts.synchronizeClassifications>
<processor type="Sitecore.Commerce.Pipelines.Products.SynchronizeClassifications.ReadSitecoreClassifications, Sitecore.Commerce">
<patch:delete />
</processor>
<processor type="Sitecore.Commerce.Pipelines.Products.SynchronizeClassifications.ResolveClassificationsChanges, Sitecore.Commerce">
<patch:delete />
</processor>
<processor type="Sitecore.Commerce.Pipelines.Products.SynchronizeClassifications.SaveClassificationsToExternalCommerceSystem, Sitecore.Commerce" >
<patch:delete />
</processor>
<processor type="Comspace.Sitecore.CommerceConnect.Hybris.Pipelines.Classifications.ReadClassifications, Comspace.Sitecore.CommerceConnect.Hybris" patch:after="processor[@type=’Sitecore.Commerce.Pipelines.Products.SynchronizeClassifications.ReadExternalCommerceSystemClassifications, Sitecore.Commerce‘]" />
<processor type="Comspace.Sitecore.CommerceConnect.Hybris.Pipelines.Classifications.ReadClassificationGroups, Comspace.Sitecore.CommerceConnect.Hybris" patch:after="processor[@type=’Sitecore.Commerce.Pipelines.Products.SynchronizeClassifications.ReadExternalCommerceSystemClassifications, Sitecore.Commerce‘]" />
</commerce.synchronizeProducts.synchronizeClassifications>
[/xml]

Processor ReadClassificationGroups

[csharp]using System.Collections.Generic;
using System.Linq;
using Comspace.Sitecore.CommerceConnect.Hybris.Connector;
using Comspace.Sitecore.CommerceConnect.Hybris.Connector.Model;
using Sitecore.Commerce.Entities.Products;
using Sitecore.Commerce.Pipelines;
using Sitecore.Commerce.Services.Products;

namespace Comspace.Sitecore.CommerceConnect.Hybris.Pipelines.Classifications
{
/// <summary>
/// commerce.synchronizeProducts.synchronizeClassifications
/// </summary>
public class ReadClassificationGroups : PipelineProcessor<ServicePipelineArgs>
{
public override void Process(ServicePipelineArgs args)
{
var request = args.Request as SynchronizationRequest;
var groups = request.Properties["ClassificationGroups"] as List<ClassificationGroup>; //integration guide (page 9)
groups = groups ?? new List<ClassificationGroup>();

//get groups from ECS
IEnumerable<ExternalCategoryGroup> categoryGroups = ClassificationConnector.Load(request.Language);

//convert and add to commerce connect list
groups.AddRange(from @group in categoryGroups
select new ClassificationGroup
{
ExternalId = @group.Code,
Name = @group.Name
});

//persist for next processor
request.Properties["ClassificationGroups"] = groups;
}
}
}[/csharp]

Processor ReadClassifications

[csharp]using System.Collections.Generic;
using System.Collections.ObjectModel;
using Comspace.Sitecore.CommerceConnect.Hybris.Connector;
using Comspace.Sitecore.CommerceConnect.Hybris.Connector.Model;
using Sitecore.Commerce.Entities.Products;
using Sitecore.Commerce.Pipelines;
using Sitecore.Commerce.Services.Products;

namespace Comspace.Sitecore.CommerceConnect.Hybris.Pipelines.Classifications
{
/// <summary>
/// commerce.synchronizeProducts.synchronizeClassifications
/// </summary>
public class ReadClassifications : PipelineProcessor<ServicePipelineArgs>
{
public override void Process(ServicePipelineArgs args)
{
var request = args.Request as SynchronizationRequest;
var groups = request.Properties["ClassificationGroups"] as List<ClassificationGroup>; ////integration guide (page 9)
groups = groups != null ? groups : new List<ClassificationGroup>();

foreach (ClassificationGroup group in groups)
{
var classifications = new List<Classification>();

//get categories from ECS
foreach (ExternalCategory externalCategory in ClassificationConnector.Load(group.ExternalId, request.Language)) //TBD
{
//convert to commerce connect classification
var classification = new Classification();
classification.ExternalId = externalCategory.Code;
classification.Name = externalCategory.Name;
classifications.Add(classification);

//…with sub-classifications
HandleSubCategories(externalCategory, classifications);
}
group.Classifications = new ReadOnlyCollection<Classification>(classifications);
}

//persist for next processor
request.Properties["ClassificationGroups"] = groups;
}

private static void HandleSubCategories(ExternalCategory parentCategory, List<Classification> allClassifications)
{
if (parentCategory.Categories != null)
{
foreach (var category in parentCategory.Categories)
{
var classification = new Classification();
classification.ExternalId = category.Code;
classification.Name = category.Name;
classification.ExternalParentId = parentCategory.Code;

allClassifications.Add(classification);
HandleSubCategories(category, allClassifications);
}
}
}
}
}
[/csharp]

Klassifizierungen Produkten zuordnen

Anschließend müssen die Klassifizierungen nur noch den Produkten zugeordnet werden. Und auch dafür muss wieder eine Pipeline der Sitecore.Commerce.Products.config erweitert werden:

Pipeline synchronizeProductClassifications

.config

[xml]<!– SYNCHRONIZE PRODUCT CLASSIFICATIONS
This pipeline is responsible for synchronizing and updating the references between a given product and associated classifications and categories within.
It’s assumed that classifications are already synchronized and present in CMS.
The references to categories are stored directly on the main product item. –>
<commerce.synchronizeProducts.synchronizeProductClassifications>
<processor type="Comspace.Sitecore.CommerceConnect.Hybris.Pipelines.Products.ReadProductClassifications, Comspace.Sitecore.CommerceConnect.Hybris" patch:after="processor[@type=’Sitecore.Commerce.Pipelines.Products.SynchronizeProductClassifications.ReadExternalCommerceSystemProductClassifications, Sitecore.Commerce‘]" />
</commerce.synchronizeProducts.synchronizeProductClassifications>[/xml]

Processor ReadProductClassifications

[csharp]using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Comspace.Sitecore.CommerceConnect.Hybris.Connector;
using Comspace.Sitecore.CommerceConnect.Hybris.Connector.Model;
using Sitecore.Commerce.Entities.Products;
using Sitecore.Commerce.Pipelines;
using Sitecore.Commerce.Services.Products;

namespace Comspace.Sitecore.CommerceConnect.Hybris.Pipelines.Products
{
/// <summary>
/// commerce.synchronizeProducts.synchronizeProductClassifications
/// </summary>
public class ReadProductClassifications : ReadProduct
{
public override void Process(ServicePipelineArgs args)
{
var request = args.Request as SynchronizeProductRequest;
var product = request.Properties["Product"] as Product;
var groups = request.Properties["ClassificationGroups"] as List<ClassificationGroup>;
groups = groups != null ? groups : new List<ClassificationGroup>();

//get product from ECS
ExternalProduct externalProduct = ProductConnector.Load(request.Language, product.ExternalId); //tbd
if (externalProduct != null && IsProductValidForImport(externalProduct))
{
//convert to commerce connect product classification groups and classifications
foreach (ExternalCategoryGroup externalCategoryGroup in externalProduct.CategoryGroups)
{
ClassificationGroup group = new ClassificationGroup();
group.ExternalId = externalCategoryGroup.Code;
group.Name = externalCategoryGroup.Name;

IEnumerable<Classification> classifications = from externalCategory in externalCategoryGroup.Categories
select new Classification
{
ExternalId = externalCategory.Code,
Name = externalCategory.Name
};
group.Classifications = new ReadOnlyCollection<Classification>(classifications.ToList());

groups.Add(group);
}
}

//persist for next processor
request.Properties["ClassificationGroups"] = groups;
}
}
}[/csharp]

Resumé

Mein erster Eindruck:

  • Es gibt viel Dokumentation, aber z.B. zum Thema Zuordnung von Klassifikationen zu Produkten konnte ich nichts finden. Da habt ihr es jetzt ja besser 😉 Häufig war dann doch dotPeek mein bester Freund.
  • Der Differenzabgleich funktionierte problemlos, Mehrsprachigkeit war im Kontext der Zuordnung von Klassifizierungen zu Produkten noch etwas holprig, da sollte ein zweiter Blick erfolgen.

Wenn ihr mehr zum Sitecore Commerce Connect wissen wollt, dann schaut mal hier:

Sitecore Commerce Connect – Teil 2: Produkte synchronisieren

Im ersten Teil dieser Serie ging es darum einen kurzen Überblick über das Sitecore Commerce Connect Modul zu verschaffen. In diesem Beitrag geht es nun um die Synchronisation von Produkten zwischen einem externen Shopsystem (kurz ECS, in unserem PoC Hybris) und Sitecore.

Zunächst ist es wichtig zu verstehen, dass Preise und Bestand im Commerce Connect nicht als Produktstammdaten gelten. Der Bestand ändert sich ständig und DEN Preis gibt es ja auch nicht, Preisfindung ist ein sehr komplexes Thema. Sitecore geht davon aus, dass diese Informationen online vom ECS ermittelt und geliefert werden. Im Teil 4 dieser Serie wird dann beschrieben, wie ihr auch an diese Informationen kommt.

image00

Die Hoheit für die Produktdaten liegt sicherlich im ECS. Für die Synchronisation der Produktdaten schlägt Sitecore folgende Varianten vor:

  1. Produkte als Items in Sitecore Datenbank (optional bidirektional)
  2. Produkte in ECS, Zugriff über Sitecore Data Provider
  3. Produkte in ECS, Zugriff über Sitecore Index

Wir haben uns im Verlauf des PoC für die Variante 1 entschieden, da diese standardmäßig vom Sitecore so vorgesehen ist und den höchsten Komfort bietet. In der Sitecore Commerce Components Overview im Kapitel “Products” sind einige Argumente für oder gegen die unterschiedlichen Variante aufgeführt.

So, jetzt aber Butter bei die Fische 🙂

Installation Modul

Falls ihr das Modul noch nicht installiert habt, findet ihr wie gewohnt eine gute Installationsanleitung auf dev.sitecore.net.

Synchronisation Produkte

Das Ziel: Titel, Beschreibung und Bilder der Produkte aus dem externen Shopsystem mit Sitecore zu synchronisieren.

image01

In folgende Pipelines der Sitecore.Commerce.Products.config muss für die unidirektionale Synchronisation der Produkte eingegriffen werden:

Pipeline getExternalCommerceSystemProductList

.config

[xml]
&lt;!– GET EXTERNAL COMMERCE SYSTEM PRODUCT LIST
This pipeline is responsible for obtaining the list of product Ids to be synchronized from the external commerce system.–&gt;
&lt;commerce.synchronizeProducts.getExternalCommerceSystemProductList&gt;
&lt;processor type="Sitecore.Commerce.Pipelines.Products.GetExternalCommerceSystemProductList.GetExternalCommerceSystemProductList, Sitecore.Commerce"&gt;
&lt;patch:delete /&gt;
&lt;/processor&gt;
&lt;processor type="Comspace.Sitecore.CommerceConnect.Hybris.Pipelines.Products.ReadProducts, Comspace.Sitecore.CommerceConnect.Hybris" /&gt;
&lt;/commerce.synchronizeProducts.getExternalCommerceSystemProductList&gt;
[/xml]

Processor ReadProducts

[csharp]
using System.Collections.Generic;
using System.Linq;
using Comspace.Sitecore.CommerceConnect.Hybris.Connector;
using Comspace.Sitecore.CommerceConnect.Hybris.Connector.Model;
using Sitecore.Commerce.Pipelines;
using Sitecore.Commerce.Services.Products;

namespace Comspace.Sitecore.CommerceConnect.Hybris.Pipelines.Products
{
/// &lt;summary&gt;
/// commerce.synchronizeProducts.getExternalCommerceSystemProductList
/// &lt;/summary&gt;
public class ReadProducts : PipelineProcessor&lt;ServicePipelineArgs&gt;
{
public override void Process(ServicePipelineArgs args)
{
var request = args.Request as SynchronizeProductsRequest;
var productIds = args.Request.Properties["ExternalCommerceSystemProductIds"] as List&lt;string&gt;; //integration guide (page 12)
productIds = productIds ?? new List&lt;string&gt;();

//get products from ECS
IEnumerable&lt;ExternalProduct&gt; externalProducts = ProductConnector.Load(request.Language);

//convert and add to commerce connect list
productIds.AddRange(from product in externalProducts
where product.Code != null
select product.Code);

//persist for next processor
args.Request.Properties["ExternalCommerceSystemProductIds"] = productIds;
}
}
}
[/csharp]

Pipeline synchronizeProductEntity

.config

[xml]
&lt;!– SYNCHRONIZE PRODUCT ITEM –&gt;
&lt;commerce.synchronizeProducts.synchronizeProductEntity&gt;
&lt;processor type="Sitecore.Commerce.Pipelines.Products.SynchronizeProductEntity.ReadProductFromSitecore, Sitecore.Commerce"&gt;
&lt;patch:delete /&gt;
&lt;/processor&gt;
&lt;processor type="Sitecore.Commerce.Pipelines.Products.SynchronizeProductEntity.SaveProductToExternalCommerceSystem, Sitecore.Commerce" &gt;
&lt;patch:delete /&gt;
&lt;/processor&gt;
&lt;processor type="Comspace.Sitecore.CommerceConnect.Hybris.Pipelines.Products.ReadProduct, Comspace.Sitecore.CommerceConnect.Hybris" patch:after="processor[@type=’Sitecore.Commerce.Pipelines.Products.SynchronizeProductEntity.ReadExternalCommerceSystemProduct, Sitecore.Commerce‘]" /&gt;
&lt;/commerce.synchronizeProducts.synchronizeProductEntity&gt;
[/xml]

Processor ReadProduct

[csharp]
using Comspace.Sitecore.CommerceConnect.Entities.Products;
using Comspace.Sitecore.CommerceConnect.Hybris.Connector;
using Comspace.Sitecore.CommerceConnect.Hybris.Connector.Model;
using Sitecore.Commerce.Pipelines;
using Sitecore.Commerce.Services.Products;
using Sitecore.Diagnostics;

namespace Comspace.Sitecore.CommerceConnect.Hybris.Pipelines.Products
{
/// &lt;summary&gt;
/// commerce.synchronizeProducts.synchronizeProductEntity
/// &lt;/summary&gt;
public class ReadProduct : PipelineProcessor&lt;ServicePipelineArgs&gt;
{
public override void Process(ServicePipelineArgs args)
{
SynchronizeProductRequest syncProdRequest = args.Request as SynchronizeProductRequest;

//get product from ECS
ExternalProduct externalProduct = ProductConnector.Load(syncProdRequest.Language, syncProdRequest.ProductId); //TBD
if (externalProduct != null &amp;&amp; IsProductValidForImport(externalProduct))
{
CustomProduct product = new CustomProduct();
product.ExternalId = externalProduct.Code;
product.Name = externalProduct.Name;
product.FullDescription = externalProduct.Summary;
product.ImageUrl = HybrisSettings.Url + externalProduct.ImageUrl; //custom property

//persist for next processor
args.Request.Properties["Product"] = product; //integration guide (page 12)
}
}

protected bool IsProductValidForImport(ExternalProduct product)
{
var result = true;
if (string.IsNullOrEmpty(product.Name)) // = item.Name
{
result = false;
Log.Info("Skip product ‚" + product.Code + "‘: Name not valid.", product); //NOTE System.Messages
}
return result;
}
}
}
[/csharp]

CustomProduct

Wenn auch die Bilder synchronisiert werden sollen, muss das Produkt-Template des Commerce Connect erweitert werden. Konkret müssen dafür folgende Anpassungen vorgenommen werden:

Template
Neues Template “CustomProduct” anlegen, welches vom Standard Commerce Connect Template „Product“ erbt.

Klassen
Erweiterte Produkt-Klasse „CustomProduct“ definieren:

[csharp]
using Sitecore.Commerce.Entities.Products;
using Sitecore.Data.Items;

namespace Comspace.Sitecore.CommerceConnect.Entities.Products
{
/// &lt;summary&gt;
/// Custom product including image field.
/// &lt;/summary&gt;
public class CustomProduct : Product
{
public string ImageUrl { get; set; }

public MediaItem Image { get; set; }
}
}
[/csharp]

Die Klasse „CustomProductRepository“ definiert dann wie das erweiterte Produkt gelesen und geschrieben wird:

[csharp]
using Comspace.Sitecore.CommerceConnect.Entities.Products;
using Comspace.Sitecore.CommerceConnect.Model.sitecore.templates.User_Defined.Comspace.CommerceConnect;
using Sitecore.Commerce.Data.Products;
using Sitecore.Data.Fields;
using Sitecore.Data.Items;
using Product = Sitecore.Commerce.Entities.Products.Product;

namespace Comspace.Sitecore.CommerceConnect.Data.Products
{
/// &lt;summary&gt;
/// Custom product repository including image field.
/// &lt;/summary&gt;
public class CustomProductRepository : ProductRepository
{
/// &lt;summary&gt;
/// Save product data to related item.
/// &lt;/summary&gt;
/// &lt;param name="entityItem"&gt;&lt;/param&gt;
/// &lt;param name="product"&gt;&lt;/param&gt;
protected override void UpdateEntityItem(Item entityItem, Product product)
{
base.UpdateEntityItem(entityItem, product);

using (new EditContext(entityItem))
{
var url = (product as CustomProduct).ImageUrl;

var image = GetMediaItem(url, product); //TBD
ImageField imagefield = entityItem.Fields[IProductConstants.ImageFieldName];
imagefield.Alt = image.Alt;
imagefield.MediaID = image.ID;
}
}

/// &lt;summary&gt;
/// Read product data from related item.
/// &lt;/summary&gt;
/// &lt;param name="entityItem"&gt;&lt;/param&gt;
/// &lt;param name="product"&gt;&lt;/param&gt;
protected override void PopulateEntity(Item entityItem, Product product)
{
base.PopulateEntity(entityItem, product);

ImageField imageField = entityItem.Fields[IProductConstants.ImageFieldName];
(product as CustomProduct).Image = imageField == null ? null : imageField.MediaItem;
}

#region Handle MediaItem
//…
#endregion
}
}
[/csharp]

.config
Angepasste Templates und Klassen in Sitecore.Commerce.Products.config registrieren:

[xml]
&lt;!– PRODUCT REPOSITORY –&gt;
&lt;productRepository type="Sitecore.Commerce.Data.Products.ProductRepository, Sitecore.Commerce"&gt;
&lt;patch:delete /&gt;
&lt;/productRepository&gt;
&lt;productRepository type="Comspace.Sitecore.CommerceConnect.Data.Products.CustomProductRepository, Comspace.Sitecore.CommerceConnect" singleInstance="true"&gt;
&lt;template&gt;{0C589D66-A119-435A-907F-43481CD5199F}&lt;/template&gt;
&lt;branch&gt;{0C589D66-A119-435A-907F-43481CD5199F}&lt;/branch&gt;
&lt;path ref="paths/products" /&gt;
&lt;Prefix&gt;Product_&lt;/Prefix&gt;
&lt;ProductsIndex&gt;commerce_products_master_index&lt;/ProductsIndex&gt;
&lt;ManufacturerRepository ref="productManufacturerRepository" /&gt;
&lt;DivisionRepository ref="productDivisionRepository" /&gt;
&lt;TypeRepository ref="productTypeRepository" /&gt;
&lt;ClassificationsRepository ref="productClassificationsFieldRepository" /&gt;
&lt;ResourcesRepository ref="productResourcesRepository" /&gt;
&lt;RelationsRepository ref="productRelationsRepository" /&gt;
&lt;GlobalSpecificationsRepository ref="productGlobalSpecificationsRepository" /&gt;
&lt;ClassificationsSpecificationsRepository ref="productClassificationsSpecificationsRepository" /&gt;
&lt;TypeSpecificationsRepository ref="productTypeSpecificationsRepository" /&gt;
&lt;/productRepository&gt;

&lt;includeTemplates&gt;
&lt;ProductTemplateId&gt;{0C589D66-A119-435A-907F-43481CD5199F}&lt;/ProductTemplateId&gt;
&lt;/includeTemplates&gt;

&lt;!– Commerce ENTITIES
Contains all the Commerce cart entities.
The configuration can be used to substitute the default entity implementation with extended one. –&gt;
&lt;commerce.Entities&gt;
&lt;Product type="Sitecore.Commerce.Entities.Products.Product, Sitecore.Commerce" &gt;
&lt;patch:delete /&gt;
&lt;/Product&gt;
&lt;Product type="Comspace.Sitecore.CommerceConnect.Entities.Products.CustomProduct, Comspace.Sitecore.CommerceConnect" /&gt;
&lt;/commerce.Entities&gt;
[/xml]

Stolpersteine

In der Klasse „Sitecore.Commerce.Templates“ existiert eine Konstante „ProductTemplateId“, deren Id fest verdrahtet ist und nicht auf die zuvor eingerichteten Konfigurationsdateien verweist. Die Konstante wird u.a. in der Klasse „ItemClassificationService“ verwendet, daher ist dieser auszutauschen:

[xml]
&lt;itemClassificationService type="Sitecore.Commerce.Products.ItemClassificationService, Sitecore.Commerce"&gt;
&lt;patch:delete /&gt;
&lt;/itemClassificationService&gt;
&lt;itemClassificationService type="Comspace.Sitecore.CommerceConnect.Entities.ItemClassificationService, Comspace.Sitecore.CommerceConnect" /&gt;
[/xml]

Resumé

Zuletzt möchte ich ein paar erste Eindrücke und Erkenntnisse zusammenfassen:

  • Der erste Einstieg durch Pipelines in Pipelines in Pipelines ist herausfordernd.
  • Es gibt umfangreiche Dokumentationen.
  • Einige hilfreiche Klassen aus Beispielen im Internet verweisen leider auf die CommerceServer API, z.B. ProductsSearchResult und CommerceConstants. Auch in dem Dynamics AX Demoshop von Sitecore (Commerce.Dynamics.Storefront) sind Verweise auf die CommerceServer API enthalten. Die Trennung bzw. Abstraktion ist m.E. noch nicht ganz sauber erfolgt.
  • Verwunderlich fand ich zunächst, dass die Synchronisation von Bildern nicht im Standard enthalten ist. Aber dem von Sitecore definierten Prinzip “kleinster gemeinsamer Nenner” folgend, ist es verständlich, denn Bild-Quelle und -Ziel sind doch sehr projektspezifisch.
  • Der “Merchandising Manager” ist NICHT Bestandteil des Commerce Connect, sondern des CommerceServer Connect.
  • In einem echten Projekt mit einem umfangreichen Datenmodell wird der größte Aufwand in das Verständnis und das Mapping der Datenmodelle gehen.

Wenn ihr mehr zum Sitecore Commerce Connect wissen wollt, dann schaut mal hier:

Sitecore Commerce Connect – Teil 1: Ein Überblick am Beispiel Hybris

Wie in meinem Vortrag zum Thema “Evaluierung einer Hybris-Anbindung an Sitecore” auf der letzten Sitecore Usergroup in Bielefeld versprochen, möchte ich mit dieser Beitragsserie unsere ersten Eindrücke von der Anbindung eines externen Shopsystems (in diesem Beispiel Hybris) an Sitecore mittels des Commerce Connect Moduls mit euch teilen.

In diesem Artikel geht es mir darum, euch einen ersten Überblick über das Marketing-Potenzial und Funktionsumfang des Moduls zu verschaffen. In den nächsten Beträgen wird es dann technischer mit konkreten Ausschnitten aus Konfigurationsdateien und Quellcode.

Warum sollten WebCMS und E-Commerce Platform verbunden werden?

Bevor wir an die technischen Details gehen, erlaube ich mir zunächst einige Gedanken aus Sicht von Produkt-Management, Marketing und Vertrieb auf Betreiberseite:

Webnutzer erwarten immer mehr eine einheitliche User-Experience, die sich über alle Kanäle und Plattformen eines Unternehmens erstrecken soll. Zudem  bringen auch Online-Shop Systeme kleinere CMS-Funktionalitäten mit und damit wird auch die Darstellung von Inhalten immer besser. Warum sollten dann CMS und Shop miteinander verbunden werden?

Sitecore bietet bereits in seiner eigenen Suite ein umfangreiches Bundle an Funktionen, um verschiedenste Touchpoints (Webseite, Newsletter, Social Media, Offline-Kanäle am POS usw.) zu einem Nutzererlebnis aus einem Guss zu verschmelzen.

Mit diesem Beispiel möchte ich Möglichkeiten aufzeigen, mit denen Besuchern auch auf Unternehmenswebseiten die Kernfunktionalitäten eines Online-Shops angeboten werden können (wie bspw. Produkte in den Warenkorb legen) und wie diese kombinierten Webseiten- und E-Commerce-Daten dann von der Unternehmenswebseite automatisch an das Shopsystem übergeben werden.

Ein Beispiel für eine Customer Journey mit Optimierungspotenzial sähe beispielsweise so aus:

Der Kunde schaut auf einer Webseite nach einem Produkt, muss sich das Produkt merken und im separaten Online-Shop danach suchen um zu bestellen. 

Das bedeutet:
Durch die zwei separaten Technologien Webseite und Shop entsteht für den Kunden Fehler- und Frustrations-Potenzial. Für Unternehmen und Shop-Anbieter kann das bedeuten: Erhöhte Abbruchgefahr und damit niedrigere Conversion-Rate.

Mit Lösungen wie dem Commerce Connect arbeitet die Technologie im Hintergrund für den Kunden, nimmt ihm Arbeitsschritte ab und erhöht damit die Wahrscheinlichkeit, dass es zu einem Verkauf kommt.

Der Endkunde bemerkt so den Technologiewechsel aus dem WebCMS in den Online-Shop überhaupt nicht und hat ein nahtloses Nutzererlebnis im Bestellprozess.

Kurzvorstellung Sitecore Commerce Connect

Sitecore Commerce Connect sieht sich als Framework und API zur nahtlosen Integration von 3rd-Party Commerce Systemen in Sitecore. Das Ziel ist die Überführung der Experience Marketing Features in die Commerce Welt:

  • Einheitliche Darstellung:  Produktkataloge, “normale” Inhalte und Bilder aus einem Guss
  • Bearbeitung von Produktkatalogen, Seiteninhalten und Bildern in einen System
  • Nutzung der Sitecore Facettensuche über ALLE Inhalte.
  • Personalisierung auch über das Kaufverhalten der Besucher
  • Tracking von Conversions und Values rund um den Einkauf
  • Identifizierung von und Einblick in die wertvollsten Kunden
  • Reaktion auf Änderungen im Geschäft, in Echtzeit

Konkreter Umfang des Commerce Connect Moduls

Das Sitecore Modul bietet die Möglichkeit Produktkataloge mit dem externen Commerce System zu synchronisieren, d.h. es stellt entsprechende Templates, Klassen, Repositories, Import-Pipelines etc. zur Verfügung:

Sitecore-Commerce-Connect-Modul

Erste Engagement-Pläne zu Warenkorb-Abbrüchen, neuen Aufträgen und Wiederverfügbarkeit von Produktbeständen werden mitgeliefert und genutzt:

Sitecore-Commerce-Connect-Engagement-Plan

Selbstverständlich kommen auch Erweiterungen für die Sitecore Rule Engine mit:

Sitecore-Commerce-Connect-Rule-Engine

Das Framework des Sitecore Commerce Connect 

Die Architektur wird von Sitecore wie folgt skizziert, wobei der Commerce Server Connector und der Dynamics AX Connector fertige Connectoren von Sitecore selbst sind und der Hybris Connector von uns im Rahmen der Evaluierung entwickelt wurde.

Service Layer:

Folgende Bereiche deckt das Modul ab:

  • Warenkorb
  • Preise
  • Kunden und Benutzer
  • Bestände
  • Produkte
  • Aufträge
  • Geschenkkarten
  • Wunschlisten
  • Bezahlung
  • Versand
  • Treueprogramme

Die einzelnen Layer sind optional und unabhängig voneinander. Ein Layer umfasst ein Datenmodell und Pipelines mit ggf. zugehörigen Service Providern. Die farblich markierten Service Layer wurden im Rahmen des PoC näher beleuchtet. Wenn ihr einen Eindruck haben möchtet was sich dahinter verbirgt, habt etwas Geduld – die zugehörigen Artikel folgen.

Prinzipien

Weil sie mir so gut gefallen haben, hier eine kurze Zusammenfassung und Übersetzung der Prinzipien welche dem Modul von Sitecore selbst auferlegt wurden:

  • Simplicity – kleinster gemeinsamer Nenner
  • Extensibility – Domain Model erweiterbar
  • Independently – keine Abhängigkeit zwischen Service Layern
  • Abstraction – keine Sitecore oder Shopsystem Abhängigkeit in Service Layern
  • Pipelines – jeder Service Layer benutzt Sitecore Pipelines
  • Fallback – fehlende Implementierungen im Shopsystem können überbrückt werden

Erstes Resumé

Mein Eindruck nach der Evaluierung des Commerce Connect anhand einer Hybris-Anbindung:

  • Der erste Einstieg ist herausfordernd, kurz stand ich davor wie “der Ochs vorm Berg”. Auf dem Partnertag in Frankfurt wurde von Sitecore eine Schulung zu dem Modul angekündigt. Die kann ich dann nur empfehlen.
  • Das bringt mich zu den zur Verfügung stehenden Materialien:
    • Es gibt umfangreiche Dokumentationen über das Modul im Developer Netzwerk.
    • Cookbooks gibt es leider keine, diese helfen sonst häufig die erste Hürde zu nehmen.
    • Wenn die Dokumentation nicht weiter hilft, gibt es im Internet aktuell leider noch wenig Material zum Commerce Connect.
    • Geholfen haben immer wieder die herunterladbaren Beispiel-Implementierungen für AX und CommerceServer und natürlich dotPeek.
  • Customizing gehört zum Grundkonzept. Durch eine gute Abstraktion ist fast alles flexibel anpassbar. Das gefällt, auch wenn es manchmal nicht einfach ist, im Pipeline-Dschungel den Überblick zu bewahren.
  • Für eine solide und benutzerfreundliche Integration ist eCommerce-KnowHow unumgänglich. Die dahinterliegenden Modelle und Prozesse müssen durchdrungen werden.
  • Die Komplexität einer Commerce Integration bringt auch höhere Konzeptions- und Abstimmungsaufwände mit sich als vielleicht sonst im CMS-Umfeld üblich.
  • Das Modul umfasst keine Layout-Komponenten und keine speziellen Applikationen.
  • Der “Merchandising Manager” ist  NICHT Bestandteil des Commerce Connect, sondern des CommerceServer Connect.
  • Eine gute Einsatzmöglichkeit für das Modul ist m.E. eine PIM-Integration.
  • Zu guter Letzt: Die Arbeit mit dem Modul hat mir Spaß gemacht!

Die Präsentation zum Vortrag:

In den kommenden Tagen werde ich diese Serie mit den folgenden Artikeln fortführen:

 

 

Sitecore Usergroup Deutschland – Entstehung, Ziele und Entwicklung

Workshop Kreativität

Was ist eine Usergroup?

Usergroups finden sich überwiegend im IT-Umfeld und verstehen sich als Anwendergruppen für eine bestimmte Software oder Technik. Die Mitglieder einer Usergroup sind bestrebt, die Software gemeinsam weiter zu entwickeln, ihre Interessen gegenüber der Herstellerfirma zu vertreten und einen regelmäßigen Erfahrungsaustausch zu pflegen.

Im Bereich der Content Management Systeme bestehen einige Usergroups bereits seit längerem, so z.B. die OpenText Usergroup und die OpenCMS Usergroup.

Von der Idee zum 1. SUG-Treffen

Sitecore Usergroup Deutschland LogoSitecore Usergroups wurden bereits bspw. in der Schweiz, den Niederlanden und den USA gegründet. Da das Sitecore CMS immer stärker auch bei Web-Projekten für den deutschen Markt eingesetzt wird, hat sich Christopher Wojciech von der netzkern AG zum Ziel gesetzt diese Community ebenfalls auch im deutschen Raum aufzubauen. Nachdem das erste Treffen in Köln ein voller Erfolg war, wollte man dies wiederholen. Aufgrund des Besuchs von webit! Gründer Sven Haubold in Köln hat man sich dazu entschlossen das nächste Treffen in Dresden zu veranstalten. Ein ebenso großes Engagement zeigte comspace aus Bielefeld und somit hat sich eine kleine Gruppe aus sehr motivierten Menschen gefunden, um die Sitecore Communtiy in Deutschland weiter nach vorne zu bringen.

Workshop Kreativität

 

Zielsetzung und Zielgruppen der Sitecore Usergroup

Da das Sitecore CMS in Deutschland einerseits noch nicht so lange auf dem Markt ist wie andere CMS-Lösungen, andererseits aber enormes Potential für digitale Marketingprojekte bietet und sich schnell weiter entwickelt, stehen der Erfahrungsaustausch und die gezielte Verbreitung von neuen Lösungen im Sitecore-Umfeld im Vordergrund.

Zu diesem Zweck wurden gemeinsam organisierte und regelmäßig stattfindende Veranstaltungen geplant, die Sitecore-Entwickler und -Anwender sowie Marketing- und IT-Verantwortliche zusammen bringen – sprich potentiell jeden, der in seinem Arbeitsalltag mit Sitecore zu tun hat, ob auf Agentur- oder Kundenseite. Diese Treffen dienen dem Wissensaustausch und der Weiterbildung, u.a. durch Fachvorträge, in denen über neue Lösungsansätze, Tools und Einsatzszenarios in der Praxis berichtet werden.

Auch außerhalb der Veranstaltungen soll ein fachlicher Austausch zu Erfahrungen, Ideen und auch Problemen mit dem Sitecore CMS nicht zu kurz kommen. Dazu dient z.Zt. eine Sitecore Usergroup Deutschland XING-Gruppe. Für die Zukunft ist eine Community geplant, die allen Sitecore Usergroup-Interessierten – unabhängig von einer XING-Mitgliedschaft – offen steht.

Nicht zuletzt bildet die Sitecore Usergroup eine gemeinsame Interessenvertretung von Anwendern und Partnern gegenüber Sitecore als Hersteller. Durch einen regelmäßigen Dialog mit Sitecore möchten wir die Wünsche und Anregungen der deutschen Anwender gesammelt und strukturiert kommunizieren.

Was die Usergroup nicht ist

Wichtig für die Organisatoren war es auch sich auf gewisse Rahmenbedingungen zu einigen. Dazu gehörte es festzulegen welche Zwecke die Sitecore Usergroup nicht verfolgt:

  •         Die Usergroup ist nicht der Platz für Kundengespräche.
  •         Die Usergroup dient nicht der Kundenakquise.
  •         Die Usergroup-Treffen sind keine Werbeveranstaltung.

Erfahrungen aus den ersten Sitecore Usergroup Treffen

Mittlerweile haben die ersten Sitecore Usergroup Treffen stattgefunden – im Herbst 2014 in Köln und im Frühjahr 2015 in Dresden. Die Events mit Vorträgen von Sitecore-Kollegen, – Partnern und -Kunden und mit einem kulturellen Rahmenprogramm wurden von allen Zielgruppen gut angenommen, auch wenn Entwickler von Sitecore-Partneragenturen in der Überzahl waren. Präsentiert wurden sowohl technische als auch Consulting-Themen oder Kundenprojekte, bspw. “Sitecore Health – Monitoring und Stabilität von Sitecore Umgebungen”, “Vernetzt ans Ziel – die neue Website der Dresdner Verkehrsbetriebe AG” oder Mehrwert für Webprojekte mit Sitecore und Microsoft Azure.

Wie geht es weiter?

Wir haben große und spannende Pläne um diese Community weiter zu vergrößern. Wir wollen eine kontinuierliche Plattform schaffen und dies auch in der Außenwirkung bekräftigen. Seid gespannt und kommt zum nächsten Treffen, dann erfahrt ihr mehr!

Daher lade ich Euch zu guter Letzt…

… herzlich zum 3. Sitecore Usergroup Treffen am 30. September 2015 im Historischen Museum in Bielefeld ein. Diese spannenden Themen stehen auf dem Programm:

  •         Evaluierung einer Hybris-Anbindung an Sitecore mittels Commerce Connect
  •         The good, the bad and the ugly Sitecore module
  •         Auf dem Weg zur Connected Customer Experience – Möglichkeiten zu omni-channel Strategien mit Sitecore

Ausführlichere Informationen zum Programm und die Möglichkeit zur Anmeldung finden Sie hier.