Skip to content

feat(maintenance): optional public 503 and an editable banner - #517

Open
t0ma5 wants to merge 1 commit into
mindstellar:developfrom
t0ma5:feature/maintenance-soft-banner
Open

feat(maintenance): optional public 503 and an editable banner#517
t0ma5 wants to merge 1 commit into
mindstellar:developfrom
t0ma5:feature/maintenance-soft-banner

Conversation

@t0ma5

@t0ma5 t0ma5 commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Why

.maintenance is still the only on/off switch. Today that file always 503s the public site. That is the right default for an upgrade (core already touches the file) and for anyone who already relies on lockout. This PR adds a second, optional layer: keep the site up and show a banner whose text the admin edits.

Nothing site-specific, no extra routes, no HTML in the banner.

Logic

  1. File on/off. Tools → Maintenance still creates or removes .maintenance. That is unchanged.
  2. Lockout defaults on. Missing/empty maintenance_lockout reads as on. Existing installs and the upgrade path that writes the file still 503 visitors. Only an explicit 0 (unchecked checkbox, saved) is the soft mode.
  3. Soft mode. File present + lockout off → HTTP 200 for everyone. __OSC_MAINTENANCE__ is defined so the header bar renders. The bar shows the saved message (escaped); if the message is blank, the previous default copy (with the site title) is used.
  4. Hard mode. File present + lockout on → public HTTP 503, same as today. Theme maintenance.php still wins if the theme ships one; otherwise osc_die() uses the same (escaped) message. Admins skip the 503 and see the bar, with copy that says only signed-in admins can see the site.
  5. Admins never 503. osc_is_admin_user_logged_in() still bypasses lockout.
  6. CLI never 503. php index.php -p cron is not an admin session, so today it would hit the 503 path during lockout and cron would not run. CLI is exempted. oc-cli.php never went through index.php and is unchanged.
  7. Plain text only. The saved message is trimmed, strip_tags, max 500 characters. HTML is not stored. Output goes through osc_esc_html (and nl2br) on the banner and on the 503 page.
  8. fclose. fopen of .maintenance only fcloses a real handle. PHP 8 type-errors if fopen failed and we still closed false.

Prefs: section osclass, maintenance_lockout BOOLEAN, maintenance_message STRING. The 503/banner decision is a pair of pure helpers so the default-on lockout and the sanitizer can be pinned without a database (tests/maintenance-mode.php).

How to test

  • Tools → Maintenance → Enable. Incognito: HTTP 503. Admin session: site works, yellow bar (admins-only copy).
  • Uncheck Block the public site, save a short message. Incognito: HTTP 200 + banner with that text. <script> in the message must not run.
  • Clear the message and save: default copy comes back.
  • php index.php -p cron -t hourly while .maintenance exists and lockout is on: cron still runs (no 503).
  • Disable maintenance: banner gone, site as usual. Re-enable: the last lockout/message choice is still there.

Made with Cursor

Keep .maintenance as the on/off switch and default lockout on so existing
sites and the upgrade path that touches the file still 503 visitors.
Unchecking lockout leaves the site up with a plain-text banner. CLI cron
is not 503'd. Only fclose the flag file when fopen succeeded.

Co-authored-by: Cursor <cursoragent@cursor.com>
@t0ma5
t0ma5 requested a review from navjottomer as a code owner August 24, 2026 15:43
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.

1 participant