LightSpeed Theme is a custom WordPress block theme built by LightSpeed for fast, accessible, and maintainable websites using the WordPress Site Editor and block editor.
This is the LightSpeed Theme repository — a production WordPress block theme for client and commercial projects.
It includes:
- A working WordPress block theme
- A Sass source layer for authored effect CSS
- Validation and linting tooling
- AI guidance files and GitHub Copilot instructions
- Structured folders for prompts, reports, tasks, docs, and AI agents
Note: This theme is not specifically packaged for WordPress.org submission. It is designed for client and commercial block theme development.
- WordPress theme developers at LightSpeed
- Developers maintaining or extending this theme
- AI agents building or maintaining block themes in this repo
| Area | Details |
|---|---|
| Theme files | style.css, theme.json, functions.php, readme.txt |
| Templates | templates/index.html |
| Parts | parts/header.html, parts/footer.html |
| Style variations | styles/dark.json |
| Assets | assets/fonts/, assets/css/, assets/js/, etc. |
| PHP includes | inc/ (empty, ready for use) |
| Patterns | patterns/ (empty, ready for use) |
| Validation | theme-utils.mjs, package.json, composer.json |
| AI guidance | AGENTS.md, CLAUDE.md, .github/copilot-instructions.md |
| Copilot prompts | .github/prompts/ |
| Reports | .github/reports/ |
| Tasks | .github/tasks/ |
| Docs | docs/ |
| Agent assets | .agents/skills/, .agents/agents/ |
| CI workflows | .github/workflows/ |
- PHP 8.1+
- WordPress 6.9+
- Node.js (see
.nvmrcfor version) - Composer 2.x
# 1. Clone the repo
# 2. Install Node dependencies
npm install
# 3. Install Composer dependencies
composer install
# 4. Validate the theme
npm run theme:validate
# 5. Compile authored CSS
npm run build:css
# 6. Validate JSON schema
npm run schema:validate/
├── AGENTS.md # AI and developer guidance
├── CLAUDE.md # Points to AGENTS.md
├── CHANGELOG.md # Keep a Changelog / SemVer
├── README.md # This file
├── readme.txt # Light distribution placeholder
├── style.css # Block theme header
├── theme.json # Primary theme settings
├── functions.php # Minimal PHP
├── screenshot.png # Create manually
├── CODEOWNERS
├── theme-utils.mjs # Validation and utilities
├── package.json
├── composer.json
├── .editorconfig
├── .gitignore
├── .gitattributes
├── .nvmrc
├── .coderabbit.yml
├── .lintstagedrc.json
├── assets/
│ ├── fonts/
│ ├── icons/
│ ├── logos/
│ ├── images/
│ ├── css/
│ └── js/
├── src/
│ └── scss/ # Sass source for authored theme CSS
├── docs/ # End-user documentation
├── inc/ # PHP includes
├── parts/
│ ├── header.html
│ └── footer.html
├── patterns/
├── styles/
│ ├── blocks/
│ ├── sections/
│ └── dark.json
├── templates/
│ └── index.html
├── .github/
│ ├── copilot-instructions.md
│ ├── instructions/
│ ├── prompts/
│ ├── reports/
│ ├── tasks/
│ └── workflows/
└── .agents/
├── skills/
└── agents/
| Command | Description |
|---|---|
npm run schema:validate |
Validate theme.json and styles JSON schemas |
npm run theme:validate |
Validate theme consistency |
npm run build:css |
Compile Sass source to assets/css/ |
npm run watch:css |
Watch Sass entry files and rebuild CSS |
npm run patterns:escape |
Check PHP patterns for escaping issues |
npm run security:scan |
Scan PHP files for security issues |
npm run lint |
Run all linting |
npm run lint:json |
Lint JSON files |
| Command | Description |
|---|---|
composer run phpcs |
PHP code sniffer |
composer run phpcbf |
Fix auto-fixable PHP issues |
composer run lint:php |
Lint PHP syntax |
theme.json— set your colour palette and typographyfunctions.php— add any theme supports you needparts/header.html— build your headerparts/footer.html— build your footertemplates/index.html— build your main templateCHANGELOG.md— track your changesCODEOWNERS— set your team as owners
| What | Where |
|---|---|
| Copilot prompts | .github/prompts/ |
| Developer reports | .github/reports/ |
| Task lists | .github/tasks/ |
| End-user documentation | docs/ |
| Portable AI skills | .agents/skills/ |
| Agent personas | .agents/agents/ |
See AGENTS.md for full guidance on AI workflow conventions.
Playwright is run manually or with an AI agent, not in CI.
npm install
cp .env.example .env # then set BASE_URL (see below)
npm run test:setup # downloads the Chromium + WebKit browsers (not installed by npm install)npm run test:setup:all also downloads Firefox, which only the desktop firefox project needs. Without the browser downloads every test fails with "Executable doesn't exist".
.env (gitignored, in the theme root) needs at least:
BASE_URL=<the site to test against>
The tests only see what BASE_URL is serving. To check a branch you haven't deployed, point it at your local site (e.g. http://localhost:8882). Pass it per run instead of editing .env if you prefer: BASE_URL=http://localhost:8882 npx playwright test ....
tests/specs/mobile-menu.spec.ts covers every mobile menu dropdown (open/close, links, tap targets, overflow), the Services phase groups, the pressed-state padding and phase colours, and an axe scan with the menu open. The press-colour tests force :active / :focus-visible through the Chrome DevTools Protocol, so they run on Chromium only and are skipped on the WebKit projects. Colours are compared against tokens read from the page, so the same tests pass whichever style variation (light or Dark) the target site is on — run them again against a site set to Dark to cover it.
A few tests are expected failures (test.fail) for known menu issues: links inside accordion <summary> elements, and undersized "See all …" and phase-heading tap targets. They report as passing, and will flip to failing once the issue is fixed, as a prompt to remove the expectation.
Two separate things decide what a run tests:
| Question | Controlled by | Example |
|---|---|---|
| Which page? | SINGLE_PAGE_URL (standing specs and mobile-menu.spec.ts) |
SINGLE_PAGE_URL="http://localhost:8882/services/" |
| Which device / browser? | The Playwright project, chosen with --project |
--project="Mobile Chrome" |
SINGLE_PAGE_URL never picks a viewport, and the page URL never implies one. A spec runs under each project it is assigned to (see playwright.config.ts). Without --project, every project runs.
| Project | Device | Runs |
|---|---|---|
chromium, firefox, webkit |
Desktop browsers | Everything except mobile-menu.spec.ts |
Mobile Chrome |
Pixel 5 (393px, touch) | mobile-menu.spec.ts + the standing accessibility and responsive-overflow specs |
Mobile Safari |
iPhone 12 (390px, touch) | mobile-menu.spec.ts |
Tablet |
iPad Mini (768px, touch) | mobile-menu.spec.ts |
The device projects use real touch and mobile emulation, not just a narrow window, so (hover: none) and tap behaviour match a phone. Which specs run on which device is set in playwright.config.ts (DEVICE_ONLY_SPECS, MOBILE_STANDING_SPECS).
| Command | Runs |
|---|---|
npx playwright test |
Everything, on every project |
npx playwright test --project=chromium |
Everything on desktop Chromium only |
npm run test:mobile |
The mobile-menu spec on Mobile Chrome, Mobile Safari and Tablet |
npx playwright test mobile-menu --project="Mobile Chrome" |
The mobile menu on one device |
SINGLE_PAGE_URL="http://localhost:8882/services/" npx playwright test mobile-menu --project="Mobile Chrome" |
One URL at one device |
SINGLE_PAGE_URL="..." npx playwright test standing/accessibility --project="Mobile Chrome" |
A standing spec on one URL at mobile width |
npx playwright test tests/specs/standing |
Only the standing regression suite |
npx playwright test tests/specs/header-search.spec.ts |
A single feature spec |
Project names are exact and case-sensitive; quote the ones with spaces.
Feature specs (header-search.spec.ts, navigation.spec.ts, keyboard-navigation.spec.ts, reduced-motion.spec.ts, mobile-menu.spec.ts, bugherd-reporter.spec.ts) test reusable, site-wide components and behaviors — not one specific page/template — and use the generic assertion helpers in tests/helpers/assertions.ts where applicable.
Standing suite (tests/specs/standing/) is content-agnostic — it discovers every reachable page on BASE_URL (via sitemap, REST, or crawl fallback) and runs a fixed set of checks against all of them: page health/PHP errors, console/runtime errors, broken same-origin resources, accessibility (axe), internal link integrity, horizontal overflow at common widths, image alt attributes, and the search/404 routes. It requires no per-template setup — new pages are covered automatically.
- Responsive overflow (
standing/responsive-overflow.spec.ts) runs two checks on every page at 320, 360, 370, 375, 390, 768, 1024 and 1440px:- The document check fails when the page scrolls sideways (
scrollWidthwider thanclientWidth). - The button check (
expectNoElementOverflowintests/helpers/responsive.ts) catches what the document check misses: a button spilling out of the left of a panel, or out of a panel narrower than the page. It fails when a.wp-block-button__link(or a.wp-block-buttonschild with no link) starts left of the viewport, ends past its right edge, or sits more than 1px outside its nearest.wp-block-buttonsrow or its nearest bordered/backgrounded panel, on either side. - Each failure lists the section (its heading and theme classes), the button text, which side overflowed, which container (
viewport,button-roworpanel), and the element and container widths. Failures useexpect.soft, so one run reports every offender. WordPress doesn't put the pattern name in the page, so find the pattern by searchingpatterns/for the section heading. - It ignores zero-width/zero-height elements, everything inside
.mobile-menu, and buttons inside a row that deliberately scrolls sideways (such as the blog's filter pills). Text clipping and vertical overflow are not checked. - Run one page with
SINGLE_PAGE_URL="http://localhost:8882/free-consultation/" npx playwright test standing/responsive-overflow --project=chromium --project=webkit --project="Mobile Chrome". Dark mode is covered by running it again against a site set to Dark. - It also runs on Mobile Chrome, so a full run files device-tagged BugHerd tasks for overflow found there;
SINGLE_PAGE_URLruns create none.
- The document check fails when the page scrolls sideways (
- The number of URLs actually tested is currently throttled by
MAX_TEST_URLSintests/fixtures/site.tswhile the suite is being verified — raise this before relying on it for full site coverage. - Failures in the standing suite are automatically logged as BugHerd tasks (deduplicated, so re-running doesn't create duplicates). This requires
BUGHERD_API_KEYandBUGHERD_PROJECT_IDin.env. Feature specs never create BugHerd tasks. SINGLE_PAGE_URLnever creates BugHerd tasks, on any project or spec. Use it for local and one-off checks.- A standing spec that fails on a device project (e.g. Mobile Chrome) gets its own BugHerd task with a
device:tag and aProject:line, separate from the same failure on desktop. Desktop browsers share one task between them. - Each created task is attributed to whoever ran the suite, via your local
git config user.email— so your name/email will show up as the reporter on any task your run creates. - No CI wiring — run manually, after
develophas been merged and the target site has redeployed.
See LICENSE.