OXID6 Child-Themes auf Basis von WAVE-Parent erstellen

WAVE-Theme untersuchen und was beim Installationsprozess passiert

Es lohnt sich als erstes das WAVE-Theme ausserhalb einer OXID-Installation zu betrachten. Dazu einfach das WAVE-GIT-Repository (klonen und) lokal auschecken.
Interessant sind dabei die drei Dateien composer.json, package.json und Gruntfile.js

WAVE: composer.json

In der Dokumentation ist der Bereich „blacklist-filter“ noch nicht erleutert. Die Funktion erklärt sich aber von selbst, denn hier wird dafür gesorgt, dass später das Theme im source-Verzeichnis der OXID6-Installation nicht mit unrelevanten Developer-Files befüllt wird.

WAVE: package.json

Mittels npm install installierst Du testweise alle Bibliotheken, die Du zur Erstellung der Theme-Resourcen (JS, CSS, Fonts) benötigst. Es ist etwas gruselig, wie viele WARNings dabei geworfen werden. Hier kannst Du später für Dein Child-Theme definitiv einiges besser machen.

WAVE: Gruntfile.js

In der Gruntfile.js sind alle Tasks definiert, die für die Erzeugung der Theme-Resourcen gebraucht werden. Es liegt nahe, die Datei einmal auszuprobieren. Dazu aber vorher die relativen Pfade (out, tmp, modules) unter project einmal so anpassen, sodass Du die erzeugten Resourcen gleich wieder findest.
Ich habe noch nicht herausgefunden, wie die WAVE-Entwickler ihr Theme-Develop-System konfiguriert haben. Aber scheinbar werden sie npm direkt im Repository des themes im vendor-Ordner der installierten Shop-Entwickler-Installation ausführen und die Tasks der Gruntfile.js dort starten und dann direkt in die Resourcen des source-Ordners schreiben lassen.
Nachdem Du die drei Pfade für Deinen Test angepasst hast, starte die Gruntfile.js via grunt. Grunt ohne Parameter startet den default-Task, so wie er am Ende der Gruntfile.js definiert ist. Der letzte Untertask nach dem einmaligen erstellen aller Resourcen ist der watch-Task. Der wartet jetzt darauf, das wir die SCSS- oder JS-Resourcen ab „jetzt“ weiter bearbeiten, damit er diese dann gleich live compiliert. Wie auch bei der package.json, gibt es hier einiges an WARNings, die man auf jeden Fall in seinem eigenen Theme verbessern kann.
Als Ergebnis findest Du aber trotzdem in Deinem Test-Ordner alle erzeugten Resourcen.

Das eigene Child-Theme

Zu Beginn braucht es ein eigenes Git-Repository für das Child-Theme. Wie ich generell die mit OXID-Repositories umgehe, habe ich in dem Beitrag: Organisation meiner OXID-Module und Themes beschrieben.
Wer der folgenden Anleitung nicht Schritt für Schritt folgen will, kann sich das fertige Repository hier klonen: in neuem Tab)“ href=“https://bitbucket.org/therealworld/wave-child-theme/“ target=“_blank“>Bitbucket

Aus dem WAVE-Theme kopiere ich:

  • composer.json
  • package.json
  • Gruntfile.js
  • theme.php
  • build-Ordner

CHILD: composer.json

Im Unterschied vom Original habe ich nur die blacklist-filter optimiert.

{
	"extra": {
		"oxideshop": {
			"blacklist-filter": [
				"*.md",
				"*.js",
				"*.json",
				".git/**/*",
				".git/**/*.*",
				"grunt/*.*",
				"build/**/*.*",
				"build/**/*"
			]
		}
	}
}

CHILD: package.json

In der package.json werden zuerst die package-Informationen angepasst: „name“, „homepage“, description“, „author“, „repository“, „license“.
Da diverse Ressourcen nicht meht auf den aktuellen Stand sind, erfolgt zunächst ein check mittels command-line: ncu
Die neuen Versionen werden mittels ncu -u in die package.json übernommen.
Dann erfolgt die erste Installation mit: npm install
Nun korrigieren wir einige Fehler die während der Installation aufgetreten sind. Für fontawesome gibt es ein neues Repository. Für postcss eine höhere Version. Alle anderen Warnungen nach älteren Verisonen von grunt und stylelint können ignoriert werden. Ein Repository muss noch ergänzt werden (node-sass). Das wird beim erstellen der Resourcen noch benötigt. Nachdem alle devDependencies angepasst sind werden beim erneuten npm install auch nur noch drei ignorierbare Warnungen erzeugt.

CHILD: Gruntfile.js

In der Gruntfile passen wir zuerst den theme-Namen an: grunt.initConfig > project > theme
Damit unsere Resourcen erst einmal im Theme-Repository landen wird der out-Pfad angepasst: grunt.initConfig > project > out: ./out/
Damit der Standard-Task nicht gleich mit einem Watch-Prozess endet, sondern erst einmal zu Ende ist, nehmen wir aus dem default-Task noch den watch raus.
Jetzt erfolgt der erste Resourcen-Builder-Lauf mit dem Command-Line-Befehl: grunt

Es kommen erst einmal zwei Fehlermeldungen:
Die erste wegen dem Autoprefixer. Die wird wie folgt gefixt: Aus dem Wort browsers wird browserlist. Korrekt lautet jetzt die options-Zeile: require(‚autoprefixer‘)({browserlist: [‚last 2 versions‘, ‚ie 11‘]})

Die zweite Meldung: Fatal error: The implementation option must be passed to the Sass task
Hier muss der sass-Block umgebaut werden:

sass: {
     createcss: {
         options: {
             implementation: sass,
             update: true,
             style: 'compressed'
         },
         files: {
             '<%= project.out %><%= project.theme %>/src/css/styles.css': [
             '<%= project.dev %>/build/scss/style.scss'
             ]
         }
     }
 },

… im Kopf der Datei folgende Zeile ergänzt werden: const sass = require(’node-sass‘);
… im watch und default-Task wird aus sass : sass:createcss

Der nächste Lauf (commandline: grunt) kommt erst einmal zum Ende, enhält aber noch einige zu behebende Warnungen:

Wanung 1: WARNING: Potentially invalid value for $container-max-widths
Hier wird in der Datei \build\scss_variables.scss im Bereich $container-max-widths: der sm-Wert wieder auf den Bootstrap-Standard-Wert gesetzt: 540px

Warnung 2: autoprefixer: …\src\css\styles.css … start value has mixed support, consider using flex-start instead
Hier wird in der Datei: \build\scss\page\compare_compare.scss im Bereich &-item-wrapper der Wert align-content auf flex-start gesetzt

Warnung 3: Skipping remote @import of „https://fonts.googleapis.com/css?family=Raleway:200,400,600,700“ as no callback given.
Wer hier nach einer Lösung via Google sucht, stösst auf das Problem, das cssmin Probleme mit extern eingebundenen CSS-Dateien hat. Ich habe das Problem so gelöst, indem ich die Schrift einfach heruntergeladen und als vendor mit eingebunden habe. Dieser etwas komplizierte Ansatz ist generell zu empfehlen, damit alle Fonts generell lokal geladen werden. Es steht Euch natürlich frei, ein ganz anderes Font als Raleway zu nutzen.

Und wo wir gleich bei den Fonts sind: fontawesome war (und ist) ja extra als npm-Package eingebunden. Trotzdem wurde im wave-Theme auf eine Kopie der Dateien zurück gegriffen. Darum habe ich die Font-Kopien gelöscht und greife direkt auf die npm-fonts zu. Dazu sind die Pfade im copy-Task der Gruntfile.js noch anzupassen.

Nun ein letzter command-line-Aufruf: grunt

Und siehe da, wir kommen fehlerfrei durch.

CHILD: theme.php

Der Inhalt der theme.php muss an ein Childtheme angepasst werden, damit die Vererbung später gut funktioniert. Aus der kopierten theme.php kommt der settings-Block raus. Dafür kommt parentTheme und parentVersions rein.

CHILD: .gitignore

Am Ende beim einchecken eures Repositories fällt Euch sicher der riesige node-modules-Ordner auf. Der kommt natürlich nicht mit ins Repository, sondern wird in die .gitignore notiert.

CHILD: Templates

Beim Child-Prinzip versucht OXID später zuerst seine Templates im child-theme zu finden. Sind sie nicht vorhanden, holt er sich die Dateien aus dem parent-theme. Das bedeutet für Eure Anpassungen, das Ihr einfach die Dateien, die ihr ändern wollt aus dem wave-theme kopiert und exakt in der gleichen Ordner-Struktur wieder ablegt.

CHILD: Sprachdateien

Richtet in der root des child-themes mindestens die beiden Ordner „de“ und „en“ an und platziert dort jeweils eine cust_lang.php. In die Datei notiert Ihr alle „Überschreibungen“ bzw. Eure „Neuwortschöpfungen“. Orientiert Euch bei der Syntax an den Sprach-Dateien des Wave-Themes.

CHILD: Dokumentation

Am Ende lege ich die Root des Repositories die beiden Dateien

  • README.md
  • CHANGELOG.md

an und notiere dort die Modulbeschreibung und die Änderungshistorie mittels Markdown.

Installation des Themes

Am Ende tragt Ihr Euer Theme-repository als weiteres „require“ in die composer.json Eures Shops. Mittels composer update –no-scripts und composer install wird Euer neues Theme mit eingebunden.

HAPPY TEMPLATEING

2 Likes

Hi,

es ist immer etwas zeitraubend, die Ordnerstruktur im Childtheme anzulegen. Ich habe daher ein fertiges wave-child, in dem die Ordnerstruktur schon fertig enthalten ist, man muss nur noch die zu ändernden tpl-Datei reinkopieren.
Das Child installiert man einfach mit: composer require ecs/wave_child

1 Like

Hallo Mario,

warum änderst Du den Pfad für out im Gruntfile?

‘project: {
theme: ‘wavechild’,
dev: ‘./’,
out: ‘./out/’,
tmp: ‘./…/…/…/tmp/’,
modules: ‘./…/…/…/modules/’,
},’
Damit bleibt der ordner out doch unter views/child-theme.
‘out: ‘./…/…/…/out/’,’ wie im Original funktioniert.

prinzipiell ist das dafür gut, wenn man das Child Theme in einer eigenen Repository speichern möchte.
Ich hätte aber Bedenken, das eigene Theme als fremde Composer Dependency zu installieren. Irgendwann macht man ein Update und die eigenen Sachen sind futsch, weil die Datein aus der fremden Repo aktualisiert werden.

@Mario_Lorenz :wink:

@nickname: Ich lege die Verzeichnisse der Childtheme-Template-Dateien immer erst an, wenn ich sie brauche. Es gab bisher kein Child-Theme, wo ich wirklich alle Dateien angefasst und geändert habe. Aber Dein Ansatz ist auch nicht verkehrt.

@windes: Ich habe das Childtheme in einem Standalone-Repository, genau wie das Flow- oder Wave-Parent-Theme. In den Parent-Repositories sind die fertig compilierten CSS- und JS-Dateien auch Teil des Theme-Repositories. Mein Grunt-“watch” und “production”-Task generiert daher beim Entwickeln die Resourcen in den ./out/-Pfad.
composer update & composer install sorgen dann während der Installation dafür, das die Resourcen aus meinem Repository genau wie beim wave- oder flow-theme an die richtige Stelle kopiert werden.
Damit ich während des Entwickelns nicht permanent composer update & composer install durchführen muss, lasse ich in meiner lokalen Entwicklungsumgebung durch die IDE den out/childthemefolder/ aus dem ChildRepository in den Shop-out/childthemefolder/ syncen.
Am Ende des Tages, nachdem ich die aktuellen Anpassungen alle in das ChildRepository gepusht habe und per composer update & composer install frisch in den Shop ziehe, werden alle manuellen Anpassungen dann “offiziell” bereitgestellt.

Wenn man aber auf ein separates Child-Theme-Repository verzichtet und sein Child-Theme einfach in das Shop-Repository mit ablegt, kann man aber auch bei den Ordner-Vorgaben aus der Parent-Theme-Gruntfile.js bleiben.

@vanilla_thunder: Wo siehst Du ein Update-Problem? In das Standalone-Repository schreibe ich nur allein, da grätscht keiner rein und zerhaut mir etwas. Oder wie können die eigenen Sachen Deiner Meinung nach kaputt gehen?

Ich denke da an folgendes Szenario:
Shopbetreiber installiert über composer das child theme, die dependency ist nun registriert.
Shopbetreiber baut sein child theme in dem Ordner dieser Dependency. In der Zwischenzeit hat sich in der ursprünglichen Repo was geändert.
Dann kommt die halbjährliche Alarm-Stufe-Rot-Email von Marco: critical security issue, update asap sonst kaputt.
Shopbetreiber macht nun composer update und wird etwa 25 tausend mal gefragt, ob er einzelne Dependencies aktualisieren möchte. Das möchte er natürlich, er will ja keinen unsicheren Shop. Und Zack hat composer den Ordner mit dem aufgebauten Child Theme durch die frische Version aus der dependency Repo ersetzt, wo quasi nur das Grundgerüst drin ist.

Ahem… das kommt maximal einmal im Jahr und wenn dann vom Security-Team :wink:
Ich bin häufig mal an den Texten beteiligt.

Hi,

das Problem sehe ich so nicht, da bei dem von Dir beschriebenen Vorgang die bereits vorhandenen Modulordner nicht zuerst gelöscht werden.
Es werden nur die Originaldateien wieder drüber kopiert, zusätzliche eigene .tpl-Dateien bleiben erhalten.

Wer trotzdem ganz sicher gehen will, kann bei der Installation die Versionsnr. mit angeben, dann ändert sich garantiert nichts mehr (composer require x/y:1.0.0) .
Alternativ könnte man die Theme-Ordner einfach umbenennen oder die Abhängigkeit wieder entfernen (aus der composer.json löschen), braucht man ja eh nicht mehr.

Es geht schließlich nur darum, das Childtheme mit geringen Aufwand in den Shop zu laden, das geht via Composer einfach schneller und komfortabler als von der Festplatte per FTP hochladen.

@vanilla_thunder: Ahh, Ich habs verstanden.

Mein Ansatz ist, das dieses Childtheme-Repository nur für diesen Shop gilt. Ich verwende das Childtheme-Repository nicht als Basis für mehrere Shops. Daher kommt in dieses Repository wirklich alles rein, was dazu gehört. Bei einem Update kann also nichts verloren gehen, was nicht vorher schon da war.

Ich bin gar nicht auf die Idee gekommen, das ich das Child-Theme-Repository habe und dann noch zusätzlich weitere Anpassungen, die das Child-Theme betreffen, ausserhalb zu platzieren. Wenn ich das tun würde, wäre tatsächlich die Gefahr, das bei einem Update etwas verloren geht.