Testen Sie Scrivito 30 Tage lang kostenlos
Testen Sie Scrivito 30 Tage lang kostenlos

Eine Produktliste auf Basis einer Suche anzeigen

Eine Produktliste auf Basis einer Suche anzeigen

Viele Websites bieten die eine oder andere Übersicht, vielleicht eine Bildergalerie, Dateien oder Artikel zum Download, und ähnliches.

Übersichten haben die Aufgabe, Inhalte nach bestimmten Kriterien zu filtern, sodass Besucher das Gesuchte schneller finden können. Im Unterschied zu einer Volltext-Suche beschränkt sich eine Übersicht also auf Inhalte eines bestimmten Typs: News-Artikel, Kontaktpersonen usw. – oder Produkte.

In dieser Anleitung, die auf der Scrivito Example App basiert, werden wir eine Objektklasse namens Product anlegen und ein einfaches Widget für Übersichten implementieren, mit dem Besucher die Liste der Produkte durchgehen können. Wenn Sie sich für etwas Umfangreicheres interessieren, empfehlen wir, einen Blick auf das in der Example App enthaltene Blog zu werfen.

Von dieser Anleitung profitieren Sie am meisten, wenn Sie sich bereits mit Scrivitos Content-Klassen und wie sie mit React zusammenhängen befasst haben.

Die „Product”-Objektklasse

Um ein Produkt in Scrivito sinnvoll abzubilden, erfassen wir dessen Daten, die für den Besucher und auch interne Vorgänge wie eine Bestellung relevant sind: einen Titel und eine Beschreibung, eine Tag-Liste (für die Kategorisierung), ein Bild und eine Bestellnummer. Spontan fallen uns noch etliche andere nützliche Eigenschaften ein (Verfügbarkeit, Beliebtheit, ähnliche Produkte), jedoch beschränken wir uns hier für den Anfang auf das Wesentliche.

Sollten Sie sich fragen, weshalb wir hier kein Produkt-Widget anlegen, sondern uns dafür entschieden haben, CMS-Objekte zu verwenden: Jedes Produkt soll es nur einmal geben, damit sämtliche Stellen im Code, die es referenzieren, dieselben Daten erhalten. Daher benötigen wir für jedes Produkt genau ein CMS-Objekt. Selbstverständlich spricht nichts dagegen, ein Produkt-Widget zu implementieren, mit dem sich ein bestimmtes Produkt auf beliebigen Seiten platzieren lässt. Dies ist jedoch nicht Gegenstand dieser Anleitung.

Hier nun die Objektklasse Product, das Datenmodell, mit dem wir im Widget für die Produktübersicht arbeiten werden: Legen Sie ein Verzeichnis namens Product in „src/Objs“ an und legen Sie die beiden im Folgenden aufgeführten Dateien darin ab:

src/Objs/Product/ProductObjClass.js
import * as Scrivito from 'scrivito'; Scrivito.provideObjClass('Product', { attributes: { title: 'string', description: 'html', orderCode: 'string', price: 'float', tags: 'stringlist', image: 'reference', }, });

Die obige Objektklasse Product deklariert die Eigenschaften (Attribute), die jede ihrer Instanzen haben soll. Die folgende Konfiguration macht diese Attribute in den Eigenschaften eines jeden Products sowie im Content Browser bearbeitbar (siehe unten wie man Product-Objekte im Content Browser zugreifbar macht).

src/Objs/Product/ProductEditingConfig.js
import * as Scrivito from 'scrivito'; Scrivito.provideEditingConfig('Product', { title: 'Product', description: 'A product.', attributes: { title: { title: 'Title', }, description: { title: 'Description', }, orderCode: { title: 'Order code', description: 'Must start with model number', }, price: { title: 'Price in USD', }, image: { title: 'Image', }, tags: { title: 'Tags', }, }, properties: ['title', 'description', 'orderCode', 'price', 'image', 'tags'], descriptionForContent: obj => obj.get('orderCode'), hideInSelectionDialogs: true, });

In der obigen Konfiguration verwenden wir hideInSelectionDialogs: true, damit Product beim Anlegen einer Seite nicht im Auswahldialog für den Seitentyp auftaucht.

Produkte über den Content Browser anlegen

Um es Redakteuren zu ermöglichen, Product-Objekte mit dem Content Browser anzulegen, fügen wir zu dessen Konfiguration in „src/config/scrivitoContentBrowser.js“einen Filter hinzu. Es gibt zwei Stellen, an denen die Product-Klasse aufgenommen werden muss, in der Funktion defaultFilters und in der Konstanten FILTER_PRESENTATIONS.

src/config/scrivitoContentBrowser.js
function defaultFilters() { return { _objClass: { options: { All: { title: "All", icon: "folder", query: Scrivito.Obj.all(), selected: true, }, Download: filterOptionsForObjClass("Download"), Video: filterOptionsForObjClass("Video"), Product: filterOptionsForObjClass("Product"), // … } const FILTER_PRESENTATIONS = { // … SearchResults: { title: "Search results", icon: "lens" }, Video: { title: "Videos", icon: "video" }, Product: { title: "Products", icon: "tag" }, }; // …

Anschließend können Sie den Filter im Content Browser auswählen, das Plus-Icon klicken, um ein Product hinzuzufügen und dann dessen Eigenschaften auf der rechten Seite zu bearbeiten.

Die Produkt-Ansicht bereitstellen

Ihnen wird aufgefallen sein, dass zur obigen Product-Klasse keine React-Komponente gehört, die die Instanzen rendert. Da diese innerhalb des noch zu implementierenden ProductListWidgets gerendert werden sollen, haben wir die Komponente in einer dedizierten Datei namens „ProductView.js“ im Verzeichnis „src/Components“ abgelegt:

src/Components/ProductView.js
import * as React from 'react'; import * as Scrivito from 'scrivito'; function ProductView({ product }) { return ( <div className='row'> <div className='col-sm-2'><Scrivito.ImageTag content={ product } attribute='image' /></div> <div className='col-sm-7'> <Scrivito.ContentTag tag='h3' content={ product } attribute='title' /> <Scrivito.ContentTag tag='h5' content={ product } attribute='description' /> </div> <div className='col-sm-3'> <h3><small>$ </small>{ product.get('price') }</h3> <Scrivito.ContentTag tag='small' content={ product } attribute='orderCode' /> </div> </div> ); }; export default Scrivito.connect(ProductView);

Die obige Komponente rendert eine Product-Instanz als Spalten einer Bootstrap-Zeile. Im Bootstrap-Raster-Layout besteht eine Zeile aus genau 12 gleich großen Abschnitten, die sich miteinander kombinieren lassen, um bis zu 12 Spalten zu erhalten. Wie Sie an den verwendeten CSS-Klassen erkennen, erzeugt die Product-Ansicht drei Spalten mit 2 + 7 + 3 = 12 Abschnitten.

Mittels Scrivito.connect verbinden wir diese Komponente (in Form einer Funktion) mit Scrivito, um sicherzustellen, dass sämtliche Produktdaten geladen wurden, bevor ein Produkt von der Komponente gerendert wird.

Das „ProductListWidget“

Es ist schwer vorherzusagen, wo auf der Website künftig eine bestimmte Übersicht Verwendung findet. Aus diesem Grund empfiehlt es sich, eine Übersicht als Widget (und nicht als Seitentyp) bereitzustellen, das Redakteure dann auf den Seiten ihrer Wahl einsetzen können.

Neben den oben erwähnten Vorteilen, die es mit sich bringt, Daten-Objekte (wie hier Produkte) mittels CMS-Objekten zu pflegen, hat dieser Ansatz einen weiteren, ausgesprochen nützlichen Aspekt: Man kann Scrivitos Such-Funktionalität verwenden, um die Inhalte einer Übersicht auf genau diejenige Art von Elementen einzuschränken, die man benötigt. In unserem Fall eines ProductListWidgets ermitteln wir einfach alle CMS-Objekte der Klasse Product. Wir haben den Code dazu im Verzeichnis „src/Widgets/ProductListWidget“ abgelegt:

src/Widgets/ProductListWidget/ProductListWidgetClass.js
import * as Scrivito from 'scrivito'; Scrivito.provideWidgetClass('ProductListWidget', { attributes: { bgColor: ['enum', { values: ['primary', 'secondary', 'info', 'light'] }], }, });
src/Widgets/ProductListWidget/ProductListWidgetComponent.js
import * as React from 'react'; import * as Scrivito from 'scrivito'; import ProductView from '../../Components/ProductView'; Scrivito.provideComponent('ProductListWidget', ({ widget }) => { const containerClass = `container bg-${widget.get('bgColor') || 'white'}`; const products = Scrivito.getClass('Product').all().order('title', 'asc'); if (!products) { return <p>No Products available. Create some using the Content Browser.</p>; } return ( <div className={ containerClass }> { [...products].map(product => { return <ProductView key={ product.id } product={ product } />; }) } </div> ); });
src/Widgets/ProductListWidget/ProductListWidgetEditingConfig.js
import * as Scrivito from 'scrivito'; Scrivito.provideEditingConfig('ProductListWidget', { title: 'Product List Widget', properties: ['bgColor'], attributes: { bgColor: { title: 'Background color', }, }, });

Die ProductListWidget-Klasse ist mit nur einem Attribut ausgestattet, bgColor. Mit ihm lässt sich die Hintergrundfarbe der Listenelemente festlegen.

Wie erwähnt, werden in der Komponente die Product-Instanzen über eine Suche ermittelt. Das Suchergebnis wird anschließend in Array-Elemente umgewandelt ([...products]), die dann mit der weiter oben definierten ProductView-Komponente gerendert werden.

Nach CMS-Objekten suchen

Um sämtliche Product-Instanzen zu finden, verwendet unsere Komponente Folgendes:

const products = Scrivito.getClass('Product').all().order('title', 'asc');

In dieser Zuweisung wird Scrivito.Obj.where nicht verwendet – weshalb ist dies dennoch eine Suche? Die Antwort liegt auf der Hand, wenn man erkennt, dass Scrivito.getClass() eine Objektklasse zurückgibt. Da alle Objektklassen Unterklassen von Obj sind, können auf sie die Suchmethoden all() und where() angewendet werden, um alle bzw. eine Untermenge der Instanzen der betreffenden Klasse zu finden.

Das Ergebnis der Objektklassen-Methoden all() und where() ist ein ObjSearch, das Ergebnis einer Suchanfrage, das mittels and(), andNot() oder order() eingeschränkt bzw. sortiert werden kann. Um beispielsweise nur solche Product-Instanzen zu erhalten, denen ein bestimmtes Tag zugewiesen wurde, können wir die folgende Anfrage verwenden:

const products = Scrivito.getClass('Product').all() .and('tags', 'equals', tag) .order('title', 'asc');

Zusammengefasst …

Mit Scrivito lassen sich Inhalte mit bestimmten Eigenschaften (beispielsweise anhand ihrer Objektklasse) leicht finden, um die Ergebnismenge als etwas anzuzeigen, das wir hier „Übersicht“ genannt haben. Je nach Anwendungsfall können Sie die Elemente auf Seiten oder in Widgets rendern: Sollen Redakteure die Übersicht auf Seiten jedweder Art platzieren können, stellen Sie ihnen ein Widget wie das obige ProductListWidget zur Verfügung. In allen anderen Fällen ist eine dedizierte Suchergebnisseite das Mittel der Wahl.

Die Suchen, die Sie mit Scrivitos Methoden Obj.all() und Obj.where() durchführen können, geben ein ObjSearch zurück, das verfeinert werden kann, und dessen Ergebnisse in Abschnitten abgeholt werden können, beginnend bei einem Versatz. Dies ermöglicht es Ihnen, Paginierung anzubieten.