Skip to content

feat: Umfassende Verbesserungen des Maintenance AddOns#156

Merged
skerbis merged 48 commits intomainfrom
feature/maintenance-improvements
Oct 29, 2025
Merged

feat: Umfassende Verbesserungen des Maintenance AddOns#156
skerbis merged 48 commits intomainfrom
feature/maintenance-improvements

Conversation

@skerbis
Copy link
Member

@skerbis skerbis commented Oct 29, 2025

Maintenance AddOn - Umfassende Verbesserungen & Neue Features

📋 Zusammenfassung

Diese PR bringt umfassende Verbesserungen, neue Features und wichtige Bugfixes für das Maintenance AddOn. Die Änderungen umfassen Performance-Optimierungen, neue Funktionen für zeitgesteuerte Wartung, Silent Mode für Staging-Umgebungen, UI-Verbesserungen und zahlreiche Bugfixes.

✨ Neue Features

1. Zeitgesteuerte Wartung (Scheduled Maintenance)

  • Automatische Aktivierung/Deaktivierung des Wartungsmodus zu festgelegten Zeiten
  • Cronjob-basiert: Funktioniert ausschließlich über den Cronjob "Geplante Wartung prüfen"
  • Neue Felder in der Konfiguration:
    • scheduled_start: Startzeitpunkt (Y-m-d H:i:s)
    • scheduled_end: Endzeitpunkt (Y-m-d H:i:s)
  • Cronjob: rex_cronjob_scheduled_maintenance für minutengenaue Ausführung
  • Automatisches Zurücksetzen der geplanten Zeiten nach Ende
  • Cronjob-Status-Anzeige: Warnung in den Einstellungen, wenn Cronjob nicht eingerichtet ist
  • Eigene Planungs-Seite: Unter Maintenance > Frontend > Planung

Verwendung:

// 1. Cronjob "Geplante Wartung prüfen" im System einrichten (erforderlich!)
// 2. In Maintenance > Frontend > Planung konfigurieren:
scheduled_start: 2025-12-31 02:00:00
scheduled_end: 2025-12-31 04:00:00

2. Wartungsankündigung

  • Ankündigung von geplanten Wartungsarbeiten im Frontend
  • Editor-Unterstützung (Redactor, TinyMCE, CKEditor, etc.)
  • Zeitraum für Anzeige der Ankündigung konfigurierbar
  • Ausgabe über Maintenance::showAnnouncement()
  • Kombiniert mit Zeitgesteuerter Wartung auf Planungs-Seite
  • Sendet nur HTTP-Status-Code ohne HTML-Inhalte
  • Ideal für Staging-Umgebungen, die nicht indexiert werden sollen
  • Verhindert Rückschlüsse auf das verwendete CMS
  • Zeigt keine Wartungsmeldungen an
  • Konfigurierbar über Checkbox in erweiterten Einstellungen

3. Silent Mode für Staging/Development

  • Sendet nur HTTP-Status-Code ohne HTML-Inhalte
  • Ideal für Staging-Umgebungen, die nicht indexiert werden sollen
  • Verhindert Rückschlüsse auf das verwendete CMS
  • Zeigt keine Wartungsmeldungen an
  • Konfigurierbar über Checkbox in erweiterten Einstellungen

4. Mehrsprachige Sperrseite mit Language-Switcher

  • Überschrift wechselt dynamisch: "Maintenance" (EN) / "Wartung" (DE)
  • Domain-Anzeige unter der Überschrift (YRewrite oder ServerName)
  • Responsive Language-Switcher in oberer rechter Ecke
  • SessionStorage-basierte Sprachpräferenz
  • Optimiertes Layout (max-width: 450px)

5. Domain-basierte Wartung (nur YRewrite)

  • Domain-spezifische Wartung nur noch über YRewrite-Domains-Seite
  • Manuelle Domain-Whitelist entfernt (vereinfacht die Konfiguration)
  • Übersichtliche Verwaltung aller YRewrite-Domains mit Toggle-Buttons
  • Einzelne Domains können gezielt gesperrt werden

🔧 Verbesserungen & Optimierungen

Performance

  • YRewrite-Check optimiert: Nur einmal statt mehrfach pro Request
  • Redundante Checks entfernt: isDomainInMaintenance() vereinfacht
  • Silent Mode Early Exit: Sofortiger Return ohne HTML-Rendering

Code-Qualität

  • PHP CS Fixer: Code-Style durchgängig vereinheitlicht
  • Inline Assets ausgelagert:
    • assets/js/frontend-advanced.js (IP-Whitelist-Management)
    • assets/js/domains.js (Domain-Toggle-Logik)
    • assets/css/ip-addresses.css (IP-Listen-Styling)
  • Tokenfield-Abhängigkeit entfernt: Einfaches Textfeld statt Bootstrap Tokenfield
  • Cronjob-Standard: lib/cronjob.php statt Unterverzeichnis

UI/UX

  • Neue Planungs-Seite: Zeitgesteuerte Wartung und Ankündigung kombiniert
    • Übersichtliche Darstellung auf einer Seite
    • Cronjob-Status-Prüfung mit Direkt-Link
    • Code-Beispiel für Ankündigungs-Ausgabe
  • Domain-Verwaltung vereinfacht:
    • Nur noch YRewrite-Domains (manuelle Whitelist entfernt)
    • Toggle-Buttons für schnelles Aktivieren/Deaktivieren
    • Übersichtliche Tabelle mit allen Domains
  • IP-Whitelist vereinfacht:
    • Exakte Upkeep-Implementierung übernommen
    • Komma-getrennte Liste statt Tokenfield
    • Click-to-Add-Buttons mit data-Attributen
    • Formatierte IP-Anzeige mit Labels
  • Sidebar optimiert: IP-Sektion entfernt (nicht mehr benötigt)
  • Responsive Layout: Bessere Mobile-Darstellung des Language-Switchers

🐛 Bugfixes

Kritische Fixes

  1. Frontend-Sperre funktioniert wieder (feat: Umfassende Verbesserungen des Maintenance AddOns #156)

    • Mehrsprachigkeits-Logik korrigiert
    • Edge-Cases in Language-Detection behoben
    • Login-Formular wird korrekt angezeigt
  2. IP Click-to-Add repariert

    • Upkeep-Implementierung als Vorbild verwendet
    • Keine Tokenfield-Abhängigkeit mehr
    • Funktioniert zuverlässig ohne Timing-Probleme
  3. rex_i18n aus Frontend-Fragment entfernt

    • Hardcoded "Language" statt translate:maintenance_language
    • Verhindert Übersetzungsfehler im Frontend
  4. Undefined Variable $currentPage

    • Variable früh im Sidebar definiert
    • Keine PHP-Warnings mehr

Kleinere Fixes

  • YRewrite-Existenzprüfung vor Zugriff auf Methoden
  • Authentifizierungs-Typo korrigiert: "authentification" → "authentication"
  • Cronjob-Registrierung in boot.php hinzugefügt
  • Cronjob nach PHPMailer-Standard neu implementiert
  • Language-Button zeigt korrekte aktuelle Sprache
  • Initiale Darstellung der Überschrift (DE als Standard)
  • IP Click-to-Add verwendet name-Attribut statt ID (rex_config_form-kompatibel)
  • Manuelle Domain-Whitelist entfernt (nur noch YRewrite-Domains)

📁 Geänderte Dateien

Neue Dateien

  • lib/cronjob.php (nach PHPMailer-Vorbild implementiert)
  • pages/frontend.scheduled.php (Planungs-Seite: Zeitgesteuerte Wartung + Ankündigung)
  • assets/js/frontend-advanced.js (IP-Whitelist-Management)
  • assets/js/domains.js (Domain-Toggle-Logik)
  • assets/css/ip-addresses.css (IP-Listen-Styling)

Hauptänderungen

  • lib/Maintenance.php:

    • checkScheduledMaintenance() - Neue Methode (nur für Cronjob)
    • checkFrontend() - Silent Mode Early Exit
    • Performance-Optimierungen
  • lib/cronjob.php:

    • Eigenständige Cronjob-Implementierung
    • Nach PHPMailer-Vorbild strukturiert
    • Direkte Config-Manipulation
  • pages/frontend.index.php:

    • Zeitgesteuerte Wartung entfernt (auf eigene Seite verschoben)
    • Vereinfachte Grundeinstellungen
  • pages/frontend.scheduled.php:

    • Neue kombinierte Planungs-Seite
    • Zeitgesteuerte Wartung mit Cronjob-Status
    • Wartungsankündigung mit Editor-Unterstützung
    • Code-Beispiel und Quick-Links
  • pages/frontend.advanced.php:

    • IP-Whitelist ohne Tokenfield
    • Externe JS/CSS-Einbindung
    • Vereinfachte Logik
  • pages/domains.php:

    • Externe JS-Einbindung
    • Inline-Script entfernt
  • fragments/maintenance/frontend.php:

    • Mehrsprachige Überschrift
    • Domain-Anzeige
    • Language-Switcher optimiert
    • Responsive Layout
  • boot.php:

    • Cronjob-Registrierung hinzugefügt
    • OUTPUT_FILTER für frontend/scheduled aktiviert
    • Tokenfield-Assets entfernt
    • Nur noch Maintenance-eigene CSS
  • package.yml:

    • Neue Unterseite "scheduled" unter frontend
    • frontend.announcement entfernt
    • Icon: fa-calendar-alt für Planungs-Seite
    • Neue Default-Config-Werte
  • lang/de_de.lang:

    • Neue Sprachkeys für Cronjob-Status und Planung
    • Editor-Hinweis korrigiert (kein "obiges" Feld mehr)
    • Aktualisierte Beschreibungen

Entfernte Dateien

  • fragments/maintenance/frontend_old.php (temporäres Backup)
  • pages/frontend.announcement.php (in frontend.scheduled.php integriert)

🔄 Breaking Changes

Keine Breaking Changes - Alle Änderungen sind abwärtskompatibel.

Bestehende Konfigurationen bleiben erhalten und funktionieren weiterhin.

📦 Migration

Update-Schritte

  1. AddOn aktualisieren
  2. Cache leeren
  3. Cronjob einrichten (erforderlich für zeitgesteuerte Wartung):
    • System > Cronjobs aufrufen
    • Neuen Cronjob erstellen
    • Typ: "Geplante Wartung prüfen" auswählen
    • Ausführungsart: z.B. "Jede Minute" oder "Alle 5 Minuten"
    • Speichern

Neue Config-Werte (automatisch gesetzt)

silent_mode: false
scheduled_start: ''
scheduled_end: ''

🧪 Testing

Getestet mit:

  • ✅ REDAXO 5.17.0+
  • ✅ PHP 8.2+
  • ✅ YRewrite (optional)
  • ✅ Mit/ohne Mehrsprachigkeit
  • ✅ Desktop & Mobile
  • ✅ Light & Dark Mode

📝 Review-Kommentare aus PR #156

Alle Review-Kommentare wurden adressiert:

  • YRewrite-Checks optimiert
  • Authentifizierungs-Typo korrigiert
  • Mehrsprachigkeits-Logik korrigiert
  • Frontend-Sperre funktioniert
  • Code-Style mit PHP CS Fixer
  • Performance-Optimierungen umgesetzt

📸 Screenshots

Planungs-Seite (Maintenance > Frontend > Planung)

  • Zeitgesteuerte Wartung mit Cronjob-Status-Anzeige
  • Wartungsankündigung mit Editor-Unterstützung
  • Code-Beispiel für Template-Integration
  • Quick-Links zur Navigation

Erweiterte Einstellungen

  • Silent Mode Checkbox
  • IP-Whitelist mit Click-to-Add

Sperrseite

  • Mehrsprachige Überschrift mit Language-Switcher
  • Domain-Anzeige
  • Responsive Layout (max-width: 450px)

Summary by CodeRabbit

Release Notes v3.5.0

New Features

  • Multilingual maintenance frontend mit EN/DE-Sprachumschalter
  • Domain-basierte Wartungsverwaltung über YRewrite-Integration
  • Zeitgesteuerte Wartung mit Cronjob-Unterstützung
  • Silent Mode für stille Wartungsarbeiten
  • Erweiterte Einstellungen und separate Admin-Seiten für Frontend, Domains und geplante Wartungen
  • Quick-Add-Buttons für IP-Whitelist-Verwaltung
  • Verbesserte Konsolen-Commands mit Status-, Frontend-, Backend- und Domain-Optionen

Improvements

  • Überarbeitete Authentifizierungskonfiguration und Fehlerbereinigung
  • FontAwesome-Icons für Wartungsstatus und UI-Verbesserungen

- Emojis durch Font Awesome 6 Icons ersetzt
- YRewrite Domain-Verwaltung hinzugefügt mit Migration
- Settings in übersichtliche Unterseiten reorganisiert (Wartung, Einstellungen, Ankündigung, Domains)
- Mehrsprachige Wartungstexte (Deutsch/Englisch) mit Sprachswitcher
- Modernes upkeep-inspiriertes Design übernommen
  - Card-basiertes Layout mit Animationen
  - Dark Mode Support
  - Responsive Design
  - Dropdown-Sprachauswahl mit Globe-Icon
- IP-Adressen per Klick zur Whitelist hinzufügen
- Login-Formular nur bei gesetztem Passwort anzeigen
- Intelligente Bypass-URL-Anzeige (nur für gesperrte Domains)
- Sidebar-Komponente für alle Frontend-Seiten
- Editor-Konfiguration in Einstellungen verschoben
- Begriffe vereinheitlicht (Wartungsmodus -> Wartung)
- Weiterleitungs-URL zu allgemeinen Einstellungen verschoben
Copilot AI review requested due to automatic review settings October 29, 2025 16:58
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 29, 2025

Warning

Rate limit exceeded

@skerbis has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 10 minutes and 38 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 6a33aa2 and b476bea.

📒 Files selected for processing (3)
  • RELEASE.md (1 hunks)
  • package.yml (3 hunks)
  • update.php (2 hunks)

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Moin,

Walkthrough

Das Maintenance-Addon wird von v3.4.0 auf v3.5.0 erweitert mit Domain-basierten Wartungsfunktionen (YRewrite-Integration), zeitgesteuerte Wartung via Cronjob, multilinguales Frontend, stille Wartung, IP-Whitelist-Verwaltung und erweiterte Einstellungen. Das Frontend wird in spezialisierte Seiten aufgeteilt und die CLI-Befehle werden mit neuen Aktionen erweitert.

Changes

Cohort / File(s) Zusammenfassung
Neue CSS-Styling-Assets
assets/css/maintenance-icons.css, assets/css/ip-addresses.css
FontAwesome-basierte Icons für Status-Indikatoren, Authentifizierungsmethoden und Wartungsblöcke; IP-Adress-UI-Styling mit flexiblem Layout für Whitelist-Verwaltung
Bootstrap und Konfiguration
boot.php
Cronjob-Typ-Registrierung, Frontend-Aktivierungsbedingungen erweitert (domain-level checks), Bootstrap-Tokenfield entfernt, maintenance-icons.css hinzugefügt, OUTPUT\_FILTER-Setup erweitert
Frontend-Fragment mit Mehrsprachigkeit
fragments/maintenance/frontend.php
HTML5-DOCTYPE, Mehrsprachunterstützung (EN/DE) mit Language-Switcher, inline nonce-geschützter Stylesheet, Domain-Rendering, sessionStorage für Sprachpersistenz, dynamische Überschriften und Meldungen
Login-Fragment Bugfix
fragments/maintenance/login.php
Typo-Behebung: authentification_modeauthentication_mode, Input-ID und autocomplete-Attribute hinzugefügt
Deutsche Sprachzeichenfolgen
lang/de_de.lang
Umfangreiche Aktualisierungen: Wartungsmodus → Wartung, Authentifizierung-Schlüssel korrigiert, neue Sections für geplante Wartung, Domain-Verwaltung, stille Wartung, erweiterte Einstellungen, Quick Links, IP/Domain-Management
Englische Sprachzeichenfolgen
lang/en_gb.lang
Hinweise zu IP-Adressen aktualisiert, neue Schlüssel für IP-Verwaltung UI-Labels (maintenance_your_ip, maintenance_server_ip, maintenance_add_ip, maintenance_add_server_ip)
Maintenance-Kernbibliothek
lib/Maintenance.php
Neue öffentliche Methoden: isDomainInMaintenance() für Domain-Basis-Checks, checkScheduledMaintenance() für Zeit-basierte Aktivierung/Deaktivierung; Silent-Mode und Domain-Status-Indikatoren
Cronjob für geplante Wartung
lib/cronjob.php
Neue Klasse rex_cronjob_scheduled_maintenance mit execute() für automatische Aktivierung/Deaktivierung basierend auf Start/End-Zeiten, getTypeName() und getParamFields()
Wartungsmodus-CLI-Befehl
lib/command/maintenance_mode.php
Action-basierter Befehlsfluss mit neuen Handlern: showStatus(), toggleFrontend(), toggleBackend(), handleDomain(), toggleAll(); neue Aktionen status/frontend/backend/domain/all; Legacy-Unterstützung für on/off
Package-Konfiguration
package.yml
Version 3.5.0, neue Frontend-Subseiten (index/advanced/scheduled), neue Seite domains, neue Config-Schlüssel (allowed\_yrewrite\_domains, authentication\_mode, domain\_status, silent\_mode, scheduled\_start/end, maintenance\_text\_en/de), Editor von redactor zu cke5 geändert
Frontend-Einstellungsseiten (aufgeteilt)
pages/frontend.index.php, pages/frontend.advanced.php, pages/frontend.scheduled.php
Ursprüngliche pages/frontend.php in spezialisierte Seiten aufgeteilt: index (Basis-Einstellungen), advanced (IP-Whitelist, stille Wartung, HTTP-Code), scheduled (zeitgesteuerte Wartung, Ankündigungen); nur Admin-Zugriff
Gelöschte Datei
pages/frontend.php
Vollständige Entfernung der ursprünglichen Frontend-Einstellungsseite (Funktionalität in neue Subseiten migriert)
Domains-Management
pages/domains.php
Neue YRewrite-Domain-Verwaltungsseite mit globalem Lockdown-Schalter und per-Domain-Statussen; speichert Konfiguration auf Formular-Submit
Frontend-Sidebar-Panel
pages/frontend.sidebar.php
Neue Sidebar mit Vorschau-Link, Bypass-URL-Liste (Standard + YRewrite-Domains), Quick-Links zu anderen Frontend-Seiten und Domain-Einstellungen
JavaScript UI-Interaktion
assets/js/domains.js
Sichtbarkeitstoggle für Per-Domain-Sektion basierend auf all\_domains\_locked Status
JavaScript IP-Verwaltung
assets/js/frontend-advanced.js
Funktionen zum Hinzufügen von IPs zur Whitelist mit Deduplizierung und Validierung; Event-Handler für Add-IP-Buttons
Migrations- und Update-Logik
update.php
Umbennung authententification_modeauthentication_mode, Migration alter allowed\_yrewrite\_domains zu neuem domain\_status mit per-Domain-Speicherung
Dokumentation
README.md
Neue Dokumentation für Silent Mode, zeitgesteuerte Wartung, erweiterte Console-Befehle, Autoren/Credits aktualisiert

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Frontend as Frontend-Besucher
    participant Boot
    participant Cronjob
    participant Maintenance as Maintenance.php
    participant Config

    rect rgb(200, 220, 255)
    note over User,Config: Zeitgesteuerte Wartung
    User->>Boot: Cronjob startet
    Boot->>Cronjob: rex_cronjob_scheduled_maintenance::execute()
    Cronjob->>Config: Lese scheduled_start/scheduled_end
    Cronjob->>Maintenance: Zeit im Fenster?
    alt Innerhalb des Zeitfensters & Frontend nicht gesperrt
        Maintenance->>Config: Setze block_frontend = true
        Cronjob-->>User: ✓ Wartung aktiviert bis [end_time]
    else Nach scheduled_end & Frontend gesperrt
        Maintenance->>Config: Setze block_frontend = false, lösche Zeiten
        Cronjob-->>User: ✓ Wartung deaktiviert
    else Keine Änderung
        Cronjob-->>User: → Wartung aktiv/geplant (keine Änderung)
    end
    end

    rect rgb(220, 255, 220)
    note over Frontend,Maintenance: Domain-basierte Wartung Prüfung
    Frontend->>Boot: REQUEST an FRONTEND
    Boot->>Maintenance: checkFrontend() aufgerufen
    Maintenance->>Maintenance: isDomainInMaintenance()?
    alt Domain gesperrt oder global all_domains_locked
        Maintenance->>Frontend: Wartungsseite mit Sprachumschalter
    else Silent Mode aktiv
        Maintenance->>Frontend: HTTP-Status-Code (silent_mode)
    else Domain nicht in Wartung
        Maintenance->>Frontend: Normale Seite
    end
    end

    rect rgb(255, 240, 200)
    note over User,Frontend: Mehrsprachige Frontend-Wartungsseite
    Frontend->>Frontend: Lade Wartungsseite (frontend.php)
    Frontend->>Frontend: Prüfe multilanguageEnabled
    alt Mehrsprache aktiviert
        Frontend->>Frontend: Zeige EN/DE Language-Switcher
        User->>Frontend: Wähle Sprache (DE)
        Frontend->>Frontend: sessionStorage[lang] = 'de'
        Frontend->>Frontend: Blende maintenance_text_de ein
    else Mehrsprache deaktiviert
        Frontend->>Frontend: Zeige default Wartungsmeldung
    end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Bereiche mit erhöhter Aufmerksamkeit:

  • lib/Maintenance.php: Neue Domain-basierte Logik und zeitgesteuerte Wartungsintegration erfordern sorgfältige Prüfung der Kontrollflussbedingungen und der Interaktion mit YRewrite
  • fragments/maintenance/frontend.php: Multilinguales Rendering mit sessionStorage und dynamischer Sprachumschaltung; clientseitige JavaScript-Logik und Inline-Nonce-Handling prüfen
  • Seitenaufspaltung (pages/frontend.index.php, pages/frontend.advanced.php, pages/frontend.scheduled.php): Unterschiedliche Admin-Checks und Sichtbarkeitsbedingungen je Seite; Redundanzvermeidung und konsistente Error-Handling prüfen
  • lib/command/maintenance_mode.php: Neue Action-Dispatch-Logik mit mehreren privaten Handlern; Domain-Argument-Validierung und Fehlerbehandlung für ungültige Actions überprüfen
  • lib/cronjob.php: Zeitfenster-Logik für geplante Wartung; Grenzfälle bei Zeitparsen und Zustandsübergängen (block_frontend Löschen nach Deaktivierung)
  • Language-Datei (lang/de_de.lang): Umfangreiche Additions und Umbenennungen; auf Konsistenz von Schlüsseln über alle neuen Seiten und Features prüfen
  • update.php Migrations-Logik: Sichere Konvertierung alter allowed_yrewrite_domains in neuen domain_status Structure; Rückwärtskompatibilität und fehlende Keys handhaben
  • pages/domains.php: Per-Domain-Status-Speicherung mit gehashtem Feldnamen; YRewrite-Abhängigkeit und Abwesenheitsbehandlung prüfen

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.10% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive Der PR-Titel "feat: Umfassende Verbesserungen des Maintenance AddOns" ist zwar tatsächlich auf das Changeset bezogen und nicht irreführend, verwendet aber eine sehr breite und generische Formulierung. Der Titel beschreibt die Änderungen nicht hinreichend spezifisch: Das PR enthält mehrere bedeutende neue Funktionen (zeitgesteuerte Wartung mit Cronjob-Integration, Silent Mode, mehrsprachige Sperrseite mit Language-Switcher, Domain-basierte Wartung) sowie umfangreiche Code-Quality- und UI/UX-Verbesserungen. Ein Entwickler, der die Git-Historie überfliegt, kann aus dem Titel "Umfassende Verbesserungen" nicht erkennen, welche Hauptmerkmale hinzugefügt wurden. Die Formulierung ist zu abstrakt und könnte auf fast jedes PR mit mehreren Änderungen zutreffen. Erwägen Sie eine präzisere Formulierung des Titels, die die Hauptmerkmale hervorhebt. Beispielsweise: "feat: Add scheduled maintenance, silent mode, and multilingual frontend" oder "feat: Scheduled maintenance with cronjob support and silent mode". Dies würde beim Überfliegen der Projekt-Historie sofort deutlich machen, welche bedeutenden Funktionen diese PR einführt, anstatt eine vage Aussage über "umfassende Verbesserungen" zu treffen.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors the maintenance addon to support per-domain maintenance mode management and improves the UI organization by splitting a monolithic frontend.php file into multiple focused subpages. The implementation adds granular control over YRewrite domains while maintaining backward compatibility.

  • Introduces domain-specific maintenance control with domain_status and all_domains_locked configuration options
  • Splits the frontend settings into separate pages: index (general), advanced (access control), and announcement
  • Adds migration logic in update.php to convert legacy allowed_yrewrite_domains whitelist to the new domain status system
  • Updates the frontend maintenance page with improved styling and multi-language support

Reviewed Changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
update.php Adds migration logic to convert old allowed_yrewrite_domains to new domain_status system
pages/frontend.php Removed monolithic frontend page (replaced by split pages)
pages/frontend.index.php New general settings page with core maintenance options
pages/frontend.advanced.php New advanced settings page for IP control and HTTP settings (admin only)
pages/frontend.announcement.php New announcement settings page (admin only)
pages/frontend.sidebar.php Shared sidebar component showing preview, bypass URLs, and quick links
pages/domains.php New domain management page for per-domain maintenance control
lib/Maintenance.php Adds isDomainInMaintenance() method and integrates domain-based checks
boot.php Integrates domain-based maintenance check in frontend blocking logic
package.yml Updates page structure with subpages and new default config values
fragments/maintenance/frontend.php Redesigned maintenance page with dark mode and language switcher
fragments/maintenance/login.php Improved login form validation logic
lang/de_de.lang Updated German translations for new features
assets/css/maintenance-icons.css New CSS for icon-based status indicators
Comments suppressed due to low confidence (3)

lib/Maintenance.php:1

  • Missing closing brace after line 251. The code has an unclosed if-statement which will cause a syntax error. Add a closing brace } after line 251.
<?php

lib/Maintenance.php:260

  • Potential error if yrewrite addon is not installed. Similar to the boot.php issue, calling rex_addon::get('yrewrite') without first checking if it exists with rex_addon::exists('yrewrite') could throw an exception.
        // If YRewrite is installed and the domain is allowed, do not block the request

lib/Maintenance.php:1

  • The imported function 'count' is never used in the new code additions. While it may be used elsewhere in the file, this import appears to be added unnecessarily in this PR.
<?php

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

$copy = '<ul class="list-group">';

// Prüfen, ob YRewrite verfügbar ist
$yrewriteAvailable = rex_addon::get('yrewrite')->isAvailable();
Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential error if yrewrite addon is not installed. The code assumes yrewrite exists but it may not be installed. Use rex_addon::exists('yrewrite') && rex_addon::get('yrewrite')->isAvailable() instead.

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +16
// Wenn YRewrite nicht verfügbar ist, Hinweis anzeigen
if (!rex_addon::get('yrewrite')->isAvailable()) {
Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential error if yrewrite addon is not installed. Check existence first with rex_addon::exists('yrewrite') before calling get() and isAvailable().

Suggested change
// Wenn YRewrite nicht verfügbar ist, Hinweis anzeigen
if (!rex_addon::get('yrewrite')->isAvailable()) {
// Wenn YRewrite nicht installiert oder nicht verfügbar ist, Hinweis anzeigen
if (!rex_addon::exists('yrewrite') || !rex_addon::get('yrewrite')->isAvailable()) {

Copilot uses AI. Check for mistakes.
update.php Outdated
if ($addon->hasConfig('allowed_yrewrite_domains') && !$addon->hasConfig('domain_status')) {
$oldAllowedDomains = (string) $addon->getConfig('allowed_yrewrite_domains', '');

if ('' !== $oldAllowedDomains && rex_addon::get('yrewrite')->isAvailable()) {
Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential error if yrewrite addon is not installed. The migration code should check rex_addon::exists('yrewrite') before calling get() to avoid exceptions.

Suggested change
if ('' !== $oldAllowedDomains && rex_addon::get('yrewrite')->isAvailable()) {
if ('' !== $oldAllowedDomains && rex_addon::exists('yrewrite') && rex_addon::get('yrewrite')->isAvailable()) {

Copilot uses AI. Check for mistakes.
$tokenfield.tokenfield('setTokens', tokens);
}

$(this).prop('disabled', true).addClass('btn-success').html('<i class="fa fa-check"></i> ' + ip + ' hinzugefügt');
Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded German text 'hinzugefügt' in JavaScript. This should use a translation key or variable from the i18n system to support internationalization.

Copilot uses AI. Check for mistakes.
Comment on lines +54 to +58
$field = $form->addSelectField('authentification_mode');
$field->setLabel($addon->i18n('maintenance_authentification_mode_label'));
$select = $field->getSelect();
$select->addOption($addon->i18n('maintenance_authentification_mode_url'), 'URL');
$select->addOption($addon->i18n('maintenance_authentification_mode_password'), 'password');
Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected spelling of 'authentification' to 'authentication'. The word 'authentification' is a misspelling; the correct term is 'authentication'.

Suggested change
$field = $form->addSelectField('authentification_mode');
$field->setLabel($addon->i18n('maintenance_authentification_mode_label'));
$select = $field->getSelect();
$select->addOption($addon->i18n('maintenance_authentification_mode_url'), 'URL');
$select->addOption($addon->i18n('maintenance_authentification_mode_password'), 'password');
$field = $form->addSelectField('authentication_mode');
$field->setLabel($addon->i18n('maintenance_authentication_mode_label'));
$select = $field->getSelect();
$select->addOption($addon->i18n('maintenance_authentication_mode_url'), 'URL');
$select->addOption($addon->i18n('maintenance_authentication_mode_password'), 'password');

Copilot uses AI. Check for mistakes.
package.yml Outdated
http_response_code: 503 # 503, 403
allowed_ips: ''
allowed_yrewrite_domains: ''
authentification_mode: 'URL' # `URL`, `password`
Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected spelling of 'authentification_mode' to 'authentication_mode'. The configuration key uses a misspelling; it should be 'authentication_mode'.

Suggested change
authentification_mode: 'URL' # `URL`, `password`
authentication_mode: 'URL' # `URL`, `password`

Copilot uses AI. Check for mistakes.
if (!rex_addon::get('yrewrite')->isAvailable()) {
return false;
}

Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential null pointer exception. The code calls rex_article::getCurrentId() and rex_clang::getCurrentId() which may return null if no current article or language is set. This should be guarded or checked for null values before use.

Copilot uses AI. Check for mistakes.
skerbis and others added 3 commits October 29, 2025 18:03
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (7)
fragments/maintenance/frontend_old.php (1)

12-12: Moin! Type-Sicherheit für Meta-Refresh-Intervall verbessern.

Das Update-Intervall sollte explizit als Integer gecastet werden, um potenzielle Injection-Probleme zu vermeiden, auch wenn rex_config vermutlich bereits sichere Werte liefert.

-    <meta http-equiv="refresh" content="<?= $maintenanceFrontendUpdateIntervalNumber > 0 ? $maintenanceFrontendUpdateIntervalNumber : '' ?>">
+    <meta http-equiv="refresh" content="<?= $maintenanceFrontendUpdateIntervalNumber > 0 ? (int) $maintenanceFrontendUpdateIntervalNumber : '' ?>">
boot.php (1)

21-27: Moin! Domain-Maintenance-Check könnte vereinfacht werden.

Die YRewrite-Verfügbarkeitsprüfung erfolgt hier und nochmal in Maintenance::isDomainInMaintenance(). Man könnte den äußeren Check entfernen, da die Methode selbst bereits prüft. Allerdings ist die aktuelle Lösung defensiver und performanter (vermeidet unnötige Methodenaufrufe).

Falls gewünscht, kann vereinfacht werden zu:

-    // Check domain-based maintenance or global frontend maintenance
-    $domainInMaintenance = false;
-    if (rex::isFrontend() && rex_addon::get('yrewrite')->isAvailable()) {
-        $domainInMaintenance = Maintenance::isDomainInMaintenance();
-    }
-
-    if (rex::isFrontend() && ((bool) $addon->getConfig('block_frontend') || $domainInMaintenance)) {
+    if (rex::isFrontend() && ((bool) $addon->getConfig('block_frontend') || Maintenance::isDomainInMaintenance())) {
         Maintenance::checkFrontend();
     }
assets/css/maintenance-icons.css (1)

55-65: Moin! Pseudo-Elemente bei Option-Tags haben begrenzte Browser-Unterstützung.

Die Verwendung von ::before auf <option>-Elementen funktioniert nicht zuverlässig in allen Browsern. Falls die Icons in den Dropdown-Optionen nicht erscheinen, sollte eine alternative Lösung erwogen werden (z.B. Custom-Dropdown oder Icons im Label).

pages/domains.php (1)

123-133: Moin! Verwende strikte Vergleiche in JavaScript.

Der lose Vergleich (==) sollte durch einen strikten Vergleich (===) ersetzt werden, um unerwartetes Typumwandlungsverhalten zu vermeiden.

-        if ($(this).val() == '1') {
+        if ($(this).val() === '1') {
pages/frontend.sidebar.php (2)

44-44: Moin! Verwende strikte Vergleiche für String-Checks.

Der Vergleich 'default' == $key sollte strikt sein (===), um unerwartete Typumwandlungen zu vermeiden.

-        if ('default' == $key) {
+        if ('default' === $key) {

48-63: Moin! Strikte Vergleiche für Domain-Status verwenden.

Die Prüfung des Domain-Status auf Zeile 51 verwendet einen losen Vergleich. Verwende strikte Vergleiche für mehr Typ-Sicherheit.

-        $isDomainLocked = $allDomainsLocked || (isset($domainStatus[$key]) && 1 == $domainStatus[$key]);
+        $isDomainLocked = $allDomainsLocked || (isset($domainStatus[$key]) && 1 === $domainStatus[$key]);
fragments/maintenance/frontend.php (1)

26-358: Moin! Inline-CSS ist funktional, könnte aber externalisiert werden.

Das inline CSS (333 Zeilen) ist vollständig und modern (CSS-Variablen, Dark Mode, Responsive), erhöht aber die Dateigröße und verhindert Browser-Caching. Die Nonce-Verwendung für CSP ist korrekt.

Erwäge, das CSS in eine externe Datei auszulagern (z.B. assets/css/maintenance-frontend.css) und per Asset-System zu laden. Das verbessert Caching und Wartbarkeit. Der Trade-off ist, dass die Wartungsseite dann von einem externen Asset abhängig ist.

Pro extern: Caching, Wartbarkeit, kleinere HTML-Datei
Pro inline: Keine externe Abhängigkeit, funktioniert auch bei Asset-Problemen

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8a32b2d and e7a5669.

📒 Files selected for processing (15)
  • assets/css/maintenance-icons.css (1 hunks)
  • boot.php (2 hunks)
  • fragments/maintenance/frontend.php (2 hunks)
  • fragments/maintenance/frontend_old.php (1 hunks)
  • fragments/maintenance/login.php (1 hunks)
  • lang/de_de.lang (4 hunks)
  • lib/Maintenance.php (4 hunks)
  • package.yml (2 hunks)
  • pages/domains.php (1 hunks)
  • pages/frontend.advanced.php (1 hunks)
  • pages/frontend.announcement.php (1 hunks)
  • pages/frontend.index.php (1 hunks)
  • pages/frontend.php (0 hunks)
  • pages/frontend.sidebar.php (1 hunks)
  • update.php (1 hunks)
💤 Files with no reviewable changes (1)
  • pages/frontend.php
🧰 Additional context used
🧬 Code graph analysis (2)
boot.php (1)
lib/Maintenance.php (3)
  • Maintenance (29-407)
  • isDomainInMaintenance (128-152)
  • getConfig (395-398)
pages/domains.php (1)
lib/Maintenance.php (1)
  • getConfig (395-398)
🔇 Additional comments (19)
package.yml (1)

75-75: Moin! Editor-Wechsel könnte Breaking Change sein.

Der Wechsel von Redactor zu CKEditor5 als Standard-Editor sollte in den Upgrade-Hinweisen dokumentiert werden, damit bestehende Installationen nicht überrascht werden.

Bitte stellt sicher, dass diese Änderung in der README oder im CHANGELOG dokumentiert ist.

fragments/maintenance/login.php (1)

2-6: Moin! Gute Absicherung des Login-Formulars.

Die Bedingung stellt sicher, dass das Passwort-Formular nur angezeigt wird, wenn tatsächlich ein Passwort konfiguriert ist. Das verhindert eine verwirrende leere Login-Maske.

update.php (1)

67-93: Moin! Saubere Migration der Domain-Whitelist.

Die Migrations-Logik invertiert korrekt die alte Whitelist (erlaubte Domains) in das neue System mit domain_status (gesperrte Domains). Die Kommentare erklären die Logik gut und die Implementierung ist korrekt.

assets/css/maintenance-icons.css (1)

13-13: Moin! FontAwesome-Abhängigkeit prüfen.

Das CSS nutzt FontAwesome-Icons (font-family: 'FontAwesome'), setzt aber voraus, dass diese bereits geladen sind. Bitte stellt sicher, dass FontAwesome im REDAXO-Backend verfügbar ist (ist normalerweise der Fall).

pages/frontend.announcement.php (2)

16-19: Moin! Zugriffskontrolle korrekt implementiert.

Die Admin-Prüfung ist korrekt umgesetzt und verhindert unautorisierten Zugriff.


30-32: Moin! Der Platzhalter wird korrekt ersetzt – kein Issue vorhanden.

Die Verifizierung zeigt, dass die Platzhalter-Syntax vollständig implementiert ist:

  • boot.php (Zeilen 47–49): Ein OUTPUT_FILTER-Hook führt str_replace() aus und ersetzt class="###maintenance-settings-editor###" mit dem tatsächlichen Editor-Klassennamen aus der Config (rex_config::get('maintenance', 'editor'))
  • pages/frontend.announcement.php (Zeile 31): Der Platzhalter wird korrekt gesetzt

Die Ersetzung erfolgt während der Output-Filterung, bevor das HTML an den Browser gesendet wird. Dies ist ein valides Muster für bedingte Klassenzuweisung in REDAXO. Der Code funktioniert wie beabsichtigt.

Likely an incorrect or invalid review comment.

pages/domains.php (3)

16-18: Moin! YRewrite-Verfügbarkeitsprüfung korrekt implementiert.

Die Prüfung verhindert sauber Fehler, falls YRewrite nicht verfügbar ist.


29-51: Moin! Speicherlogik ist korrekt implementiert.

Die Formularverarbeitung ist sauber strukturiert: Erst die globale Einstellung, dann die individuellen Domain-Einstellungen nur wenn nötig. Die Verwendung von md5() für Feldnamen ist akzeptabel, um Sonderzeichen in Domain-Namen zu handhaben.


76-91: Moin! XSS-Schutz für Domain-URLs fehlt teilweise.

Auf Zeile 80 wird htmlspecialchars($domain->getUrl()) verwendet, aber der Domain-Name selbst wird direkt ausgegeben. Obwohl YRewrite diese Daten kontrolliert, sollte zur Absicherung auch der Domain-Name escaped werden.

Wende diesen Diff an:

-        $content .= '<td><strong>' . htmlspecialchars($name) . '</strong><br><small class="text-muted">' . htmlspecialchars($domain->getUrl()) . '</small></td>';
+        $content .= '<td><strong>' . rex_escape($name) . '</strong><br><small class="text-muted">' . rex_escape($domain->getUrl()) . '</small></td>';

Likely an incorrect or invalid review comment.

pages/frontend.advanced.php (2)

16-19: Moin! Admin-Zugriffskontrolle korrekt umgesetzt.


83-110: Moin! IP-Hinzufügen-Logik ist gut implementiert.

Die Implementierung prüft korrekt auf Duplikate, aktualisiert sowohl den Input-Wert als auch das Tokenfield-Widget und verhindert mehrfaches Hinzufügen durch Deaktivierung des Buttons.

lib/Maintenance.php (4)

20-20: Moin! Import der count()-Funktion ist korrekt.

Der Import wird für die Domain-Zählung in der Indicator-Logik benötigt.


351-361: Moin! Domain-Indicator-Logik ist sauber implementiert.

Die Anzeige unterscheidet korrekt zwischen "Alle Domains gesperrt" und individuellen Domain-Sperren. Die Verwendung von array_filter() ist effizient.


125-153: Moin! Keine Probleme mit der Domain-Maintenance-Logik.

Die Verifizierung zeigt: $domainStatus wird konsistent mit booleschen Werten populiert:

  • In update.php (Zeile 82): !in_array() liefert boolean
  • In pages/domains.php (Zeile 41): rex_post(..., 'bool', false) liefert boolean

Der Truthiness-Check in Zeile 146 funktioniert deshalb einwandfrei. Keine Gefahr von unerwartetem Verhalten durch Strings oder andere Werte.


247-253: Moin! Die Verhaltensänderung ist intentional, aber verdient dokumentiert zu werden.

Ich habe die Implementierung überprüft:

Alte Version (HEAD~1): Alle Prüfungen (IP, YRewrite, Host, Secret, User) liefen direkt und bedingungslos.

Neue Version (HEAD): Eine neue Domain-Maintenance-Prüfung wurde vorgeschaltet. Sie gatet alle anderen Checks – sie laufen nur noch, wenn die Domain im Wartungsmodus ist.

Dies ist kein Fehler, sondern beabsichtigte Architektur der umfassenden Verbesserung (Commit 6ed3e02). Die YRewrite-Domain-Verwaltung ist eine neue Feature.

Potenzielle Auswirkungen:

  • Wenn isDomainInMaintenance() false zurückgibt (keine Domains konfiguriert), wird sofort erlaubt – die bisherigen Checks werden übersprungen
  • Bestehende Installationen, die sich auf die alten Checks verlassen, könnten betroffen sein

Empfehlung: Dokumentiert diese Verhaltensänderung in den Release Notes. Prüft, ob Backward-Compatibility mit Installationen gewährleistet ist, die die neue Domain-basierte Logik nicht aktiviert haben.

pages/frontend.sidebar.php (1)

74-107: Moin! Quick-Links-Implementierung ist gut strukturiert.

Die Navigation berücksichtigt korrekt die aktuelle Seite und zeigt Admin-Links nur für Admins an. Die YRewrite-Integration ist sauber implementiert.

fragments/maintenance/frontend.php (3)

2-9: Moin! Mehrsprachigkeits-Logik ist sauber implementiert.

Die Prüfung ob beide Sprachen vorhanden sind erfolgt korrekt und ermöglicht eine konditionale Anzeige des Sprachschalters.


362-385: Moin! Sprachauswahl-UI ist gut umgesetzt.

Der konditionale Sprachschalter mit SVG-Icon und Dropdown-Menü ist modern und benutzerfreundlich gestaltet. Die Default-Aktivierung von Englisch ist sinnvoll.


416-478: Moin! JavaScript für Sprachwechsel ist robust implementiert.

Die Implementierung behandelt korrekt:

  • Dropdown-Toggle und Außerhalb-Klicks
  • Sprachwechsel mit visuellen Updates
  • SessionStorage-Persistierung mit Try-Catch für Privacy Mode
  • Wiederherstellung der Sprachpräferenz beim Laden

skerbis and others added 2 commits October 29, 2025 18:07
- Check rex_addon::exists('yrewrite') before calling methods
- Prevents exceptions when yrewrite addon is not installed
- Affected files: frontend.php, frontend.sidebar.php (2x), Maintenance.php (2x)
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
fragments/maintenance/frontend.php (1)

396-396: Moin! Redundante Bedingung im Ternary-Operator.

Die Bedingung '' === $maintenanceTextDe ist überflüssig, da sie bereits durch !$multilanguageEnabled abgedeckt wird. Wenn $maintenanceTextDe leer ist, ist $multilanguageEnabled bereits false (siehe Zeile 8).

Vereinfache die Bedingung:

-        <div class="maintenance-message maintenance-text <?= !$multilanguageEnabled || '' === $maintenanceTextDe ? 'active' : '' ?>" data-lang="en">
+        <div class="maintenance-message maintenance-text <?= !$multilanguageEnabled ? 'active' : '' ?>" data-lang="en">
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e7a5669 and 1acf059.

📒 Files selected for processing (3)
  • boot.php (2 hunks)
  • fragments/maintenance/frontend.php (2 hunks)
  • fragments/maintenance/frontend_old.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • fragments/maintenance/frontend_old.php
🧰 Additional context used
🧬 Code graph analysis (1)
boot.php (1)
lib/Maintenance.php (3)
  • Maintenance (30-408)
  • isDomainInMaintenance (129-153)
  • getConfig (396-399)
🔇 Additional comments (7)
boot.php (4)

21-25: Moin! Saubere Implementierung der Domain-basierten Wartung.

Die Prüfung auf rex_addon::exists('yrewrite') vor isAvailable() und isDomainInMaintenance() ist korrekt und verhindert Exceptions, wenn YRewrite nicht installiert ist.


27-27: Moin! Logische Verknüpfung der Wartungsbedingungen ist korrekt.

Die Kombination aus globalem block_frontend und domain-basiertem $domainInMaintenance ermöglicht flexible Wartungsszenarien. Die OR-Verknüpfung ist semantisch richtig.


41-41: Moin! CSS-Datei hinzugefügt.

Die neue maintenance-icons.css ergänzt das bestehende Styling. Keine Bedenken.


43-45: Moin! Erweiterte Seitenerkennung für OUTPUT_FILTER.

Die zusätzlichen Pfade maintenance/frontend/index und maintenance/frontend/announcement sind konsistent mit der Reorganisation in Unterseiten. Logik ist korrekt.

fragments/maintenance/frontend.php (3)

26-26: Moin! Korrekte Verwendung von Content Security Policy Nonces.

Die Verwendung von rex_response::getNonce() für inline Styles und Scripts schützt effektiv gegen XSS-Angriffe. Gut gemacht!

Also applies to: 416-416


393-393: Moin! Output Escaping korrekt implementiert.

Die Verwendung von rex_escape() für alle nutzergenerierten Inhalte (Headline und Wartungstexte) verhindert XSS-Vulnerabilities. Sicherheit wird gewährleistet.

Also applies to: 397-397, 403-403


417-477: Moin! JavaScript-Implementierung ist solide.

Die Sprachumschaltung ist gut strukturiert:

  • Try-catch-Blöcke schützen vor sessionStorage-Fehlern (z.B. im Inkognito-Modus)
  • Event-Propagation korrekt gestoppt
  • Sprachauswahl wird persistent gespeichert und wiederhergestellt
  • DOM-Manipulation ist sauber und verständlich

skerbis and others added 8 commits October 29, 2025 18:11
- Fix: Internationalize hardcoded German text 'hinzugefügt'
  Added maintenance_ip_added translation key

- Fix: Correct spelling 'authentification' to 'authentication'
  Updated in package.yml, lang files, PHP code
  Added migration for existing installations

- Already fixed: Ternary operator logic in frontend.php
- Already fixed: YRewrite existence checks
- Fix login.php: Use authentication_mode instead of authentification_mode
- Improve update.php migration: Always remove old config key
- All files now consistently use 'authentication' (correct spelling)
README changes:
- Set Thomas Skerbis as lead developer
- Remove sponsor references
- Update project team structure

Console command enhancements:
- Add 'status' command to show current maintenance state
- Add 'frontend on/off' for frontend maintenance
- Add 'backend on/off' for backend maintenance
- Add 'all on/off' to toggle all modes at once
- Add 'domain <name> --lock/--unlock' for YRewrite domains
- Maintain backward compatibility with legacy 'on/off' commands
- Add comprehensive documentation for all commands
Problem: When only German text (maintenance_text_de) was filled and English
text was empty, no text was displayed because the DE block didn't receive
the 'active' class.

Solution: Add fallback logic for DE block:
- DE is active if multilanguage is disabled OR only DE text exists
- EN is active if multilanguage is disabled OR only EN text exists

This ensures at least one text block is always visible when text is provided.
Removed overly restrictive condition that required both password mode AND
a set secret. The login form should be displayed whenever password mode
is selected, regardless of whether a secret is actually configured.

This allows users to see the login form immediately after selecting
password authentication mode, even before setting a password.
- Add id attribute to password input field for better accessibility
- Add autocomplete='off' for better security
- Improve code formatting and comments
- Add debug comment placeholder for troubleshooting
Implements feature request for permanent site blocking without maintenance
messaging, ideal for staging environments in deployment processes.

Features:
- New 'silent_mode' config option
- Sends only HTTP status code (503/403) without HTML content
- Prevents information disclosure about CMS
- Perfect for staging systems that should be permanently offline
- Accessible only via backend login, IP whitelist, or secret URL

Changes:
- Added silent_mode to package.yml default_config
- Added silent_mode checkbox in advanced settings
- Implemented logic in Maintenance::checkFrontend()
- Added German translations
- Updated README with Silent Mode documentation

Use case: Production preview systems that need permanent protection
without revealing 'maintenance mode' or CMS information.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
fragments/maintenance/frontend.php (1)

26-358: Moin! Optional: Erwäge Auslagerung der CSS-Styles in eine externe Datei.

Der inline Style-Block umfasst ~332 Zeilen. Für bessere Wartbarkeit könnte man die Styles in eine separate CSS-Datei auslagern (z.B. assets/css/maintenance-frontend.css). Dies würde die Lesbarkeit des Templates verbessern und CSS-Caching ermöglichen.

Für eine eigenständige Maintenance-Page ist inline CSS jedoch akzeptabel, zumal die CSP-Nonce korrekt verwendet wird.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0813f0e and 9cbc56f.

📒 Files selected for processing (10)
  • README.md (3 hunks)
  • fragments/maintenance/frontend.php (1 hunks)
  • fragments/maintenance/login.php (1 hunks)
  • lang/de_de.lang (4 hunks)
  • lib/Maintenance.php (6 hunks)
  • lib/command/maintenance_mode.php (3 hunks)
  • package.yml (3 hunks)
  • pages/frontend.advanced.php (1 hunks)
  • pages/frontend.index.php (1 hunks)
  • update.php (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • pages/frontend.index.php
  • update.php
  • pages/frontend.advanced.php
🧰 Additional context used
🧬 Code graph analysis (1)
lib/command/maintenance_mode.php (1)
lib/Maintenance.php (1)
  • getConfig (405-408)
🪛 LanguageTool
README.md

[grammar] ~50-~50: Ersetze das Satzzeichen
Context: ...staltung erfolgen. ### Silent Mode für Staging/Development-Umgebungen Der **Silent Mo...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_STAGINGSLASHDEVELOPMENTDASHUMGEBUNGEN_STAGINGDASHSLASHDEVELOPMENTDASHUMGEBUNGEN)


[grammar] ~50-~50: Hier könnte ein Fehler sein.
Context: ... Mode für Staging/Development-Umgebungen Der Silent Mode ist ideal für Stagin...

(QB_NEW_DE)


[grammar] ~52-~52: Hier könnte ein Fehler sein.
Context: ...gen, die permanent gesperrt sein sollen: * Sendet nur den HTTP-Status-Code (z.B. 50...

(QB_NEW_DE)


[uncategorized] ~54-~54: Uneinheitliche Verwendung von Bindestrichen. Der Text enthält sowohl ‚HTTP-Status-Code‘ als auch ‚HTTP-Statuscode‘.
Context: ...gesperrt sein sollen: * Sendet nur den HTTP-Status-Code (z.B. 503 oder 403) * Zeigt keine H...

(DE_COMPOUND_COHERENCY)


[grammar] ~54-~54: Ergänze ein Leerzeichen
Context: ...: * Sendet nur den HTTP-Status-Code (z.B. 503 oder 403) * Zeigt keine HTML-W...

(QB_NEW_DE_OTHER_ERROR_IDS_MISSING_ORTHOGRAPHY_SPACE)


[uncategorized] ~55-~55: Fehlendes Komma: Teilsätze, Einschübe, Aufzählungen und direkte Rede müssen durch ein Komma vom Rest des Satzes getrennt werden.
Context: ...3) * Zeigt keine HTML-Wartungsseite an * Verhindert Rückschlüsse auf das verwe...

(AI_DE_KOMMA_MISSING_COMMA)


[grammar] ~57-~57: Hier könnte ein Fehler sein.
Context: ...ie nur nach Login zugänglich sein sollen Aktivierung: In den erweiterten Einste...

(QB_NEW_DE)


[grammar] ~59-~59: Passe das Symbol an
Context: ...n zugänglich sein sollen Aktivierung: In den erweiterten Einstellungen (Einst...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_OTHER)


[grammar] ~59-~59: Ersetze das Satzzeichen
Context: ...ten Einstellungen (Einstellungen) unter "HTTP-Einstellungen" die Option "Silent Mode"...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_„)


[grammar] ~59-~59: Ersetze das Satzzeichen
Context: ...nstellungen (Einstellungen) unter "HTTP-Einstellungen" die Option "Silent Mode" aktivieren. #...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_L_DOUBLE_QUOT)


[grammar] ~59-~59: Ersetze das Satzzeichen
Context: ...) unter "HTTP-Einstellungen" die Option "Silent Mode" aktivieren. ## Anzeige des aktue...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_„)


[grammar] ~59-~59: Ersetze das Satzzeichen
Context: ..."HTTP-Einstellungen" die Option "Silent Mode" aktivieren. ## Anzeige des aktuellen S...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_L_DOUBLE_QUOT)


[grammar] ~59-~59: Hier könnte ein Fehler sein.
Context: ...en" die Option "Silent Mode" aktivieren. ## Anzeige des aktuellen Status im REDAXO-H...

(QB_NEW_DE)


[grammar] ~81-~81: Verwende Bindestriche bei Nomen
Context: ...` wieder crawlen. 🕵🏻 ## Konsole Das Addon bietet verschiedene Konsolen-Befehle zu...

(QB_NEW_DE_OTHER_ERROR_IDS_ADD_ON_2)


[grammar] ~81-~81: Wähle ein passenderes Wort
Context: ... Konsole Das Addon bietet verschiedene Konsolen-Befehle zur Verwaltung des Wartungsmodus: ### ...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_NOUN)


[grammar] ~81-~81: Hier könnte ein Fehler sein.
Context: ...efehle zur Verwaltung des Wartungsmodus: ### Status anzeigen Zeigt den aktuellen Sta...

(QB_NEW_DE)


[grammar] ~83-~83: Hier könnte ein Fehler sein.
Context: ... des Wartungsmodus: ### Status anzeigen Zeigt den aktuellen Status aller Wartung...

(QB_NEW_DE)


[grammar] ~85-~85: Hier könnte ein Fehler sein.
Context: ... aktuellen Status aller Wartungsmodi an: bash php redaxo/bin/console maintenance:mode status ### Frontend-Wartungsmodus Aktivieren: ```b...

(QB_NEW_DE)


[grammar] ~91-~91: Hier könnte ein Fehler sein.
Context: ...e status ### Frontend-Wartungsmodus Aktivieren:bash php redaxo/bin/conso...

(QB_NEW_DE)


[grammar] ~93-~93: Hier könnte ein Fehler sein.
Context: ... ### Frontend-Wartungsmodus Aktivieren: bash php redaxo/bin/console maintenance:mode frontend on Deaktivieren: ```bash php redaxo/bin/con...

(QB_NEW_DE)


[grammar] ~98-~98: Hier könnte ein Fehler sein.
Context: ...ance:mode frontend on Deaktivieren:bash php redaxo/bin/console maintenance:mode frontend off ### Backend-Wartungsmodus Aktivieren:ba...

(QB_NEW_DE)


[grammar] ~103-~103: Hier könnte ein Fehler sein.
Context: ...ntend off ### Backend-Wartungsmodus Aktivieren:bash php redaxo/bin/conso...

(QB_NEW_DE)


[grammar] ~105-~105: Hier könnte ein Fehler sein.
Context: ... ### Backend-Wartungsmodus Aktivieren: bash php redaxo/bin/console maintenance:mode backend on Deaktivieren: ```bash php redaxo/bin/con...

(QB_NEW_DE)


[grammar] ~110-~110: Hier könnte ein Fehler sein.
Context: ...nance:mode backend on Deaktivieren:bash php redaxo/bin/console maintenance:mode backend off ``` ### Alle Modi gleichzeitig Alle Wartungsmod...

(QB_NEW_DE)


[grammar] ~115-~115: Hier könnte ein Fehler sein.
Context: ...kend off ``` ### Alle Modi gleichzeitig Alle Wartungsmodi (Frontend, Backend und...

(QB_NEW_DE)


[grammar] ~117-~117: Hier könnte ein Fehler sein.
Context: ...d, Backend und alle Domains) aktivieren: bash php redaxo/bin/console maintenance:mode all on Alle Wartungsmodi deaktivieren: ```bash ...

(QB_NEW_DE)


[grammar] ~122-~122: Hier könnte ein Fehler sein.
Context: ... on Alle Wartungsmodi deaktivieren:bash php redaxo/bin/console maintenance:mode all off ``` ### Domain-spezifische Wartung (YRewrite) E...

(QB_NEW_DE)


[grammar] ~127-~127: Hier könnte ein Fehler sein.
Context: ...## Domain-spezifische Wartung (YRewrite) Einzelne Domain sperren: ```bash php red...

(QB_NEW_DE)


[grammar] ~129-~129: Hier könnte ein Fehler sein.
Context: ...ung (YRewrite) Einzelne Domain sperren: bash php redaxo/bin/console maintenance:mode domain example.com --lock Einzelne Domain entsperren: ```bash php ...

(QB_NEW_DE)


[grammar] ~134-~134: Hier könnte ein Fehler sein.
Context: ... --lock Einzelne Domain entsperren:bash php redaxo/bin/console maintenance:mode domain example.com --unlock ``` ### Legacy-Unterstützung Die alten Befehle ...

(QB_NEW_DE)


[grammar] ~139-~139: Hier könnte ein Fehler sein.
Context: ...m --unlock ``` ### Legacy-Unterstützung Die alten Befehle funktionieren weiterhi...

(QB_NEW_DE)


[grammar] ~141-~141: Hier könnte ein Fehler sein.
Context: ...terhin (steuern nur den Frontend-Modus): bash php redaxo/bin/console maintenance:mode on php redaxo/bin/console maintenance:mode off ## Autor Thomas Skerbis – [KLXM Crossm...

(QB_NEW_DE)


[grammar] ~148-~148: Hier könnte ein Fehler sein.
Context: ...nsole maintenance:mode off ``` ## Autor Thomas Skerbis – [KLXM Crossmedia](htt...

(QB_NEW_DE)


[grammar] ~150-~150: Hier könnte ein Fehler sein.
Context: ...r Thomas SkerbisKLXM Crossmedia ## Projekt-Lead * [Thomas Skerbis](https:/...

(QB_NEW_DE)


[grammar] ~152-~152: Hier könnte ein Fehler sein.
Context: ...media](https://klxm.de) ## Projekt-Lead * [Thomas Skerbis](https://github.com/skerb...

(QB_NEW_DE)


[grammar] ~154-~154: Hier könnte ein Fehler sein.
Context: ....de) ## Projekt-Lead * Thomas Skerbis ## Credits Danke an: * [Christian Gehrke]...

(QB_NEW_DE)


[grammar] ~157-~157: Hier könnte ein Fehler sein.
Context: ...https://github.com/skerbis) ## Credits Danke an: * [Christian Gehrke](https://...

(QB_NEW_DE)


[grammar] ~159-~159: Hier könnte ein Fehler sein.
Context: ...hub.com/skerbis) ## Credits Danke an: * [Christian Gehrke](https://github.com/chr...

(QB_NEW_DE)


[grammar] ~161-~161: Wähle ein passenderes Wort
Context: ... Credits Danke an: * Christian Gehrke // first ...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_NOUN)

🔇 Additional comments (4)
fragments/maintenance/frontend.php (1)

416-478: Moin! JavaScript-Implementierung ist solide.

Die clientseitige Sprachverwaltung ist gut umgesetzt:

  • Event-Handler korrekt gebunden
  • stopPropagation() verhindert sofortiges Schließen des Dropdowns
  • Try-catch um sessionStorage-Zugriffe schützt vor Privacy-Modi
  • Sprachpräferenz wird persistent gespeichert und wiederhergestellt

Der Code ist CSP-konform (Nonce verwendet) und funktioniert auch bei deaktiviertem sessionStorage.

Hinweis: Die Sprachwahl funktioniert korrekt, aber der kritische Bug in den Textblöcken (Zeilen 395-405) muss behoben werden, damit beim Erstbesuch standardmäßig englischer Text angezeigt wird.

package.yml (3)

18-30: Moin! Subpage-Struktur ist sauber umgesetzt.

Die neuen verschachtelten Unterseiten unter frontend sind logisch strukturiert:

  • index: Allgemeine Einstellungen (Zugriff via maintenance[frontend])
  • advanced: Erweiterte Einstellungen (nur Admin)
  • announcement: Ankündigung (nur Admin)

Die Berechtigungszuordnung ist sinnvoll und folgt REDAXO-Konventionen.


35-38: Moin! Domains-Subpage korrekt konfiguriert.

Die neue domains-Unterseite ist sinnvoll für die YRewrite-Domain-Verwaltung implementiert. Icon-Wahl (fa-sitemap) passt gut zur Funktionalität, und die Berechtigung maintenance[frontend] ist angemessen.


67-84: Moin! Neue Config-Keys sind sinnvoll definiert.

Die hinzugefügten Konfigurationsschlüssel unterstützen die neuen Features gut:

  • allowed_yrewrite_domains, domain_status, all_domains_locked: Ermöglichen domain-spezifische Wartung
  • authentication_mode: Korrekte Schreibweise (✓ fix from "authentification")
  • maintenance_text_en / maintenance_text_de: Mehrsprachige Wartungstexte mit vernünftigen Defaults
  • silent_mode: Praktisch für HTTP-Status ohne Content
  • editor: Migration zu CKEditor 5 ist zeitgemäß

Die Defaults sind sicher gewählt (Flags auf false, Arrays leer, Strings leer).

Hinweis: Die Editor-Migration sollte in update.php behandelt werden (lt. PR-Beschreibung "Migrationen vorhanden").

skerbis and others added 2 commits October 29, 2025 19:02
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

Copilot AI commented Oct 29, 2025

@skerbis I've opened a new pull request, #157, to work on those changes. Once the pull request is ready, I'll request review from you.

- Behebt Ternary-Operator Fehler: EN-Text war immer als 'active' markiert
- DE-Text ist jetzt standardmäßig 'active', EN-Text nur wenn kein DE-Text vorhanden
- DE-Text ist jetzt standardmäßig aktiv
- EN-Text nur aktiv wenn kein DE-Text vorhanden
- Konsistente Logik zwischen frontend.php und frontend_old.php
- Behebt kritischen Bug: Early-Return umging block_frontend-Schalter
- checkFrontend() prüft jetzt sowohl block_frontend als auch domainbasierte Wartung
- Frontend wird nur dann erlaubt, wenn BEIDE Flags inaktiv sind

Fixes: #156 (comment)
- YRewrite Existenz-Check in domains.php hinzugefügt (verhindert Exception)
- Redundanten Domain-Check in boot.php entfernt (isDomainInMaintenance in checkFrontend)
- Silent Mode Check früher durchgeführt (direkt nach Maintenance-Check)
  * Spart unnötige IP/Host/Secret-Checks bei Silent Mode
  * Verbessert Performance für Staging-Umgebungen
skerbis and others added 6 commits October 29, 2025 18:35
Probleme behoben:
- Button zum Hinzufügen der eigenen IP fehlte in Sidebar
- JavaScript nutzt jetzt Event-Delegation (document.on)
- Timeout für Tokenfield-Initialisierung hinzugefügt
- Feedback für bereits vorhandene IPs

Verbesserungen:
- Zeigt eigene IP-Adresse in Sidebar (nur auf Advanced-Seite)
- Button wechselt zu Erfolg (grün) oder Warnung (gelb)
- CSP-Nonce für inline JavaScript
- Neue Sprachschlüssel: maintenance_my_ip_title, maintenance_add_my_ip
- rex_i18n::msg() funktioniert nicht im Frontend (AddOn-Sprachdateien nicht geladen)
- Hardcode 'Language' statt translate:maintenance_language
- Behebt [translate:maintenance_language] Anzeige im Frontend
Fixes:
- $currentPage wird jetzt am Anfang der Sidebar definiert (Zeile 8 statt 94)
- Verhindert 'Undefined variable' Warning

IP-Button Verbesserungen:
- waitForTokenfield() Funktion für robuste Tokenfield-Initialisierung
- Verwendet tokenfield('getTokens') statt String-Splitting
- Besseres Timing-Handling mit Retry-Mechanismus
- Entfernt btn-xs Klasse bei Feedback für bessere Sichtbarkeit
- Console-Fehlerbehandlung
- Tokenfield-Abhängigkeit entfernt, einfaches Textfeld verwendet
- IP-Sektion aus Sidebar entfernt
- Vereinfachte JavaScript-Logik nach Upkeep-Vorbild
- Verbesserte UI mit formatierten IP-Zeilen
- Sprachschlüssel ergänzt (maintenance_your_ip, maintenance_server_ip, etc.)
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
lib/Maintenance.php (1)

142-143: Moin! Potenzieller Null-Pointer-Access beim Domain-Check.

Die Methode rex_yrewrite::getDomainByArticleId() kann null oder false zurückgeben, wenn kein aktueller Artikel oder keine Sprache gesetzt ist. In Zeile 143 wird ohne Null-Check getName() aufgerufen.

Füge einen expliziten Null-Check hinzu:

-        if ($ydomain = rex_yrewrite::getDomainByArticleId(rex_article::getCurrentId(), rex_clang::getCurrentId())) {
+        $ydomain = rex_yrewrite::getDomainByArticleId(rex_article::getCurrentId(), rex_clang::getCurrentId());
+        if ($ydomain && $ydomain instanceof rex_yrewrite_domain) {
             $domainName = $ydomain->getName();
fragments/maintenance/frontend.php (1)

395-405: Moin! KRITISCHER BUG: Inkonsistente Sprach-Anzeige bei Mehrsprachigkeit!

Die aktuelle Logik führt zu einem kritischen Darstellungsfehler, wenn beide Sprachtexte vorhanden sind:

Problem-Szenario: Beide Texte gefüllt (maintenance_text_en UND maintenance_text_de)

  • multilanguageEnabled = true
  • Language-Dropdown zeigt EN als aktiv (Zeile 374) ✓
  • EN-Textblock (Zeile 396): '' === $maintenanceTextDe ? 'active' : '' = '' (KEINE active-Klasse) ✗
  • DE-Textblock (Zeile 402): Hard-codiert active
  • Ergebnis: DE-Text wird angezeigt, aber EN ist im Dropdown markiert → Inkonsistenz!

Frühere Reviews haben dieses Problem identifiziert, aber die Korrektur wurde nicht vollständig angewendet.

Korrigiere die Ternary-Operatoren:

 <?php if ('' !== $maintenanceTextEn): ?>
-        <div class="maintenance-message maintenance-text <?= '' === $maintenanceTextDe ? 'active' : '' ?>" data-lang="en">
+        <div class="maintenance-message maintenance-text <?= $multilanguageEnabled || '' === $maintenanceTextDe ? 'active' : '' ?>" data-lang="en">
             <?= nl2br(rex_escape($maintenanceTextEn)) ?>
         </div>
 <?php endif ?>
         
 <?php if ('' !== $maintenanceTextDe): ?>
-        <div class="maintenance-message maintenance-text active" data-lang="de">
+        <div class="maintenance-message maintenance-text <?= !$multilanguageEnabled && '' === $maintenanceTextEn ? 'active' : '' ?>" data-lang="de">
             <?= nl2br(rex_escape($maintenanceTextDe)) ?>
         </div>
 <?php endif ?>

Logik nach Korrektur:

  • EN aktiv wenn: Multilanguage aktiviert (Standard EN) ODER nur EN vorhanden
  • DE aktiv wenn: Nur DE vorhanden (kein Multilanguage, kein EN)
  • JavaScript übernimmt dann die Sprachumschaltung bei Mehrsprachigkeit
🧹 Nitpick comments (7)
lib/Maintenance.php (1)

169-173: Moin! Doppelter Config-Read der authentication_mode.

Der Config-Wert authentication_mode wird in Zeile 169 gelesen und dann in Zeile 172 erneut. Die zweite Zeile ist redundant.

Entferne die doppelte Zuweisung:

         $maintenance_secret = rex_request('maintenance_secret', 'string', '');
         $authentication_mode = (string) self::getConfig('authentication_mode', '');
 
         // Authentifizierung prüfen - für URL-Parameter und auch bei leerem Modus
-        $authentication_mode = (string) self::getConfig('authentication_mode', '');
         if (('' === $authentication_mode || 'URL' === $authentication_mode || 'password' === $authentication_mode)
lib/cronjob/scheduled_maintenance.php (1)

32-41: Moin! Hardcodierte deutsche Strings im Cronjob.

Die Log-Messages in Zeilen 35, 37 und 40 sind auf Deutsch hardcodiert, während getTypeName() (Zeile 48) korrekt rex_i18n::msg() verwendet. Das ist inkonsistent.

Verwende i18n-Keys für die Messages:

         // Log what happened
         if ('' !== $scheduledStart || '' !== $scheduledEnd) {
             if ($blockFrontend) {
-                $this->setMessage('Wartungsmodus ist aktiv (geplant bis: ' . $scheduledEnd . ')');
+                $this->setMessage(rex_i18n::msg('maintenance_cronjob_active_until', $scheduledEnd));
             } else {
-                $this->setMessage('Wartungsmodus ist inaktiv (geplanter Start: ' . $scheduledStart . ')');
+                $this->setMessage(rex_i18n::msg('maintenance_cronjob_scheduled_start', $scheduledStart));
             }
         } else {
-            $this->setMessage('Keine geplante Wartung konfiguriert');
+            $this->setMessage(rex_i18n::msg('maintenance_cronjob_not_configured'));
         }

Die entsprechenden Keys müssten dann in lang/de_de.lang ergänzt werden.

lang/de_de.lang (1)

24-25: Moin! Cronjob-Übersetzungskeys unvollständig.

In Zeile 25 ist nur maintenance_cronjob_scheduled_name definiert. Für die Cronjob-Messages (siehe Review zu lib/cronjob/scheduled_maintenance.php) fehlen jedoch Keys wie:

  • maintenance_cronjob_active_until
  • maintenance_cronjob_scheduled_start
  • maintenance_cronjob_not_configured

Falls die Messages im Cronjob internationalisiert werden sollen, ergänze diese Keys. Ansonsten können die deutschen Strings im Cronjob bleiben (ist dann aber inkonsistent mit getTypeName()).

pages/frontend.index.php (3)

31-39: Moin! Erwäge TextAreaField für längere Wartungstexte.

Die Wartungstexte (maintenance_text_en und maintenance_text_de) verwenden addTextField(), was für potenziell längere, mehrzeilige Nachrichten einschränkend sein könnte. Für bessere Benutzerfreundlichkeit könnte addTextAreaField() geeigneter sein.

Beispiel-Diff:

-$field = $form->addTextField('maintenance_text_en');
+$field = $form->addTextAreaField('maintenance_text_en');
 $field->setLabel($addon->i18n('maintenance_text_en_label'));
 $field->setNotice($addon->i18n('maintenance_text_en_notice'));

-$field = $form->addTextField('maintenance_text_de');
+$field = $form->addTextAreaField('maintenance_text_de');
 $field->setLabel($addon->i18n('maintenance_text_de_label'));
 $field->setNotice($addon->i18n('maintenance_text_de_notice'));

47-51: Moin! Zufälliges Beispiel im Notice-Text könnte verwirren.

Das Notice-Feld generiert bei jedem Seitenaufruf einen neuen Zufallswert via bin2hex(random_bytes(16)). Das könnte Nutzer irritieren, da sich der Beispieltext ständig ändert. Erwäge einen festen Beispielwert im i18n-String.

Beispiel:

-$field->setNotice($addon->i18n('maintenance_secret_notice', bin2hex(random_bytes(16))));
+$field->setNotice($addon->i18n('maintenance_secret_notice'));

Und in der Lang-Datei einen festen Beispielwert ergänzen.


80-90: Moin! Erwäge datetime-local Input für bessere UX.

Die Felder scheduled_start und scheduled_end verwenden einfache Textfelder für Datetime-Eingaben. Das erhöht das Risiko von Formatfehlern. Erwäge die Verwendung von type="datetime-local" für bessere Benutzerfreundlichkeit und Browser-native Datumspicker.

Beispiel-Diff:

 $field = $form->addTextField('scheduled_start');
 $field->setLabel($addon->i18n('maintenance_scheduled_start_label'));
 $field->setNotice($addon->i18n('maintenance_scheduled_start_notice') . '<br><small>' . $addon->i18n('maintenance_scheduled_example') . '</small>');
-$field->setAttribute('placeholder', '2025-12-31 02:00:00');
+$field->setAttribute('type', 'datetime-local');

 $field = $form->addTextField('scheduled_end');
 $field->setLabel($addon->i18n('maintenance_scheduled_end_label'));
 $field->setNotice($addon->i18n('maintenance_scheduled_end_notice') . '<br><small>' . $addon->i18n('maintenance_scheduled_example') . '</small>');
-$field->setAttribute('placeholder', '2025-12-31 06:00:00');
+$field->setAttribute('type', 'datetime-local');

Hinweis: Datetime-local verwendet ISO 8601 Format (YYYY-MM-DDTHH:MM), Backend-Validierung muss entsprechend angepasst werden.

fragments/maintenance/frontend.php (1)

26-358: Moin! Umfangreiches Inline-Styling mit CSP-Compliance.

Das Inline-CSS mit Nonce (Zeile 26) ist CSP-konform und für eine Wartungsseite angemessen. Das Styling umfasst Dark Mode, Responsive Design und Animationen – gut umgesetzt.

Optionale Anmerkung: Für bessere Wartbarkeit könnte das CSS in ein separates Template-Fragment ausgelagert werden, aber für eine Wartungsseite ist die Inline-Variante akzeptabel.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9cbc56f and 5c4c049.

📒 Files selected for processing (9)
  • README.md (3 hunks)
  • boot.php (2 hunks)
  • fragments/maintenance/frontend.php (1 hunks)
  • lang/de_de.lang (4 hunks)
  • lib/Maintenance.php (6 hunks)
  • lib/cronjob/scheduled_maintenance.php (1 hunks)
  • package.yml (3 hunks)
  • pages/domains.php (1 hunks)
  • pages/frontend.index.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • pages/domains.php
  • boot.php
🧰 Additional context used
🧬 Code graph analysis (2)
lib/cronjob/scheduled_maintenance.php (1)
lib/Maintenance.php (3)
  • Maintenance (30-461)
  • checkScheduledMaintenance (244-277)
  • getConfig (449-452)
pages/frontend.index.php (1)
lib/Maintenance.php (1)
  • getConfig (449-452)
🪛 LanguageTool
README.md

[grammar] ~24-~24: Hier könnte ein Fehler sein.
Context: ...rsion 3.5.0) ### Zeitgesteuerte Wartung Die zeitgesteuerte Wartung ermöglich...

(QB_NEW_DE)


[grammar] ~26-~26: Hier könnte ein Fehler sein.
Context: ...punkt zu aktivieren und zu deaktivieren: * Request-basiert: Wird bei jedem Seiten...

(QB_NEW_DE)


[grammar] ~28-~28: Ergänze ein Satzzeichen
Context: ...uf geprüft (keine Cronjob-Konfiguration nötig) * Optional per Cronjob: Für präzise...

(QB_NEW_DE_OTHER_ERROR_IDS_MISSING_PUNCTUATION_PERIOD)


[grammar] ~29-~29: Ersetze das Satzzeichen
Context: ...ür präzisere Steuerung kann der Cronjob "Geplante Wartung prüfen" eingerichtet werden * *...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_„)


[grammar] ~29-~29: Ersetze das Satzzeichen
Context: ...rung kann der Cronjob "Geplante Wartung prüfen" eingerichtet werden * **Automatische Be...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_L_DOUBLE_QUOT)


[grammar] ~29-~29: Ergänze ein Satzzeichen
Context: ... "Geplante Wartung prüfen" eingerichtet werden * Automatische Bereinigung: Nach er...

(QB_NEW_DE_OTHER_ERROR_IDS_MISSING_PUNCTUATION_PERIOD)


[grammar] ~30-~30: Hier könnte ein Fehler sein.
Context: ...ie geplanten Zeiten automatisch gelöscht Verwendung: 1. In den Frontend-Einste...

(QB_NEW_DE)


[grammar] ~32-~32: Hier könnte ein Fehler sein.
Context: ...iten automatisch gelöscht Verwendung: 1. In den Frontend-Einstellungen unter "Zei...

(QB_NEW_DE)


[grammar] ~34-~34: Ersetze das Satzzeichen
Context: ... 1. In den Frontend-Einstellungen unter "Zeitgesteuerte Wartung": - Startzeitpunkt einge...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_„)


[grammar] ~34-~34: Ersetze das Satzzeichen
Context: ...end-Einstellungen unter "Zeitgesteuerte Wartung": - Startzeitpunkt eingeben (z.B. ...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_L_DOUBLE_QUOT)


[grammar] ~35-~35: Ergänze ein Leerzeichen
Context: ...g": - Startzeitpunkt eingeben (z.B. 2025-12-31 02:00:00) - **Endzeitp...

(QB_NEW_DE_OTHER_ERROR_IDS_MISSING_ORTHOGRAPHY_SPACE)


[grammar] ~36-~36: Ergänze ein Leerzeichen
Context: ...:00) - **Endzeitpunkt** eingeben (z.B. 2025-12-31 06:00:00`) 2. Speichern - ...

(QB_NEW_DE_OTHER_ERROR_IDS_MISSING_ORTHOGRAPHY_SPACE)


[grammar] ~37-~37: Ersetze das Satzzeichen
Context: ...ingeben (z.B. 2025-12-31 06:00:00) 2. Speichern - der Wartungsmodus wird zur konfiguriert...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_DASH_–)


[grammar] ~37-~37: Hier könnte ein Fehler sein.
Context: ...it automatisch aktiviert und deaktiviert Format: YYYY-MM-DD HH:MM:SS (z.B. `2...

(QB_NEW_DE)


[grammar] ~39-~39: Entferne ein Wort
Context: ...utomatisch aktiviert und deaktiviert Format: YYYY-MM-DD HH:MM:SS (z.B. `2025-12-31...

(QB_NEW_DE_OTHER_ERROR_IDS_UNNECESSARY_NOUN)


[grammar] ~39-~39: Ergänze ein Leerzeichen
Context: ...t Format: YYYY-MM-DD HH:MM:SS (z.B. 2025-12-31 23:59:59) ### Sperren de...

(QB_NEW_DE_OTHER_ERROR_IDS_MISSING_ORTHOGRAPHY_SPACE)


[grammar] ~39-~39: Hier könnte ein Fehler sein.
Context: ...D HH:MM:SS(z.B.2025-12-31 23:59:59`) ### Sperren des REDAXO-Backends * Sperren d...

(QB_NEW_DE)


[grammar] ~68-~68: Ersetze das Satzzeichen
Context: ...staltung erfolgen. ### Silent Mode für Staging/Development-Umgebungen Der **Silent Mo...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_STAGINGSLASHDEVELOPMENTDASHUMGEBUNGEN_STAGINGDASHSLASHDEVELOPMENTDASHUMGEBUNGEN)


[grammar] ~68-~68: Hier könnte ein Fehler sein.
Context: ... Mode für Staging/Development-Umgebungen Der Silent Mode ist ideal für Stagin...

(QB_NEW_DE)


[grammar] ~70-~70: Hier könnte ein Fehler sein.
Context: ...gen, die permanent gesperrt sein sollen: * Sendet nur den HTTP-Status-Code (z.B. 50...

(QB_NEW_DE)


[uncategorized] ~72-~72: Uneinheitliche Verwendung von Bindestrichen. Der Text enthält sowohl ‚HTTP-Status-Code‘ als auch ‚HTTP-Statuscode‘.
Context: ...gesperrt sein sollen: * Sendet nur den HTTP-Status-Code (z.B. 503 oder 403) * Zeigt keine H...

(DE_COMPOUND_COHERENCY)


[grammar] ~72-~72: Ergänze ein Leerzeichen
Context: ...: * Sendet nur den HTTP-Status-Code (z.B. 503 oder 403) * Zeigt keine HTML-W...

(QB_NEW_DE_OTHER_ERROR_IDS_MISSING_ORTHOGRAPHY_SPACE)


[uncategorized] ~73-~73: Fehlendes Komma: Teilsätze, Einschübe, Aufzählungen und direkte Rede müssen durch ein Komma vom Rest des Satzes getrennt werden.
Context: ...3) * Zeigt keine HTML-Wartungsseite an * Verhindert Rückschlüsse auf das verwe...

(AI_DE_KOMMA_MISSING_COMMA)


[grammar] ~75-~75: Hier könnte ein Fehler sein.
Context: ...ie nur nach Login zugänglich sein sollen Aktivierung: In den erweiterten Einste...

(QB_NEW_DE)


[grammar] ~77-~77: Passe das Symbol an
Context: ...n zugänglich sein sollen Aktivierung: In den erweiterten Einstellungen (Einst...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_OTHER)


[grammar] ~77-~77: Ersetze das Satzzeichen
Context: ...ten Einstellungen (Einstellungen) unter "HTTP-Einstellungen" die Option "Silent Mode"...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_„)


[grammar] ~77-~77: Ersetze das Satzzeichen
Context: ...nstellungen (Einstellungen) unter "HTTP-Einstellungen" die Option "Silent Mode" aktivieren. #...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_L_DOUBLE_QUOT)


[grammar] ~77-~77: Ersetze das Satzzeichen
Context: ...) unter "HTTP-Einstellungen" die Option "Silent Mode" aktivieren. ## Anzeige des aktue...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_„)


[grammar] ~77-~77: Ersetze das Satzzeichen
Context: ..."HTTP-Einstellungen" die Option "Silent Mode" aktivieren. ## Anzeige des aktuellen S...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_L_DOUBLE_QUOT)


[grammar] ~77-~77: Hier könnte ein Fehler sein.
Context: ...en" die Option "Silent Mode" aktivieren. ## Anzeige des aktuellen Status im REDAXO-H...

(QB_NEW_DE)


[grammar] ~99-~99: Ergänze ein Satzzeichen
Context: ...` wieder crawlen. 🕵🏻 ## Konsole Das Addon bietet verschiedene Konsolen-Befehle zu...

(QB_NEW_DE_OTHER_ERROR_IDS_MISSING_PUNCTUATION_ADDDASHON)


[grammar] ~99-~99: Wähle ein passenderes Wort
Context: ... Konsole Das Addon bietet verschiedene Konsolen-Befehle zur Verwaltung des Wartungsmodus: ### ...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_NOUN)


[grammar] ~99-~99: Hier könnte ein Fehler sein.
Context: ...efehle zur Verwaltung des Wartungsmodus: ### Status anzeigen Zeigt den aktuellen Sta...

(QB_NEW_DE)


[grammar] ~101-~101: Hier könnte ein Fehler sein.
Context: ... des Wartungsmodus: ### Status anzeigen Zeigt den aktuellen Status aller Wartung...

(QB_NEW_DE)


[grammar] ~103-~103: Hier könnte ein Fehler sein.
Context: ... aktuellen Status aller Wartungsmodi an: bash php redaxo/bin/console maintenance:mode status ### Frontend-Wartungsmodus Aktivieren: ```b...

(QB_NEW_DE)


[grammar] ~109-~109: Hier könnte ein Fehler sein.
Context: ...e status ### Frontend-Wartungsmodus Aktivieren:bash php redaxo/bin/conso...

(QB_NEW_DE)


[grammar] ~111-~111: Hier könnte ein Fehler sein.
Context: ... ### Frontend-Wartungsmodus Aktivieren: bash php redaxo/bin/console maintenance:mode frontend on Deaktivieren: ```bash php redaxo/bin/con...

(QB_NEW_DE)


[grammar] ~116-~116: Hier könnte ein Fehler sein.
Context: ...ance:mode frontend on Deaktivieren:bash php redaxo/bin/console maintenance:mode frontend off ### Backend-Wartungsmodus Aktivieren:ba...

(QB_NEW_DE)


[grammar] ~121-~121: Hier könnte ein Fehler sein.
Context: ...ntend off ### Backend-Wartungsmodus Aktivieren:bash php redaxo/bin/conso...

(QB_NEW_DE)


[grammar] ~123-~123: Hier könnte ein Fehler sein.
Context: ... ### Backend-Wartungsmodus Aktivieren: bash php redaxo/bin/console maintenance:mode backend on Deaktivieren: ```bash php redaxo/bin/con...

(QB_NEW_DE)


[grammar] ~128-~128: Hier könnte ein Fehler sein.
Context: ...nance:mode backend on Deaktivieren:bash php redaxo/bin/console maintenance:mode backend off ``` ### Alle Modi gleichzeitig Alle Wartungsmod...

(QB_NEW_DE)


[grammar] ~133-~133: Hier könnte ein Fehler sein.
Context: ...kend off ``` ### Alle Modi gleichzeitig Alle Wartungsmodi (Frontend, Backend und...

(QB_NEW_DE)


[grammar] ~135-~135: Hier könnte ein Fehler sein.
Context: ...d, Backend und alle Domains) aktivieren: bash php redaxo/bin/console maintenance:mode all on Alle Wartungsmodi deaktivieren: ```bash ...

(QB_NEW_DE)


[grammar] ~140-~140: Hier könnte ein Fehler sein.
Context: ... on Alle Wartungsmodi deaktivieren:bash php redaxo/bin/console maintenance:mode all off ``` ### Domain-spezifische Wartung (YRewrite) E...

(QB_NEW_DE)


[grammar] ~145-~145: Hier könnte ein Fehler sein.
Context: ...## Domain-spezifische Wartung (YRewrite) Einzelne Domain sperren: ```bash php red...

(QB_NEW_DE)


[grammar] ~147-~147: Hier könnte ein Fehler sein.
Context: ...ung (YRewrite) Einzelne Domain sperren: bash php redaxo/bin/console maintenance:mode domain example.com --lock Einzelne Domain entsperren: ```bash php ...

(QB_NEW_DE)


[grammar] ~152-~152: Hier könnte ein Fehler sein.
Context: ... --lock Einzelne Domain entsperren:bash php redaxo/bin/console maintenance:mode domain example.com --unlock ``` ### Legacy-Unterstützung Die alten Befehle ...

(QB_NEW_DE)


[grammar] ~157-~157: Hier könnte ein Fehler sein.
Context: ...m --unlock ``` ### Legacy-Unterstützung Die alten Befehle funktionieren weiterhi...

(QB_NEW_DE)


[grammar] ~159-~159: Hier könnte ein Fehler sein.
Context: ...terhin (steuern nur den Frontend-Modus): bash php redaxo/bin/console maintenance:mode on php redaxo/bin/console maintenance:mode off ## Autor Thomas Skerbis – [KLXM Crossm...

(QB_NEW_DE)


[grammar] ~166-~166: Hier könnte ein Fehler sein.
Context: ...nsole maintenance:mode off ``` ## Autor Thomas Skerbis – [KLXM Crossmedia](htt...

(QB_NEW_DE)


[grammar] ~168-~168: Hier könnte ein Fehler sein.
Context: ...r Thomas SkerbisKLXM Crossmedia ## Projekt-Lead * [Thomas Skerbis](https:/...

(QB_NEW_DE)


[grammar] ~170-~170: Hier könnte ein Fehler sein.
Context: ...media](https://klxm.de) ## Projekt-Lead * [Thomas Skerbis](https://github.com/skerb...

(QB_NEW_DE)


[grammar] ~172-~172: Hier könnte ein Fehler sein.
Context: ....de) ## Projekt-Lead * Thomas Skerbis ## Credits Danke an: * [Christian Gehrke]...

(QB_NEW_DE)


[grammar] ~175-~175: Hier könnte ein Fehler sein.
Context: ...https://github.com/skerbis) ## Credits Danke an: * [Christian Gehrke](https://...

(QB_NEW_DE)


[grammar] ~177-~177: Hier könnte ein Fehler sein.
Context: ...hub.com/skerbis) ## Credits Danke an: * [Christian Gehrke](https://github.com/chr...

(QB_NEW_DE)


[grammar] ~179-~179: Wähle ein passenderes Wort
Context: ... Credits Danke an: * Christian Gehrke // first ...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_NOUN)

🔇 Additional comments (20)
README.md (1)

1-185: LGTM! Umfassende und klare Dokumentation der neuen Features.

Die Dokumentation der neuen Features (zeitgesteuerte Wartung, Silent Mode, erweiterte Konsolenbefehle, Domain-Verwaltung) ist sehr gut strukturiert und verständlich. Die Beispiele sind praxisnah und das Format für datetime-Angaben ist klar definiert.

lib/Maintenance.php (3)

240-277: Moin! Scheduled Maintenance Logik sieht solide aus.

Die Auto-Aktivierung und Auto-Deaktivierung sind sauber implementiert mit entsprechenden Guards (!$blockFrontend bzw. $blockFrontend). Das Cleanup nach erfolgreicher Deaktivierung ist gut gelöst.

Kleiner Edge-Case-Hinweis: Wenn beide Zeiten (scheduled_start und scheduled_end) bereits in der Vergangenheit liegen, wird die Wartung kurz aktiviert und sofort wieder deaktiviert. Das ist zwar kein Bug, könnte aber in den Logs etwas verwirrend sein.

Optional: Überlege, ob ein zusätzlicher Check sinnvoll wäre, dass startTime < endTime beim Speichern der Zeiten validiert wird (z.B. in der Settings-Page).


282-367: Moin! Frontend-Check Logik ist jetzt korrekt.

Die Integration der zeitgesteuerten Wartung (Zeile 287) und die kombinierte Prüfung von blockFrontend und domainInMaintenance (Zeilen 293-296) ist gut gelöst. Der Silent Mode (Zeilen 299-304) mit frühem Exit ist eine saubere Implementierung.

Die zuvor gemeldete Issue mit der Frontend-Sperre wurde korrekt behoben.


404-413: Moin! Domain-Indikatoren sind sauber implementiert.

Die Anzeige der Domain-Wartungsstatus im Backend-Menü ist gut gelöst. Die Unterscheidung zwischen globaler Sperre (D:All) und einzelnen gesperrten Domains (D:count) ist intuitiv.

package.yml (2)

64-65: Moin! Cronjob-Interval-Platzhalter {i} unklar.

In Zeile 65 wird interval: '{i}' verwendet. Was bedeutet dieser Platzhalter? Ist das eine REDAXO-Konvention für ein variablen Intervall oder ein Tippfehler?

Bitte kläre, ob {i} durch einen konkreten Wert ersetzt werden sollte (z.B. {1} für minütlich) oder ob das so korrekt ist. Falls das ein Template-Platzhalter ist, sollte das im Code oder in einem Kommentar erklärt werden.


70-71: Moin! Legacy-Config allowed_yrewrite_domains und Authentifizierung.

Zeile 70: Der Key allowed_yrewrite_domains wird noch in der default_config definiert. Lt. PR-Beschreibung wurde doch von allowed_yrewrite_domains zu domain_status migriert. Ist dieser Legacy-Key noch notwendig oder kann er entfernt werden?

Zeile 71: Die Schreibweise authentication_mode ist jetzt korrekt (früher authentification_mode).

Prüfe, ob allowed_yrewrite_domains noch benötigt wird oder ob die Migration in update.php diesen komplett durch domain_status ersetzt.

lib/cronjob/scheduled_maintenance.php (1)

22-44: Moin! Cronjob execute() Logik ist korrekt.

Die Methode ruft checkScheduledMaintenance() auf und gibt dann den aktuellen Status zurück. Der Return-Wert true ist korrekt für erfolgreiche Cronjob-Ausführung.

lang/de_de.lang (1)

1-176: Moin! Sprachdatei ist umfassend und konsistent.

Die Übersetzungen decken alle neuen Features ab (Domain-Verwaltung, zeitgesteuerte Wartung, Silent Mode, erweiterte Einstellungen). Die Terminologie ist einheitlich und die Texte sind verständlich formuliert.

pages/frontend.index.php (7)

1-17: Moin! Saubere Initialisierung und Standard-Pattern.

Die Datei-Header und Form-Initialisierung folgen den REDAXO-Konventionen korrekt. Keine Probleme erkennbar.


19-25: Moin! Korrekte Select-Field-Implementierung.

Das Feld block_frontend ist sauber implementiert mit i18n-Unterstützung.


41-45: Moin! Korrekte Number-Input-Implementierung.

Das Update-Interval-Feld ist sauber implementiert.


53-58: Moin! Rechtschreibung korrekt - vorheriger Hinweis wurde umgesetzt.

Das Feld authentication_mode verwendet die korrekte Schreibweise. Der frühere Hinweis zur Korrektur von "authentification" wurde erfolgreich umgesetzt.


60-66: Moin! Standard-Implementierung ohne Probleme.

Das Feld block_frontend_rex_user ist korrekt umgesetzt.


68-72: Moin! Saubere URL-Feld-Implementierung.

Das Redirect-URL-Feld mit HTML5-Typ-Validierung ist korrekt implementiert.


108-121: Moin! Sauberes Layout-Rendering mit Fragment-Pattern.

Die Fragment-Initialisierung und das zweispaltige Layout sind korrekt implementiert. Die Sidebar-Integration ist sauber gelöst.

fragments/maintenance/frontend.php (5)

1-9: Moin! Multilanguage-Logik ist korrekt implementiert.

Die Prüfung in Zeile 8 aktiviert die Sprachauswahl nur, wenn beide Texte vorhanden sind. Das ist die richtige Logik für die Mehrsprachigkeits-Aktivierung.


10-25: Moin! Saubere HTML-Head-Implementierung mit defensiven Checks.

Die YRewrite-Existenzprüfungen in Zeile 19 sind korrekt implementiert mit null-safe operator. Die Meta-Tags und der Titel sind gut strukturiert.


360-385: Moin! Language-Switcher korrekt implementiert.

Der Sprachschalter wird nur bei aktivierter Mehrsprachigkeit angezeigt (Zeile 362). Die Verwendung von rex_i18n::msg('maintenance_language') in Zeile 371 ist korrekt – der frühere Hinweis zu hard-codiertem Text wurde umgesetzt. EN ist standardmäßig aktiv (Zeile 374), was der erwarteten Logik entspricht.


407-413: Moin! Saubere Subfragment-Integration.

Die Ausgabe der Subfragments für Ankündigung, Login und Reload ist korrekt implementiert.


415-478: Moin! Solide JavaScript-Implementierung mit CSP-Compliance.

Das JavaScript für die Sprachauswahl ist gut strukturiert:

  • CSP-konform mit Nonce (Zeile 416) ✓
  • Keyboard-freundlich und zugänglich ✓
  • SessionStorage mit try-catch für Fehlerbehandlung ✓
  • Sprach-Persistierung über Seitenaufrufe ✓

redirect_backend_to_url: '' # `https://example.com/maintenance.html`
secret: ''
editor: 'class="form-control redactor-editor--default"'
editor: 'class="form-control cke5-editor" data-profile="default"'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Moin! Editor-Wechsel von Redactor zu CKEditor 5 könnte Nutzer betreffen.

Die Änderung des Standard-Editors von redactor-editor--default zu cke5-editor (Zeile 78) ist ein potenzieller Breaking Change für Installationen, die nur Redactor installiert haben. CKEditor 5 muss als AddOn vorhanden sein, damit der Editor funktioniert.

Empfehlung:

  • Im Update-Prozess (update.php) könnte geprüft werden, ob CKEditor 5 verfügbar ist
  • Falls nicht, den alten Editor-Wert beibehalten
  • Oder: Im README einen Hinweis auf die Editor-Anforderung ergänzen
🤖 Prompt for AI Agents
In package.yml around line 78 the default editor was changed to CKEditor 5 which
can break installs that only have Redactor; update the migration/update logic
(e.g., update.php) to detect whether the CKEditor 5 addon/plugin is installed
and only switch the stored editor value to the CKEditor 5 class when that addon
is present, otherwise preserve the existing Redactor value as the fallback;
alternatively add a clear note to the README/upgrade instructions that CKEditor
5 must be installed before changing the default editor so administrators can
prepare.

Comment on lines +92 to +106
// Aktuellen Status anzeigen
$scheduledStart = (string) $addon->getConfig('scheduled_start', '');
$scheduledEnd = (string) $addon->getConfig('scheduled_end', '');
if ('' !== $scheduledStart || '' !== $scheduledEnd) {
$statusHtml = '<div class="alert alert-info">';
$statusHtml .= '<strong>' . $addon->i18n('maintenance_scheduled_active') . '</strong><br>';
if ('' !== $scheduledStart) {
$statusHtml .= $addon->i18n('maintenance_scheduled_starts_at') . ': <code>' . rex_escape($scheduledStart) . '</code><br>';
}
if ('' !== $scheduledEnd) {
$statusHtml .= $addon->i18n('maintenance_scheduled_ends_at') . ': <code>' . rex_escape($scheduledEnd) . '</code>';
}
$statusHtml .= '</div>';
$field = $form->addRawField($statusHtml);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Moin! Status-Anzeige könnte irreführend sein bei alten oder ungültigen Daten.

Die Status-Anzeige wird angezeigt, sobald scheduled_start oder scheduled_end gesetzt sind, ohne zu prüfen, ob die Zeiten gültig oder aktuell sind. Das könnte verwirrend sein, wenn alte oder abgelaufene Wartungszeiten noch angezeigt werden.

Erwäge eine Validierung hinzuzufügen:

 $scheduledStart = (string) $addon->getConfig('scheduled_start', '');
 $scheduledEnd = (string) $addon->getConfig('scheduled_end', '');
-if ('' !== $scheduledStart || '' !== $scheduledEnd) {
+
+$now = new DateTimeImmutable();
+$isActive = false;
+$startTime = null;
+$endTime = null;
+
+try {
+    if ('' !== $scheduledStart) {
+        $startTime = new DateTimeImmutable($scheduledStart);
+    }
+    if ('' !== $scheduledEnd) {
+        $endTime = new DateTimeImmutable($scheduledEnd);
+    }
+    if ($startTime || $endTime) {
+        $isActive = true;
+    }
+} catch (Exception $e) {
+    // Invalid datetime format
+}
+
+if ($isActive) {
     $statusHtml = '<div class="alert alert-info">';
     $statusHtml .= '<strong>' . $addon->i18n('maintenance_scheduled_active') . '</strong><br>';
     if ('' !== $scheduledStart) {
         $statusHtml .= $addon->i18n('maintenance_scheduled_starts_at') . ': <code>' . rex_escape($scheduledStart) . '</code><br>';
     }
     if ('' !== $scheduledEnd) {
         $statusHtml .= $addon->i18n('maintenance_scheduled_ends_at') . ': <code>' . rex_escape($scheduledEnd) . '</code>';
     }
     $statusHtml .= '</div>';
     $field = $form->addRawField($statusHtml);
 }

Committable suggestion skipped: line range outside the PR's diff.

skerbis and others added 18 commits October 29, 2025 19:48
- package.yml: Cronjob-Definition vereinfacht (war falsch formatiert)
- boot.php: Tokenfield JavaScript/CSS entfernt (nicht mehr benötigt)
- Cronjob sollte nun im Cronjob-Addon sichtbar sein
- lib/cronjob/scheduled_maintenance.php → lib/cronjob.php (REDAXO-Standard)
- package.yml: Cronjob-Deklaration entfernt (automatische Erkennung)
- Inline JavaScript nach assets/js/frontend-advanced.js ausgelagert
- Inline JavaScript nach assets/js/domains.js ausgelagert
- Inline CSS nach assets/css/ip-addresses.css ausgelagert
- IP-Adressen als data-Attribute statt PHP-Interpolation
- Fragments behalten inline CSS/JS (Sperrseiten)
- Überschrift zeigt 'Maintenance' (EN) / 'Wartung' (DE) je nach Sprachwahl
- Domain wird unter der Überschrift angezeigt (YRewrite oder ServerName)
- CSS angepasst für inline maintenance-text Spans in Überschrift
- Funktioniert nur bei aktivierter Mehrsprachigkeit
- max-width: 450px, width: 100% für Container
- padding-top: 4rem (Desktop) / 3.5rem (Mobile) für Platz über Icon
- Language-Switcher bleibt in oberer rechter Ecke (auch mobil)
- Kompaktere Buttons auf Mobile (120px statt 140px)
- Verhindert Überlappung mit Info-Icon
- Überschrift 'Wartung' (DE) wird initial angezeigt
- Entspricht dem Verhalten der Texte (DE ist Standard)
- Sprachwechsler funktioniert wie bisher
- Language-Option DE initial als 'active' markiert
- Überschrift 'Wartung' (DE) mit 'active' Klasse
- Konsistent mit den Nachrichtentexten (DE ist Standard)
- Sprachwechsler zeigt nun korrekt DE als gewählte Sprache
- Initial 'Deutsch' statt 'Language'
- Button-Text wechselt bei Sprachwahl (English/Deutsch)
- Extrahiert Sprachname aus Option-Text (ohne EN/DE Prefix)
- Konsistent mit aktivem Dropdown-Item
- execute(): bool → execute()
- getTypeName(): string → getTypeName()
- getParamFields(): array → getParamFields()
- Entspricht REDAXO-Standard (wie PHPMailer, Backup)
- Cronjob sollte nun in Auswahl erscheinen
- Feldauswahl mit name-Attribut statt ID (rex_config_form Standard)
- Event-Delegation mit $(document).on() für dynamische Elemente
- Null-Check für data-ip Attribut
- Error-Logging wenn Feld nicht gefunden
- Entspricht genau der Upkeep-Implementierung
- Exakte Struktur wie phpmailer cronjob
- Eigenständige Logik ohne Aufruf von Maintenance::checkScheduledMaintenance()
- Direkte Config-Manipulation für aktivieren/deaktivieren
- Besseres Logging mit Status-Updates
- rex_cronjob_manager::registerType() im boot.php
- Prüfung ob Cronjob-Addon verfügbar ist
- Folgt dem Standard von Backup/PHPMailer AddOns
- Schritt-für-Schritt-Anleitung zur Cronjob-Konfiguration
- Erklärung aller relevanten Einstellungen
- Hinweis auf optionale Nutzung (Request-basiert funktioniert auch)
- checkScheduledMaintenance() aus checkFrontend() entfernt
- Cronjob-Status-Warnung in Frontend-Einstellungen
- Direkt-Link zum Cronjob erstellen wenn nicht vorhanden
- README und Sprachdateien aktualisiert
- Klarstellung: Funktion nur über Cronjob, nicht request-basiert
…niert

- Neue Unterseite 'Planung' (frontend.scheduled.php) unter Frontend
- Zeitgesteuerte Wartung von frontend.index.php entfernt
- Wartungsankündigung von frontend.announcement.php integriert
- Beide Features jetzt unter Maintenance > Frontend > Planung
- package.yml: scheduled als Unterseite von frontend
- Icon: fa-calendar-alt für Planungs-Seite
- boot.php: OUTPUT_FILTER für frontend/scheduled aktiviert
- Editor-Einstellung wird wieder berücksichtigt
- Sidebar mit Schnellzugriffen und Code-Beispiel für Ankündigung
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/Maintenance.php (1)

295-364: Moin Silent Mode blockiert Whitelist-Zugriffe

Der Silent Mode bricht hier sofort ab, bevor IP-/Host-Whitelist, Secret oder eingeloggte User geprüft werden – damit verlieren bestehende Ausnahmeregeln ihre Wirkung, sobald der Silent Mode aktiv ist. Bitte erst nach den Allow-Checks entscheiden, ob nur der Statuscode ohne HTML gesendet werden soll.

-        $silentMode = (bool) self::getConfig('silent_mode', false);
-        if ($silentMode) {
-            $responsecode = (int) self::getConfig('http_response_code', 503);
-            header('HTTP/1.1 ' . $responsecode);
-            exit;
-        }
+        $silentMode = (bool) self::getConfig('silent_mode', false);
@@
-        $redirect_url = (string) self::getConfig('redirect_frontend_to_url', '');
-        $responsecode = (int) self::getConfig('http_response_code', 503);
+        $redirect_url = (string) self::getConfig('redirect_frontend_to_url', '');
+        $responsecode = (int) self::getConfig('http_response_code', 503);
+
+        if ($silentMode) {
+            header('HTTP/1.1 ' . $responsecode);
+            exit;
+        }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5c4c049 and 6a33aa2.

📒 Files selected for processing (16)
  • README.md (3 hunks)
  • assets/css/ip-addresses.css (1 hunks)
  • assets/js/domains.js (1 hunks)
  • assets/js/frontend-advanced.js (1 hunks)
  • boot.php (2 hunks)
  • fragments/maintenance/frontend.php (1 hunks)
  • lang/de_de.lang (3 hunks)
  • lang/en_gb.lang (1 hunks)
  • lib/Maintenance.php (6 hunks)
  • lib/cronjob.php (1 hunks)
  • package.yml (3 hunks)
  • pages/domains.php (1 hunks)
  • pages/frontend.advanced.php (1 hunks)
  • pages/frontend.index.php (1 hunks)
  • pages/frontend.scheduled.php (1 hunks)
  • pages/frontend.sidebar.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • pages/frontend.index.php
  • pages/domains.php
🧰 Additional context used
🧬 Code graph analysis (3)
boot.php (2)
lib/cronjob.php (1)
  • rex_cronjob_scheduled_maintenance (6-59)
lib/Maintenance.php (3)
  • getConfig (446-449)
  • Maintenance (30-458)
  • isDomainInMaintenance (129-153)
pages/frontend.scheduled.php (1)
lib/Maintenance.php (1)
  • getConfig (446-449)
lib/cronjob.php (1)
lib/Maintenance.php (1)
  • getConfig (446-449)
🪛 LanguageTool
README.md

[grammar] ~24-~24: Hier könnte ein Fehler sein.
Context: ...rsion 3.5.0) ### Zeitgesteuerte Wartung Die zeitgesteuerte Wartung ermöglich...

(QB_NEW_DE)


[grammar] ~26-~26: Hier könnte ein Fehler sein.
Context: ...punkt zu aktivieren und zu deaktivieren: * Cronjob-basiert: Die Ausführung erfolg...

(QB_NEW_DE)


[grammar] ~28-~28: Ergänze ein Wort
Context: ...zu aktivieren und zu deaktivieren: * Cronjob-basiert: Die Ausführung erfolgt aussc...

(QB_NEW_DE_OTHER_ERROR_IDS_MISSING_NOUN)


[grammar] ~28-~28: Ersetze das Satzzeichen
Context: ...erfolgt ausschließlich über den Cronjob "Geplante Wartung prüfen" * **Automatische Berein...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_„)


[grammar] ~28-~28: Ersetze das Satzzeichen
Context: ...lich über den Cronjob "Geplante Wartung prüfen" * Automatische Bereinigung: Nach erfolgr...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_L_DOUBLE_QUOTPERIOD)


[grammar] ~29-~29: Hier könnte ein Fehler sein.
Context: ...ie geplanten Zeiten automatisch gelöscht Verwendung: 1. Cronjob einrichten...

(QB_NEW_DE)


[grammar] ~31-~31: Hier könnte ein Fehler sein.
Context: ...iten automatisch gelöscht Verwendung: 1. Cronjob einrichten (erforderlich): ...

(QB_NEW_DE)


[grammar] ~33-~33: Ergänze ein Wort
Context: ...matisch gelöscht Verwendung: 1. Cronjob einrichten (erforderlich): - Im RE...

(QB_NEW_DE_OTHER_ERROR_IDS_MISSING_NOUN)


[grammar] ~35-~35: Ersetze das Satzzeichen
Context: ...stem > Cronjobs** navigieren - Auf "+" klicken, um einen neuen Cronjob zu ...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_„)


[grammar] ~35-~35: Ersetze das Satzzeichen
Context: ...em > Cronjobs** navigieren - Auf "+" klicken, um einen neuen Cronjob zu er...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_L_DOUBLE_QUOT)


[grammar] ~37-~37: Korrigiere die Fehler
Context: ...tellungen vornehmen: - Name: z.B. "Geplante Wartung prüfen" - **Typ...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_MULTITOKEN)


[grammar] ~37-~37: Hier könnte ein Fehler sein.
Context: ...lungen vornehmen: - Name: z.B. "Geplante Wartung prüfen" - Typ: `Geplan...

(QB_NEW_DE)


[grammar] ~37-~37: Ersetze das Satzzeichen
Context: ... - Name: z.B. "Geplante Wartung prüfen" - Typ: `Geplante Wartung prüfe...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_L_DOUBLE_QUOT)


[grammar] ~39-~39: Korrigiere die Fehler
Context: ...wn wählen) - Ausführungsart: z.B. "Jede Minute" oder "Alle 5 Minuten" ...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_MULTITOKEN)


[grammar] ~39-~39: Hier könnte ein Fehler sein.
Context: ...wählen) - Ausführungsart: z.B. "Jede Minute" oder "Alle 5 Minuten" - **...

(QB_NEW_DE)


[grammar] ~39-~39: Ersetze das Satzzeichen
Context: ...) - Ausführungsart: z.B. "Jede Minute" oder "Alle 5 Minuten" - **Umgebung...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_L_DOUBLE_QUOT)


[grammar] ~39-~39: Ersetze das Satzzeichen
Context: ...sführungsart**: z.B. "Jede Minute" oder "Alle 5 Minuten" - Umgebung: "Fronte...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_„)


[grammar] ~39-~39: Ersetze das Satzzeichen
Context: ...sart**: z.B. "Jede Minute" oder "Alle 5 Minuten" - Umgebung: "Frontend, Backend...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_L_DOUBLE_QUOT)


[grammar] ~40-~40: Ersetze das Satzzeichen
Context: ...r "Alle 5 Minuten" - Umgebung: "Frontend, Backend, Skript" - Speichern 2. In...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_„)


[grammar] ~40-~40: Ersetze das Satzzeichen
Context: ... - Umgebung: "Frontend, Backend, Skript" - Speichern 2. In den Frontend-Eins...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_L_DOUBLE_QUOT)


[grammar] ~41-~41: Hier könnte ein Fehler sein.
Context: ...rontend, Backend, Skript" - Speichern 2. In den Frontend-Einstellungen unter "Zei...

(QB_NEW_DE)


[grammar] ~43-~43: Ersetze das Satzzeichen
Context: ... 2. In den Frontend-Einstellungen unter "Zeitgesteuerte Wartung": - Startzeitpunkt einge...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_„)


[grammar] ~43-~43: Ersetze das Satzzeichen
Context: ...end-Einstellungen unter "Zeitgesteuerte Wartung": - Startzeitpunkt eingeben (z.B. ...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_L_DOUBLE_QUOT)


[grammar] ~44-~44: Ergänze ein Leerzeichen
Context: ...g": - Startzeitpunkt eingeben (z.B. 2025-12-31 02:00:00) - **Endzeitp...

(QB_NEW_DE_OTHER_ERROR_IDS_MISSING_ORTHOGRAPHY_SPACE)


[grammar] ~45-~45: Ergänze ein Leerzeichen
Context: ...:00) - **Endzeitpunkt** eingeben (z.B. 2025-12-31 06:00:00`) 3. Speichern - ...

(QB_NEW_DE_OTHER_ERROR_IDS_MISSING_ORTHOGRAPHY_SPACE)


[grammar] ~46-~46: Ersetze das Satzzeichen
Context: ...ingeben (z.B. 2025-12-31 06:00:00) 3. Speichern - der Wartungsmodus wird zur konfiguriert...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_DASH_–)


[grammar] ~46-~46: Hier könnte ein Fehler sein.
Context: ...it automatisch aktiviert und deaktiviert Format: YYYY-MM-DD HH:MM:SS (z.B. `2...

(QB_NEW_DE)


[grammar] ~48-~48: Entferne ein Wort
Context: ...utomatisch aktiviert und deaktiviert Format: YYYY-MM-DD HH:MM:SS (z.B. `2025-12-31...

(QB_NEW_DE_OTHER_ERROR_IDS_UNNECESSARY_NOUN)


[grammar] ~48-~48: Ergänze ein Leerzeichen
Context: ...t Format: YYYY-MM-DD HH:MM:SS (z.B. 2025-12-31 23:59:59) Wichtig: O...

(QB_NEW_DE_OTHER_ERROR_IDS_MISSING_ORTHOGRAPHY_SPACE)


[grammar] ~48-~48: Hier könnte ein Fehler sein.
Context: ...D HH:MM:SS(z.B.2025-12-31 23:59:59`) Wichtig: Ohne eingerichteten Cronjob f...

(QB_NEW_DE)


[grammar] ~50-~50: Entferne ein Wort
Context: ...:MM:SS(z.B.2025-12-31 23:59:59`) Wichtig: Ohne eingerichteten Cronjob funktionier...

(QB_NEW_DE_OTHER_ERROR_IDS_UNNECESSARY_NOUN)


[grammar] ~50-~50: Hier könnte ein Fehler sein.
Context: ...oniert die zeitgesteuerte Wartung nicht! ### Sperren des REDAXO-Backends * Sperren d...

(QB_NEW_DE)


[grammar] ~79-~79: Ersetze das Satzzeichen
Context: ...staltung erfolgen. ### Silent Mode für Staging/Development-Umgebungen Der **Silent Mo...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_STAGINGSLASHDEVELOPMENTDASHUMGEBUNGEN_STAGINGDASHSLASHDEVELOPMENTDASHUMGEBUNGEN)


[grammar] ~79-~79: Hier könnte ein Fehler sein.
Context: ... Mode für Staging/Development-Umgebungen Der Silent Mode ist ideal für Stagin...

(QB_NEW_DE)


[grammar] ~81-~81: Hier könnte ein Fehler sein.
Context: ...gen, die permanent gesperrt sein sollen: * Sendet nur den HTTP-Status-Code (z.B. 50...

(QB_NEW_DE)


[uncategorized] ~83-~83: Uneinheitliche Verwendung von Bindestrichen. Der Text enthält sowohl ‚HTTP-Status-Code‘ als auch ‚HTTP-Statuscode‘.
Context: ...gesperrt sein sollen: * Sendet nur den HTTP-Status-Code (z.B. 503 oder 403) * Zeigt keine H...

(DE_COMPOUND_COHERENCY)


[grammar] ~83-~83: Ergänze ein Leerzeichen
Context: ...: * Sendet nur den HTTP-Status-Code (z.B. 503 oder 403) * Zeigt keine HTML-W...

(QB_NEW_DE_OTHER_ERROR_IDS_MISSING_ORTHOGRAPHY_SPACE)


[uncategorized] ~84-~84: Fehlendes Komma: Teilsätze, Einschübe, Aufzählungen und direkte Rede müssen durch ein Komma vom Rest des Satzes getrennt werden.
Context: ...3) * Zeigt keine HTML-Wartungsseite an * Verhindert Rückschlüsse auf das verwe...

(AI_DE_KOMMA_MISSING_COMMA)


[grammar] ~86-~86: Hier könnte ein Fehler sein.
Context: ...ie nur nach Login zugänglich sein sollen Aktivierung: In den erweiterten Einste...

(QB_NEW_DE)


[grammar] ~88-~88: Passe das Symbol an
Context: ...n zugänglich sein sollen Aktivierung: In den erweiterten Einstellungen (Einst...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_OTHER)


[grammar] ~88-~88: Ersetze das Satzzeichen
Context: ...ten Einstellungen (Einstellungen) unter "HTTP-Einstellungen" die Option "Silent Mode"...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_„)


[grammar] ~88-~88: Ersetze das Satzzeichen
Context: ...nstellungen (Einstellungen) unter "HTTP-Einstellungen" die Option "Silent Mode" aktivieren. #...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_L_DOUBLE_QUOT)


[grammar] ~88-~88: Ersetze das Satzzeichen
Context: ...) unter "HTTP-Einstellungen" die Option "Silent Mode" aktivieren. ## Anzeige des aktue...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_„)


[grammar] ~88-~88: Ersetze das Satzzeichen
Context: ..."HTTP-Einstellungen" die Option "Silent Mode" aktivieren. ## Anzeige des aktuellen S...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_QUOTE_L_DOUBLE_QUOT)


[grammar] ~88-~88: Hier könnte ein Fehler sein.
Context: ...en" die Option "Silent Mode" aktivieren. ## Anzeige des aktuellen Status im REDAXO-H...

(QB_NEW_DE)


[grammar] ~110-~110: Ergänze ein Satzzeichen
Context: ...` wieder crawlen. 🕵🏻 ## Konsole Das Addon bietet verschiedene Konsolen-Befehle zu...

(QB_NEW_DE_OTHER_ERROR_IDS_MISSING_PUNCTUATION_ADDDASHON)


[grammar] ~110-~110: Wähle ein passenderes Wort
Context: ... Konsole Das Addon bietet verschiedene Konsolen-Befehle zur Verwaltung des Wartungsmodus: ### ...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_NOUN)


[grammar] ~110-~110: Hier könnte ein Fehler sein.
Context: ...efehle zur Verwaltung des Wartungsmodus: ### Status anzeigen Zeigt den aktuellen Sta...

(QB_NEW_DE)


[grammar] ~112-~112: Hier könnte ein Fehler sein.
Context: ... des Wartungsmodus: ### Status anzeigen Zeigt den aktuellen Status aller Wartung...

(QB_NEW_DE)


[grammar] ~114-~114: Hier könnte ein Fehler sein.
Context: ... aktuellen Status aller Wartungsmodi an: bash php redaxo/bin/console maintenance:mode status ### Frontend-Wartungsmodus Aktivieren: ```b...

(QB_NEW_DE)


[grammar] ~120-~120: Hier könnte ein Fehler sein.
Context: ...e status ### Frontend-Wartungsmodus Aktivieren:bash php redaxo/bin/conso...

(QB_NEW_DE)


[grammar] ~122-~122: Hier könnte ein Fehler sein.
Context: ... ### Frontend-Wartungsmodus Aktivieren: bash php redaxo/bin/console maintenance:mode frontend on Deaktivieren: ```bash php redaxo/bin/con...

(QB_NEW_DE)


[grammar] ~127-~127: Hier könnte ein Fehler sein.
Context: ...ance:mode frontend on Deaktivieren:bash php redaxo/bin/console maintenance:mode frontend off ### Backend-Wartungsmodus Aktivieren:ba...

(QB_NEW_DE)


[grammar] ~132-~132: Hier könnte ein Fehler sein.
Context: ...ntend off ### Backend-Wartungsmodus Aktivieren:bash php redaxo/bin/conso...

(QB_NEW_DE)


[grammar] ~134-~134: Hier könnte ein Fehler sein.
Context: ... ### Backend-Wartungsmodus Aktivieren: bash php redaxo/bin/console maintenance:mode backend on Deaktivieren: ```bash php redaxo/bin/con...

(QB_NEW_DE)


[grammar] ~139-~139: Hier könnte ein Fehler sein.
Context: ...nance:mode backend on Deaktivieren:bash php redaxo/bin/console maintenance:mode backend off ``` ### Alle Modi gleichzeitig Alle Wartungsmod...

(QB_NEW_DE)


[grammar] ~144-~144: Hier könnte ein Fehler sein.
Context: ...kend off ``` ### Alle Modi gleichzeitig Alle Wartungsmodi (Frontend, Backend und...

(QB_NEW_DE)


[grammar] ~146-~146: Hier könnte ein Fehler sein.
Context: ...d, Backend und alle Domains) aktivieren: bash php redaxo/bin/console maintenance:mode all on Alle Wartungsmodi deaktivieren: ```bash ...

(QB_NEW_DE)


[grammar] ~151-~151: Hier könnte ein Fehler sein.
Context: ... on Alle Wartungsmodi deaktivieren:bash php redaxo/bin/console maintenance:mode all off ``` ### Domain-spezifische Wartung (YRewrite) E...

(QB_NEW_DE)


[grammar] ~156-~156: Hier könnte ein Fehler sein.
Context: ...## Domain-spezifische Wartung (YRewrite) Einzelne Domain sperren: ```bash php red...

(QB_NEW_DE)


[grammar] ~158-~158: Hier könnte ein Fehler sein.
Context: ...ung (YRewrite) Einzelne Domain sperren: bash php redaxo/bin/console maintenance:mode domain example.com --lock Einzelne Domain entsperren: ```bash php ...

(QB_NEW_DE)


[grammar] ~163-~163: Hier könnte ein Fehler sein.
Context: ... --lock Einzelne Domain entsperren:bash php redaxo/bin/console maintenance:mode domain example.com --unlock ``` ### Legacy-Unterstützung Die alten Befehle ...

(QB_NEW_DE)


[grammar] ~168-~168: Hier könnte ein Fehler sein.
Context: ...m --unlock ``` ### Legacy-Unterstützung Die alten Befehle funktionieren weiterhi...

(QB_NEW_DE)


[grammar] ~170-~170: Hier könnte ein Fehler sein.
Context: ...terhin (steuern nur den Frontend-Modus): bash php redaxo/bin/console maintenance:mode on php redaxo/bin/console maintenance:mode off ## Autor Thomas Skerbis – [KLXM Crossm...

(QB_NEW_DE)


[grammar] ~177-~177: Hier könnte ein Fehler sein.
Context: ...nsole maintenance:mode off ``` ## Autor Thomas Skerbis – [KLXM Crossmedia](htt...

(QB_NEW_DE)


[grammar] ~179-~179: Hier könnte ein Fehler sein.
Context: ...r Thomas SkerbisKLXM Crossmedia ## Projekt-Lead * [Thomas Skerbis](https:/...

(QB_NEW_DE)


[grammar] ~181-~181: Hier könnte ein Fehler sein.
Context: ...media](https://klxm.de) ## Projekt-Lead * [Thomas Skerbis](https://github.com/skerb...

(QB_NEW_DE)


[grammar] ~183-~183: Hier könnte ein Fehler sein.
Context: ....de) ## Projekt-Lead * Thomas Skerbis ## Credits Danke an: * [Christian Gehrke]...

(QB_NEW_DE)


[grammar] ~186-~186: Hier könnte ein Fehler sein.
Context: ...https://github.com/skerbis) ## Credits Danke an: * [Christian Gehrke](https://...

(QB_NEW_DE)


[grammar] ~188-~188: Hier könnte ein Fehler sein.
Context: ...hub.com/skerbis) ## Credits Danke an: * [Christian Gehrke](https://github.com/chr...

(QB_NEW_DE)


[grammar] ~190-~190: Wähle ein passenderes Wort
Context: ... Credits Danke an: * Christian Gehrke // first ...

(QB_NEW_DE_OTHER_ERROR_IDS_REPLACEMENT_NOUN)

Comment on lines +4 to +12
$(document).on('rex:ready', function() {
$('#all-domains-locked').on('change', function() {
if ($(this).val() == '1') {
$('#individual-domains').slideUp();
} else {
$('#individual-domains').slideDown();
}
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Moin Initialzustand des Domain-Blocks fehlt

Der Handler reagiert nur auf spätere Änderungen. Wenn die Seite mit value="1" geladen wird, bleibt der Bereich sichtbar, bis der Admin manuell toggelt. Bitte beim Laden einmal anwenden:

$(document).on('rex:ready', function() {
-    $('#all-domains-locked').on('change', function() {
-        if ($(this).val() == '1') {
-            $('#individual-domains').slideUp();
-        } else {
-            $('#individual-domains').slideDown();
-        }
-    });
+    var $toggle = $('#all-domains-locked');
+    var applyToggle = function() {
+        if ($toggle.val() === '1') {
+            $('#individual-domains').slideUp();
+        } else {
+            $('#individual-domains').slideDown();
+        }
+    };
+    $toggle.on('change', applyToggle);
+    applyToggle();
});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$(document).on('rex:ready', function() {
$('#all-domains-locked').on('change', function() {
if ($(this).val() == '1') {
$('#individual-domains').slideUp();
} else {
$('#individual-domains').slideDown();
}
});
});
$(document).on('rex:ready', function() {
var $toggle = $('#all-domains-locked');
var applyToggle = function() {
if ($toggle.val() === '1') {
$('#individual-domains').slideUp();
} else {
$('#individual-domains').slideDown();
}
};
$toggle.on('change', applyToggle);
applyToggle();
});
🤖 Prompt for AI Agents
In assets/js/domains.js around lines 4 to 12, the change handler only runs on
future user interactions so if the page loads with #all-domains-locked value "1"
the #individual-domains block remains visible; invoke the same logic on load by
either triggering the change handler once (e.g. call
.change()/.trigger('change') on #all-domains-locked after binding) or by
immediately checking its value and calling slideUp()/slideDown() accordingly so
the initial state matches the current value.

Comment on lines +69 to 75
maintenance_authentication_mode_label = Authentifizierung
maintenance_authentication_mode_notice = Authentifizierungsmethode auswählen, um Zugriff zu erhalten.

maintenance_authentification_mode_none = Keine Authentifizierung
maintenance_authentification_mode_password = 🔑 Passwort
maintenance_authentification_mode_url = 🔗 Geheim-URL (Standard)
maintenance_authentication_mode_none = Keine Authentifizierung
maintenance_authentication_mode_password = Passwort
maintenance_authentication_mode_url = Geheim-URL (Standard)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Moin Neue Schlüssel ohne passende en-Übersetzung

Mit diesem Rename zu maintenance_authentication_* fehlen in lang/en_gb.lang die korrespondierenden Keys (dort stehen weiterhin maintenance_authentification_*). Im englischen Backend werden damit nur Platzhalter angezeigt. Bitte die en-Übersetzungen anpassen, z. B.:

- maintenance_authentification_mode_label = Authentication
+ maintenance_authentication_mode_label = Authentication
- maintenance_authentification_mode_notice = Choose the authentication method to gain access.
+ maintenance_authentication_mode_notice = Choose the authentication method to gain access.
- maintenance_authentification_mode_none = No Authentication
+ maintenance_authentication_mode_none = No Authentication
- maintenance_authentification_mode_password = 🔑 Password
+ maintenance_authentication_mode_password = 🔑 Password
- maintenance_authentification_mode_url = 🔗 Secret URL (default)
+ maintenance_authentication_mode_url = 🔗 Secret URL (default)

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In lang/de_de.lang around lines 69 to 75 you renamed keys to
maintenance_authentication_*, but the corresponding keys in lang/en_gb.lang
still use maintenance_authentification_*, causing missing placeholders in the
English UI; update lang/en_gb.lang by adding or renaming the matching keys to
maintenance_authentication_mode_label, maintenance_authentication_mode_notice,
maintenance_authentication_mode_none, maintenance_authentication_mode_password
and maintenance_authentication_mode_url with the correct English strings (remove
or deprecate the old maintenance_authentification_* entries to avoid
duplicates).

Comment on lines +114 to +122
$info = '<div class="alert alert-info">';
$info .= '<h4><i class="rex-icon fa-info-circle"></i> ' . $addon->i18n('maintenance_announcement_info_title') . '</h4>';
$info .= '<p>' . $addon->i18n('maintenance_announcement_info_text') . '</p>';
$info .= '<p><strong>' . $addon->i18n('maintenance_announcement_usage') . ':</strong></p>';
$info .= '<div style="position: relative;">';
$info .= '<pre style="margin-bottom: 0;"><code>' . htmlspecialchars($codeExample) . '</code></pre>';
$info .= '<button class="btn btn-xs btn-default" style="position: absolute; top: 5px; right: 5px;" onclick="navigator.clipboard.writeText(' . htmlspecialchars(json_encode($codeExample), ENT_QUOTES) . '); this.innerHTML=\'<i class=\\\'rex-icon fa-check\\\'></i> ' . $addon->i18n('maintenance_copied') . '\'; setTimeout(() => this.innerHTML=\'<i class=\\\'rex-icon fa-copy\\\'></i> ' . $addon->i18n('maintenance_copy') . '\', 2000);"><i class="rex-icon fa-copy"></i> ' . $addon->i18n('maintenance_copy') . '</button>';
$info .= '</div>';
$info .= '</div>';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Moin JS-Strings für Übersetzungen korrekt escapen
Wird die Oberfläche in einer Sprache mit Apostrophen (z. B. Französisch) übersetzt, brechen maintenance_copied bzw. maintenance_copy das in einfache Anführungszeichen gesetzte onclick-Literal – der Copy-Button reagiert dann gar nicht mehr. Bite die Texte vor dem Einfügen in den JS-String mit der js-Strategie escapen und für den sichtbaren Button-Text HTML-escaping nutzen.

+        $copiedLabelJs = rex_escape($addon->i18n('maintenance_copied'), 'js');
+        $copyLabelJs = rex_escape($addon->i18n('maintenance_copy'), 'js');
+        $copyLabelHtml = rex_escape($addon->i18n('maintenance_copy'));
         $info .= '<div style="position: relative;">';
         $info .= '<pre style="margin-bottom: 0;"><code>' . htmlspecialchars($codeExample) . '</code></pre>';
-        $info .= '<button class="btn btn-xs btn-default" style="position: absolute; top: 5px; right: 5px;" onclick="navigator.clipboard.writeText(' . htmlspecialchars(json_encode($codeExample), ENT_QUOTES) . '); this.innerHTML=\'<i class=\\\'rex-icon fa-check\\\'></i> ' . $addon->i18n('maintenance_copied') . '\'; setTimeout(() => this.innerHTML=\'<i class=\\\'rex-icon fa-copy\\\'></i> ' . $addon->i18n('maintenance_copy') . '\', 2000);"><i class="rex-icon fa-copy"></i> ' . $addon->i18n('maintenance_copy') . '</button>';
+        $info .= '<button class="btn btn-xs btn-default" style="position: absolute; top: 5px; right: 5px;" onclick="navigator.clipboard.writeText(' . htmlspecialchars(json_encode($codeExample), ENT_QUOTES) . '); this.innerHTML=\'<i class=\\\'rex-icon fa-check\\\'></i> ' . $copiedLabelJs . '\'; setTimeout(() => this.innerHTML=\'<i class=\\\'rex-icon fa-copy\\\'></i> ' . $copyLabelJs . '\', 2000);"><i class="rex-icon fa-copy"></i> ' . $copyLabelHtml . '</button>';
🤖 Prompt for AI Agents
In pages/frontend.scheduled.php around lines 114 to 122, the translated strings
maintenance_copied and maintenance_copy are injected directly into a
single-quoted onclick JS literal and break when translations contain
apostrophes; escape those translations for inclusion in JS using the js strategy
(e.g. pass through the translator's js escape) and keep the visible button label
HTML-escaped (htmlspecialchars) so the onclick value remains valid while the
button text is safe for HTML; update the concatenation so the onclick uses the
js-escaped variants and the inner visible text uses the HTML-escaped variants.

Comment on lines +31 to +63
if (rex_config::get('maintenance', 'block_frontend') || $allDomainsLocked) {
$url = '' . rex::getServer() . '?maintenance_secret=' . rex_config::get('maintenance', 'maintenance_secret');
$copy .= '<li class="list-group-item">';
$copy .= '<label for="maintenance-mode-url">' . $addon->i18n('maintenance_bypass_url_default') . '</label>';
$copy .= '
<clipboard-copy for="maintenance-mode-url" class="input-group">
<input id="maintenance-mode-url" type="text" value="' . $url . '" readonly class="form-control">
<span class="input-group-addon"><i class="rex-icon fa-clone"></i></span>
</clipboard-copy></li>';
}

// YRewrite-Domains nur anzeigen, wenn sie gesperrt sind
if ($yrewriteAvailable && count(rex_yrewrite::getDomains()) > 1) {
foreach (rex_yrewrite::getDomains() as $key => $domain) {
if ('default' == $key) {
continue;
}

// Domain nur anzeigen, wenn:
// - Alle Domains gesperrt sind ODER
// - Diese spezifische Domain gesperrt ist
$isDomainLocked = $allDomainsLocked || (isset($domainStatus[$key]) && 1 == $domainStatus[$key]);

if ($isDomainLocked) {
$url = $domain->getUrl() . '?maintenance_secret=' . rex_config::get('maintenance', 'maintenance_secret');
$copy .= '<li class="list-group-item">';
$copy .= '<label for="maintenance-mode-url-' . $key . '">YRewrite: ' . htmlspecialchars($key) . '</label>';
$copy .= '
<clipboard-copy for="maintenance-mode-url-' . $key . '" class="input-group">
<input id="maintenance-mode-url-' . $key . '" type="text" value="' . $url . '" readonly class="form-control">
<span class="input-group-addon"><i class="rex-icon fa-clone"></i></span>
</clipboard-copy></li>';
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Moin Falscher Config-Key für Bypass-Links

Hier wird rex_config::get('maintenance', 'maintenance_secret') verwendet. In package.yml lautet der Default-Key jedoch secret, dadurch bleibt der Parameter leer und alle generierten Bypass-URLs funktionieren nicht. Bitte auf den korrekten Key umstellen.

-    $url = '' . rex::getServer() . '?maintenance_secret=' . rex_config::get('maintenance', 'maintenance_secret');
+    $url = rex::getServer() . '?maintenance_secret=' . rex_config::get('maintenance', 'secret');-            $url = $domain->getUrl() . '?maintenance_secret=' . rex_config::get('maintenance', 'maintenance_secret');
+            $url = $domain->getUrl() . '?maintenance_secret=' . rex_config::get('maintenance', 'secret');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (rex_config::get('maintenance', 'block_frontend') || $allDomainsLocked) {
$url = '' . rex::getServer() . '?maintenance_secret=' . rex_config::get('maintenance', 'maintenance_secret');
$copy .= '<li class="list-group-item">';
$copy .= '<label for="maintenance-mode-url">' . $addon->i18n('maintenance_bypass_url_default') . '</label>';
$copy .= '
<clipboard-copy for="maintenance-mode-url" class="input-group">
<input id="maintenance-mode-url" type="text" value="' . $url . '" readonly class="form-control">
<span class="input-group-addon"><i class="rex-icon fa-clone"></i></span>
</clipboard-copy></li>';
}
// YRewrite-Domains nur anzeigen, wenn sie gesperrt sind
if ($yrewriteAvailable && count(rex_yrewrite::getDomains()) > 1) {
foreach (rex_yrewrite::getDomains() as $key => $domain) {
if ('default' == $key) {
continue;
}
// Domain nur anzeigen, wenn:
// - Alle Domains gesperrt sind ODER
// - Diese spezifische Domain gesperrt ist
$isDomainLocked = $allDomainsLocked || (isset($domainStatus[$key]) && 1 == $domainStatus[$key]);
if ($isDomainLocked) {
$url = $domain->getUrl() . '?maintenance_secret=' . rex_config::get('maintenance', 'maintenance_secret');
$copy .= '<li class="list-group-item">';
$copy .= '<label for="maintenance-mode-url-' . $key . '">YRewrite: ' . htmlspecialchars($key) . '</label>';
$copy .= '
<clipboard-copy for="maintenance-mode-url-' . $key . '" class="input-group">
<input id="maintenance-mode-url-' . $key . '" type="text" value="' . $url . '" readonly class="form-control">
<span class="input-group-addon"><i class="rex-icon fa-clone"></i></span>
</clipboard-copy></li>';
}
if (rex_config::get('maintenance', 'block_frontend') || $allDomainsLocked) {
$url = rex::getServer() . '?maintenance_secret=' . rex_config::get('maintenance', 'secret');
$copy .= '<li class="list-group-item">';
$copy .= '<label for="maintenance-mode-url">' . $addon->i18n('maintenance_bypass_url_default') . '</label>';
$copy .= '
<clipboard-copy for="maintenance-mode-url" class="input-group">
<input id="maintenance-mode-url" type="text" value="' . $url . '" readonly class="form-control">
<span class="input-group-addon"><i class="rex-icon fa-clone"></i></span>
</clipboard-copy></li>';
}
// YRewrite-Domains nur anzeigen, wenn sie gesperrt sind
if ($yrewriteAvailable && count(rex_yrewrite::getDomains()) > 1) {
foreach (rex_yrewrite::getDomains() as $key => $domain) {
if ('default' == $key) {
continue;
}
// Domain nur anzeigen, wenn:
// - Alle Domains gesperrt sind ODER
// - Diese spezifische Domain gesperrt ist
$isDomainLocked = $allDomainsLocked || (isset($domainStatus[$key]) && 1 == $domainStatus[$key]);
if ($isDomainLocked) {
$url = $domain->getUrl() . '?maintenance_secret=' . rex_config::get('maintenance', 'secret');
$copy .= '<li class="list-group-item">';
$copy .= '<label for="maintenance-mode-url-' . $key . '">YRewrite: ' . htmlspecialchars($key) . '</label>';
$copy .= '
<clipboard-copy for="maintenance-mode-url-' . $key . '" class="input-group">
<input id="maintenance-mode-url-' . $key . '" type="text" value="' . $url . '" readonly class="form-control">
<span class="input-group-addon"><i class="rex-icon fa-clone"></i></span>
</clipboard-copy></li>';
}
🤖 Prompt for AI Agents
pages/frontend.sidebar.php around lines 31 to 63: the code uses
rex_config::get('maintenance', 'maintenance_secret') but the package.yml default
key is named "secret", so the generated bypass URLs are empty; change all uses
of rex_config::get('maintenance', 'maintenance_secret') to
rex_config::get('maintenance', 'secret') (or call rex_config::get('maintenance',
'secret', '<fallback>') if you want a fallback) so the correct config value is
retrieved and the bypass URLs are built properly.

@skerbis skerbis merged commit 10bdba6 into main Oct 29, 2025
2 checks passed
@skerbis skerbis deleted the feature/maintenance-improvements branch October 29, 2025 19:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants