You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Tracking / design issue — capturing the idea + decisions so far. To be picked
up later. Related to #40 (the hardening this board would verify).
Motivation
Our recommended project settings (security hardening, caching, SEO, performance,
mail deliverability, accessibility) are spread across plugin checkboxes whose
state lives in the DB, not in git. The recurring pain: it's hard to find out retroactively "what click is set where" on a given site. There's no single place
that says "here is what Porta recommends, and here is what is actually active
right now on this install."
Idea: a TimberKit-provided health check-list surfaced in WordPress Site Health
(Tools → Site Health), which lists our recommended settings and verifies the real,
effective state — so auditing a site is one screen, not archaeology through plugin
admin pages.
Why Site Health (native site_status_tests API):
Built-in UI with good / recommended / critical statuses + per-test
description and "Actions" link.
Supports async (REST-backed) tests for checks that do real probes.
Editors/admins already know where it lives; no custom admin page to maintain.
Decisions already made (from design discussion)
Scope: full "Porta recommended" board, not security-only — security,
caching, SEO, performance, mail deliverability, accessibility. But built as an extensible check registry, security checks first, other categories added
incrementally. One cohesive subsystem (registry + Site Health adapter), many
checks — no need to split into separate features.
Verification model: hybrid — each check declares its own method. The core
supports all three; every check picks what fits:
effect — probe the real outcome, plugin-agnostic. Preferred where possible
because it survives plugin swaps (e.g. the Add dev media proxy #2 NinjaFirewall → AIOS
consolidation) and checks results, not a specific vendor's checkbox.
Examples: does /wp-json/wp/v2/users return data to an anonymous request?
is get_the_generator('xhtml') empty? did the response carry HSTS?
does apply_filters('xmlrpc_enabled', true) return false?
config — read a specific plugin's stored option when there's no observable
effect (e.g. NinjaFirewall nfw_options[enum_restapi], Breeze settings,
SMTP host configured). Thin per-plugin adapter, used only as needed.
both — cross-check effect against config to catch "checkbox on but not
actually working" (cache layer, edge proxy, etc.).
This directly dissolves the core pain: for effect checks you stop caring which click produced the result — you verify the result itself.
Proposed architecture (to refine when implemented)
HealthCheck — a small value object / interface each check implements:
run(): Result returning good|recommended|critical + a human message +
optional remediation hint / link
CheckRegistry — collects checks, lets projects add/override/disable per
site (a child class or filter — consistent with the existing protected bool
override pattern in StarterBase).
SiteHealthAdapter — maps registered checks onto site_status_tests
(sync where cheap, async REST for real probes). The ONLY coupling to WP Site
Health; the registry + checks stay framework-agnostic and unit-testable.
(optional later) a compact "Porta status" summary widget that aggregates the
board into one pass/fail count.
Per the design-for-isolation principle: checks are independent units (one purpose,
own run()), the adapter is the only Site Health touchpoint, the registry is the
only wiring — each testable in isolation.
Starter checks per category (seed list, not exhaustive)
Caching: a page-cache plugin active (Breeze/Rocket/…); object cache present;
expected Cache-Control / cache-provider header observed.
SEO: exactly one SEO plugin active (no Yoast+AIOSEO overlap — see Add dev media proxy #2);
sitemap reachable; robots.txt not blocking; canonical/meta present on a probe.
Performance: PHP version >= target; gzip/deflate on; images served as
WebP/AVIF; no obvious render-block flagged.
Mail deliverability: an SMTP/mailer plugin configured (host set); SPF/DKIM
hint (config-level, can't fully verify from PHP).
Accessibility: lightweight static hints (lang attribute, skip-link, alt
coverage sample) — clearly "advisory", not a full audit.
Non-goals
Not a replacement for a real WAF, a real Lighthouse/a11y audit, or external
deliverability testing — these checks are configuration-presence + effect
smoke checks, deliberately cheap.
No heavy per-request work; probes run inside Site Health (on demand), never on
front-end page loads.
Open questions (resolve at implementation time)
Sync vs async split — which checks justify the async REST test?
How do projects opt a check out / change its severity (filter vs subclass)?
Do we ship a CLI (wp porta:health) mirror for CI/headless, or Site-Health-only?
Per-plugin config adapters: ship NinjaFirewall + Breeze first; how to keep them
optional so the package has zero hard plugin dependency?
Acceptance (high level)
HealthCheck interface + Result type
CheckRegistry with per-project add/override/disable
SiteHealthAdapter registering checks via site_status_tests
Motivation
Our recommended project settings (security hardening, caching, SEO, performance,
mail deliverability, accessibility) are spread across plugin checkboxes whose
state lives in the DB, not in git. The recurring pain: it's hard to find out
retroactively "what click is set where" on a given site. There's no single place
that says "here is what Porta recommends, and here is what is actually active
right now on this install."
Idea: a TimberKit-provided health check-list surfaced in WordPress Site Health
(Tools → Site Health), which lists our recommended settings and verifies the real,
effective state — so auditing a site is one screen, not archaeology through plugin
admin pages.
Why Site Health (native
site_status_testsAPI):good/recommended/criticalstatuses + per-testdescription and "Actions" link.
Decisions already made (from design discussion)
Scope: full "Porta recommended" board, not security-only — security,
caching, SEO, performance, mail deliverability, accessibility. But built as an
extensible check registry, security checks first, other categories added
incrementally. One cohesive subsystem (registry + Site Health adapter), many
checks — no need to split into separate features.
Verification model: hybrid — each check declares its own method. The core
supports all three; every check picks what fits:
effect— probe the real outcome, plugin-agnostic. Preferred where possiblebecause it survives plugin swaps (e.g. the Add dev media proxy #2 NinjaFirewall → AIOS
consolidation) and checks results, not a specific vendor's checkbox.
Examples: does
/wp-json/wp/v2/usersreturn data to an anonymous request?is
get_the_generator('xhtml')empty? did the response carry HSTS?does
apply_filters('xmlrpc_enabled', true)return false?config— read a specific plugin's stored option when there's no observableeffect (e.g. NinjaFirewall
nfw_options[enum_restapi], Breeze settings,SMTP host configured). Thin per-plugin adapter, used only as needed.
both— cross-check effect against config to catch "checkbox on but notactually working" (cache layer, edge proxy, etc.).
This directly dissolves the core pain: for
effectchecks you stop caringwhich click produced the result — you verify the result itself.
Proposed architecture (to refine when implemented)
HealthCheck— a small value object / interface each check implements:id,label,category(security|caching|seo|performance|mail|a11y)recommendation(what Porta recommends + why)method(effect|config|both)run(): Resultreturninggood|recommended|critical+ a human message +optional remediation hint / link
CheckRegistry— collects checks, lets projects add/override/disable persite (a child class or filter — consistent with the existing
protected booloverride pattern in
StarterBase).SiteHealthAdapter— maps registered checks ontosite_status_tests(sync where cheap, async REST for real probes). The ONLY coupling to WP Site
Health; the registry + checks stay framework-agnostic and unit-testable.
board into one pass/fail count.
Per the design-for-isolation principle: checks are independent units (one purpose,
own
run()), the adapter is the only Site Health touchpoint, the registry is theonly wiring — each testable in isolation.
Starter checks per category (seed list, not exhaustive)
the_generatorempty); REST usersendpoint restricted for anon;
?author=N+ author sitemap blocked; XML-RPC off;Application Passwords off;
DISALLOW_FILE_EDIT; 6 response headers present(incl. HSTS proxy-safe);
wp-loginnot enumerable.expected
Cache-Control/ cache-provider header observed.sitemap reachable;
robots.txtnot blocking; canonical/meta present on a probe.WebP/AVIF; no obvious render-block flagged.
hint (config-level, can't fully verify from PHP).
coverage sample) — clearly "advisory", not a full audit.
Non-goals
deliverability testing — these checks are configuration-presence + effect
smoke checks, deliberately cheap.
front-end page loads.
Open questions (resolve at implementation time)
wp porta:health) mirror for CI/headless, or Site-Health-only?configadapters: ship NinjaFirewall + Breeze first; how to keep themoptional so the package has zero hard plugin dependency?
Acceptance (high level)
HealthCheckinterface +ResulttypeCheckRegistrywith per-project add/override/disableSiteHealthAdapterregistering checks viasite_status_testseffect/config/bothsupported with at least one of each