{
  "security": {
    "https": {
      "metric_key": "security.https",
      "title": "HTTPS",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>HTTPS (HTTP over TLS) encrypts traffic between browsers and your server. In WordPress, both the <code>home</code> and <code>site</code> URLs should use <code>https://</code>.</p><p><strong>Why it matters:</strong> Prevents credential/session theft, protects data integrity, improves SEO ranking signals, and is required for modern browser features (e.g., Service Workers, HTTP/2).</p><p><strong>Good to know:</strong> Mixed HTTP/HTTPS configurations can break cookies, cause mixed-content warnings, and hurt crawlability. Use a valid certificate and HSTS for best practice.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action (partial HTTPS or mixed content):</strong></p><ol><li>Install a valid TLS certificate (Let’s Encrypt or vendor).</li><li>Update <em>Settings → General</em> so both <code>WordPress Address (URL)</code> and <code>Site Address (URL)</code> use <code>https://</code>.</li><li>Replace hard-coded <code>http://</code> asset URLs (search &amp; replace or use a plugin like Better Search Replace).</li><li>Ensure reverse proxy/CDN forwards protocol headers (<code>X-Forwarded-Proto</code>).</li></ol></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (HTTP only):</strong></p><ol><li>Provision and install a TLS certificate (Let’s Encrypt via host/panel).</li><li>Force HTTPS at the edge (server or CDN) and add a 301 HTTP→HTTPS redirect.</li><li>Switch WordPress/Site URLs to <code>https://</code> in <em>Settings → General</em>.</li><li>Enable HSTS once stable (<code>max-age=31536000; includeSubDomains; preload</code>).</li></ol></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>Manual fix option: move the site to HTTPS</h3><div class=\"ss-how-to\"><ol><li><strong>Confirm a certificate exists</strong><br>In your hosting panel look for an SSL/TLS or Security section. Enable a free Let’s Encrypt certificate or upload a purchased one for the main domain (and <code>www</code> if used).</li><li><strong>Switch WordPress URLs</strong><br>In <strong>Settings → General</strong>, change both <em>WordPress Address (URL)</em> and <em>Site Address (URL)</em> from <code>http://</code> to <code>https://</code>.</li><li><strong>Force HTTPS redirects</strong><br>Use your host/CDN UI or server config to redirect all <code>http://</code> requests to <code>https://</code> with a 301 redirect (for Apache this is usually in <code>.htaccess</code>, for Nginx in the server block).</li><li><strong>Fix mixed content</strong><br>Search the DB for hard-coded <code>http://</code> URLs to your own domain (plugins like “Better Search Replace” help) and replace with <code>https://</code>. Reload key pages and check browser dev tools for mixed-content warnings.</li><li><strong>Add HSTS once stable</strong><br>When everything works over HTTPS only, add <code>Strict-Transport-Security</code> at the server/CDN level so browsers always use HTTPS.</li></ol><p class=\"ss-how-to-note\"><strong>Note:</strong> Exact controls and file locations vary a lot by host. If you’re unsure where to put redirects or headers, open a ticket with your hosting provider and attach this report.</p></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": "<p><strong>Cache:</strong> If you terminate HTTPS at a CDN or reverse proxy, Scope may be seeing the edge, not the origin. When debugging protocol or mixed-content issues, check both the cached front door (CDN) and the raw origin URL, and clear/purge caches after changing URLs or redirects.</p>",
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "security",
        "metric_id": "https"
      }
    },
    "admin_hygiene": {
      "metric_key": "security.admin_hygiene",
      "title": "Admin Hygiene",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>A set of quick checks to reduce common attack surfaces (e.g., default usernames, legacy features, indexing).</p><p><strong>Why it matters:</strong> Attackers scan for easy wins—default <code>admin</code> usernames, exposed XML-RPC, or directory listings make brute-force and reconnaissance easier.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Review and harden:</p><ul><li>Rename/replace default <code>admin</code> user; use a unique username.</li><li>Require strong passwords + 2FA for administrators.</li><li>Limit login attempts and enable application firewall rules.</li></ul></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (high risk):</strong></p><ol><li>Create a new administrator user with a unique username and strong password; reassign content; delete the <code>admin</code> user.</li><li>Enforce 2FA for admin roles immediately.</li><li>Install/enable rate-limiting and login protections (e.g., WAF).</li></ol></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>Manual fix option: harden admin hygiene</h3><div class=\"ss-how-to\"><ol><li><strong>Remove the default <code>admin</code> user</strong><br>Go to <strong>Users → Add New</strong>, create a new admin account with a unique username, log out, then log in as the new account. Edit the old <code>admin</code> user and choose “Delete” → “Attribute all content to” your new admin before confirming.</li><li><strong>Enforce strong passwords + 2FA</strong><br>Install a reputable security plugin that supports 2FA (e.g. via TOTP app) and require it for administrator roles. Encourage passphrases instead of short passwords.</li><li><strong>Limit login attempts</strong><br>In your security or WAF plugin, enable login rate-limiting or reCAPTCHA to slow down brute-force attempts.</li><li><strong>Lock down admin access where possible</strong><br>If you have a VPN or static office IPs, consider IP-allowlisting for <code>/wp-admin/</code> at the firewall/proxy level.</li></ol><p class=\"ss-how-to-note\"><strong>Note:</strong> The exact 2FA and rate-limit settings live inside whatever security plugin or WAF you use; this tile simply reminds you to turn them on and verify they’re enforced for all admin users.</p></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "security",
        "metric_id": "admin_hygiene"
      }
    },
    "xmlrpc": {
      "metric_key": "security.xmlrpc",
      "title": "XML-RPC",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>XML-RPC is a legacy remote procedure call endpoint used by some publishing tools and the mobile app (older flows). It exposes methods for authentication and posting.</p><p><strong>Why it matters:</strong> If you don’t need it, disabling reduces the attack surface and brute-force vectors. If needed, rate-limit and protect it behind security tooling.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> If not required, disable XML-RPC via a security plugin or server rule. If required (e.g., Jetpack legacy), enable rate-limiting and WAF rules for <code>xmlrpc.php</code>.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (actively exposed):</strong></p><ol><li>Disable XML-RPC at application (security plugin) or server layer (deny access to <code>/xmlrpc.php</code>).</li><li>If unavoidable, allowlist IPs, require WAF bot protections, and enable brute-force mitigation.</li></ol></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>Manual fix option: lock down XML-RPC</h3><div class=\"ss-how-to\"><ol><li><strong>Decide if you still need XML-RPC</strong><br>Modern WordPress apps and integrations mostly use the REST API. If you don’t rely on legacy tools like old Jetpack flows or offline blog editors, you can usually disable XML-RPC entirely.</li><li><strong>Application-level block (recommended first)</strong><br>Install or configure a security plugin that offers a “Disable XML-RPC” or “Block xmlrpc.php” toggle. Enable it and re-test this report.</li><li><strong>Server-level block (Apache)</strong><br>In the site’s <code>.htaccess</code> or vhost:<pre><code>&lt;Files xmlrpc.php&gt; Require all denied&lt;/Files&gt;</code></pre>Save, then clear caches.</li><li><strong>Server-level block (Nginx)</strong><br>In your server block:<pre><code>location = /xmlrpc.php { deny all; }</code></pre>Reload Nginx and purge any reverse-proxy caches.</li><li><strong>If you must keep it</strong><br>Use your WAF (Cloudflare, Sucuri, etc.) to throttle or allowlist <code>/xmlrpc.php</code> by IP and enable bot/credential-stuffing protections.</li></ol><p class=\"ss-how-to-note\"><strong>Note:</strong> Blocking at the server level affects all apps using XML-RPC. Make a quick list of known integrations before you disable it so you can test them afterward.</p></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": "Inferred Signal",
      "meta": {
        "section": "security",
        "metric_id": "xmlrpc"
      }
    },
    "dir_indexing": {
      "metric_key": "security.dir_indexing",
      "title": "Directory Indexing",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>If a directory lacks an index file and web server listing is enabled, visitors may see the entire file list (e.g., <code>wp-content/uploads</code>).</p><p><strong>Why it matters:</strong> Exposes file names, backup archives, and clues that assist attackers. Block listing at the server level or via rules (e.g., <code>Options -Indexes</code> in Apache).</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Disable indexing in web server config (Apache: <code>Options -Indexes</code>; Nginx: omit <code>autoindex on</code>) or place a blank <code>index.html</code> in public directories.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (publicly exposed):</strong></p><ol><li>Disable auto-indexing immediately (Apache/Nginx rule).</li><li>Audit exposed directories (<code>uploads</code>, backups) and remove sensitive files.</li><li>Add <code>index.html</code> placeholders if server access is limited.</li></ol></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>Manual fix option: disable directory indexing</h3><div class=\"ss-how-to\"><ol><li><strong>Apache: turn off indexing</strong><br>In the main Apache config, vhost, or <code>.htaccess</code>, add:<pre><code>Options -Indexes</code></pre>Then reload Apache. This prevents “Index of /…” listings.</li><li><strong>Nginx: remove <code>autoindex on</code></strong><br>In any <code>location</code> blocks serving your site, either delete <code>autoindex on;</code> or explicitly set:<pre><code>autoindex off;</code></pre>Reload Nginx when finished.</li><li><strong>Fallback: add empty index files</strong><br>If you can’t change server config, create a blank <code>index.html</code> in exposed directories such as <code>wp-content/uploads</code> so the server serves that instead of a listing.</li><li><strong>Re-run the report</strong><br>After changes, reload the site and this report to confirm that directory listings are no longer exposed.</li></ol><p class=\"ss-how-to-note\"><strong>Note:</strong> On managed or shared hosting, the indexing toggle is often exposed as a simple “directory listing” or “Indexes” checkbox in the control panel instead of raw config.</p></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": "Inferred Signal",
      "meta": {
        "section": "security",
        "metric_id": "dir_indexing"
      }
    },
    "user_enum": {
      "metric_key": "security.user_enum",
      "title": "User Enumeration",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>The ability to derive usernames (e.g., via <code>?author=1</code> redirects or error messages).</p><p><strong>Why it matters:</strong> Knowing valid usernames halves the brute-force problem. Block enumeration to force attackers to guess both username and password.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Add rewrite rules to block author archive enumeration, and configure your security plugin to mask usernames in errors and endpoints.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (enumeration detected):</strong></p><ol><li>Block <code>?author=</code> patterns (rewrite to 404) or map to display names only.</li><li>Hide usernames from REST and login errors.</li><li>Rotate weak credentials and enable 2FA for admins.</li></ol></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>Manual fix option: block user enumeration</h3><div class=\"ss-how-to\"><ol><li><strong>Harden <code>?author=</code> URLs</strong><br>If your theme exposes author archives, prefer public “display names” instead of usernames. Using an SEO or security plugin, redirect <code>?author=ID</code> patterns to a safe URL or 404.</li><li><strong>Mask usernames in error messages</strong><br>Configure your security plugin to always return generic login errors (e.g., “Invalid credentials”) instead of revealing whether the username exists.</li><li><strong>Restrict REST user endpoints</strong><br>Use a security plugin or custom code to limit access to <code>/wp-json/wp/v2/users</code> to authenticated users, or to hide email/username fields from anonymous callers.</li><li><strong>Audit public profile URLs</strong><br>Scan the site for places where the raw login name is exposed (author slugs, directories, feeds) and switch to display names or anonymized IDs where possible.</li></ol><p class=\"ss-how-to-note\"><strong>Note:</strong> Blocking enumeration doesn’t remove the need for strong passwords and 2FA; it simply makes attacks more expensive by hiding valid usernames.</p></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": "Low-Confidence Signal",
      "meta": {
        "section": "security",
        "metric_id": "user_enum"
      }
    },
    "headers": {
      "metric_key": "security.headers",
      "title": "Security Headers",
      "summary": {
        "html": "<h3>Description</h3><p>HTTP response headers that enforce browser-side security policies.</p><p><strong>Why:</strong> They mitigate XSS, clickjacking, MIME sniffing, and protocol-downgrade risks by pushing guardrails into the browser.</p>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": null
        },
        "bad": {
          "body_html": null
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": null,
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "security",
        "metric_id": "headers"
      }
    },
    "headers.csp": {
      "metric_key": "security.headers.csp",
      "title": "Content-Security-Policy (CSP)",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>The <strong>Content-Security-Policy</strong> header controls which sources the browser may load for scripts, styles, images, etc., drastically reducing XSS and injection risk.</p><h3>Example</h3><pre><code>Content-Security-Policy: default-src 'self'; img-src 'self' data: https:; script-src 'self' cdn.example.com; style-src 'self' 'unsafe-inline'; object-src 'none'; frame-ancestors 'self'</code></pre><h3>Notes</h3><ul><li>Start with <code>Content-Security-Policy-Report-Only</code> to collect violations before enforcing.</li><li>Prefer nonces or hashes over <code>unsafe-inline</code> for scripts.</li><li>Add <code>report-to</code>/<code>report-uri</code> to receive violation reports.</li></ul><h3>CSP Reporting</h3><p>You can instruct browsers to send JSON reports when violations occur by adding either <code>report-to</code> (modern) or <code>report-uri</code> (legacy) directives.</p><pre><code>Content-Security-Policy: default-src 'self'; report-to csp-endpoint;</code></pre><p>Combine this with a server or endpoint that records CSP violation reports for debugging (e.g., <code>/csp-report</code> endpoint, Report URI, or self-hosted collector).</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Ship a <code>Report-Only</code> CSP with a minimal allowlist; fix violations; then enforce a tighter CSP (remove broad wildcards, replace inline JS with nonces/hashes).</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (missing CSP):</strong></p><ol><li>Add a CSP at your web server or CDN (<code>default-src 'self'</code> baseline, explicit <code>script-src</code>/<code>style-src</code>).</li><li>Eliminate <code>unsafe-inline</code> where possible; iterate using <code>Report-Only</code> first.</li></ol></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>Manual fix option: add a basic Content-Security-Policy</h3><div class=\"ss-how-to\"><ol><li><strong>Start in Report-Only mode</strong><br>Add a header like this at the web server or CDN level:<pre><code>Content-Security-Policy-Report-Only: default-src 'self'</code></pre>Optionally add <code>report-to</code> or <code>report-uri</code> to collect violation reports.</li><li><strong>Exercise key pages</strong><br>Browse the front-end, admin, cart/checkout, and any web apps while monitoring the browser console and your CSP reports for blocked resources.</li><li><strong>Tighten the policy</strong><br>Add explicit <code>script-src</code>, <code>style-src</code>, <code>img-src</code>, etc. for the domains you actually use. Where possible, replace inline scripts with nonce or hash-based allowances.</li><li><strong>Switch to enforcing CSP</strong><br>Once you’re comfortable with the violations, change the header name to <code>Content-Security-Policy</code> (dropping <code>-Report-Only</code>), then retest critical flows.</li></ol><p class=\"ss-how-to-note\"><strong>Important:</strong> CSP is powerful and easy to misconfigure. Always test in staging or during a low-risk window, and keep a way to quickly roll back header changes if something critical breaks.</p></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": "<p><strong>Cache:</strong> CSP headers are often set at the CDN or proxy layer. After changing CSP, purge any page and edge caches or you may keep seeing violations from an old policy. If origin and CDN send different headers, Scope will only reflect the layer it is actually hitting.</p>",
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "security",
        "metric_id": "headers.csp"
      }
    },
    "headers.hsts": {
      "metric_key": "security.headers.hsts",
      "title": "Strict-Transport-Security (HSTS)",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p><strong>HSTS</strong> tells browsers to always use HTTPS for your domain, preventing SSL-stripping/downgrade attacks after first visit.</p><h3>Example</h3><pre><code>Strict-Transport-Security: max-age=31536000; includeSubDomains; preload</code></pre><h3>Notes</h3><ul><li>Enable only when the entire site (and subdomains, if using <code>includeSubDomains</code>) is HTTPS-only.</li><li>Use a long <code>max-age</code> (≥ 1 year) once stable.</li><li><code>preload</code> + submission adds your domain to browser preload lists.</li></ul></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Confirm site-wide HTTPS, then start with a smaller <code>max-age</code> (e.g., 10800) and ramp to 31536000; add <code>includeSubDomains</code> when ready.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (no HSTS on HTTPS site):</strong></p><ol><li>Add <code>Strict-Transport-Security: max-age=31536000; includeSubDomains; preload</code>.</li><li>Once stable, submit for HSTS preload.</li></ol></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>Manual fix option: enable HSTS safely</h3><div class=\"ss-how-to\"><ol><li><strong>Verify 100% HTTPS coverage</strong><br>Confirm <em>every</em> hostname you plan to protect (including subdomains if you will use <code>includeSubDomains</code>) serves valid HTTPS and no mixed-content errors.</li><li><strong>Add a short HSTS header first</strong><br>Start with a conservative <code>max-age</code>, for example:<pre><code>Strict-Transport-Security: max-age=10800</code></pre>so you can easily back out if needed.</li><li><strong>Ramp up max-age</strong><br>Once confident, increase to <code>max-age=31536000</code> (1 year) and add <code>includeSubDomains</code> when all subdomains are HTTPS-only.</li><li><strong>Optional: preload</strong><br>After running a strict policy for a while, you can add <code>preload</code> and submit the domain to the HSTS preload list.</li></ol><p class=\"ss-how-to-note\"><strong>Warning:</strong> Long HSTS + <code>preload</code> is effectively irreversible in the short term. Do not enable it until you are certain you’ll never need to serve HTTP on that domain again.</p></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": "<p><strong>Cache:</strong> HSTS is cached by browsers for its entire <code>max-age</code>, independent of your HTML/page cache. Once you ship a strict HSTS header and it is cached, users will keep enforcing it even if you roll back at the server. Treat changes carefully and don’t rely on cache clears to undo HSTS quickly.</p>",
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "security",
        "metric_id": "headers.hsts"
      }
    },
    "headers.xfo": {
      "metric_key": "security.headers.xfo",
      "title": "X-Frame-Options",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p><strong>X-Frame-Options</strong> controls whether your pages can be framed by other sites, mitigating clickjacking.</p><h4>Example</h4><pre><code>X-Frame-Options: SAMEORIGIN</code></pre><h4>Notes</h4><ul><li>Use <code>DENY</code> to forbid all framing, or <code>SAMEORIGIN</code> to allow your own origin.</li><li><code>ALLOW-FROM</code> is deprecated—prefer CSP <code>frame-ancestors</code> for multi-origin control.</li></ul></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Set <code>X-Frame-Options: SAMEORIGIN</code> (or CSP <code>frame-ancestors 'self'</code>) except where embedding is explicitly required.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (missing):</strong> Add <code>X-Frame-Options: SAMEORIGIN</code> globally (or define a CSP <code>frame-ancestors</code> policy).</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>Manual fix option: set X-Frame-Options</h3><div class=\"ss-how-to\"><ol><li><strong>Decide on framing policy</strong><br>If you never need your pages inside iframes, use <code>DENY</code>. If you only frame your own pages, use <code>SAMEORIGIN</code>.</li><li><strong>Configure at server or CDN</strong><br>Add a response header:<pre><code>X-Frame-Options: SAMEORIGIN</code></pre>(or <code>DENY</code>) via your web server config or CDN rules.</li><li><strong>Check for legitimate embeds</strong><br>If you provide widgets others embed on their sites, consider moving framing rules into CSP <code>frame-ancestors</code> instead, where you can specify multiple allowed origins.</li><li><strong>Retest UIs using iframes</strong><br>Verify any admin previews, page builders, or payment forms that rely on iframes still function as expected.</li></ol><p class=\"ss-how-to-note\"><strong>Note:</strong> Browser support has evolved toward CSP <code>frame-ancestors</code>; for new setups, prefer CSP plus a conservative fallback X-Frame-Options header.</p></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": "<p><strong>Cache:</strong> If different cache layers or backends send different <code>X-Frame-Options</code>, users may see inconsistent framing behavior. Make sure the policy is set in a single place (origin or CDN) and then purge caches so all responses agree.</p>",
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "security",
        "metric_id": "headers.xfo"
      }
    },
    "headers.xcto": {
      "metric_key": "security.headers.xcto",
      "title": "X-Content-Type-Options",
      "summary": {
        "html": "<div class=\"ss-body\"><p><strong>X-Content-Type-Options</strong> prevents MIME sniffing so browsers don’t treat files as a different type than declared, reducing certain injection risks.</p><h3>Example</h3><pre><code>X-Content-Type-Options: nosniff</code></pre><h3>Notes</h3><ul><li><code>nosniff</code> is the only valid/recommended value.</li><li>Ensure correct <code>Content-Type</code> headers for HTML/CSS/JS.</li></ul></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Add <code>X-Content-Type-Options: nosniff</code> at server/CDN level.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (missing):</strong> Enforce <code>nosniff</code> globally; verify presence on HTML/CSS/JS responses.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>Manual fix option: add X-Content-Type-Options</h3><div class=\"ss-how-to\"><ol><li><strong>Set the header globally</strong><br>At the web server or CDN layer, add:<pre><code>X-Content-Type-Options: nosniff</code></pre>for HTML, CSS, JS, and other text assets.</li><li><strong>Verify correct MIME types</strong><br>Use browser dev tools (Network tab) to ensure assets are sent with appropriate <code>Content-Type</code> values (e.g., <code>text/html</code>, <code>text/css</code>, <code>application/javascript</code>).</li><li><strong>Retest key flows</strong><br>Browse the site normally and check for console warnings or blocked resources related to MIME types.</li></ol><p class=\"ss-how-to-note\"><strong>Note:</strong> This header is low-risk; most modern stacks already expect and recommend <code>nosniff</code>.</p></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": "<p><strong>Cache:</strong> Some CDNs or optimization plugins can strip or rewrite security headers, including <code>X-Content-Type-Options</code>. If Scope shows this header missing but you added it at the origin, check edge/cache rules and purge caches to ensure the header isn’t being dropped.</p>",
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "security",
        "metric_id": "headers.xcto"
      }
    },
    "headers.referrer_policy": {
      "metric_key": "security.headers.referrer_policy",
      "title": "Referrer-Policy",
      "summary": {
        "html": "<div class=\"ss-body\"><p><strong>Referrer-Policy</strong> controls how much of the referring URL is shared when users navigate away from your pages or load subresources. It protects user privacy and reduces accidental data leakage through query strings.</p><h3>Example</h3><pre><code>Referrer-Policy: strict-origin-when-cross-origin</code></pre><h3>Notes</h3><ul><li><code>strict-origin-when-cross-origin</code> is a balanced default (secure and analytics-friendly).</li><li><code>no-referrer</code> provides maximal privacy but may impact analytics and referral tracking.</li><li><code>unsafe-url</code> (legacy default) is insecure—avoid it.</li></ul></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Set <code>Referrer-Policy: strict-origin-when-cross-origin</code> (or stricter) on HTML responses.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (missing/weak policy):</strong> Add a restrictive <code>Referrer-Policy</code> to prevent leaking sensitive URLs; validate that analytics still receive necessary referrer info.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>Manual fix option: set a safe Referrer-Policy</h3><div class=\"ss-how-to\"><ol><li><strong>Pick a default policy</strong><br>For most production sites, <code>Referrer-Policy: strict-origin-when-cross-origin</code> balances privacy and analytics.</li><li><strong>Add the header</strong><br>Configure the header at the server or CDN level so that HTML responses include the desired <code>Referrer-Policy</code> value.</li><li><strong>Test analytics and referral data</strong><br>After deployment, confirm that your analytics platform still shows meaningful referrers while sensitive query strings are not leaked cross-origin.</li></ol><p class=\"ss-how-to-note\"><strong>Note:</strong> You can go stricter (like <code>no-referrer</code>) if privacy is more important than seeing referrer details in analytics.</p></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": "<p><strong>Cache:</strong> Referrer-Policy is usually set at the edge. If analytics or referrer behavior doesn’t match what Scope reports, verify which layer (origin vs CDN) is actually sending the header and clear/page-rules caches after changing it.</p>",
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "security",
        "metric_id": "headers.referrer_policy"
      }
    },
    "permissions": {
      "metric_key": "security.permissions",
      "title": "Filesystem Permissions",
      "summary": {
        "html": "<h3>Description</h3><p>Effective UNIX permissions on sensitive files and directories (e.g., <code>wp-config.php</code>, <code>wp-content/uploads</code>).</p><p><strong>Why it matters:</strong> Overly permissive modes let other system users or processes read/alter configuration or upload shells. Follow least privilege.</p>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": null
        },
        "bad": {
          "body_html": null
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": null,
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "security",
        "metric_id": "permissions"
      }
    },
    "permissions.wp_config_mode": {
      "metric_key": "security.permissions.wp_config_mode",
      "title": "wp-config.php Permissions",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Permission mask for <code>wp-config.php</code> (e.g., <code>0640</code>).</p><p><strong>Why it matters:</strong> Contains DB credentials and keys. Ensure it’s not world-readable. Common safe values: <code>0640</code> or <code>0600</code> depending on PHP handler.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Tighten to <code>0640</code> or <code>0600</code> (owner read; group read where required). Ensure ownership matches PHP user.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (too permissive):</strong> Immediately set <code>chmod 600 wp-config.php</code> (or <code>640</code> if group-read is needed) and verify correct ownership.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<div class=\"ss-how-to\"><h3>Manual fix option: tighten <code>wp-config.php</code> permissions</h3><ol><li><strong>Identify the PHP user</strong><br>On managed hosting this is usually documented. On SSH shells you can often infer it from the owner of existing WordPress files.</li><li><strong>Adjust file mode safely</strong><br>From the web root (where <code>wp-config.php</code> lives), run:<pre><code>chmod 640 wp-config.php</code></pre>or, on single-tenant hosts:<pre><code>chmod 600 wp-config.php</code></pre></li><li><strong>Verify ownership</strong><br>Ensure the file is owned by the user and group that PHP runs as so WordPress can still read it.</li><li><strong>Re-run the report</strong><br>Confirm that permissions are no longer flagged as too permissive.</li></ol><p class=\"ss-how-to-note\"><strong>Warning:</strong> Do not change ownership to <code>root</code> or a user that PHP cannot read; that can break the site. When in doubt, ask your host to apply a secure mode for you.</p></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "security",
        "metric_id": "permissions.wp_config_mode"
      }
    },
    "permissions.uploads_mode": {
      "metric_key": "security.permissions.uploads_mode",
      "title": "Uploads Directory Permissions",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Permission mask for <code>wp-content/uploads</code>.</p><p><strong>Why it matters:</strong> Too permissive can allow execution of malicious uploads or unintended reads. Typical safe pattern: directories <code>0755</code>, files <code>0644</code>, with server rules to block PHP execution.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Normalize to dir <code>0755</code>, files <code>0644</code>; block PHP execution in <code>uploads</code> via <code>.htaccess</code> or Nginx <code>location</code> rules.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (insecure):</strong> Lock down file modes immediately; add <code>php_flag engine off</code> (Apache) or Nginx rules to prevent code execution in <code>uploads</code>.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>Manual fix option: normalize uploads permissions</h3><div class=\"ss-how-to\"><ol><li><strong>Standardize directory and file modes</strong><br>From the WordPress root (or via your hosting file manager), apply:<pre><code>find wp-content/uploads -type d -exec chmod 755 {} \\; find wp-content/uploads -type f -exec chmod 644 {} \\;</code></pre>This matches common shared-hosting defaults.</li><li><strong>Block PHP execution in uploads</strong><br>On Apache, add an <code>.htaccess</code> inside <code>wp-content/uploads</code>:<pre><code>&lt;FilesMatch \"\\.php$\"&gt; Deny from all&lt;/FilesMatch&gt;</code></pre>On Nginx, use a <code>location</code> rule that denies executing PHP scripts under <code>/wp-content/uploads</code>.</li><li><strong>Retest media flows</strong><br>Upload a new image from <strong>Media → Add New</strong> and ensure it renders normally on the front-end.</li></ol><p class=\"ss-how-to-note\"><strong>Note:</strong> Some managed hosts already enforce these rules; if your changes are being auto-reverted, check host documentation for their recommended approach.</p></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "security",
        "metric_id": "permissions.uploads_mode"
      }
    },
    "updates": {
      "metric_key": "security.updates",
      "title": "Update Posture",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>A summary of pending updates for WordPress core, plugins, and themes.</p><p><strong>Why it matters:</strong> Many compromises exploit known, patched vulnerabilities. Establish a cadence (e.g., weekly) and use staging for smoke tests.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Schedule a maintenance window to apply pending updates in staging, verify key flows, then promote to production.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (overdue/critical):</strong> Update immediately starting with core and high-risk plugins. Back up first; test; then deploy to production.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>Manual fix option: create a safe update routine</h3><div class=\"ss-how-to\"><ol><li><strong>Establish a backup habit</strong><br>Before any large batch of updates, ensure you have a recent file and database backup (from a backup plugin or host snapshot).</li><li><strong>Use staging when available</strong><br>If your host provides a staging environment, clone production, apply updates there first, and smoke-test key flows (login, checkout, forms).</li><li><strong>Update core, then plugins, then themes</strong><br>In <strong>Dashboard → Updates</strong>, update WordPress core, then critical plugins (security, e-commerce), then the rest, followed by themes.</li><li><strong>Schedule a recurring window</strong><br>Pick a low-traffic weekly or bi-weekly window to repeat this process so the “pending updates” count stays small.</li></ol><p class=\"ss-how-to-note\"><strong>Note:</strong> For high-traffic or revenue-critical sites, treat updates like mini-deployments: changelog review, staging tests, timed rollout, and ability to roll back.</p></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "security",
        "metric_id": "updates"
      }
    },
    "updates.core": {
      "metric_key": "security.updates.core",
      "title": "Core Updates",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Available updates to WordPress core.</p><p><strong>Why it matters:</strong> Core releases often include security patches and compatibility improvements. Keep core current, especially on LTS branches.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Update to the latest minor release; review plugin/theme compatibility notes.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (outdated core):</strong> Backup, update core immediately, and re-run a security scan once live.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>Manual fix option: update WordPress core</h3><div class=\"ss-how-to\"><ol><li><strong>Back up first</strong><br>Ensure you have a current database and file backup (via plugin or hosting snapshot).</li><li><strong>Update via Dashboard</strong><br>Go to <strong>Dashboard → Updates</strong> and click <em>Update Now</em> under WordPress core. Wait for the process to complete without closing the browser tab.</li><li><strong>Verify the site</strong><br>Check front-end, login, and a few admin screens for fatal errors or layout issues. Clear caches if something looks stale.</li><li><strong>Fallback plan</strong><br>If the update breaks the site and you can’t quickly fix it, restore from the backup you took at step 1 and investigate in staging.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "security",
        "metric_id": "updates.core"
      }
    },
    "updates.plugins": {
      "metric_key": "security.updates.plugins",
      "title": "Plugin Updates",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Available updates to installed plugins.</p><p><strong>Why it matters:</strong> Third-party plugins are a leading source of vulnerabilities. Audit riskier plugins and keep them patched.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Update all non-breaking plugins; stage-test feature-critical ones.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (security risk):</strong> Immediately update plugins with known vulnerabilities; consider temporary deactivation if patches aren’t available.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>Manual fix option: update plugins safely</h3><div class=\"ss-how-to\"><ol><li><strong>Prioritize security-sensitive plugins</strong><br>Update items that handle auth, payments, forms, and admin access first, especially if their changelog mentions security fixes.</li><li><strong>Use bulk update with care</strong><br>In <strong>Plugins → Installed Plugins</strong>, select a small batch, choose “Update” from the bulk actions menu, and apply. Avoid updating dozens at once on mission-critical sites.</li><li><strong>Test critical flows</strong><br>After each batch, test checkout, forms, login, and any custom flows that generate revenue or important data.</li><li><strong>Remove unused plugins</strong><br>Deactivate and delete plugins you no longer need; they still represent risk even if inactive.</li></ol><p class=\"ss-how-to-note\"><strong>Note:</strong> Auto-updates are convenient but can break sites silently. Use them selectively and keep staging in the loop for larger stacks.</p></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "security",
        "metric_id": "updates.plugins"
      }
    },
    "updates.themes": {
      "metric_key": "security.updates.themes",
      "title": "Theme Updates",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Available updates to installed themes.</p><p><strong>Why it matters:</strong> Themes can ship PHP and JS with vulnerabilities. Update and remove unused themes.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Update child/parent themes; remove unused themes to reduce surface.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (security/compat):</strong> Update active theme now; if blocked by customizations, port changes to a child theme and update base.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>Manual fix option: update and clean up themes</h3><div class=\"ss-how-to\"><ol><li><strong>Ensure a child theme for customizations</strong><br>If you’ve modified theme files directly, create a child theme and move customizations there before updating the parent.</li><li><strong>Update active parent/child</strong><br>In <strong>Appearance → Themes</strong> or <strong>Dashboard → Updates</strong>, apply updates to the active theme pair.</li><li><strong>Remove unused themes</strong><br>Delete old or unused themes (apart from one default theme you keep for debugging) to reduce surface area.</li><li><strong>Check templates</strong><br>Visit a few template variations (blog index, single post, page, any custom templates) to confirm layout and functionality remain intact.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "security",
        "metric_id": "updates.themes"
      }
    }
  },
  "plugins": {
    "summary": {
      "metric_key": "plugins.summary",
      "title": "Plugin Inventory",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>A breakdown of total, active, inactive, and must-use (MU) plugins.</p><p><strong>Why it matters:</strong> Each plugin adds code paths and supply-chain risk. Fewer, well-maintained plugins mean lower attack surface and better performance.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Trim unused plugins; consolidate overlapping functionality; keep only supported, frequently updated plugins.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (risky footprint):</strong> Deactivate/remove unused and unmaintained plugins immediately; replace with supported alternatives.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to audit your plugin inventory</h3><div class=\"ss-how-to\"><ol><li>In WordPress, go to <strong>Plugins → Installed Plugins</strong>.</li><li>Make a quick list: must-have, nice-to-have, and unused plugins.</li><li>Deactivate one unused plugin at a time and verify the site still behaves as expected.</li><li>Once confident, delete unused plugins (files and data) to reduce attack surface.</li><li>Document which plugins are business-critical so you can spot surprises when this inventory changes.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "plugins",
        "metric_id": "summary"
      }
    },
    "list": {
      "metric_key": "plugins.list",
      "title": "Installed Plugins",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>The list of installed plugins with version, author, status, and update availability.</p><p><strong>Why it matters:</strong> Helps you spot outdated or risky plugins. Prefer reputable vendors with frequent updates and clear changelogs.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Prioritize updates for security-sensitive plugins (forms, e-commerce, auth). Review changelogs before deploying.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (high-risk set):</strong> Remove abandoned plugins; patch critical ones first; enable a staging test cycle for the rest.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to use the installed plugins list</h3><div class=\"ss-how-to\"><ol><li>Open <strong>Plugins → Installed Plugins</strong> in the WordPress admin.</li><li>Sort or visually scan for plugins that show available updates (usually highlighted or marked).</li><li>For each critical plugin (e.g., forms, e-commerce, auth), read the changelog before updating.</li><li>Apply updates in a staging site first when possible; then repeat on production.</li><li>Remove any plugins you do not recognize or that your team no longer relies on, after verifying impact.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "plugins",
        "metric_id": "list"
      }
    },
    "mu_plugins": {
      "metric_key": "plugins.mu_plugins",
      "title": "Must-Use (MU) Plugins",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Plugins auto-loaded from <code>wp-content/mu-plugins</code>.</p><p><strong>Why it matters:</strong> They always run and can’t be deactivated from the standard UI. Use for site-critical bootstrap code, not routine features.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Review MU plugins; ensure they’re minimal, documented, and version controlled.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (misuse):</strong> Move non-essential MU plugins to standard plugins; keep MU for critical bootstrap only.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to review MU plugins</h3><div class=\"ss-how-to\"><ol><li>In the admin, go to <strong>Plugins → Must-Use</strong> (if your host exposes that tab).</li><li>Using SSH/SFTP, inspect the <code>wp-content/mu-plugins/</code> directory to see exactly which files are loaded.</li><li>Confirm each MU plugin is tracked in version control or deployment scripts; avoid ad-hoc edits in production.</li><li>Move non-critical functionality out of MU into regular plugins so they can be deactivated/updated more safely.</li><li>Document which MU plugins are required for the site to boot correctly (caching drop-ins, security bootstraps, etc.).</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "plugins",
        "metric_id": "mu_plugins"
      }
    },
    "abandoned": {
      "metric_key": "plugins.abandoned",
      "title": "Potentially Abandoned",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Heuristic indicating plugins that haven’t seen updates in a long time (e.g., > 12 months).</p><p><strong>Why it matters:</strong> Unmaintained code accumulates vulnerabilities. Vet or replace with maintained alternatives.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Evaluate vendor activity and community reports; plan replacement if maintenance is uncertain.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (unmaintained):</strong> Replace immediately with a supported plugin; validate data migration paths.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to handle potentially abandoned plugins</h3><div class=\"ss-how-to\"><ol><li>From <strong>Plugins → Installed Plugins</strong>, click each flagged plugin’s <strong>View details</strong> link.</li><li>Check the <em>Last updated</em> date and <em>Tested up to</em> version in the plugin details or WordPress.org page.</li><li>Search the plugin slug plus <strong>“vulnerability”</strong> or check a security database if this plugin is widely used.</li><li>If the vendor appears inactive, research alternatives that provide similar functionality and are actively maintained.</li><li>Plan and test a replacement: migrate settings/data in a staging site, then switch in production during a maintenance window.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "plugins",
        "metric_id": "abandoned"
      }
    },
    "duplicates.cache_plugins": {
      "metric_key": "plugins.duplicates.cache_plugins",
      "title": "Multiple Caching Plugins",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Detection of more than one caching/optimization plugin.</p><p><strong>Why it matters:</strong> Overlapping features cause conflicts, stale caches, and performance regressions. Consolidate to a single cache layer.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Choose one primary page/object cache; disable others; clear all caches.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (conflicts likely):</strong> Immediately deactivate redundant cache plugins; keep a single, well-supported solution.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to resolve multiple caching plugins</h3><div class=\"ss-how-to\"><ol><li>List all active caching/optimization plugins (page cache, object cache, full-page CDN integrations).</li><li>Decide which layer is primary (for example, host-level cache or a single WordPress caching plugin).</li><li>Deactivate extra caching plugins one at a time and clear all caches after each change.</li><li>Verify page behavior, logins, and admin performance before moving to the next deactivation.</li><li>Once stable, keep one primary cache and configure purge/invalidation rules around deploys and content edits.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": "<p><strong>Cache:</strong> Multiple page/object/cache plugins plus a CDN can hide which layer is serving a response. When chasing odd behavior in other tiles (headers, HTTPS, SEO), temporarily disable extra cache plugins, clear all caches, and test through a single, known cache layer.</p>",
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "plugins",
        "metric_id": "duplicates.cache_plugins"
      }
    },
    "licenses_missing": {
      "metric_key": "plugins.licenses_missing",
      "title": "License/Key Gaps",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Plugins that require licenses/keys but none detected.</p><p><strong>Why it matters:</strong> Missing licenses can block updates and security patches. Ensure production has valid keys.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Add/update license keys on production to restore updates.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (blocked updates):</strong> Enter valid licenses now to receive security patches; remove the plugin if a license cannot be procured.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to fix license/key gaps</h3><div class=\"ss-how-to\"><ol><li>From <strong>Plugins</strong>, open each plugin that requires a license or API key; look for a dedicated settings page or a <strong>License</strong> tab.</li><li>Log into the vendor account or marketplace (e.g., WooCommerce.com, Envato, vendor portal) and locate your license keys.</li><li>Enter the key into the plugin’s settings on the <em>production</em> site, not just on staging.</li><li>Trigger a manual update check (<strong>Dashboard → Updates</strong>) to confirm that updates are now available.</li><li>Keep a secure internal record of license locations and renewal dates so this doesn’t silently regress.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "plugins",
        "metric_id": "licenses_missing"
      }
    }
  },
  "server": {
    "database": {
      "metric_key": "server.database",
      "title": "Database",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Database vendor and version (MySQL or MariaDB).</p><p><strong>Why it matters:</strong> Newer engines offer performance, stability, and features (e.g., improved InnoDB). Some WP plugins require minimum versions.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Plan an upgrade to a currently supported LTS release; verify backups and staging compatibility (charset/collation) before migration.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (outdated/unsupported):</strong> Migrate to a supported version ASAP; take full backups, test restores, and schedule a maintenance window.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to check and upgrade the database server</h3><div class=\"ss-how-to\"><ol><li>In your hosting control panel or via <code>mysql --version</code>, confirm the current MySQL/MariaDB version.</li><li>Compare it against the host’s documented supported versions and WordPress recommendations.</li><li>If you are below a supported LTS version, open a ticket or schedule an upgrade in your hosting dashboard.</li><li>Before upgrading, take a full database backup (via phpMyAdmin, WP-CLI <code>wp db export</code>, or your backup tool).</li><li>After the upgrade, re-run key site flows and re-check the Scope report for any new warnings.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "server",
        "metric_id": "database"
      }
    },
    "opcache": {
      "metric_key": "server.opcache",
      "title": "OPcache",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>PHP bytecode cache (and optional JIT) that keeps compiled scripts in memory.</p><p><strong>Why it matters:</strong> Dramatically reduces CPU and improves response times under load.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Enable OPcache with sensible defaults; ensure adequate memory (<code>opcache.memory_consumption</code>) and set <code>revalidate_freq</code> for your deploy process.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (disabled/misconfigured):</strong> Turn on OPcache; size memory (e.g., 128–256MB for typical sites), and confirm it survives restarts.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to enable and tune OPcache</h3><div class=\"ss-how-to\"><ol><li>Locate your PHP configuration (<code>php.ini</code>, <code>.user.ini</code>, or hosting UI).</li><li>Ensure <code>opcache.enable=1</code> and <code>opcache.enable_cli=1</code> (if you use CLI tools) are set.</li><li>Set <code>opcache.memory_consumption</code> to a reasonable size (e.g., 128–256M for typical WordPress sites).</li><li>Configure <code>opcache.max_accelerated_files</code> high enough for your codebase (e.g., 10000+).</li><li>Restart PHP / your web server, then confirm OPcache is active via <code>phpinfo()</code> or your host’s tools.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": "<p><strong>Cache:</strong> OPcache is separate from page/CDN caches. If you change PHP code or configuration and don’t see it reflected, you may need to flush OPcache <em>and</em> clear any full-page caches so Scope (and users) see the updated behavior.</p>",
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "server",
        "metric_id": "opcache"
      }
    },
    "object_cache": {
      "metric_key": "server.object_cache",
      "title": "Object Cache",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Persistent cache layer (Redis/Memcached) for WordPress objects and queries.</p><p><strong>Why it matters:</strong> Reduces database load and speeds up dynamic pages and admin.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Enable a persistent object cache (Redis or Memcached) and verify connection health and eviction policy.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (none/unstable):</strong> Install and configure Redis/Memcached; monitor hit ratio and memory pressure; fix timeouts.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to configure a persistent object cache</h3><div class=\"ss-how-to\"><ol><li>Decide on a backend (Redis or Memcached), usually based on host support.</li><li>Enable the service in your hosting panel or provision it yourself (managed Redis, container, or VM).</li><li>Install a reputable object cache plugin (e.g., Redis Object Cache, Memcached-based plugin) and follow its connection instructions.</li><li>Verify connection status and watch for errors in debug logs.</li><li>Measure admin and frontend performance before and after enabling object cache to confirm benefit.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": "<p><strong>Cache:</strong> A persistent object cache can keep options and transients around after you change settings. If a tile still reports old values, clear the object cache (Redis/Memcached) and re-run the report, especially after big config or plugin changes.</p>",
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "server",
        "metric_id": "object_cache"
      }
    },
    "php_version": {
      "metric_key": "server.php_version",
      "title": "PHP Version",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>The PHP runtime version executing WordPress.</p><p><strong>Why it matters:</strong> Supported versions get security fixes and run faster. Upgrading often yields major performance gains.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Plan upgrade to a currently supported PHP (e.g., 8.1+). Test in staging for deprecated features before rollout.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (EOL PHP):</strong> Upgrade PHP immediately via hosting panel or ops; fix deprecated API usage in staging, then go live.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to safely upgrade PHP</h3><div class=\"ss-how-to\"><ol><li>Check the current PHP version via Scope, <code>phpinfo()</code>, or your hosting panel.</li><li>In a staging environment, switch to the target PHP version (for example, 8.1+), then run through key flows (checkout, forms, logins, editor).</li><li>Fix any deprecation notices or fatals by updating plugins/themes or contacting vendors.</li><li>Once staging is clean, change PHP version for the production site from the hosting panel.</li><li>Monitor error logs and the Scope report for 24–48 hours for any new issues.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "server",
        "metric_id": "php_version"
      }
    },
    "mysql_version": {
      "metric_key": "server.mysql_version",
      "title": "MySQL/MariaDB Version",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>The database server version (MySQL or MariaDB).</p><p><strong>Why it matters:</strong> Newer engines bring better performance and features (e.g., improved InnoDB). Ensure compatibility with your host.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Schedule DB engine upgrade to a supported LTS; verify charset/collation and backups beforehand.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (outdated DB):</strong> Migrate to a supported version; run backups and test restore, then perform in a maintenance window.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to plan a DB engine upgrade</h3><div class=\"ss-how-to\"><ol><li>Confirm the exact database engine and version (MySQL vs MariaDB) via your host or <code>SELECT VERSION();</code>.</li><li>Check your host’s documentation for recommended upgrade paths and whether in-place or migration upgrades are used.</li><li>Take full backups (database export and, ideally, a snapshot) before any change.</li><li>Schedule the upgrade during a low-traffic window, and coordinate with your host if they handle the change.</li><li>Afterward, verify connection credentials, charset/collation, and run through critical site workflows.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "server",
        "metric_id": "mysql_version"
      }
    },
    "server_software": {
      "metric_key": "server.server_software",
      "title": "Web Server",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>The HTTP server stack (Apache, Nginx, LiteSpeed, etc.).</p><p><strong>Why it matters:</strong> Determines available modules, rewrite rules, and tuning knobs. Align caching/compression with the stack.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Ensure TLS/HTTP/2 or 3 is enabled; align rewrite and caching modules with your chosen stack; remove unused modules.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (misconfig/legacy):</strong> Update server packages; standardize a modern stack (e.g., Nginx/LiteSpeed with HTTP/2/3) and reapply hardened configs.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to align with your web server stack</h3><div class=\"ss-how-to\"><ol><li>Identify the stack via Scope (Apache, Nginx, LiteSpeed, etc.) or your hosting panel.</li><li>Review how redirects, compression, and caching are configured at the server or CDN level.</li><li>Ensure there is a single, clear source of truth for redirects (either application or server, not both competing).</li><li>Confirm HTTP/2 or HTTP/3 is enabled if supported by your host.</li><li>Document where configuration actually lives (vhosts, .htaccess, Nginx includes, or host UI) so changes are reproducible.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": "<p><strong>Cache:</strong> Stack detection can be skewed by a CDN masking the true origin (for example, seeing “cloudflare” instead of Apache/Nginx). If results look off, hit the origin host directly or bypass the CDN, then re-run the report to get an accurate view of the underlying server and cache stack.</p>",
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "server",
        "metric_id": "server_software"
      }
    },
    "memory_limit": {
      "metric_key": "server.memory_limit",
      "title": "PHP Memory Limit",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Max memory the PHP process can consume.</p><p><strong>Why it matters:</strong> Too low can cause fatals under load; too high masks memory leaks. Typical WordPress sites run comfortably at 256–512MB.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Raise to at least <code>256M</code> in <code>php.ini</code>/<code>.user.ini</code> or host UI; profile heavy plugins.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (too low/fatals likely):</strong> Increase to <code>256M–512M</code> immediately; audit error logs for OOM and optimize offending plugins.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to adjust PHP memory limit</h3><div class=\"ss-how-to\"><ol><li>Check the current <code>memory_limit</code> via Scope or <code>phpinfo()</code>.</li><li>If your host allows it, raise <code>memory_limit</code> in <code>php.ini</code>, <code>.user.ini</code>, or the hosting UI (e.g., 256M–512M).</li><li>On managed hosts, you may need to open a ticket to request a higher limit.</li><li>After changing, reload PHP and confirm the new limit via Scope or a phpinfo page.</li><li>If you still see out-of-memory errors, profile heavy plugins or processes instead of raising the limit indefinitely.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "server",
        "metric_id": "memory_limit"
      }
    },
    "upload_max": {
      "metric_key": "server.upload_max",
      "title": "Upload Max Filesize",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Max allowed size for a single uploaded file (<code>upload_max_filesize</code>).</p><p><strong>Why it matters:</strong> Impacts media/library workflows. Keep aligned with CDN and post limits.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Align <code>upload_max_filesize</code> with editorial needs (e.g., 64–128MB for media-heavy sites) and ensure <code>post_max_size</code> ≥ this value.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (too low):</strong> Raise both <code>upload_max_filesize</code> and <code>post_max_size</code> to meet workflow; verify server/client timeouts.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to increase upload_max_filesize</h3><div class=\"ss-how-to\"><ol><li>Locate the php configuration controls (php.ini, .user.ini, or hosting UI).</li><li>Set <code>upload_max_filesize</code> to a value that fits your editorial workload (for example, 64M or 128M).</li><li>Ensure <code>post_max_size</code> is at least as large as <code>upload_max_filesize</code>.</li><li>Restart PHP / web server if required.</li><li>Test by uploading a file slightly under the new limit in <strong>Media → Add New</strong>.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "server",
        "metric_id": "upload_max"
      }
    },
    "post_max": {
      "metric_key": "server.post_max",
      "title": "Post Max Size",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Max size of POST request payload (<code>post_max_size</code>).</p><p><strong>Why it matters:</strong> Must be ≥ upload limit to allow larger uploads/forms. Coordinate with server-level limits.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Set <code>post_max_size</code> ≥ <code>upload_max_filesize</code> (e.g., 128MB) and ensure reverse proxy/client limits match.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (blocking uploads):</strong> Increase <code>post_max_size</code> and web server/proxy <code>client_max_body_size</code> (Nginx)/<code>LimitRequestBody</code> (Apache).</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to adjust post_max_size</h3><div class=\"ss-how-to\"><ol><li>Open your php settings (php.ini, .user.ini, or host UI).</li><li>Set <code>post_max_size</code> to be equal to or larger than <code>upload_max_filesize</code>.</li><li>Check your reverse proxy or web server for body size limits (<code>client_max_body_size</code> on Nginx, <code>LimitRequestBody</code> on Apache).</li><li>Restart services if needed and test large uploads or form submissions.</li><li>If issues persist, check error logs for the exact component rejecting the request.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "server",
        "metric_id": "post_max"
      }
    },
    "max_execution_time": {
      "metric_key": "server.max_execution_time",
      "title": "Max Execution Time",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Max seconds a PHP script may run.</p><p><strong>Why it matters:</strong> Long imports/updates may need higher thresholds; excessively high values risk resource lockups.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> For import-heavy workflows, raise to ~<code>120</code>s and optimize slow queries; otherwise keep conservative (30–60s).</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (too low/timeout errors):</strong> Temporarily raise to <code>120–300</code>s for batch tasks; fix root-cause slowness and revert to a safer default.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to change max_execution_time</h3><div class=\"ss-how-to\"><ol><li>Locate the PHP configuration and search for <code>max_execution_time</code>.</li><li>Increase it to a reasonable value for your workload (e.g., 60–120 seconds for import-heavy admin tasks).</li><li>For long-running CLI processes, prefer running via WP-CLI or background workers rather than huge single web requests.</li><li>Restart PHP / web server and confirm the new value via Scope or <code>phpinfo()</code>.</li><li>Monitor logs to ensure long-running tasks complete without timeouts and without locking up resources.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "server",
        "metric_id": "max_execution_time"
      }
    },
    "max_input_vars": {
      "metric_key": "server.max_input_vars",
      "title": "Max Input Vars",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Max number of input variables PHP will accept in a single request.</p><p><strong>Why it matters:</strong> Large menus or settings forms can exceed defaults; raise carefully if needed.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Increase to <code>3000–5000</code> if menu/settings save fails; prefer structural simplification over large single forms.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (saves failing):</strong> Raise <code>max_input_vars</code> (e.g., 5000+), split forms, and remove unused menu items.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to raise max_input_vars</h3><div class=\"ss-how-to\"><ol><li>If menu saves or very large forms are failing, open your php configuration and find <code>max_input_vars</code>.</li><li>Raise it incrementally (e.g., 3000–5000) rather than jumping to extremely high values.</li><li>Apply the change and reload PHP.</li><li>Retry the failing operation (saving menus/settings).</li><li>If you still have issues, consider restructuring forms or splitting settings across multiple pages.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "server",
        "metric_id": "max_input_vars"
      }
    },
    "disk_free": {
      "metric_key": "server.disk_free",
      "title": "Disk Space (Free)",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Approximate free disk on the filesystem that hosts your WordPress path (via PHP <code>disk_free_space()</code>).</p><p><strong>Why it matters:</strong> Low space breaks uploads, updates, and backups.</p><p><strong>Note on shared/virtual hosting:</strong> This value reflects the <em>filesystem’s</em> free space, not your account quota. On shared or containerized hosts, your panel (cPanel/Plesk) quota can be much smaller.</p><p><strong>How to verify:</strong> Check your hosting panel’s disk/quota metrics and inode usage. If the panel shows lower free space, trust the panel.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Free space by clearing caches/backups and pruning logs. Verify your <em>account quota</em> in the hosting panel; if nearing quota, purchase more storage or offload media to object storage.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (critical):</strong> Immediately free space (rotate logs, purge caches, offload media), then expand storage or reduce quota usage. Verify inode usage if errors persist.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to free disk space safely</h3><div class=\"ss-how-to\"><ol><li>Check both filesystem free space and your hosting account’s quota/inode usage in the hosting control panel.</li><li>Delete old backups, large logs, and cache directories (plugin caches, staging artifacts) after confirming they are safe to remove.</li><li>Offload large media (video, archives) to a CDN or object storage when possible.</li><li>Review backup configuration to avoid storing many generations on the same disk.</li><li>If you are consistently nearing capacity, coordinate with your host to increase the volume size or plan a migration.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "server",
        "metric_id": "disk_free"
      }
    },
    "disk_total": {
      "metric_key": "server.disk_total",
      "title": "Disk Space (Total)",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Total capacity of the volume hosting uploads/content.</p><p><strong>Why it matters:</strong> Helps capacity planning for media-heavy sites.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Plan capacity upgrades and/or offload media to a CDN/object storage.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (undersized):</strong> Increase volume size or offload media immediately to maintain operations.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to plan for disk capacity</h3><div class=\"ss-how-to\"><ol><li>Use your host’s analytics or monitoring to understand how quickly disk usage is growing.</li><li>Identify large tables, media libraries, and backup files that drive most of the usage.</li><li>Move non-essential assets (archives, old exports, temp files) off the main web volume.</li><li>Increase storage capacity through your hosting plan if growth is steady and legitimate.</li><li>Implement regular cleanup routines so you are not relying solely on manual intervention.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "server",
        "metric_id": "disk_total"
      }
    },
    "autoload_size_kb": {
      "metric_key": "server.autoload_size_kb",
      "title": "Autoloaded Options Size",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Total size of options loaded on every request (<code>autoload = yes</code>).</p><p><strong>Why it matters:</strong> Large autoload bloat slows every page. Audit and de-autoload non-critical entries.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Identify large autoloaded options; de-autoload non-critical plugin settings; consider persistent object cache.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (bloat):</strong> Remove orphaned/unused autoload rows, refactor offending plugins, and enable object caching.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to reduce autoload bloat</h3><div class=\"ss-how-to\"><ol><li>Use a DB tool (phpMyAdmin, Adminer, or WP-CLI) to inspect <code>wp_options</code> rows where <code>autoload='yes'</code> and size is large.</li><li>Identify options created by plugins that do not need to load on every request (logs, caches, large settings blobs).</li><li>For each candidate, either adjust plugin settings or manually set <code>autoload='no'</code> after confirming it is safe.</li><li>Remove orphaned options from deactivated plugins.</li><li>Re-run the Scope report to confirm autoload size has decreased.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": "Inferred Signal",
      "meta": {
        "section": "server",
        "metric_id": "autoload_size_kb"
      }
    },
    "error_log_tail": {
      "metric_key": "server.error_log_tail",
      "title": "Error Log (Recent)",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Count of recent PHP errors in the server's error log.</p><p><strong>Why it matters:</strong> A rising error rate signals bugs, deprecations, or resource issues. Fix at source; don’t suppress.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Triage recurring warnings/notices; fix deprecations; keep <code>WP_DEBUG_LOG</code> enabled (display off) in production.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (frequent errors):</strong> Investigate stack traces, roll back the last change if needed, and hotfix critical errors before proceeding.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to triage recent PHP errors</h3><div class=\"ss-how-to\"><ol><li>Locate your PHP or web server error log (often available in the hosting panel or via SSH).</li><li>Filter for the most recent entries matching the time window Scope reports.</li><li>Group errors by root cause (plugin, theme, custom code) and frequency.</li><li>Fix issues starting with fatals and high-frequency warnings, ideally in staging first.</li><li>After deploying fixes, clear the log (or note a marker) and confirm that error rates drop over the next day or two.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "server",
        "metric_id": "error_log_tail"
      }
    },
    "cron": {
      "metric_key": "server.cron",
      "title": "WP-Cron Health",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>WordPress's pseudo-cron job status: overdue counts and time to next event.</p><p><strong>Why it matters:</strong> Overdue tasks indicate traffic/loopback problems. Consider real cron + <code>DISABLE_WP_CRON</code> for busy sites.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Ensure <code>wp-cron.php</code> can run (no auth blocks); reduce overdue jobs; consider real cron for reliability.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (stalled):</strong> Switch to system cron that hits <code>wp-cron.php</code>, fix loopback failures, and clear stuck jobs.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to stabilize WP-Cron</h3><div class=\"ss-how-to\"><ol><li>From the dashboard, install a cron inspector plugin or use WP-CLI (<code>wp cron event list</code>) to see overdue tasks.</li><li>If <code>DISABLE_WP_CRON</code> is true, ensure a real system cron is calling <code>wp-cron.php</code> on a schedule (e.g., every 5–10 mins).</li><li>Fix loopback issues (auth blocks, firewalls) that prevent WordPress from calling itself.</li><li>Clear obviously stuck jobs and re-schedule them if needed.</li><li>Monitor scheduled tasks for a few days to ensure new events run on time.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "server",
        "metric_id": "cron"
      }
    },
    "timezone": {
      "metric_key": "server.timezone",
      "title": "Time zone alignment",
      "summary": {
        "html": "<p>WordPress uses its own configured time zone for scheduling posts, cron jobs, and how dates are shown in the admin. The underlying PHP/server time zone can be different.</p><p>When these disagree, you may see confusing timestamps (\"off by a few hours\"), missed or late cron events, and reports that don&#39;t line up with reality.</p><p>Ideally, WordPress should be set to a named city time zone (for example, <code>America/Chicago</code>) under <strong>Settings → General</strong>, and your server&#39;s PHP <code>date.timezone</code> should match. If this card is flagged, ask your host or devops to align the PHP time zone with WordPress, or adjust the WordPress setting if the server time zone is your source of truth.</p>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": null
        },
        "bad": {
          "body_html": null
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": null,
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "server",
        "metric_id": "timezone"
      }
    },
    "image_toolkit": {
      "metric_key": "server.image_toolkit",
      "title": "Image Toolkit",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>WordPress uses server-side libraries (Imagick and/or GD) to resize and process images. If neither is available, thumbnail generation and media edits can fail. WebP/AVIF support reduces file size and improves page performance.</p><ul><li><strong>Imagick</strong> is generally more feature-complete and offloads heavy work to ImageMagick.</li><li><strong>GD</strong> is widely available and sufficient for most cases.</li><li><strong>WebP/AVIF</strong> support enables smaller, faster images, especially on mobile.</li></ul><p><strong>Note:</strong> AVIF/HEIC support depends on how ImageMagick/GD was compiled on your host.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": null
        },
        "bad": {
          "body_html": null
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to improve image processing support</h3><div class=\"ss-how-to\"><ol><li>Ask your host which image libraries are installed (Imagick, GD) and which formats they support (WebP, AVIF).</li><li>If Imagick is missing and your workload is image-heavy, request it be enabled or upgrade to a plan that includes it.</li><li>Enable WebP (and AVIF if available) in your image optimization or CDN tool.</li><li>Test uploading and regenerating thumbnails to ensure there are no processing errors.</li><li>Consider moving large image optimization tasks to a background worker or external service if performance is an issue.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "server",
        "metric_id": "image_toolkit"
      }
    }
  },
  "performance": {
    "cache_detected": {
      "metric_key": "performance.cache_detected",
      "title": "Page Cache",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Whether a known caching layer/plugin is active.</p><p><strong>Why it matters:</strong> Static caching drastically reduces TTFB and CPU usage. Use exactly one page caching layer to avoid conflicts.</p><p><strong>Tip:</strong> If your CDN does full-page caching, configure the plugin to handle purges rather than double-caching.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Enable a single, reputable page cache (e.g., server cache, LiteSpeed, or a plugin) and purge on deploys.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (no caching):</strong> Install and configure page caching immediately; verify headers and cache hit ratios.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to enable effective page caching</h3><div class=\"ss-how-to\"><ol><li>Decide whether caching is handled at the host/CDN level or via a WordPress plugin.</li><li>If you choose a plugin, install one reputable page cache and follow its setup wizard.</li><li>Configure cache purge rules for content edits, deploys, and plugin/theme updates.</li><li>Use browser dev tools or response headers to confirm cache hits (look for cache-related headers from your CDN or plugin).</li><li>Avoid stacking multiple page caches; rely on one main layer and a separate object cache if needed.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": "<p><strong>Cache:</strong> This check only tells you that some cache layer is likely present, not whether it is correctly purging. If you see stale or contradictory results in other tiles, treat this as a hint to review page cache, CDN rules, and invalidation hooks.</p>",
      "links": [],
      "titleBadge": "Inferred Signal",
      "meta": {
        "section": "performance",
        "metric_id": "cache_detected"
      }
    },
    "compression": {
      "metric_key": "performance.compression",
      "title": "HTTP Compression",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Gzip/Brotli compression of responses.</p><p><strong>Why it matters:</strong> Shrinks payloads and speeds transfer. Brotli generally compresses better (for HTTPS). Ensure it’s enabled for text assets.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Enable gzip/Brotli for HTML/CSS/JS; confirm via response headers (<code>content-encoding</code>).</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (disabled):</strong> Turn on compression in web server/CDN; verify effective compression for all text assets.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to enable HTTP compression</h3><div class=\"ss-how-to\"><ol><li>Check if <code>content-encoding: gzip</code> or <code>br</code> appears in your response headers via browser dev tools.</li><li>If not, enable Gzip/Brotli in your hosting control panel or in your web server config (Apache, Nginx, or LiteSpeed directives).</li><li>Ensure compression is applied at least to HTML, CSS, JS, JSON, and XML responses.</li><li>Validate again with dev tools or an external performance test to confirm compression is active.</li><li>Watch CPU usage; in most modern setups compression is cheap, but very limited hardware can be impacted.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": "<p><strong>Cache:</strong> Compression can be handled by either the origin or CDN. If Scope shows compression disabled but GTmetrix/WebPageTest disagree, you may be looking at different cache layers. Confirm where gzip/Brotli is actually enabled and purge caches after toggling it.</p>",
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "performance",
        "metric_id": "compression"
      }
    },
    "db_hygiene": {
      "metric_key": "performance.db_hygiene",
      "title": "Database Hygiene",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Signals around transients, revisions, and autoload size.</p><p><strong>Why it matters:</strong> Excess transients and revisions bloat tables and slow queries. Clean up regularly; use persistent object caching where appropriate.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Prune expired transients, cap revisions, and move non-critical options off autoload.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (heavy bloat):</strong> Purge transients with SQL, enable object cache (Redis/Memcached), and refactor plugins creating excessive options.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to improve database hygiene</h3><div class=\"ss-how-to\"><ol><li>Use a DB tool or WP-CLI to inspect tables for transients, revisions, and very large options rows.</li><li>Clear expired transients with a safe cleanup tool or <code>wp transient delete-expired</code>.</li><li>Limit post revisions via <code>WP_POST_REVISIONS</code> and prune old revisions.</li><li>Address autoload bloat by de-autoloading non-critical options and cleaning up orphaned rows.</li><li>Re-run Scope and observe whether DB- and autoload-related metrics have improved.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "performance",
        "metric_id": "db_hygiene"
      }
    },
    "db_size": {
      "metric_key": "performance.db_size",
      "title": "Database Size",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Total size of your database (data + indexes).</p><p><strong>Why it matters:</strong> Larger DBs need indexing, query tuning, and proper backups. Monitor growth by table.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Add indexes to slow tables, archive old data, and ensure nightly backups.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (very large/slow):</strong> Optimize and partition heavy tables; add read replicas if needed; ensure reliable offsite backups.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to manage database size</h3><div class=\"ss-how-to\"><ol><li>From phpMyAdmin or WP-CLI, inspect table sizes (data + index).</li><li>Identify unusually large tables (logs, sessions, analytics, custom plugin tables).</li><li>Archive or purge old data where safe (for example, ancient logs, expired sessions, transient-like tables).</li><li>Run <code>OPTIMIZE TABLE</code> or host-provided optimization tools on bloated tables.</li><li>Implement a recurring cleanup schedule so growth stays predictable.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "performance",
        "metric_id": "db_size"
      }
    },
    "transient_count": {
      "metric_key": "performance.transient_count",
      "title": "Transients",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Count of cached key/value pairs stored in <code>wp_options</code>.</p><p><strong>Why it matters:</strong> Excess transients indicate plugin misuse or failing external APIs. Prune expired and consider a proper object cache.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Clear expired transients; fix plugins that rewrite transients too frequently; add object cache.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (excessive):</strong> Bulk-delete orphaned transients; audit offending plugins and migrate to persistent object cache.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to reduce transient bloat</h3><div class=\"ss-how-to\"><ol><li>Inspect the count and largest transient-related tables via phpMyAdmin or WP-CLI.</li><li>Use a plugin or <code>wp transient delete --all</code> (with care) to clear expired and orphaned transients.</li><li>Identify plugins that generate large numbers of transients (API connectors, page builders, heavy dashboards).</li><li>Adjust plugin settings to reduce overly aggressive caching in <code>wp_options</code>.</li><li>Consider moving to persistent object caching so transients live outside of <code>wp_options</code>.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": "Inferred Signal",
      "meta": {
        "section": "performance",
        "metric_id": "transient_count"
      }
    },
    "transient_bloat": {
      "metric_key": "performance.transient_bloat",
      "title": "Transient Bloat Level",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>A simple indicator (low/medium/high) derived from transient counts.</p><p><strong>Why it matters:</strong> High bloat hurts admin performance and option autoload times.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Reduce plugins creating transients; prune regularly with a scheduled task.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (high):</strong> Immediate cleanup of transients via SQL/CLI; re-architect caching behavior in plugins.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to handle high transient bloat</h3><div class=\"ss-how-to\"><ol><li>If this metric is flagged as high, treat it as a prompt to review both transient counts and autoload size.</li><li>Use a DB viewer or dedicated cleanup plugin to list and prune transients responsible for most of the weight.</li><li>Work with developers or vendors of the top offenders to reduce write frequency or move to a better caching strategy.</li><li>Implement background jobs to periodically clear expired transients.</li><li>Re-check performance metrics after cleanup to confirm improvement.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "performance",
        "metric_id": "transient_bloat"
      }
    },
    "revision_count": {
      "metric_key": "performance.revision_count",
      "title": "Post Revisions",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Total count of stored revisions.</p><p><strong>Why it matters:</strong> Excess revisions consume space. Set sane limits via <code>WP_POST_REVISIONS</code> and prune old revisions.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Set <code>WP_POST_REVISIONS</code> to a reasonable cap (e.g., 10) and prune older revisions.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (bloat):</strong> Run a revision cleanup tool; cap going forward; verify DB size reductions.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to tame post revisions</h3><div class=\"ss-how-to\"><ol><li>Estimate how many revisions you truly need per post/page (e.g., 10–20 for editorial workflows).</li><li>Add or adjust <code>WP_POST_REVISIONS</code> in <code>wp-config.php</code> to a sane limit.</li><li>Use a reputable cleanup plugin or custom SQL to prune older revisions beyond that limit.</li><li>Test editing and rollback workflows to ensure you still have enough history.</li><li>Repeat cleanup periodically or make it part of routine maintenance.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "performance",
        "metric_id": "revision_count"
      }
    },
    "heartbeat.throttled": {
      "metric_key": "performance.heartbeat.throttled",
      "title": "Heartbeat Throttling",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Whether the WP Heartbeat API is disabled or throttled.</p><p><strong>Why it matters:</strong> Heartbeat keeps admin features in sync but can generate high PHP load on busy dashboards. Throttle instead of disabling if you rely on autosave.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Throttle Heartbeat (e.g., 60s+) on admin screens; keep enabled for autosave if editors rely on it.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (disabled with issues):</strong> Re-enable but throttled; ensure autosave and locks work; monitor server load.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to tune Heartbeat</h3><div class=\"ss-how-to\"><ol><li>Confirm whether a Heartbeat control plugin or custom code is already altering intervals.</li><li>If Heartbeat is causing load issues, throttle it (for example, to 60+ seconds) instead of fully disabling it.</li><li>Keep a reasonable interval on post edit screens to preserve autosave and locking behavior.</li><li>Test multi-author editing and locking after changes to ensure you haven’t broken collaboration flows.</li><li>Monitor server load during busy editorial windows to verify that tuning helped.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "performance",
        "metric_id": "heartbeat.throttled"
      }
    },
    "loopback_ttfb": {
      "metric_key": "performance.loopback_ttfb",
      "title": "Loopback TTFB",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Time-to-first-byte for a local HTTP request to the site (server-to-itself).</p><p><strong>Why it matters:</strong> A quick proxy for backend responsiveness—slow values hint at PHP/DB work, external calls, or blocking.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Profile the slow path (plugins, queries, remote APIs); enable OPcache and a persistent object cache; verify no network DNS/proxy delays.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (consistently high):</strong> Capture callgrind/XHProf traces, optimize heavy queries, and reduce remote blocking calls; consider scaling resources.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to debug slow loopback TTFB</h3><div class=\"ss-how-to\"><ol><li>Use WP-CLI or a curl request from the server to hit the site homepage and measure response time.</li><li>If responses are consistently slow, enable a profiler (XHProf, Blackfire, or similar) in staging to see which plugins or queries dominate.</li><li>Check for slow external API calls that may be blocking page generation.</li><li>Enable OPcache and a persistent object cache if not already in place.</li><li>Iterate on the heaviest offenders and re-measure loopback response times.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": "<p><strong>Cache:</strong> Loopback checks usually bypass the public page cache, so TTFB here can be slower than what real visitors see behind a CDN or page cache. Use it to spot backend bottlenecks, not to judge fully cached front-end performance.</p>",
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "performance",
        "metric_id": "loopback_ttfb"
      }
    },
    "cache_plugins": {
      "metric_key": "performance.cache_plugins",
      "title": "Caching Plugins",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Detected caching plugins and whether they are active.</p><p><strong>Why it matters:</strong> Exactly one page-caching layer should be active. Multiple layers often conflict and can slow the site.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Consolidate to a single page cache (server, CDN, or plugin) and ensure proper purge/invalidation on deploys.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (conflicting/missing):</strong> Remove duplicate layers and enable one well-supported cache; verify cache headers and hit ratios.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to rationalize caching plugins</h3><div class=\"ss-how-to\"><ol><li>List all cache-related plugins detected by Scope and confirm which ones are truly necessary.</li><li>Determine whether your host or CDN already performs page caching at the edge.</li><li>Disable overlapping cache plugins, keeping only the one that best integrates with your host/CDN.</li><li>After each change, clear caches and verify logins, personalized content, and admin pages behave correctly.</li><li>Document your chosen caching strategy so future changes don’t accidentally reintroduce conflicts.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "performance",
        "metric_id": "cache_plugins"
      }
    }
  },
  "seo": {
    "indexing_allowed": {
      "metric_key": "seo.indexing_allowed",
      "title": "Search Engine Visibility",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Whether WordPress is set to discourage search engines (<code>blog_public</code>).</p><p><strong>Why it matters:</strong> Accidentally blocking indexing on production tanks discoverability. Ensure indexing is allowed unless intentionally private.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> If the site is public, uncheck <em>Discourage search engines</em> in <em>Settings → Reading</em>.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (blocked indexing):</strong> Disable the discourage setting; remove any <code>noindex</code> directives; resubmit sitemaps in Search Console.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to fix search engine visibility</h3><div class=\"ss-how-to\"><ol><li>In WordPress, go to <strong>Settings → Reading</strong>.</li><li>Locate <strong>Search engine visibility</strong> and ensure <em>Discourage search engines from indexing this site</em> is unchecked for public sites.</li><li>Check for <code>noindex</code> meta tags in your SEO plugin settings for key pages.</li><li>Update and resubmit your sitemap in Search Console or your preferred search tools.</li><li>Monitor indexing status over time to confirm recovery.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": "<p><strong>Cache:</strong> Robots rules and meta tags can be cached aggressively. After changing <code>noindex</code>/<code>index</code> settings or <code>robots.txt</code>, purge caches (and any CDN) before relying on this tile, and remember that search engines may also cache older directives.</p>",
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "seo",
        "metric_id": "indexing_allowed"
      }
    },
    "robots_txt_present": {
      "metric_key": "seo.robots_txt_present",
      "title": "robots.txt",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>A file that suggests crawl rules to search bots.</p><p><strong>Why it matters:</strong> Can guide or inadvertently block crawling. Keep it minimal; don’t rely on it for sensitive content.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Ensure <code>robots.txt</code> isn’t blocking key paths; reference sitemap URL.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (overblocking/missing):</strong> Add a minimal <code>robots.txt</code> and remove broad <code>Disallow</code> lines that block content.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to manage robots.txt</h3><div class=\"ss-how-to\"><ol><li>Check <code>/robots.txt</code> in a browser to see the current contents.</li><li>For simple setups, use your SEO plugin or host to edit robots.txt rather than maintaining it manually on disk.</li><li>Avoid broad <code>Disallow: /</code> directives on production unless the site is intentionally private.</li><li>Add a <code>Sitemap:</code> line pointing to your primary sitemap URL.</li><li>After changes, re-fetch robots.txt in Search Console if needed.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": "<p><strong>Cache:</strong> Some hosts/CDNs serve a generated <code>/robots.txt</code> that can be cached separately from WordPress. If you’ve edited robots rules and Scope still shows the old version, bypass the CDN or clear caches and fetch robots.txt directly from the origin.</p>",
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "seo",
        "metric_id": "robots_txt_present"
      }
    },
    "sitemap_present": {
      "metric_key": "seo.sitemap_present",
      "title": "Sitemap",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>An XML index of site URLs for search engines.</p><p><strong>Why it matters:</strong> A well-formed sitemap accelerates discovery of new content. Ensure it’s reachable and up to date.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Enable and expose a sitemap (core or SEO plugin); link to it in <code>robots.txt</code>.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (missing/broken):</strong> Fix sitemap generation; ensure HTTP 200 and correct URLs; submit in Search Console.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to ensure a healthy sitemap</h3><div class=\"ss-how-to\"><ol><li>Enable XML sitemaps either from WordPress core or your SEO plugin (Yoast, Rank Math, etc.).</li><li>Verify the sitemap URL returns HTTP 200 and lists the expected content types (posts, pages, key taxonomies).</li><li>Link to the sitemap from <code>robots.txt</code>.</li><li>Submit the sitemap URL in Search Console and monitor for errors.</li><li>Check that new content appears in the sitemap soon after publishing.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": "<p><strong>Cache:</strong> XML sitemaps may be cached by SEO plugins, page caches, and CDNs. After enabling or changing sitemaps, clear plugin/page/CDN caches and then re-run the report to confirm the new sitemap is what search engines will see.</p>",
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "seo",
        "metric_id": "sitemap_present"
      }
    },
    "home_title_present": {
      "metric_key": "seo.home_title_present",
      "title": "Homepage Title",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Presence of a document <code>&lt;title&gt;</code> on the homepage.</p><p><strong>Why it matters:</strong> Essential for SEO and SERP snippets. Ensure unique, descriptive titles.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Define a unique, concise homepage <code>&lt;title&gt;</code> via theme/SEO plugin.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (missing):</strong> Implement a <code>&lt;title&gt;</code> tag immediately; verify it renders server-side.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to set your homepage &lt;title&gt;</h3><div class=\"ss-how-to\"><ol><li>Open your SEO plugin’s settings for the homepage (or the page set as <em>Front page</em> under <strong>Settings → Reading</strong>).</li><li>Define a concise, descriptive title that includes your brand and primary topic.</li><li>Aim for a reasonable length (rough guideline: 50–60 characters) to prevent truncation in SERPs.</li><li>Save changes and view the page source to confirm the title tag is output.</li><li>Use Search Console’s URL inspection tool to request a re-crawl if you just fixed a missing title.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": "Inferred Signal",
      "meta": {
        "section": "seo",
        "metric_id": "home_title_present"
      }
    },
    "home_description_present": {
      "metric_key": "seo.home_description_present",
      "title": "Meta Description",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Presence of a meta description on the homepage.</p><p><strong>Why it matters:</strong> Improves click-through from SERPs. Keep to ~150–160 chars and unique per page.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Add a concise, compelling description via SEO plugin; avoid duplication.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (missing):</strong> Your homepage doesn't define a <code>&lt;meta name=\"description\"&gt;</code>. Without one, search engines may pull arbitrary text from the page instead. Add a description via your SEO plugin now.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to set your homepage meta description</h3><div class=\"ss-how-to\"><ol><li>In your SEO plugin, edit the homepage’s meta description field.</li><li>Write a human-friendly summary of what your site offers, targeted at searchers deciding whether to click.</li><li>Keep it roughly 150–160 characters and avoid keyword stuffing.</li><li>Save changes and confirm a <code>&lt;meta name=\"description\" ...&gt;</code> tag appears in page source.</li><li>Monitor CTR in Search Console to see whether the new description is effective.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": "Inferred Signal",
      "meta": {
        "section": "seo",
        "metric_id": "home_description_present"
      }
    },
    "canonical_consistent": {
      "metric_key": "seo.canonical_consistent",
      "title": "Canonical URLs",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Whether <code>home_url</code> and <code>site_url</code> align (scheme/host).</p><p><strong>Why it matters:</strong> Mismatches cause duplicate content, session issues, and confusing redirects. Standardize to a single canonical host.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Align <code>home_url</code> and <code>site_url</code> to a single canonical host (www vs non-www) and scheme.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (mismatch):</strong> Fix URLs in <em>Settings → General</em>, update redirects, and clear caches to prevent duplication and login issues.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to fix canonical consistency</h3><div class=\"ss-how-to\"><ol><li>Decide on a single canonical base domain (with or without <code>www</code>) and HTTPS everywhere.</li><li>Set <strong>WordPress Address</strong> and <strong>Site Address</strong> in <strong>Settings → General</strong> to that canonical URL.</li><li>Configure 301 redirects from any alternate hosts (non-www to www, HTTP to HTTPS) at the server or CDN level.</li><li>Ensure your SEO plugin outputs canonical tags that match the chosen base.</li><li>Clear caches and verify that all entry points redirect to the canonical host/scheme.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": "Inferred Signal",
      "meta": {
        "section": "seo",
        "metric_id": "canonical_consistent"
      }
    },
    "permalink_structure": {
      "metric_key": "seo.permalink_structure",
      "title": "Permalink Structure",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>The URL pattern used for posts (e.g., <code>/%postname%/</code>).</p><p><strong>Why it matters:</strong> Human-readable permalinks improve UX and SEO. Avoid query-string-only structures in production.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Switch to a readable structure like <code>/%postname%/</code> in <em>Settings → Permalinks</em>.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (default query IDs):</strong> Change to a human-readable structure and flush rewrites; update internal links if needed.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to change permalink structure safely</h3><div class=\"ss-how-to\"><ol><li>In <strong>Settings → Permalinks</strong>, choose a human-readable structure like <code>/%postname%/</code>.</li><li>Before changing on a long-lived site, map important old URLs to new ones with redirects to preserve SEO.</li><li>After saving, WordPress will flush rewrite rules automatically (you can also do this via <code>flush_rewrite_rules()</code> or WP-CLI).</li><li>Test a sample of older URLs and confirm redirects behave as expected.</li><li>Update any hard-coded internal URLs in templates or content if necessary.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "seo",
        "metric_id": "permalink_structure"
      }
    },
    "homepage_type": {
      "metric_key": "seo.homepage_type",
      "title": "Homepage Type",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Whether the homepage shows a static page or latest posts.</p><p><strong>Why it matters:</strong> Affects site architecture and internal linking. Choose based on content strategy.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Ensure the chosen homepage type aligns with SEO strategy and internal linking.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action:</strong> Reconfigure home display to match business goals; adjust menus and redirects accordingly.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to choose homepage behavior</h3><div class=\"ss-how-to\"><ol><li>Go to <strong>Settings → Reading</strong>.</li><li>Choose between <em>Your latest posts</em> or <em>A static page</em> depending on your content strategy.</li><li>If using a static page, set both the <em>Homepage</em> and <em>Posts page</em> (blog index) appropriately.</li><li>Check menus and internal links to ensure they still point to the right home and blog URLs.</li><li>Review your homepage structure to ensure it highlights important content for both users and search engines.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "seo",
        "metric_id": "homepage_type"
      }
    }
  },
  "config": {
    "debug_enabled": {
      "metric_key": "config.debug_enabled",
      "title": "Debug Mode",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Whether <code>WP_DEBUG</code> is enabled.</p><p><strong>Why it matters:</strong> Don’t expose debug output on production. Use <code>WP_DEBUG_LOG</code> to log privately when needed.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Turn off <code>WP_DEBUG_DISPLAY</code> in production; keep <code>WP_DEBUG_LOG</code> on if investigating issues.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (debug visible):</strong> Disable debug display immediately; move to file logging; remove error output from public pages.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to configure debug mode safely</h3><div class=\"ss-how-to\"><ol><li>Open <code>wp-config.php</code> in a safe editor.</li><li>On production, ensure <code>WP_DEBUG</code> is <code>true</code> only if you route errors to logs, not the browser.</li><li>Set <code>WP_DEBUG_DISPLAY</code> to <code>false</code> and <code>WP_DEBUG_LOG</code> to <code>true</code> to log privately.</li><li>Confirm <code>display_errors</code> is disabled at the PHP level for production.</li><li>Monitor logs periodically and rotate/clean them so they don’t grow indefinitely.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "config",
        "metric_id": "debug_enabled"
      }
    },
    "cron_disabled": {
      "metric_key": "config.cron_disabled",
      "title": "WP-Cron Disabled",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p><code>DISABLE_WP_CRON</code> toggles WordPress’s internal cron triggers.</p><p><strong>Why it matters:</strong> On high-traffic sites, disable WP-Cron and run a real system cron hitting <code>wp-cron.php</code> for reliability.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> If disabled, ensure a system cron calls <code>wp-cron.php</code> regularly; otherwise enable WP-Cron.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (jobs failing):</strong> Re-enable WP-Cron or set up a reliable system cron; verify scheduled tasks run.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to manage WP-Cron vs system cron</h3><div class=\"ss-how-to\"><ol><li>Check <code>wp-config.php</code> for <code>DISABLE_WP_CRON</code>.</li><li>If it is <code>true</code>, configure a real system cron (via hosting panel or crontab) to call <code>wp-cron.php</code> every few minutes.</li><li>If you cannot set up system cron, consider leaving <code>DISABLE_WP_CRON</code> as <code>false</code> so normal traffic triggers events.</li><li>Use a cron inspector plugin or WP-CLI to verify events are running on schedule.</li><li>Adjust frequency if you see either too many overlapping cron runs or long gaps.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "config",
        "metric_id": "cron_disabled"
      }
    },
    "active_theme": {
      "metric_key": "config.active_theme",
      "title": "Active Theme",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>The theme currently rendering your site.</p><p><strong>Why it matters:</strong> Theme quality drives performance and security posture. Keep child/parent themes updated.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Update theme and dependencies; remove unused parent/child themes.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (outdated/vulnerable):</strong> Patch or switch themes; apply a child theme for customizations to enable safe updates.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to evaluate your active theme</h3><div class=\"ss-how-to\"><ol><li>In <strong>Appearance → Themes</strong>, confirm which theme is active and whether it is a child or parent theme.</li><li>Check for available updates for both the active theme and any parent theme.</li><li>Review your customizations: if modifications are made directly in the parent theme, migrate them into a child theme.</li><li>Test alternative themes on a staging site if performance or maintainability is a concern.</li><li>Document any theme-specific dependencies (page builder, custom blocks) before making large changes.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "config",
        "metric_id": "active_theme"
      }
    },
    "active_theme_version": {
      "metric_key": "config.active_theme_version",
      "title": "Theme Version",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Version of the active theme.</p><p><strong>Why it matters:</strong> Track against changelogs and security notices; update regularly.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Update to the latest compatible version and test templates.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (behind/known issues):</strong> Update urgently; if blocked by custom code, migrate overrides to a child theme.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to keep the theme version current</h3><div class=\"ss-how-to\"><ol><li>From <strong>Appearance → Themes</strong>, click on your active theme and review version and changelog.</li><li>Check the vendor’s site or marketplace for release notes, especially security fixes.</li><li>Apply theme updates in a staging environment if you rely on heavy customizations.</li><li>After updating, test templates, widgets, and key layouts for regressions.</li><li>Repeat on production once you are confident the update is safe.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "config",
        "metric_id": "active_theme_version"
      }
    },
    "debug.constants": {
      "metric_key": "config.debug.constants",
      "title": "Debug Constants",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Snapshot of <code>WP_DEBUG</code>, <code>WP_DEBUG_LOG</code>, <code>WP_DEBUG_DISPLAY</code>, <code>SCRIPT_DEBUG</code>, and <code>DISALLOW_FILE_EDIT</code>.</p><p><strong>Why it matters:</strong> Production should generally have display off, logging on (to file), and file edit disabled in the admin.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Set <code>DISALLOW_FILE_EDIT</code> true; keep display off; log to file for troubleshooting.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (unsafe):</strong> Disable in-admin file editing and public error display immediately; enable private logging.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to harden debug-related constants</h3><div class=\"ss-how-to\"><ol><li>Open <code>wp-config.php</code> and locate <code>WP_DEBUG</code>, <code>WP_DEBUG_LOG</code>, <code>WP_DEBUG_DISPLAY</code>, <code>SCRIPT_DEBUG</code>, and <code>DISALLOW_FILE_EDIT</code>.</li><li>Set <code>DISALLOW_FILE_EDIT</code> to <code>true</code> on production to block editor-based code edits.</li><li>Ensure public debug display is off (<code>WP_DEBUG_DISPLAY</code> false) while logging to a file for troubleshooting.</li><li>Use <code>SCRIPT_DEBUG</code> only temporarily when debugging asset issues.</li><li>Re-run the report to confirm constants now match your production policy.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "config",
        "metric_id": "debug.constants"
      }
    },
    "email_deliverability": {
      "metric_key": "config.email_deliverability",
      "title": "Email Deliverability",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Checks whether an SMTP/transactional email plugin is active and the last test email status.</p><p><strong>Why it matters:</strong> WordPress uses the server's <code>mail()</code> function by default, which often fails or lands in spam. Broken email impacts user registrations, password resets, orders, and alerts.</p><p><strong>Good to know:</strong> Popular SMTP options include WP Mail SMTP, FluentSMTP, and Post SMTP. They integrate with providers like SendGrid, Mailgun, Postmark, and Amazon SES.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Consider installing an SMTP plugin to improve email reliability. Send a test email to verify delivery is working.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action:</strong> Email test failed or no SMTP helper detected. Fix SMTP credentials or install a plugin to prevent email delivery issues.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to set up reliable email for WordPress</h3><div class=\"ss-how-to\"><ol><li><strong>Choose an SMTP plugin</strong><br>Popular free options: WP Mail SMTP, FluentSMTP, Post SMTP. All support major providers.</li><li><strong>Select a transactional email provider</strong><br>Options include SendGrid, Mailgun, Postmark, Amazon SES, or your host's SMTP. Free tiers often cover small sites.</li><li><strong>Configure credentials</strong><br>Enter API key or SMTP credentials in the plugin settings. Most plugins have a setup wizard.</li><li><strong>Set up DNS records</strong><br>Add SPF, DKIM, and optionally DMARC records to your domain. The plugin or provider usually provides these.</li><li><strong>Send a test email</strong><br>Use the button below or your SMTP plugin's test feature. Check spam folders and email headers if delivery fails.</li></ol><p class=\"ss-how-to-note\"><strong>Note:</strong> Email logging helps debug issues—enable it if your plugin offers it.</p></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "config",
        "metric_id": "email_deliverability"
      }
    },
    "backup": {
      "metric_key": "config.backup",
      "title": "Backups",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Detection of common backup plugins and last-run signals (if available).</p><p><strong>Why it matters:</strong> Offsite, frequent, tested backups are your safety net. Verify restores periodically.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> Ensure nightly offsite backups for files and DB; test a restore quarterly.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (no recent backups):</strong> Enable daily offsite backups now and perform a test restore.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to verify and improve backups</h3><div class=\"ss-how-to\"><ol><li>Identify which backup solution is currently in use (plugin, host-level, or external service).</li><li>Confirm backup frequency, retention period, and whether both files and database are covered.</li><li>Run a manual backup and ensure it completes without errors.</li><li>Perform a test restore in a staging environment to validate that backups are actually usable.</li><li>Document how to initiate restores and who is responsible during an incident.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "config",
        "metric_id": "backup"
      }
    },
    "maintenance_mode": {
      "metric_key": "config.maintenance_mode",
      "title": "Maintenance Mode",
      "summary": {
        "html": "<h3>Description</h3><div class=\"ss-body\"><p>Presence of <code>.maintenance</code> indicates WordPress maintenance mode.</p><p><strong>Why it matters:</strong> Should be temporary during updates. If it persists, an update likely failed—remove the flag to restore access.</p></div>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": "<div class=\"ss-body-warn\"><p><strong>Action:</strong> If unexpected, remove <code>.maintenance</code>; re-run the last update safely.</p></div>"
        },
        "bad": {
          "body_html": "<div class=\"ss-body-bad\"><p><strong>Action (site stuck):</strong> Delete <code>.maintenance</code>, clear caches, and complete the failed update manually.</p></div>"
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": "<h3>How to resolve stuck maintenance mode</h3><div class=\"ss-how-to\"><ol><li>If your site appears stuck in maintenance mode, check the root WordPress directory for a <code>.maintenance</code> file.</li><li>Delete the <code>.maintenance</code> file via FTP/SFTP or your file manager.</li><li>Clear any caches (plugin, server, CDN) that might be serving cached maintenance responses.</li><li>Re-run the previously failing update, ideally in a maintenance window.</li><li>Consider using a dedicated maintenance mode plugin for more controlled downtime messaging.</li></ol></div>",
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": "<p><strong>Cache:</strong> Maintenance pages can be bypassed by stale edge or page caches. If you toggle maintenance mode but some users still see normal pages (or vice versa), clear the cache at every layer and confirm that the maintenance response isn’t being cached unexpectedly.</p>",
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "config",
        "metric_id": "maintenance_mode"
      }
    }
  },
  "meta": {
    "generated_at": {
      "metric_key": "meta.generated_at",
      "title": "Generated At",
      "summary": {
        "html": "<h3>Description</h3><p>Timestamp (ISO 8601) for when this report was produced.</p><p><strong>Why it matters:</strong> Helps you judge data freshness during troubleshooting.</p>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": null
        },
        "bad": {
          "body_html": null
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": null,
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "meta",
        "metric_id": "generated_at"
      }
    },
    "schema_version": {
      "metric_key": "meta.schema_version",
      "title": "Schema Version",
      "summary": {
        "html": "<h3>Description</h3><p>Version of the report payload format.</p><p><strong>Why it matters:</strong> Useful for dashboards/clients that parse the report and need to handle changes gracefully.</p>",
        "evergreen": true
      },
      "states": {
        "default": {
          "body_html": null
        },
        "warn": {
          "body_html": null
        },
        "bad": {
          "body_html": null
        }
      },
      "how_to": {
        "evergreen_html": null,
        "state_overrides": {
          "default": null,
          "warn": null,
          "bad": null
        }
      },
      "cache_note_html": null,
      "links": [],
      "titleBadge": null,
      "meta": {
        "section": "meta",
        "metric_id": "schema_version"
      }
    }
  }
}