WordPress-Themes wie Software behandeln: Deployment mit GitHub Actions

AutomationInfrastructureSoftware EngineeringSSH & Remote AccessSystem Engineering

Ein selbst entwickeltes WordPress-Theme ist Software.

Es enthält PHP, JavaScript, CSS, Templates, Assets und Konfiguration. Änderungen an einer Datei können Auswirkungen auf andere Teile des Systems haben. Fehler können die komplette Website unbrauchbar machen.

Trotzdem werden WordPress-Themes erstaunlich oft anders behandelt als andere Software:

Theme ändern
    ↓
ZIP erstellen
    ↓
WordPress öffnen
    ↓
Theme hochladen
    ↓
hoffen

Oder noch direkter:

FTP
 ↓
Datei überschreiben
 ↓
fertig

Für kleine Änderungen funktioniert das erstaunlich lange.

Bis es nicht mehr funktioniert.

Dann entstehen unangenehme Fragen:

  • Welcher Stand läuft gerade auf dem Server?
  • Entspricht dieser Stand überhaupt noch dem lokalen Projekt?
  • Welche Dateien wurden beim letzten Update verändert?
  • Liegen alte Dateien auf dem Server, die lokal längst gelöscht wurden?
  • Welcher Commit entspricht der Produktion?
  • Kann der vorherige Zustand wiederhergestellt werden?
  • Wurde das Theme vor dem Deployment überhaupt geprüft?
  • Funktioniert die Website nach dem Deployment tatsächlich?

Die Lösung ist nicht ein besserer FTP-Client.

Die Lösung besteht darin, das Theme wie das zu behandeln, was es ist:

ein deploybares Software-Artefakt.


Das eigentliche Problem: Wo liegt die Wahrheit?

Bei einem manuell gepflegten WordPress-Theme entstehen schnell mehrere Zustände:

Lokaler Rechner
      │
      ├── Version A
      │
GitHub
      ├── Version B
      │
Webserver
      └── Version C

Solange alle drei ungefähr gleich sind, fällt das kaum auf.

Nach einigen manuellen Änderungen sieht die Realität möglicherweise so aus:

Git Repository
├── functions.php
├── style.css
├── assets/
│   ├── site.css
│   └── browser.js
└── templates/


Produktionsserver
├── functions.php
├── style.css
├── assets/
│   ├── site.css
│   ├── browser.js
│   ├── category-sort.js
│   └── old-navigation.js
└── templates/

Die letzten beiden JavaScript-Dateien wurden im Repository längst entfernt.

Auf dem Server existieren sie aber weiterhin.

Ein klassischer Datei-Upload kennt keinen gewünschten Gesamtzustand. Er kopiert Dateien.

Ein Deployment sollte etwas anderes tun:

Der Zustand im Repository definiert den Zustand des deployten Themes.

Damit wird Git zum Source of Truth.

Git Repository
      │
      │ Source of Truth
      ▼
Validation
      │
      ▼
Deployment
      │
      ▼
WordPress Production

Produktion wird aus Git hergestellt.

Nicht umgekehrt.


Von Dateiübertragung zu CI/CD

An dieser Stelle lohnt sich die Trennung zweier Begriffe, die häufig zusammengeworfen werden:

  • Continuous Integration
  • Continuous Delivery beziehungsweise Continuous Deployment

Für ein WordPress-Theme lässt sich die Trennung sehr konkret zeigen.

Continuous Integration

CI beantwortet die Frage:

Ist dieser Stand grundsätzlich deploybar?

Zum Beispiel:

Commit
  │
  ▼
PHP Syntax Check
  │
  ▼
JavaScript Syntax Check
  │
  ▼
Theme Structure Check
  │
  ▼
weitere Tests

Erst wenn diese Prüfungen erfolgreich sind, darf der nächste Schritt beginnen.

Continuous Deployment

CD beantwortet anschließend:

Wie kommt der geprüfte Stand kontrolliert auf das Produktionssystem?

Validierter Commit
       │
       ▼
SSH-Verbindung
       │
       ▼
Backup
       │
       ▼
Deployment
       │
       ▼
Smoke Tests

GitHub Actions kann beide Aufgaben übernehmen.


Die einfachste mögliche GitHub Action

Eine sehr kleine Deployment-Pipeline könnte so aussehen:

name: Deploy WordPress Theme

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Deploy
        run: |
          rsync -az --delete \
            ./ \
            user@server:/path/to/wp-content/themes/my-theme/

Das Prinzip ist bereits sichtbar:

Push auf main
      ↓
GitHub Actions
      ↓
Repository auschecken
      ↓
rsync
      ↓
Produktionsserver

Aber produktionsreif ist das noch nicht.

Vor allem fehlen:

  • Validierung
  • sichere Credentials
  • Schutz des Deployment-Ziels
  • Vorschau der Änderungen
  • Backup
  • Verifikation nach dem Deployment
  • brauchbares Feedback

Diese Punkte machen aus einem automatisierten Datei-Upload eine Deployment-Pipeline.


SSH statt Zugangsdaten im Workflow

GitHub Actions muss sich am Webserver authentifizieren können.

Dafür eignet sich ein separater SSH-Key.

Ein Ed25519-Key kann beispielsweise erzeugt werden mit:

ssh-keygen \
  -t ed25519 \
  -C "github-actions-wordpress" \
  -f github-actions-wordpress

Es entstehen zwei Dateien:

github-actions-wordpress
github-actions-wordpress.pub

Die .pub-Datei enthält den öffentlichen Schlüssel.

Dieser wird auf dem Server autorisiert.

Der private Schlüssel gehört dagegen weder in das Theme noch in das Repository.


GitHub Secrets

GitHub Actions stellt dafür Repository Secrets bereit.

Für ein einfaches WordPress-Deployment können beispielsweise folgende Werte benötigt werden:

SSH_HOST
SSH_USER
SSH_PRIVATE_KEY
THEME_PATH

Der Zielpfad könnte konzeptionell so aussehen:

/home/user/public_html/wp-content/themes/my-theme

Der Workflow kann anschließend darauf zugreifen:

${{ secrets.SSH_HOST }}
${{ secrets.SSH_USER }}
${{ secrets.SSH_PRIVATE_KEY }}
${{ secrets.THEME_PATH }}

Der private Schlüssel taucht damit nicht im Repository auf.

Das ist ein grundlegendes Prinzip von Deployment-Konfiguration:

Code gehört ins Repository. Secrets nicht.


SSH vorbereiten

Der Runner von GitHub Actions existiert nur für die Dauer des Jobs.

Die SSH-Konfiguration muss deshalb während des Workflows erstellt werden.

Beispielsweise:

- name: Configure SSH
  shell: bash
  run: |
    mkdir -p ~/.ssh
    chmod 700 ~/.ssh

    printf '%s\n' \
      "${{ secrets.SSH_PRIVATE_KEY }}" \
      > ~/.ssh/id_ed25519

    chmod 600 ~/.ssh/id_ed25519

    ssh-keyscan \
      -H "${{ secrets.SSH_HOST }}" \
      >> ~/.ssh/known_hosts

Danach kann der Workflow den Server erreichen.

Ein separater Verbindungstest ist sinnvoll:

- name: Test SSH connection
  run: |
    ssh user@server "
      echo 'SSH connection established'
      hostname
      whoami
    "

Das wirkt zunächst redundant.

Für die Fehlersuche ist die Trennung aber wertvoll.

Scheitert später rsync, ist bereits bekannt, ob grundsätzlich ein SSH-Problem vorliegt oder tatsächlich das Deployment fehlschlägt.


Vor dem Deployment muss das Theme geprüft werden

Automatisierung sollte Fehler nicht nur schneller ausliefern.

Sie sollte bekannte Fehlerklassen verhindern.

Bei einem klassischen WordPress-Theme können bereits sehr einfache Prüfungen viel abfangen.

PHP-Syntax prüfen

PHP besitzt dafür bereits einen eingebauten Syntaxcheck:

php -l functions.php

Für alle PHP-Dateien:

find . \
  -type f \
  -name "*.php" \
  -print0 \
  | xargs -0 -n1 php -l

Ein Syntaxfehler führt zum Abbruch der Pipeline.

Damit kann beispielsweise ein versehentlich fehlendes Semikolon nicht mehr einfach auf Produktion landen.


JavaScript prüfen

Node kann JavaScript-Dateien zumindest syntaktisch prüfen:

node --check assets/js/browser.js

Automatisiert:

for file in $(find assets -type f -name "*.js"); do
    node --check "$file"
done

Das ersetzt keine Tests und keinen Linter.

Es verhindert aber bereits triviale Syntaxfehler.


WordPress-Struktur prüfen

Auch die erwartete Theme-Struktur lässt sich kontrollieren.

Zum Beispiel:

REQUIRED_FILES=(
    "style.css"
    "functions.php"
    "index.php"
    "header.php"
    "footer.php"
    "404.php"
)

for FILE in "${REQUIRED_FILES[@]}"; do
    if [ ! -f "$FILE" ]; then
        echo "Missing: $FILE"
        exit 1
    fi
done

Damit lässt sich eine weitere Klasse unangenehmer Fehler verhindern:

Eine zentrale Datei wurde beim Refactoring versehentlich gelöscht oder nicht committed.

Man kann noch weitergehen und beispielsweise leere PHP-Templates erkennen:

if [ ! -s "$FILE" ]; then
    echo "Template is empty: $FILE"
    exit 1
fi

Das ist simpel.

Aber genau solche simplen Guardrails sind wertvoll.


Poka-Yoke in der Deployment-Pipeline

Das Prinzip dahinter ist dasselbe wie bei Poka-Yoke in Softwarearchitektur und Entwicklungsprozessen:

Einen vermeidbaren Fehler nicht dokumentieren, sondern technisch erschweren oder unmöglich machen.

Eine README könnte sagen:

Vor dem Deployment bitte kontrollieren, ob index.php vorhanden ist.

Eine Pipeline kann stattdessen sagen:

index.php fehlt
      ↓
Pipeline rot
      ↓
kein Deployment

Die zweite Variante ist zuverlässiger.


Warum rsync?

Für ein klassisches WordPress-Theme ist rsync ein sehr passendes Werkzeug.

Es synchronisiert Verzeichnisse effizient und überträgt nur notwendige Änderungen.

Ein typischer Aufruf:

rsync -az \
  ./ \
  user@server:/path/to/theme/

Interessant wird insbesondere die Option:

--delete

Damit werden Dateien auf dem Ziel entfernt, die im Quellverzeichnis nicht mehr existieren.


Warum --delete wichtig ist

Nehmen wir an, ein Theme enthielt früher:

assets/js/
├── browser.js
├── category-sort.js
└── old-navigation.js

Nach einem Refactoring existiert im Repository nur noch:

assets/js/
└── browser.js

Ein normaler Upload überschreibt möglicherweise browser.js.

Die anderen Dateien bleiben aber auf dem Server.

Mit:

rsync --delete

wird das Ziel tatsächlich synchronisiert.

Danach gilt:

Repository
    =
Produktionsverzeichnis

Das ist genau das gewünschte Verhalten.


Warum --delete gleichzeitig gefährlich ist

Angenommen, der konfigurierte Zielpfad lautet versehentlich:

/wp-content/

statt:

/wp-content/themes/my-theme/

Dann bekommt der Begriff --delete plötzlich eine völlig andere Bedeutung.

Deshalb sollte eine produktive Pipeline das Deployment-Ziel überprüfen.

Beispielsweise:

TARGET="${THEME_PATH}"
EXPECTED_SUFFIX="/wp-content/themes/my-theme"

if [[ "$TARGET" != *"$EXPECTED_SUFFIX" ]]; then
    echo "Unsafe deployment target"
    exit 1
fi

Erst danach darf rsync --delete ausgeführt werden.

Das ist wieder Poka-Yoke:

Konfigurationsfehler
       ↓
Guard erkennt falschen Pfad
       ↓
Deployment wird gestoppt

statt:

Konfigurationsfehler
       ↓
rsync --delete
       ↓
Problem

Erst ansehen, dann verändern: rsync --dry-run

Ein weiterer sinnvoller Guardrail ist ein Dry Run.

rsync kann berechnen, was passieren würde, ohne tatsächlich etwas zu verändern:

rsync -azn \
  --delete \
  --itemize-changes \
  ./ \
  user@server:/path/to/theme/

Das n steht für Dry Run.

Mit:

--itemize-changes

wird zusätzlich sichtbar, welche Änderungen geplant sind.

Beispielsweise:

>f.st...... assets/css/site.css
>f.st...... functions.php
>f+++++++++ inc/helpers.php
*deleting   assets/js/category-sort.js

Damit besitzt die Pipeline vor dem eigentlichen Deployment bereits eine Art Änderungsplan.

Das ist insbesondere nach größeren Refactorings hilfreich.


Backup vor Deployment

Validierung reduziert das Risiko.

Sie beseitigt es nicht.

Deshalb sollte unmittelbar vor dem Deployment der aktuelle Produktionsstand gesichert werden.

Ein Backupname kann beispielsweise enthalten:

my-theme-20260913-112500-a91e42f

Darin stecken:

Theme
Timestamp
Commit

Konzeptionell:

Aktuelles Production Theme
          │
          ├──────────────► Backup
          │
          ▼
     neues Deployment

Ein einfacher serverseitiger Backup-Schritt könnte so aussehen:

TIMESTAMP=$(date -u +"%Y%m%d-%H%M%S")

cp -a \
  /path/to/theme \
  /path/to/backups/theme-${TIMESTAMP}

Damit hängt die Wiederherstellung nicht davon ab, ob irgendwo noch eine passende ZIP-Datei existiert.


Backups brauchen eine Retention Policy

Automatische Backups erzeugen ein neues Problem:

Sie funktionieren.

Bei jedem Deployment entsteht ein weiteres Verzeichnis.

Nach genügend Deployments sieht der Server so aus:

backups/
├── theme-001
├── theme-002
├── theme-003
├── ...
├── theme-184
└── theme-185

Deshalb gehört zur Backup-Strategie auch eine Retention Policy.

Beispielsweise:

Die letzten zehn Deployments werden behalten.

Ältere Backups werden automatisch entfernt.

Das Prinzip ist allgemeiner als WordPress:

Ein Backup-Konzept definiert nicht nur, wie Sicherungen entstehen, sondern auch, wie lange sie existieren.


Das eigentliche Deployment

Nach Validierung, Zielprüfung, Dry Run und Backup kann synchronisiert werden:

rsync -az \
  --delete \
  --itemize-changes \
  --stats \
  --human-readable \
  --exclude=".git/" \
  --exclude=".github/" \
  --exclude=".gitignore" \
  --exclude="README.md" \
  ./ \
  user@server:/path/to/theme/

Mehrere Optionen verbessern dabei nicht das Deployment selbst, sondern dessen Beobachtbarkeit.

--itemize-changes zeigt die einzelnen Änderungen.

--stats liefert Statistiken.

--human-readable macht Größen verständlicher.

Dadurch ist im GitHub-Actions-Log nicht nur sichtbar:

Process exited with code 0

sondern auch, was tatsächlich verändert wurde.


Ein grünes rsync bedeutet nicht, dass die Website funktioniert

Das ist einer der wichtigsten Punkte der gesamten Pipeline.

Angenommen:

rsync
  ↓
Exit Code 0

Dann wissen wir:

Die Dateien wurden erfolgreich synchronisiert.

Wir wissen nicht:

WordPress funktioniert.

Ein PHP-Fehler könnte erst beim Ausführen eines bestimmten Templates auftreten.

Eine Funktion könnte zwar syntaktisch korrekt sein, aber zur Laufzeit scheitern.

Ein Template könnte falsche Daten erwarten.

Eine Seite könnte nach dem Deployment leer sein.

Deshalb endet das Deployment nicht mit rsync.


Smoke Tests gegen Produktion

Nach dem Deployment kann GitHub Actions die echte Website aufrufen.

Zum Beispiel:

curl \
  --silent \
  --show-error \
  --location \
  --output /tmp/homepage.html \
  --write-out "%{http_code}" \
  "https://example.com/"

Dann wird der HTTP-Status geprüft:

if [ "$HTTP_CODE" != "200" ]; then
    exit 1
fi

Dasselbe kann für zentrale Seiten geschehen:

Homepage
Articles
wichtige Landingpage

Damit prüft die Pipeline erstmals nicht mehr nur Dateien.

Sie prüft das laufende System.


HTTP 200 reicht ebenfalls nicht

Auch das ist nur eine erste Näherung.

Eine Website kann HTTP 200 zurückgeben und trotzdem kaputt sein.

Beispielsweise könnte die Antwort enthalten:

Fatal error

oder:

There has been a critical error on this website.

Deshalb kann ein einfacher Smoke Test zusätzlich nach bekannten Fehlermustern suchen:

grep -Eqi \
  'Fatal error|Parse error|Uncaught Error|critical error'

Werden solche Muster gefunden, schlägt die Pipeline fehl.

Zusätzlich kann erwartetes Markup kontrolliert werden:

grep -qi "<html" /tmp/homepage.html
grep -qi "<body" /tmp/homepage.html

Auch das beweist nicht, dass die Website vollständig korrekt funktioniert.

Das ist nicht der Anspruch eines Smoke Tests.

Der Smoke Test beantwortet eine kleinere Frage:

Ist das System nach dem Deployment grundsätzlich noch am Leben?


Validierung, Tests und Monitoring sind nicht dasselbe

Die Pipeline enthält inzwischen mehrere Schutzebenen:

Static Validation
        │
        │ PHP syntaktisch korrekt?
        │ JS syntaktisch korrekt?
        │ Theme vollständig?
        ▼
Deployment Guards
        │
        │ Zielpfad korrekt?
        │ Änderungen plausibel?
        ▼
Backup
        │
        ▼
Deployment
        │
        ▼
Smoke Tests
        │
        │ Server erreichbar?
        │ HTTP 200?
        │ HTML vorhanden?
        │ Fatal Error?
        ▼
Production

Jede Ebene beantwortet andere Fragen.

Keine davon macht die anderen überflüssig.


Deployment-Feedback ist Teil des Systems

Ein Deployment-Workflow sollte nicht nur funktionieren.

Er sollte verständlich erklären, was passiert ist.

Eine minimale Action zeigt vielleicht:

Validate       ✓
Deploy         ✓

Das ist besser als nichts.

Es fehlen aber wichtige Informationen.

Eine aussagekräftigere Zusammenfassung könnte so aussehen:

Production deployment succeeded

Theme               my-theme
Previous version    1.3.1
Deployed version    1.4.0
Commit              41ef712
Planned changes     17
Planned deletions   4
Backup              Created
Backups remaining   10
Homepage            HTTP 200
Articles            HTTP 200
Fatal-error scan    Passed

GitHub Actions stellt dafür GITHUB_STEP_SUMMARY bereit.

Beispielsweise:

{
    echo "## Production deployment succeeded"
    echo ""
    echo "| Item | Result |"
    echo "|---|---|"
    echo "| Homepage | HTTP 200 |"
    echo "| Backup | Created |"
    echo "| Fatal-error scan | Passed |"
} >> "$GITHUB_STEP_SUMMARY"

Damit wird die Pipeline selbst zu einem kleinen Deployment-Protokoll.


Die Theme-Version mitführen

WordPress-Themes besitzen in style.css bereits Metadaten:

/*
Theme Name: My Theme
Version: 1.4.0
*/

Die Pipeline kann diese Version auslesen:

VERSION=$(sed -n \
  's/^[[:space:]]*Version:[[:space:]]*//p' \
  style.css \
  | head -1)

Vor dem Deployment lässt sich die produktive Version auslesen.

Danach die neue.

Das Ergebnis:

Previous version: 1.3.1
Deployed version: 1.4.0

Damit wird die Theme-Version Teil des Deployment-Prozesses statt nur eine dekorative Angabe in WordPress.


Was gehört nicht auf den Server?

Das Repository enthält möglicherweise Dateien, die zur Entwicklung gehören, aber nicht zum Theme.

Beispielsweise:

.git/
.github/
.gitignore
README.md
*.zip
*.tmp
*.bak

Diese können beim Deployment ausgeschlossen werden:

--exclude=".git/"
--exclude=".github/"
--exclude=".gitignore"
--exclude="README.md"
--exclude="*.zip"
--exclude="*.tmp"
--exclude="*.bak"

Damit wird aus dem Repository gezielt das Produktionsartefakt erzeugt.

Bei komplexeren Projekten wäre ein expliziter Build-Schritt noch sauberer.

Für ein klassisches PHP-WordPress-Theme reicht eine kontrollierte Synchronisation häufig aus.


main automatisch deployen oder Releases verwenden?

Ein Push auf main kann unmittelbar Produktion aktualisieren:

on:
  push:
    branches:
      - main

Das ist echtes Continuous Deployment.

Der Ablauf:

Commit
  ↓
Push main
  ↓
Validation
  ↓
Deployment
  ↓
Production

Eine konservativere Variante verwendet Git-Tags:

on:
  push:
    tags:
      - "v*"

Dann:

git tag v1.4.0
git push origin v1.4.0

Der Tag wird zum expliziten Release-Signal.

Beide Modelle sind legitim.

Die Entscheidung hängt davon ab, welche Bedeutung main im Entwicklungsprozess hat.


Noch eine Stufe weiter: GitHub Environments

GitHub unterstützt Environments wie:

development
staging
production

Ein Deployment-Job kann explizit einem Environment zugeordnet werden:

environment:
  name: production
  url: https://example.com

Darauf lassen sich weitere Regeln aufbauen.

Bei größeren Systemen entsteht daraus beispielsweise:

Pull Request
     │
     ▼
CI
     │
     ▼
Merge
     │
     ▼
Staging
     │
     ▼
Approval
     │
     ▼
Production

Für einen persönlichen WordPress-Blog kann das überdimensioniert sein.

Das zugrunde liegende Konzept bleibt trotzdem wichtig:

Deployment-Ziele sind eigene Umgebungen mit eigenen Regeln und Secrets.


Was diese Pipeline nicht löst

Automatisierung sollte nicht mit Sicherheit verwechselt werden.

Die beschriebene Pipeline schützt beispielsweise nicht automatisch vor:

  • semantischen PHP-Fehlern
  • fehlerhaftem CSS
  • kaputtem Responsive Design
  • JavaScript-Logikfehlern
  • falschen WordPress Queries
  • Datenbankproblemen
  • Plugin-Inkompatibilitäten
  • Änderungen an WordPress-Inhalten
  • defekten externen Diensten

Ein Theme kann alle Syntaxchecks bestehen und trotzdem visuell zerstört sein.

Dafür wären weitere Ebenen notwendig:

Unit Tests
Integration Tests
Browser Tests
Visual Regression Tests
Staging
Monitoring

Eine Pipeline muss nicht alles prüfen.

Sie sollte aber klar definieren, was ein grüner Status bedeutet.

In diesem Fall bedeutet er ungefähr:

Der erwartete Theme-Code ist vollständig, syntaktisch valide, wurde auf das richtige Ziel synchronisiert und die wichtigsten WordPress-Seiten antworten danach ohne offensichtlichen Laufzeitfehler.

Das ist bereits erheblich stärker als:

Der Upload ist fertig.


Der vollständige Denkprozess

Am Anfang steht häufig dieses Modell:

Ich habe ein WordPress-Theme.

Ich ändere Dateien.

Dann lade ich sie hoch.

Das führt fast automatisch zu einem dateizentrierten Prozess.

Das bessere Modell lautet:

Ich entwickle Software.

Das Repository beschreibt einen definierten Zustand.

Dieser Zustand wird validiert.

Ein validierter Zustand wird deployt.

Der vorherige Zustand wird gesichert.

Das Deployment wird anschließend verifiziert.

Daraus entsteht:

Git Repository
      │
      │ Source of Truth
      ▼
┌─────────────────┐
│   Validation    │
│                 │
│ PHP             │
│ JavaScript      │
│ Theme structure │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ Deployment Guard│
│                 │
│ SSH             │
│ Target check    │
│ rsync dry-run   │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│     Backup      │
│                 │
│ Timestamp       │
│ Commit          │
│ Retention       │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│    Deployment   │
│                 │
│ rsync           │
│ --delete        │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  Verification   │
│                 │
│ HTTP            │
│ HTML            │
│ Fatal errors    │
└────────┬────────┘
         │
         ▼
     Production

GitHub Actions ist dabei nicht der entscheidende Teil.

Auch GitLab CI/CD, Jenkins, Azure DevOps oder ein anderes System könnten denselben Prozess abbilden.

Die entscheidende Veränderung ist die Architektur des Entwicklungsprozesses.


Vom Theme-Upload zum Software-Deployment

Der Unterschied zwischen beiden Ansätzen lässt sich auf wenige Zeilen reduzieren.

Vorher:

Dateien ändern
    ↓
Dateien hochladen
    ↓
fertig

Nachher:

Änderung
    ↓
Git
    ↓
Validierung
    ↓
Dry Run
    ↓
Backup
    ↓
Deployment
    ↓
Smoke Test
    ↓
Production

Das wirkt für ein WordPress-Theme zunächst nach viel Infrastruktur.

Die einzelnen Bausteine sind jedoch klein.

Ein PHP-Syntaxcheck kostet fast nichts.

Ein SSH-Verbindungstest kostet fast nichts.

Ein rsync --dry-run kostet fast nichts.

Ein Backup vor dem Überschreiben kostet wenig.

Ein HTTP-Smoke-Test kostet wenige Sekunden.

Zusammen verändern diese kleinen Guardrails die Eigenschaft des gesamten Prozesses.

Das Theme liegt nicht mehr einfach auf einem Webserver.

Es besitzt einen nachvollziehbaren Lebenszyklus.

Und genau das sollte für ein WordPress-Theme genauso selbstverständlich sein wie für jede andere Software.