diff --git a/README.md b/README.md
index 5157207..6b5d115 100644
--- a/README.md
+++ b/README.md
@@ -27,9 +27,10 @@ This repo holds the source of the site at
## What the site holds
- A [playground](https://gatepost-dev.github.io/docs/playground/) where you check a postcode in your browser.
+- A page on the postcode format, with a regex, and a page that validates a postcode in TypeScript, PHP and an HTML form.
- Guides for the TypeScript core, the TypeScript client, the PHP package, the HTML field, the React field and the WooCommerce plugin.
- An API reference that the build writes from the TSDoc comments and the PHP doc comments.
-- The spec pages: the grammar, the client contract, the field and the glossary.
+- The spec pages: the grammar, the client contract, the field, the glossary and the state codes.
- A [readiness tracker](https://gatepost-dev.github.io/docs/readiness/) of common tools that reject the new postcode.
## Run it on your computer
diff --git a/astro.config.mjs b/astro.config.mjs
index 954e2e5..104c0f7 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -109,7 +109,7 @@ export default defineConfig({
reactTypeDoc(typeDocOf('react')),
],
sidebar: [
- { label: 'Start', items: ['start', 'playground'] },
+ { label: 'Start', items: ['start', 'postcode-format', 'validate-postcode', 'playground'] },
{ label: 'Guides', items: [{ autogenerate: { directory: 'guides' } }] },
{ label: 'Spec', items: [{ autogenerate: { directory: 'spec' } }] },
{
diff --git a/scripts/spec-pages.ts b/scripts/spec-pages.ts
index e7b7c28..698e54a 100644
--- a/scripts/spec-pages.ts
+++ b/scripts/spec-pages.ts
@@ -1,7 +1,8 @@
// SPDX-FileCopyrightText: 2026 The Gatepost authors
// SPDX-License-Identifier: Apache-2.0
// Writes the spec pages of the site from the spec submodule, so that the site shows the grammar,
-// the client contract, the field and the glossary that the SDKs implement, word for word.
+// the client contract, the field and the glossary that the SDKs implement, word for word. The page
+// of state codes comes from the data file that the SDKs read, so it cannot drift from them.
import { execFileSync } from 'node:child_process';
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
@@ -94,6 +95,59 @@ export function specPages(specDir: string, commit: string): readonly SpecPage[]
});
}
+interface StateData {
+ readonly source: string;
+ readonly states: readonly {
+ readonly code: string;
+ readonly name: string;
+ readonly iso: string;
+ }[];
+}
+
+/**
+ * Builds the page that lists the state codes, from `data/states.json` of a spec folder. People
+ * search for these codes, so the page has a title and a description of its own.
+ *
+ * @param specDir - The spec folder, such as the `spec` submodule.
+ * @param commit - The commit of the spec folder, for the link to the data file.
+ * @returns The page, with its front matter.
+ */
+export function stateCodesPage(specDir: string, commit: string): SpecPage {
+ const version = readFileSync(join(specDir, 'VERSION'), 'utf8').trim();
+ const file = 'data/states.json';
+ const { source, states } = JSON.parse(readFileSync(join(specDir, file), 'utf8')) as StateData;
+ const url = `https://github.com/gatepost-dev/spec/blob/${commit}/${file}`;
+ const description =
+ `The ${String(states.length)} two-letter state codes that start a Nigerian postcode, ` +
+ 'with the name and the ISO 3166-2:NG code of each state.';
+ const lines = [
+ '---',
+ 'title: Nigerian state codes for postcodes',
+ `description: "${description}"`,
+ 'editUrl: false',
+ `sidebar: { label: State codes, order: ${String(SOURCES.length + 1)} }`,
+ '---',
+ '',
+ `:::note\nThis page shows [\`${file}\`](${url}) from spec ${version}.\n:::`,
+ '',
+ 'The first segment of a postcode is the state. It is a code of two letters.',
+ 'The table lists the code of each state and of the Federal Capital Territory.',
+ '`parse` gives `unknown_state` for any other two letters.',
+ '',
+ '## Codes and names',
+ '',
+ '| Code | State | ISO 3166-2 |',
+ '|---|---|---|',
+ ...states.map(({ code, name, iso }) => `| \`${code}\` | ${name} | \`${iso}\` |`),
+ '',
+ '## Source',
+ '',
+ source,
+ '',
+ ];
+ return { slug: 'state-codes', text: wrapTables(lines.join('\n')) };
+}
+
/**
* Writes the spec pages into the docs collection. The build calls it before it reads the pages.
*
@@ -104,7 +158,8 @@ export function writeSpecPages(root: string): void {
const commit = execFileSync('git', ['-C', specDir, 'rev-parse', 'HEAD'], { encoding: 'utf8' });
const folder = join(root, 'src/content/docs/spec');
mkdirSync(folder, { recursive: true });
- for (const { slug, text } of specPages(specDir, commit.trim())) {
+ const pages = [...specPages(specDir, commit.trim()), stateCodesPage(specDir, commit.trim())];
+ for (const { slug, text } of pages) {
writeFileSync(join(folder, `${slug}.md`), text);
}
}
diff --git a/src/content/docs/guides/html.md b/src/content/docs/guides/html.md
index d0e79b9..3f530fe 100644
--- a/src/content/docs/guides/html.md
+++ b/src/content/docs/guides/html.md
@@ -1,6 +1,6 @@
---
-title: Add a postcode field to a web form
-description: Use the gatepost-postcode-field element in any HTML form, with or without a framework.
+title: Add a Nigerian postcode field to an HTML form
+description: Add a Nigerian postcode field to any HTML form with the gatepost-postcode-field element. It checks the format while the user types.
sidebar:
label: HTML field
order: 4
diff --git a/src/content/docs/guides/php.md b/src/content/docs/guides/php.md
index a2b12b7..481a1cb 100644
--- a/src/content/docs/guides/php.md
+++ b/src/content/docs/guides/php.md
@@ -1,6 +1,6 @@
---
-title: Check and look up postcodes in PHP
-description: Read Nigeria's digital postcodes offline and query NIPOST's gateway with gatepost/postcode.
+title: Validate and look up Nigerian postcodes in PHP
+description: Validate Nigeria's digital postcodes offline, and call the NIPOST postcode API, in PHP with the gatepost/postcode Composer package.
sidebar:
label: PHP
order: 3
diff --git a/src/content/docs/guides/react.md b/src/content/docs/guides/react.md
index b259dde..69ff3d7 100644
--- a/src/content/docs/guides/react.md
+++ b/src/content/docs/guides/react.md
@@ -1,6 +1,6 @@
---
-title: Add a postcode field to a React form
-description: Use the PostcodeField component of @gatepost/react in React 18 or 19, and in Next.js.
+title: Add a Nigerian postcode field to a React form
+description: Add a Nigerian postcode field to a React 18 or 19 form, or to Next.js, with the PostcodeField component of @gatepost/react.
sidebar:
label: React
order: 5
diff --git a/src/content/docs/guides/typescript-client.md b/src/content/docs/guides/typescript-client.md
index bc36e15..25758aa 100644
--- a/src/content/docs/guides/typescript-client.md
+++ b/src/content/docs/guides/typescript-client.md
@@ -1,6 +1,6 @@
---
-title: Look up postcodes in TypeScript
-description: Ask NIPOST's gateway about a postcode, a place or a typed code with @gatepost/client.
+title: Use the NIPOST postcode API from TypeScript
+description: Look up a Nigerian postcode with NIPOST's API and @gatepost/client. Find the postcode of a place, and complete a postcode as the user types.
sidebar:
label: TypeScript client
order: 2
diff --git a/src/content/docs/guides/typescript.md b/src/content/docs/guides/typescript.md
index 180eae0..17b800b 100644
--- a/src/content/docs/guides/typescript.md
+++ b/src/content/docs/guides/typescript.md
@@ -1,6 +1,6 @@
---
-title: Check postcodes in TypeScript
-description: Read, clean and format Nigeria's digital postcodes with @gatepost/core, with no network call.
+title: Check Nigerian postcodes in TypeScript
+description: Parse and validate Nigeria's digital postcodes in TypeScript or JavaScript with @gatepost/core. It works offline and needs no API key.
sidebar:
label: TypeScript
order: 1
diff --git a/src/content/docs/guides/woocommerce.md b/src/content/docs/guides/woocommerce.md
index 198b359..965e07d 100644
--- a/src/content/docs/guides/woocommerce.md
+++ b/src/content/docs/guides/woocommerce.md
@@ -1,6 +1,6 @@
---
-title: Add the postcode to a WooCommerce checkout
-description: Install Gatepost Postcode for WooCommerce, and choose how it checks each postcode.
+title: Add the Nigerian postcode to a WooCommerce checkout
+description: Show the Nigerian postcode field in the WooCommerce checkout, and check each postcode. The plugin can ask NIPOST whether a postcode exists.
sidebar:
label: WooCommerce
order: 6
diff --git a/src/content/docs/index.mdx b/src/content/docs/index.mdx
index da37196..a3a1c32 100644
--- a/src/content/docs/index.mdx
+++ b/src/content/docs/index.mdx
@@ -1,6 +1,39 @@
---
-title: Tools for Nigeria's digital postcode
-description: Unofficial, open-source developer tools for Nigeria's digital postcode.
+title: Tools for Nigeria's NIPOST digital postcode
+description: Unofficial open-source tools that check, format and look up Nigeria's NIPOST digital postcode in TypeScript, PHP, HTML forms and WooCommerce.
+head:
+ - tag: meta
+ attrs:
+ property: og:type
+ content: website
+ # Search engines read this data to name the site and its software. It loads nothing.
+ - tag: script
+ attrs:
+ type: application/ld+json
+ content: |
+ {
+ "@context": "https://schema.org",
+ "@graph": [
+ {
+ "@type": "WebSite",
+ "@id": "https://gatepost-dev.github.io/docs/#website",
+ "name": "Gatepost",
+ "url": "https://gatepost-dev.github.io/docs/",
+ "description": "Unofficial open-source developer tools for Nigeria's digital postcode.",
+ "inLanguage": "en-GB"
+ },
+ {
+ "@type": "SoftwareSourceCode",
+ "@id": "https://gatepost-dev.github.io/docs/#software",
+ "name": "Gatepost",
+ "description": "Open-source tools that check, format and look up Nigeria's NIPOST digital postcode. Unofficial. Not made or endorsed by NIPOST.",
+ "url": "https://gatepost-dev.github.io/docs/",
+ "codeRepository": "https://github.com/gatepost-dev",
+ "programmingLanguage": ["TypeScript", "PHP"],
+ "license": "https://www.apache.org/licenses/LICENSE-2.0"
+ }
+ ]
+ }
template: splash
hero:
title: Gatepost
@@ -14,7 +47,7 @@ hero:
variant: minimal
---
-On 1 October 2026, NIPOST launched a digital postcode for addressable buildings and locations in Nigeria. A postcode such as `EK-01-A03-FK-01` has five segments. From large to small, they are the state, the LGA, the district, the area and the unit. The unit is one building.
+On 1 October 2026, NIPOST launched a digital postcode for addressable buildings and locations in Nigeria. A postcode such as `EK-01-A03-FK-01` has five segments. From large to small, they are the state, the LGA, the district, the area and the unit. The unit is one building. The [postcode format](postcode-format/) page explains each segment, and the [state codes](spec/state-codes/) page lists each state.
Gatepost helps apps, websites and online stores accept these postcodes.
@@ -24,7 +57,7 @@ Gatepost helps apps, websites and online stores accept these postcodes.
- Recognise an old 6-digit postcode.
- Ask NIPOST's gateway about a postcode with your own API key.
-Only NIPOST's gateway can say whether a building has a given postcode. Gatepost checks the form first, so your app calls the gateway less often and with clean input.
+Only NIPOST's gateway can say whether a building has a given postcode. Gatepost checks the form first, so your app calls the gateway less often and with clean input. [Validate a Nigerian postcode](validate-postcode/) shows the check in TypeScript, PHP and an HTML form.
Gatepost is independent. NIPOST did not make it and does not support it. For a problem with NIPOST's own app, data or API, contact NIPOST through its official website.
diff --git a/src/content/docs/playground.mdx b/src/content/docs/playground.mdx
index 51b6ea5..dc192f2 100644
--- a/src/content/docs/playground.mdx
+++ b/src/content/docs/playground.mdx
@@ -1,6 +1,8 @@
---
-title: Playground
-description: Try the postcode parser of @gatepost/core in your browser, with no network call.
+title: Nigerian postcode checker
+description: Check the format of a Nigerian postcode in your browser, and see its segments, its state and its three forms. Nothing you type leaves the page.
+sidebar:
+ label: Playground
---
import ClientSamples from '../../components/ClientSamples.astro';
diff --git a/src/content/docs/postcode-format.md b/src/content/docs/postcode-format.md
new file mode 100644
index 0000000..ddb93c6
--- /dev/null
+++ b/src/content/docs/postcode-format.md
@@ -0,0 +1,99 @@
+---
+title: Nigeria's digital postcode format
+description: "The format of Nigeria's NIPOST postcode: five segments, three written forms, the characters of each segment and a regex for the format check."
+sidebar:
+ label: Postcode format
+---
+
+On 1 October 2026, NIPOST launched a digital postcode for addressable buildings and locations in Nigeria. A postcode has 11 letters and digits in five segments, such as `EK-01-A03-FK-01`. This page describes the format. The [postcode grammar](../spec/grammar/) holds the full rules that every Gatepost SDK follows.
+
+## The five segments
+
+From large to small, the segments are the state, the LGA, the district, the area and the unit. The unit names one building or delivery point.
+
+
+
+| Segment | Example | Length | Characters | Rule |
+| -------- | ------- | ------ | ----------------- | ------------------------------------------------- |
+| State | `EK` | 2 | letters | one of the 37 [state codes](../spec/state-codes/) |
+| LGA | `01` | 2 | digits | `01` to `99` |
+| District | `A03` | 3 | letters or digits | any combination of letters and digits |
+| Area | `FK` | 2 | letters | any two letters |
+| Unit | `01` | 2 | digits | `01` to `99` |
+
+
+
+The letters are A to Z, and the digits are 0 to 9. The LGA is a local government area within the state. The district is within the LGA. The area is the smallest polygon in the system.
+
+`00` is never a valid LGA or unit. Both segments run from `01` to `99`, so an area holds at most 99 units. `parse` rejects `EK-01-A03-FK-00` with the error `bad_segment`.
+
+## Partial postcodes
+
+A partial postcode stops after the state, the LGA, the district or the area. It has 2, 4, 7 or 9 letters and digits, such as `EK-01-A03` for a district. `parse` accepts a partial postcode only with the option `allowPartial`.
+
+## Written forms
+
+Gatepost writes a postcode in three forms. All three name the same postcode.
+
+
+
+| Form | Example | Use |
+| --------- | ----------------- | ---------------------- |
+| Canonical | `EK-01-A03-FK-01` | APIs and logs |
+| Display | `EK 01 A03 FK 01` | screens and print |
+| Compact | `EK01A03FK01` | storage and comparison |
+
+
+
+People type postcodes in many ways. Before Gatepost checks a postcode, it normalises the text in three steps:
+
+1. It applies Unicode NFKC. This changes full-width letters and digits to ASCII.
+2. It removes each separator: white space, hyphens and dashes, the full stop and zero-width characters.
+3. It changes the letters a to z to upper case.
+
+So `ek 01 a03 fk 01`, `EK.01.A03.FK.01` and `EK01A03FK01` are the same postcode.
+
+## Old 6-digit postcodes
+
+Before the digital postcode, NIPOST used postcodes of 6 digits. Many records still hold such a legacy postcode.
+
+
+
+| Detail | Legacy postcode | Digital postcode |
+| ---------- | --------------- | ------------------------ |
+| Example | `900108` | `EK-01-A03-FK-01` |
+| Length | 6 | 11 |
+| Characters | digits | letters and digits |
+| Names | an area | one building or location |
+
+
+
+`parse` gives the error `legacy_code` for exactly 6 digits, and `isLegacy` recognises a legacy postcode. Your form can then ask for the new postcode.
+
+## A regex for the format check
+
+`parse` is the full check. Use a regex where no Gatepost SDK runs, such as in a database rule. This regex accepts the three forms in upper case. It checks the state code and the range of the LGA and the unit.
+
+```ts
+const POSTCODE =
+ /^(?:AB|AD|AK|AN|BA|BE|BR|BY|CR|DE|EB|ED|EK|EN|FC|GM|IM|JI|KD|KE|KG|KN|KT|KW|LA|NA|NI|OG|ON|OS|OY|PL|RI|SK|TA|YB|ZA)[ -]?(?:0[1-9]|[1-9][0-9])[ -]?[A-Z0-9]{3}[ -]?[A-Z]{2}[ -]?(?:0[1-9]|[1-9][0-9])$/;
+
+POSTCODE.test('EK-01-A03-FK-01'); // true
+POSTCODE.test('EK 01 A03 FK 01'); // true
+POSTCODE.test('EK01A03FK01'); // true
+POSTCODE.test('EK-01-A03-FK-00'); // false
+POSTCODE.test('XX-01-A03-FK-01'); // false
+POSTCODE.test('900108'); // false
+```
+
+The regex does less than `parse`. It does not normalise the text. Remove the white space at the start and the end, and change the letters to upper case first. The regex gives no reason for a failure and no suggestion for a typo.
+
+:::note
+A postcode in the right format can still be one that NIPOST did not assign. Only NIPOST's gateway can say whether a postcode exists. [Look up a postcode](../guides/typescript-client/) to ask it.
+:::
+
+## Next steps
+
+- [Validate a postcode](../validate-postcode/) in TypeScript, PHP or an HTML form.
+- [Find the code of a state](../spec/state-codes/).
+- [Check a postcode in the playground](../playground/).
diff --git a/src/content/docs/privacy.md b/src/content/docs/privacy.md
index e4616c8..0fbff4e 100644
--- a/src/content/docs/privacy.md
+++ b/src/content/docs/privacy.md
@@ -1,6 +1,8 @@
---
-title: Privacy
-description: What this site keeps, what it sends and what GitHub logs.
+title: Privacy of the Gatepost docs
+description: This site has no analytics, no tracking and no cookies. Read what your browser keeps, what the site sends and what GitHub logs.
+sidebar:
+ label: Privacy
---
This site has no analytics, no tracking and no cookies. Every script, font, image and style comes from this site itself. No page loads anything from another website.
diff --git a/src/content/docs/readiness.md b/src/content/docs/readiness.md
index 115d2cf..5657ebe 100644
--- a/src/content/docs/readiness.md
+++ b/src/content/docs/readiness.md
@@ -1,6 +1,8 @@
---
-title: Readiness tracker
-description: Common tools that reject or hide Nigeria's new postcode, and the state of the fix for each one.
+title: Readiness tracker for Nigeria's new postcode
+description: Common tools, such as Shopify worldwide and WooCommerce, that reject or hide Nigeria's new postcode, and the state of the fix for each one.
+sidebar:
+ label: Readiness tracker
---
On 1 October 2026, NIPOST launched a postcode of 11 letters and digits, as [its docs](https://docs.postcode.gov.ng) describe. Some common tools still accept only the old 6-digit postcode, or hide the postcode field for Nigeria. Gatepost has sent a fix to three of the five tools below and has not sent a fix to the other two. This page shows the state on 3 October 2026.
diff --git a/src/content/docs/start.md b/src/content/docs/start.md
index d3e499e..2463d69 100644
--- a/src/content/docs/start.md
+++ b/src/content/docs/start.md
@@ -1,6 +1,8 @@
---
-title: Choose a tool
-description: Find the Gatepost package that fits your app, and learn what each one needs.
+title: Choose a tool for Nigerian postcodes
+description: Find the Gatepost package that checks or looks up Nigerian postcodes in TypeScript, PHP, an HTML or React form, or a WooCommerce shop.
+sidebar:
+ label: Choose a tool
---
Each Gatepost tool follows the same spec, so each one reads a postcode in the same way. Choose by the language of your app and by what it must know.
diff --git a/src/content/docs/validate-postcode.md b/src/content/docs/validate-postcode.md
new file mode 100644
index 0000000..561c022
--- /dev/null
+++ b/src/content/docs/validate-postcode.md
@@ -0,0 +1,86 @@
+---
+title: Validate a Nigerian postcode
+description: Validate a Nigerian postcode in TypeScript, PHP or an HTML form. Check the format offline, then ask NIPOST's gateway whether it exists.
+sidebar:
+ label: Validate a postcode
+---
+
+A check of a postcode has two steps.
+
+1. Check the format. Gatepost does this offline, with no API key and no network call. The check finds typos, old 6-digit postcodes and unknown state codes.
+2. Ask NIPOST's gateway whether the postcode exists. Only the gateway knows, and it needs your own API key.
+
+Each example below checks the format. It accepts spaces, hyphens and any letter case, so `ek 01 a03 fk 01` gives `EK-01-A03-FK-01`. The [postcode format](../postcode-format/) page explains the rules.
+
+## TypeScript or JavaScript
+
+`parse` from `@gatepost/core` takes the text that a user typed. It returns a result, and it never throws. The package runs in Node 22 or later and in current browsers.
+
+```sh
+pnpm add @gatepost/core
+```
+
+The first alpha is not published yet. This page will say when it is.
+
+```ts
+import { parse } from '@gatepost/core';
+
+const result = parse('ek 01 a03 fk 01');
+if (result.ok) {
+ result.value.canonical; // 'EK-01-A03-FK-01'
+}
+
+const typo = parse('EK-O1-A03-FK-01');
+if (!typo.ok) {
+ typo.error.code; // 'bad_segment'
+ typo.error.suggestion; // 'EK-01-A03-FK-01'
+}
+```
+
+When `ok` is false, `error.code` names the first problem. The [TypeScript guide](../guides/typescript/#tell-the-user-what-is-wrong) lists each code. Show a suggestion as a question, and let the user accept it.
+
+## PHP
+
+`Postcode::parse` from `gatepost/postcode` works in the same way. It needs PHP 8.1 or later. The [PHP guide](../guides/php/#install) shows how to install it with Composer.
+
+```php
+isOk()) {
+ echo $result->value->canonical, "\n"; // EK-01-A03-FK-01
+}
+
+$typo = Postcode::parse('EK-O1-A03-FK-01');
+echo $typo->error?->code->value, "\n"; // bad_segment
+echo $typo->error?->suggestion, "\n"; // EK-01-A03-FK-01
+```
+
+## An HTML form
+
+`@gatepost/field` adds a postcode field to any HTML form. It checks the format while the user types. When the text is a postcode, the form sends its canonical form.
+
+```html
+
+
+```
+
+A user who types `fc 01 z99 zz 01` sends `postcode=FC-01-Z99-ZZ-01`. With no key, the field checks the format offline and sends no request. The [HTML field guide](../guides/html/) shows how to install the field, and it explains each setting.
+
+## Ask NIPOST whether a postcode exists
+
+A postcode in the right format can still be one that NIPOST did not assign. A lookup asks NIPOST's gateway about the postcode. [Get a key](../start/#get-a-key) from NIPOST, and then follow the guide for your language.
+
+- [Look up a postcode in TypeScript](../guides/typescript-client/).
+- [Look up a postcode in PHP](../guides/php/#look-up-a-postcode).
+
+With a publishable key, the HTML field also asks the gateway about each whole postcode.
+
+## A WooCommerce shop
+
+Gatepost Postcode for WooCommerce shows the postcode field for Nigerian addresses in the checkout, and it checks each postcode. Read the [WooCommerce guide](../guides/woocommerce/).
diff --git a/test/site/pages.test.ts b/test/site/pages.test.ts
index 4d46d9e..878f2fb 100644
--- a/test/site/pages.test.ts
+++ b/test/site/pages.test.ts
@@ -50,6 +50,60 @@ describe('the preview of a shared link', () => {
expect(page?.text).toMatch(/[^<|]*\| Gatepost<\/title>/);
expect(page?.text).not.toContain('Gatepost | Gatepost');
});
+
+ it('calls the home page a website and every other page an article', () => {
+ for (const { path, text } of PAGES) {
+ const type = path === 'index.html' ? 'website' : 'article';
+ expect(text, path).toContain(` {
+ it.each([
+ ['index.html', "Nigeria's NIPOST digital postcode"],
+ ['postcode-format/index.html', "Nigeria's digital postcode format"],
+ ['validate-postcode/index.html', 'Validate a Nigerian postcode'],
+ ['spec/state-codes/index.html', 'Nigerian state codes'],
+ ['playground/index.html', 'Nigerian postcode checker'],
+ ['guides/typescript-client/index.html', 'NIPOST postcode API'],
+ ['guides/php/index.html', 'Nigerian postcodes in PHP'],
+ ['guides/woocommerce/index.html', 'Nigerian postcode to a WooCommerce checkout'],
+ ])('%s names "%s"', (path, words) => {
+ const title = /([^<]*)<\/title>/.exec(
+ PAGES.find((page) => page.path === path)?.text ?? '',
+ )?.[1];
+ expect(title?.replaceAll(''', "'")).toContain(words);
+ });
+});
+
+// Search engines read the structured data of the home page to name the site and its software.
+describe('the structured data of the home page', () => {
+ const home = PAGES.find(({ path }) => path === 'index.html')?.text ?? '';
+ const blocks = Array.from(
+ home.matchAll(/