Install
This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/drift-creative-systems/drift-curtain/archive/refs/heads/main.zip
Drift: Curtain
Free WordPress plugin by Drift Creative Systems. Shows logged-out visitors a customisable maintenance page with a proper 503 status while you keep working. Includes scheduling, client preview links, an IP allowlist and an optional site password.
- WordPress.org slug:
drift-curtain(submission pending) - Licence: GPL-2.0-or-later
- Requires WordPress 6.0+, PHP 7.4+
The user-facing documentation is readme.txt, which WordPress.org displays. This file is for developers.
How it works
template_redirect(priority 1) serves the page with503,Retry-Afterand no-cache headers, then exits.- Not gated: wp-admin, REST, AJAX, cron, WP-CLI, feeds, previews, users with
manage_options(filterable), valid preview link or cookie, allowlisted IPs and visitors who have entered the site password. - Schedule times are stored as
datetime-localstrings and parsed in the site timezone (wp_timezone()). - The site password is stored with
wp_hash_password(). The access cookie isexpiry|HMAC(expiry|hash, auth salt), so changing the password signs everyone out. Failed attempts: 5 per IP per 15 minutes (transient keyed on an MD5 of the IP). - Settings → Drift: Curtain has four tabs. Each tab is its own option group, because
options.phpblanks every option in a group that isn't in the submitted form. Fields come fromdrift_curtain_settings_schema().
Update screen override
With Also show this page while WordPress installs updates ticked (single site only), the plugin writes two files to wp-content:
| File | Contents |
|---|---|
maintenance.php |
Copy of includes/maintenance-dropin.php. Fixed code, with no user content |
drift-curtain.html |
Static render of the page (without the password form), which the drop-in prints |
They're rewritten at the end of any request that saves a drift_curtain_* option, and removed when the option is unticked, on deactivation and in uninstall.php. Writes go through WP_Filesystem only when the method is direct. A maintenance.php without the Drift: Curtain drop-in marker is never overwritten or deleted.
Options
All options are prefixed drift_curtain_. They're stored data, so never rename them.
| Tab | Options |
|---|---|
| Status | enabled, show_main_content, override_wp_maintenance, schedule_enabled, schedule_start, schedule_end |
| Preview & access | preview_token, ip_allowlist, site_password (hash), password_days |
| Design | logo, background_image, bg_colour, font_colour |
| Content & SEO | badge_text, header_text, main_content, embed_content, footer_text, linkedin, facebook, instagram, seo_title, seo_description |
embed_content is printed unescaped by design (see the note at the top of drift-curtain.php). Changing it needs unfiltered_html.
Cookies: drift_curtain_preview (one day) and drift_curtain_access (password, as configured). Query parameter: ?drift_curtain_preview=TOKEN.
Hooks
| Hook | Type | Purpose |
|---|---|---|
drift_curtain_is_active |
filter | Whether maintenance mode is on |
drift_curtain_bypass_capability |
filter | Capability that sees the live site. Default manage_options |
drift_curtain_can_bypass |
filter | Return true to let the current visitor through |
drift_curtain_retry_after |
filter | Retry-After seconds |
drift_curtain_page_html |
filter | Page HTML: ( $html, $args ) |
drift_curtain_settings_after_fields |
action | Extra fields in the form: ( $tab ) |
These are the extension points for a paid add-on, sold outside WordPress.org. Nothing in this plugin is gated.
Development
- Coding standard:
phpcs.xml.dist(WordPress, prefixesdrift_curtain/DRIFT_CURTAIN). - Run Plugin Check before every release. The PHPCS-based checks don't work in WordPress Playground (its filesystem can't
flock()), so use a real install, e.g. WP-CLI with the SQLite drop-in:wp plugin install plugin-check --activate wp plugin check drift-curtain --include-low-severity-errors --include-low-severity-warnings \ --require=./wp-content/plugins/plugin-check/cli.phpCheck a copy built from
.distignore, not the repo, so dev files don't trip thefile_typecheck. - Directory guidelines review: the
wp-plugin-directory-guidelinesClaude Code skill.
Releasing
- Bump the version in three places: the
Version:header,DRIFT_CURTAIN_VERSIONandStable tag:inreadme.txt. Add a changelog entry to bothreadme.txtandCHANGELOG.md. - Merge
develop→main, then publish a GitHub release taggedvX.Y.Z. .github/workflows/release.ymlchecks the three versions match, buildsdrift-curtain.zipfrom.distignoreand attaches it to the release.- Once approved on WordPress.org, set the repo variable
WPORG_DEPLOY=trueand the secretsSVN_USERNAME/SVN_PASSWORD. Releases then deploy to SVN automatically, and readme/asset changes onmainsync on their own (wporg-assets.yml).
WordPress.org assets (icon, banners, screenshots) live in .wordpress-org/.
Licence
GPL-2.0-or-later. See LICENSE.