Messbarer Erfolg «10 Punkte-Checkliste für ein zukunftssicheres CMS» White Paper
Messbarer Erfolg - White Paper

Inhalte automatisch validieren

Inhalte automatisch validieren

Als Ergänzung zu Styleguides und Workflows sowie Absprachen und Vereinbarungen zu Inhalten und deren Struktur können Validierungen dazu beitragen, die von Redakteuren erstellten Inhalte konsistent und vollständig zu halten. Insbesondere im geschäftlichen Umfeld ist die Möglichkeit, Validierungen einzurichten, nicht mehr nur ein optionales Feature, sondern eine Anforderung, wenn es um den Einsatz von Content-Management-Lösungen oder Publikationssystemen geht.

Mit Scrivito können Validierungen für alle Typen von CMS-Objekten und Widgets eingerichtet werden, um bei Seiteninhalten auf nicht eingehaltene Regeln aufmerksam zu machen. Redakteure können an der Gestaltung der Benachrichtigung die Dringlichkeit des Anliegens erkennen. Es gibt Fehler (rot), Warnungen (orange) und Hinweise (blau).

Fehler bewirken, dass die betreffende Arbeitskopie nicht veröffentlicht werden kann, während dies bei Warnungen und Hinweisen nicht der Fall ist.

Beachten Sie bitte, dass nur Seiten validiert werden, die in der Arbeitskopie geändert wurden. Dadurch wird verhindert, dass Seiten, die sich nicht von ihrer veröffentlichten Version unterscheiden, plötzlich fehlerbehaftet sind.

Beispiele für Validierungen

Wenn man Code für Validierungen schreibt, sollten die umgesetzten Regeln einfach und leicht zu verstehen sein. Machen Sie in den Benachrichtigungen deutlich, ob es bei dem festgestellten Umstand um ein zwingend zu behebendes Problem geht oder um eine Unstimmigkeit, deren Behebung empfohlen wird, oder ob lediglich darauf hingewiesen wird. Hier ein paar Beispiele:

AnforderungErläuterung
Die „meta description“ einer Seite darf weder leer sein noch dem Titel entsprechen.Die Seitenbeschreibung wird auf Suchmaschinen-Ergebnisseiten angezeigt. Für SEO ist es wichtig, dass die Beschreibung vorhanden ist und wiedergibt, worum es auf der Seite geht.
Jeder Artikel muss mindestens ein Bild enthalten.Besucher schätzen es sehr, wenn Artikel durch eingebundene Bilder angenehmer zu lesen oder leichter zu verstehen sind. Diese Anforderung könnte auf bestimmte Seitentypen beschränkt werden, etwa Blogposts.
Text muss ein vorgegebenes Format haben.Vor allem strukturierte Inhalte (wie Kontakte, Anschriften, usw.) können Daten enthalten, die nach bestimmten Regeln formatiert sein müssen (u.a. Telefonnummern, E-Mail-Adressen). Es ist sinnvoll, solche Daten nicht zu akzeptieren, wenn diese Regeln verletzt werden.
Eine Zeitspanne muss gültig sein, d.h. ihr Ende darf nicht vor ihrem Beginn liegen.Bei der Arbeit mit Inhalten, die nur für einen bestimmten Zeitraum gelten, sollten dessen Beginn und Ende sinnvoll gewählt werden. Dies lässt sich (in Grenzen) überprüfen.
Spalten sollten nicht leer sein.Wenn man nicht möchte, dass leere Spalten als Ersatz für fehlendes CSS verwendet werden, um horizontalen Leerraum zu erzeugen, könnte man in diesem Fall eine Warnung anzeigen.

Lassen Sie uns nun diese Anforderungen als Validierungen implementieren. Wir greifen wieder auf die Scrivito Example App als unsere Grundlage zurück.

Die Seitenbeschreibung angeben

Validierungen können in der Konfiguration für die Bearbeitung von CMS-Objekten und Widgets definiert werden. Sie können dort als Callbacks für eine Klasse insgesamt (klassenbasiert) oder für einzelne Attribute (attributbasiert) angegeben werden.

In diesem Beispiel einer attributbasierten Validation stellen wir sicher, dass nicht vergessen wurde, die „meta description“ anzugeben, und sie auch nicht vom Seitentitel übernommen wurde.

In der Example App können Redakteure die Seitenbeschreibung über den „Metadata“-Reiter in den Seiteneigenschaften angeben. Um zu prüfen, ob dieser Wert leer ist oder dem Seitentitel entspricht, verwenden wir den folgenden Code in der Konfiguration der Seitenklasse Page:

src/Objs/Page/PageEditingConfig.js
// Imports
Scrivito.provideEditingConfig("Page", {
// ...
  validations: [
    [
      "metaDataDescription",

      (metaDataDescription, { obj }) => {
        if (!metaDataDescription || metaDataDescription === obj.get("title")) {
          return "The page description must be present and not equal to the title.";
        }
      },
    ],
  ],
});

Den Wert des Attributs metaDataDescription, in dem die Seitenbeschreibung enthalten ist, entnehmen wir (zusammen mit anderen Metadaten-Attributwerten) der Konstanten metadataAttributes, die in der Datei „_metadataDescription.js“ im übergeordneten Verzeichnis definiert ist.

Im Array validations sind einzelne attributbasierte Validierungen wiederum als je ein Array repräsentiert, das den Attributnamen und die Callback-Funktion enthält.

Mindestens ein Bild in Artikeln

Im Gegensatz zur obigen Validierung der Seitenbeschreibung benötigen wir hier eine klassenbasierte Validierung, weil die Bedingung bereits erfüllt ist, wenn ein einziges beliebiges widgetlist-Attribut des Artikels (und nicht ein bestimmtes) mindestens ein Bild enthält. Auch hier fügen wir den Callback zur Konfiguration der Page-Klasse hinzu:

src/Objs/Page/PageEditingConfig.js
// Imports
Scrivito.provideEditingConfig("Page", {
// ...
  validations: [
    obj => {
      const images = obj
        .widgets()
        .filter(w => w.objClass() === "ImageWidget").length;

      if (!images) {
        return "A page must include at least one image";
      }
    },
    // Further validation callbacks may go here...
  ],
});

Bei klassenbasierten Validierungen gibt es nur die Callback-Funktion, die direkt als einziges Element des validations-Arrays angegeben wird.

Wenn Sie jetzt in der Example App im Bearbeitungsmodus beispielsweise die „Jobs“-Seite aus dem „About“-Menü öffnen, dann einen Blick auf die Seitenleiste werfen und kein Icon mit Hinweis auf einen Fehler sehen (siehe Screenshot), haben Sie die Seite entweder noch nicht geändert oder bereits ein Bild zu ihr hinzugefügt.

In der Seitenleiste müssten Sie unter „Benachrichtigungen“ nach einem Klick auf das Icon nun die Fehlermeldung sehen, die wir oben für die Validierung angegeben haben.

Ihnen ist bestimmt aufgefallen, dass der Fehler angezeigt wird, obwohl sich auf der Seite mehrere Bilder befinden. Weder das Header-Bild noch die Bilder auf den „Social Cards“ in den Eigenschaften zählen, weil es sich dabei nicht um Widgets handelt. Doch weshalb wird das Carousel-Widget weiter unten nicht berücksichtigt? Wir müssten verlangen, dass die Seite mindestens ein ImageWidget or CarouselWidget enthält, indem wir die Filterfunktion entsprechend erweitern:

src/Objs/Page/PageEditingConfig.js
// ...
  validations: [
    obj => {
      const images = obj
        .widgets()
        .filter(w => ["ImageWidget", "CarouselWidget"].includes(w.objClass()))
        .length;

      if (!images) {
        return "A page must include at least one image or carousel";
      }
    },
    // Further validation callbacks may go here...
  ],

// ...

Wenn Sie diese Validierung auch bei Seiten anderen Typs einsetzen möchten, können Sie den Code einfach in einer separaten Datei ablegen, die Funktion in die gewünschte Konfiguration importieren und schließlich in der Definition der Validierung aufrufen.

Text muss ein vorgegebenes Format haben

Die Postleitzahlen in Großbritannien sind eine Mischung aus fünf bis sieben Ziffern und Großbuchstaben, optional mit einem Leerzeichen zwischen den Codes für den äußeren und den inneren Zustellbereich wie bei SW1A 1AA für Buckingham Palace. Um zu verhindern, dass ungültige Codes veröffentlicht werden, würden Sie einen recht umfangreichen regulären Ausdruck benötigen. Da wir hier jedoch nur das Funktionsprinzip aufzeigen möchten, beschänken wir uns auf etwas weniger Kompliziertes: das Format von Preisangaben.

In der Example App gibt es ein PricingWidget mit Attributen für die Preise von drei Tarifen sowie einem Attribut für die Währung. Aus Gründen der Flexibilität sind diese Attribute Zeichenketten, also sollte gewährleistet sein, dass die Preise so formatiert sind, wie der Kunde es erwartet, mit einem Tausender-Separator und einem Dezimalzeichen entsprechend der Währung. Der Kürze wegen werden wir hier nur das Format des höchsten Tarifs validieren, also den Wert von largePlanPrice, abhängig davon, ob currency gleich $ ist oder nicht.

Validierungen funktionieren bei Widgets genau so wie bei CMS-Objekten, d.h. sie können auf die Instanzen von Widgets als Ganzes oder, wie in diesem Fall, auf eines der Widget-Attribute angewendet werden. Hier die Definition:

src/Widgets/PricingWidget/PricingWidgetEditingConfig.js
// Imports
Scrivito.provideEditingConfig("PricingWidget", {
// ...
  validations: [
    [
      "largePlanPrice",

      (largePlanPrice, { widget }) => {
        const VALID_NUMBER_FORMATS = {
          us: /^(0|[1-9][0-9]{0,2}(,[0-9]{3})*)(\.[0-9]{2})?$/,
          eu: /^(0|[1-9][0-9]{0,2}(\.[0-9]{3})*)(,[0-9]{2})?$/,
        };

        const format = widget.get("currency") === "$" ? "us" : "eu";

        if (!largePlanPrice.match(VALID_NUMBER_FORMATS[format])) {
          return "Use separators in accordance with the currency. Examples: € 1.199,95 or $ 1,199.95";
        }
      },
    ],
  ],
});

Wie auch in den Beispielen davor gibt die Funktion zur Validierung im Falle eines Fehlers den Benachrichtigungstext als Zeichenkette zurück. Es ist auch möglich, ein String-Array zurückzugeben, falls es mehrere Unstimmigkeiten gibt, die als einzelne Benachrichtigungen präsentiert werden sollen.

Eine Zeitspanne muss gültig sein

Es gibt etliche Anwendungsfälle, in denen Datumsangaben eine Rolle spielen: Pressemitteilungen werden häufig an einem festgelegten Datum veröffentlicht, ein Produkt- oder Stellenangebot ist nur beschränkt gültig, usw.

In der Example App verfügen Stellenangebote über zwei Attribute vom Typ date, datePosted und validThrough. Obwohl beide Datumsangaben auf Job-Seiten gut zu sehen sind, kann es vorkommen, dass sie versehentlich nicht angepasst werden, nachdem ein Stellenangebot kopiert wurde, um darauf basierend ein neues zu erstellen. Stellen wir also wenigstens sicher, dass das validThrough-Datum nach datePosted liegt:

src/Objs/Job/JobEditingConfig.js
// ...
  validations: [
    [
      "validThrough",

      (validThrough, { obj }) => {
        if (validThrough <= obj.get("datePosted")) {
          return "The job offer must not expire before it has been posted.";
        }
      },
    ],
  ],
// ...

Wir nehmen hier an, dass der Wert von validThrough fehlerhaft ist, und benachrichtigen den Redakteur darüber auch dann, wenn eigentlich datePosted korrigiert werden müsste. In Ihrer eigenen Umsetzung könnten Sie die Attribute jedoch vertauschen und den Vergleich anpassen oder auch beide Attribute validieren. Auch wäre es sinnvoll, das aktuelle Datum bei der Überprüfung der Werte zu berücksichtigen.

Insbesondere bei Datumswerten sollte man im Hinterkopf behalten, dass Seiteninhalte manchmal nachbearbeitet werden und daher keine Bedingungen formuliert werden sollten, die später die erneute Veröffentlichung der Seiten verhindern.

Spalten sollten nicht leer sein

Als ein Beispiel dafür, wie man den Inhalt eines Struktur-Widgets überprüft und eine Benachrichtigung anzeigt, falls etwas verbesserungswürdig ist, betrachten wir in unserem letzten Anwendungsfall das Column-Container-Widget (das bei der Widget-Auswahl schlicht als „Columns“ erscheint). Das ColumnContainerWidget der Example App hat ein Attribut namens columns, eine widgetlist, die mit drei ColumnWidgets initialisiert wird, von denen jedes ebenfalls mit einem widgetlist-Attribut ausgestattet ist, das content heißt. Wir möchten den Redakteur nun darauf hinweisen, wenn content in einer der columns leer ist:

src/Widgets/ColumnContainerWidget/ColumnContainerWidgetEditingConfig.js
// ...
  validations: [
    widget => {
      const columns = widget.get("columns");
      for (var i = 0; i < columns.length; ++i) {
        const column = columns[i].get("content");
        if (!column || !column.length) {
          return {
            message: "Columns should not be left empty.",
            severity: "warning",
          };
        }
      }
    },
  ],
// ...

Der obige Code läuft über die columns und, sofern darin ein leeres content-Attribut gefunden wurde, gibt er ein JavaScript-Objekt zurück, das eine message und eine severity, den Schweregrad, enthält. Würden wir lediglich den Benachrichtigungstext oder ein Array solcher Texte zurückgeben, um einen Fehler anzuzeigen, wäre der Schweregrad error. Stattdessen ein Objekt zurückzugeben, erlaubt es uns, einen anderen Schweregrad anzugeben. Dieser kann error (die Voreinstellung), warning oder info sein.

Abschließende Worte

Validierungen sind eine leicht zu implementierende Maßnahme gegen die Veröffentlichung von Inhalten, die aus dem einen oder anderen Grund nicht regelkonform sind. Als Entwickler kann man dazu beitragen, dass Redakteure Fehler schnell erkennen, verstehen und beheben können, indem leicht zu verstehende und eindeutige Fehlermeldungen gewählt werden, vielleicht sogar ergänzt um kleine Beispiele für die richtige Schreibweise, das richtige Format usw.

Als Ergänzung zur Implementierung klassen- oder attributbasierter Callbacks wie hier gezeigt, lassen sich mit Scrivito auch Restriktionen deklarieren und deren Einhaltung mit Hilfe eines Callbacks überprüfen. Hierfür stehen Bibliotheken von Drittanbietern zur Verfügung, etwa Validate.js. In der API-Dokumentation 🇺🇸 finden Sie eine detaillierte Anleitung zu diesem Thema. Allgemein gesagt, sind Scrivitos eigene Mechanismen etwas flexibler, weil man damit jedwede Validierung umsetzen und auch Abhängigkeiten zwischen Attributen einfließen lassen kann. Die Bibliotheken dagegen bieten eine feste Zahl an Restriktionen, die jedoch leichter angewendet werden können.