Repository navigation
Development and releases
This page is for people who work on SafeHouse itself: setting up the development environment, how the code is organised, how to add a module, and how a release is made. The README holds the short version and the rules every change must follow.
You need Docker. You do not need PHP or Composer on your machine.
cd dev && docker compose up -d && ./setup.shThis starts WordPress with WooCommerce and Wordfence at http://localhost:8894 (user admin, password admin), with the plugin mounted from plugin/. Mailpit catches every e-mail at http://localhost:8025.
| Command | What it does |
|---|---|
./dev/wp.sh shouse status |
Runs WP-CLI inside the container |
./dev/lint.sh |
PHPCS (WordPress coding standards) and PHPStan, in the composer:2 image. --fix fixes what PHPCS can. |
./dev/smoke.sh |
HTTP and WP-CLI regression checks against the dev site |
./dev/i18n.sh |
Regenerates shouse.pot, merges it into every .po, and compiles .mo and .l10n.php
|
Other test environments:
-
dev/ols/: OpenLiteSpeed with Redis, for the page cache, object cache, login limits and Cloudflare tests -
dev/update-test.sh: signed updates end to end, on an isolated site with a throwaway key -
dev/package-test.sh: install and uninstall from a release ZIP -
dev/updates-test.shanddev/ingest-test.sh: the update host Workers against a local storage bucket -
dev/cve-watch-test.sh: the vulnerability watch issue logic against a mock GitHub API
| Path | Holds |
|---|---|
plugin/shouse.php |
Plugin header, PHP version check, autoloader |
plugin/src/Plugin.php |
Boot order and the list of modules |
plugin/src/Core/ |
Settings, safe mode, activity log, alerts, visitor address, updater, WP-CLI, Turnstile, object cache commands, content-change dispatcher |
plugin/src/Modules/ |
One class per module, plus their WP-CLI command classes |
plugin/src/ObjectCache/ |
The Redis object cache drop-in and its loader |
plugin/src/Admin/Page.php |
The settings page |
plugin/languages/ |
Translations |
updates/ |
The update host Worker, and updates/ingest/, the token-protected Worker that accepts release files and vulnerability data |
site/ |
The landing page |
dev/ |
Docker environments, tests and release tools |
Release ZIPs are built from plugin/ only.
A module is a class in plugin/src/Modules/ that extends SafeHouse\Core\AbstractModule. The settings page, the switch, WP-CLI status and SHOUSE_MODULES all work from the class alone.
-
Implement the required methods:
Method Returns id()The stable ID used as the settings key and in WP-CLI label(),description()Translated name and one-paragraph description defaults()Field defaults; must not call translation functions, because it runs before initfields()The field schema: type(toggle,text,email_list,textarea,html,code,number,select),label, and optionalhelp,options,min,max,max_lengthboot()Registers hooks; called on plugins_loadedonly when the module is enabled and available -
Override what the module needs:
Method Use default_enabled()Return trueto have the module on before anyone saves a choiceavailable(),unavailable_reason()When the module cannot run on a site, and why coverage()field => provider namefor features another plugin already provides; those fields step asidetasks(),handle_task()Buttons in the module's Details; capability and nonce are checked for you render_panel()Read-only status under the fields; escape all output settings_saved()React to a save, whether or not the module is enabled -
Add the class to
Plugin::MODULESinplugin/src/Plugin.php. The order there is the order on the settings page. -
If the module replaces other plugins, add their slugs to
PluginHealth::REPLACEABLE, and updateGROUPSindesign/hero/index.html(see its README). -
Run
./dev/i18n.shfor the new strings, then./dev/lint.sh. -
Document the module in the README,
plugin/readme.txtand this wiki.
Releases are made by maintainers.
- Add a
## x.y.zsection toCHANGELOG.md. WordPress shows it in the update's View details window. - On a clean
main, run./dev/release.sh x.y.z. It sets the version inplugin/shouse.phpandplugin/readme.txt, runs the linters, commits "Release x.y.z" and creates the tagvx.y.z. - Push:
git push origin main vx.y.z. - The Release workflow lints and test-builds without secrets, then waits for a maintainer to approve the
releaseenvironment. After approval it builds and signs the release from the tag and publishes the same three files to the update host and as a GitHub release.
Without GitHub Actions, a maintainer with the release key can run ./dev/release.sh build x.y.z && ./dev/publish.sh x.y.z.
Before each release, also run ./dev/cloudflare-ips.sh. It refreshes the Cloudflare address ranges built into the plugin, which sites receive only through updates.
How sites verify releases, and how anyone can rebuild one, is on Signed updates and Verify a download.
Report vulnerabilities privately: on the repository's Security tab, select Report a vulnerability. Do not open a public issue.
These pages describe SafeHouse 0.2.0 and were last reviewed on 2026-10-07. · Repository · Releases · Changelog · Report a problem with these pages
Search every page and heading in the Pages box.
Start here
Modules
- All modules
- Security: Hardening · Login limits · Bot protection · Install lockdown
- Alerts: Change alerts · Plugin health · Vulnerability alerts
- Performance: LiteSpeed page cache · Cloudflare cache · Redis object cache
- WooCommerce: Omnibus price history
- Site tools: SMTP mail · Header and footer scripts · Duplicate posts and pages · Maintenance mode · Tweaks
Guides
- Behind Cloudflare or a proxy
- Running with Wordfence
- Configure in wp-config
- Deploy with git or CI
- Replacing other plugins
- Upgrade from WPHouse
Reference
Trust
Help