Skip to content

Site Health: Porta recommended settings check-list (extensible registry, hybrid effect/config verification) #41

Description

@parisek

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)

  1. 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.

  2. 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:
    • id, label, category (security|caching|seo|performance|mail|a11y)
    • recommendation (what Porta recommends + why)
    • method (effect | config | both)
    • 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)

  • Security (mirrors Security hardening: info-disclosure gaps vs WAF layer + optional security-headers emitter #40): WP version hidden (the_generator empty); REST users
    endpoint 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-login not enumerable.
  • 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions