Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,12 @@ jobs:
- name: Build plugin package
# Same file selection as the wordpress.org deployment (.distignore).
run: |
mkdir -p build/wirecore-disable-rest
rsync -a --exclude-from=.distignore ./ build/wirecore-disable-rest/ --exclude=/build
mkdir -p build/wirecore-rest-control
rsync -a --exclude-from=.distignore ./ build/wirecore-rest-control/ --exclude=/build
- uses: wordpress/plugin-check-action@v1
with:
build-dir: build/wirecore-disable-rest
slug: wirecore-disable-rest
build-dir: build/wirecore-rest-control
slug: wirecore-rest-control
include-experimental: true
# Warnings fail the build as well – the plugin is free of both.
strict: true
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Check version numbers
run: |
tag="${GITHUB_REF_NAME}"
header=$(sed -n 's/^Version: *//p' wirecore-disable-rest.php | tr -d '\r')
header=$(sed -n 's/^Version: *//p' wirecore-rest-control.php | tr -d '\r')
stable=$(sed -n 's/^Stable tag: *//p' readme.txt | tr -d '\r')
echo "Tag: $tag, plugin header: $header, readme stable tag: $stable"
if [ "$tag" != "$header" ] || [ "$tag" != "$stable" ]; then
Expand All @@ -45,7 +45,7 @@ jobs:
env:
SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
SLUG: wirecore-disable-rest
SLUG: wirecore-rest-control
ASSETS_DIR: .wordpress-org

- name: Create GitHub release
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ All notable changes to this project are documented in this file. The format is b
- Global allow lists, global IP deny list and "never block administrators".
- Custom error message and status code, HTTPS-only, JSONP off, removal of REST links, hiding blocked routes in the REST index.
- Optional log of blocked requests with configurable IP storage.
- Self-test, JSON export/import and WP-CLI commands (`wp wirecore-dr`).
- Self-test, JSON export/import and WP-CLI commands (`wp wirecore-rest`).
- Multisite support with settings per site.
- German translations (`de_DE`, `de_DE_formal`).
34 changes: 17 additions & 17 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
# WireCore Disable REST
# WireCore REST Control

WordPress plugin, published on wordpress.org (slug `wirecore-disable-rest`) and installed via WPackagist. All repository content – code comments, UI source strings, docs – is in English; German UI texts exist only in `languages/`.
WordPress plugin, published on wordpress.org (slug `wirecore-rest-control`) and installed via WPackagist. All repository content – code comments, UI source strings, docs – is in English; German UI texts exist only in `languages/`.

## Conventions

- Static classes `WireCore_DR_*` in `includes/class-wirecore-dr-*.php`, no autoloader, no namespaces. Each class has an `init()` that registers its hooks.
- Prefix everything global: functions/options/hooks/nonces `wirecore_dr_`, constants `WIRECORE_DR_`, CSS classes/IDs `wirecore-dr-`, text domain `wirecore-disable-rest`, WP-CLI command `wp wirecore-dr`.
- Static classes `WireCore_RC_*` in `includes/class-wirecore-rc-*.php`, no autoloader, no namespaces. Each class has an `init()` that registers its hooks.
- Prefix everything global: functions/options/hooks/nonces `wirecore_rc_`, constants `WIRECORE_RC_`, CSS classes/IDs `wirecore-rc-`, text domain `wirecore-rest-control`, WP-CLI command `wp wirecore-rest`.
- Admin pages in plain PHP with `admin-post.php` forms, nonces, `wp_safe_redirect()` plus a notice query arg. No build step for JS; the only CSS build is `npm run build:css` (below).
- UI in the WireLayer corporate design: the markup uses the `.wc-*` classes of `@wirecore/wirelayer-css` (class reference: `node_modules/@wirecore/wirelayer-css/llms-full.txt`). `npm run build:css` writes the used components, scoped to `#wirecore-dr`, to `assets/wirelayer/` – committed, CI checks it is up to date. Add a component to the list in `package.json` before using its classes, and run the command again after updating the package. `wirecore-dr-*` classes are hooks for `admin.js` and page layout in `assets/admin.css` (scoped to `#wirecore-dr`, colors and spacing from WireLayer variables). Icons are inline Lucide SVGs (`WireCore_DR_Admin::icon()`).
- UI in the WireLayer corporate design: the markup uses the `.wc-*` classes of `@wirecore/wirelayer-css` (class reference: `node_modules/@wirecore/wirelayer-css/llms-full.txt`). `npm run build:css` writes the used components, scoped to `#wirecore-rc`, to `assets/wirelayer/` – committed, CI checks it is up to date. Add a component to the list in `package.json` before using its classes, and run the command again after updating the package. `wirecore-rc-*` classes are hooks for `admin.js` and page layout in `assets/admin.css` (scoped to `#wirecore-rc`, colors and spacing from WireLayer variables). Icons are inline Lucide SVGs (`WireCore_RC_Admin::icon()`).
- Minimum versions: WordPress 5.8, PHP 7.4 (verified with PHPCompatibility and a WP 5.8/PHP 7.4 instance) – do not use newer functions without raising them.
- Formatting with Prettier (tabs, single quotes). Plugin Check must stay free of errors and warnings; justified exceptions are marked with `phpcs:ignore`/`phpcs:disable` plus a comment explaining why.

## Architecture

- `WireCore_DR_Settings` – one option `wirecore_dr_settings`; everything that is stored (form, import, CLI) goes through `sanitize()`.
- `WireCore_DR_Routes` – reads `rest_get_server()->get_routes()` and detects via reflection which plugin or theme registered a route.
- `WireCore_DR_Guard` – check order in `decide()`: HTTPS → deny lists (global and "Advanced", also for admins) → admin bypass/global allow lists → allowances from "Advanced" → rule (route → namespace → automatic allowance → default). Enforced via `rest_request_before_callbacks`, which also covers `_embed` and `/batch/v1`, and also when WordPress already produced an error (otherwise blocked visitors would see parameter errors). `rule()` and `decide()` are the only place where rules are evaluated; `assets/admin.js` mirrors the inheritance for the display – keep both in sync.
- `WireCore_DR_Admin` – page under Settings → REST API.
- The route list is loaded via JS through the REST index (`/wp-json/?wirecore_dr_routes=1&_fields=wirecore_dr_routes`), because plugins like WooCommerce only register some namespaces during REST requests for exactly that namespace or the index – they would be missing in wp-admin. The guard never blocks this request for admins.
- `WireCore_RC_Settings` – one option `wirecore_rc_settings`; everything that is stored (form, import, CLI) goes through `sanitize()`.
- `WireCore_RC_Routes` – reads `rest_get_server()->get_routes()` and detects via reflection which plugin or theme registered a route.
- `WireCore_RC_Guard` – check order in `decide()`: HTTPS → deny lists (global and "Advanced", also for admins) → admin bypass/global allow lists → allowances from "Advanced" → rule (route → namespace → automatic allowance → default). Enforced via `rest_request_before_callbacks`, which also covers `_embed` and `/batch/v1`, and also when WordPress already produced an error (otherwise blocked visitors would see parameter errors). `rule()` and `decide()` are the only place where rules are evaluated; `assets/admin.js` mirrors the inheritance for the display – keep both in sync.
- `WireCore_RC_Admin` – page under Settings → REST API.
- The route list is loaded via JS through the REST index (`/wp-json/?wirecore_rc_routes=1&_fields=wirecore_rc_routes`), because plugins like WooCommerce only register some namespaces during REST requests for exactly that namespace or the index – they would be missing in wp-admin. The guard never blocks this request for admins.
- The routes tab sends all rules as one JSON field (`rules_json`), because hundreds of selects would exceed `max_input_vars`.
- `WireCore_DR_Log`, `WireCore_DR_Cli` – log of blocked requests and WP-CLI commands.
- `WireCore_RC_Log`, `WireCore_RC_Cli` – log of blocked requests and WP-CLI commands.

## Translations

All UI strings are English in the code and translated in `languages/`: `de_DE` (informal) and `de_DE_formal` (formal). WP-CLI output stays English and untranslated. `load_plugin_textdomain()` is kept for the bundled translations until language packs exist on translate.wordpress.org.

After changing strings (inside the Docker container, `P=wp-content/plugins/wirecore-disable-rest`):
After changing strings (inside the Docker container, `P=wp-content/plugins/wirecore-rest-control`):

```bash
docker compose exec wordpress wp --allow-root i18n make-pot $P $P/languages/wirecore-disable-rest.pot --domain=wirecore-disable-rest --exclude=node_modules,db-data,languages
docker compose exec wordpress wp --allow-root i18n update-po $P/languages/wirecore-disable-rest.pot $P/languages
docker compose exec wordpress wp --allow-root i18n make-pot $P $P/languages/wirecore-rest-control.pot --domain=wirecore-rest-control --exclude=node_modules,db-data,languages
docker compose exec wordpress wp --allow-root i18n update-po $P/languages/wirecore-rest-control.pot $P/languages
# translate new or changed entries in both .po files, then:
docker compose exec wordpress wp --allow-root i18n make-mo $P/languages
docker compose exec wordpress wp --allow-root i18n make-php $P/languages
Expand All @@ -39,14 +39,14 @@ docker compose exec wordpress wp --allow-root i18n make-php $P/languages

## Package contents

Only `wirecore-disable-rest.php`, `uninstall.php`, `index.php`, `readme.txt`, `LICENSE`, `includes/`, `assets/` and `languages/` are shipped. New development or configuration files must be added to both `.distignore` and `.gitattributes` (`export-ignore`).
Only `wirecore-rest-control.php`, `uninstall.php`, `index.php`, `readme.txt`, `LICENSE`, `includes/`, `assets/` and `languages/` are shipped. New development or configuration files must be added to both `.distignore` and `.gitattributes` (`export-ignore`).

## Checks

CI (`.github/workflows/ci.yml`) must stay green: PHP lint 7.4–8.4, `composer phpcs` (PHPCompatibilityWP, `phpcs.xml.dist`), PHPUnit on PHP 7.4 and 8.3, `npm run format:check`, `assets/wirelayer/` up to date with `npm run build:css`, Plugin Check in strict mode on the package built from `.distignore`.

Tests live in `tests/` (`test-*.php`, base class `WireCore_DR_TestCase`). They are integration tests against the WordPress test suite: dispatch requests through `rest_get_server()->dispatch()` (the bootstrap defines `REST_REQUEST`), and register fixture routes in `tests/bootstrap.php` – the route list is cached, so routes must exist before the first REST server is created. Run them inside the Docker container (see README) against the separate database `wordpress_test`.
Tests live in `tests/` (`test-*.php`, base class `WireCore_RC_TestCase`). They are integration tests against the WordPress test suite: dispatch requests through `rest_get_server()->dispatch()` (the bootstrap defines `REST_REQUEST`), and register fixture routes in `tests/bootstrap.php` – the route list is cached, so routes must exist before the first REST server is created. Run them inside the Docker container (see README) against the separate database `wordpress_test`.

## Release

Bump `Version:` in `wirecore-disable-rest.php` and `Stable tag:` in `readme.txt` together, and add the entry to the changelog in `readme.txt` and `CHANGELOG.md`. Pushing a tag like `1.0.1` (no `v`) runs `.github/workflows/release.yml`, which verifies the version numbers and deploys to the wordpress.org SVN repository.
Bump `Version:` in `wirecore-rest-control.php` and `Stable tag:` in `readme.txt` together, and add the entry to the changelog in `readme.txt` and `CHANGELOG.md`. Pushing a tag like `1.0.1` (no `v`) runs `.github/workflows/release.yml`, which verifies the version numbers and deploys to the wordpress.org SVN repository.
Loading
Loading