| Field | Value |
|---|---|
| Project team | project-design |
| Repository role | Spectre WordPress theme shell |
| Package/artifact | @phcdevworks/spectre-base |
| Current version/status | 1.0.0 |
- Read AGENTS.md, then the agent-specific guide for the task.
- Check TODO.md and ROADMAP.md for current scope.
- Make the smallest repo-local change that satisfies the task.
- Run
npm run checkwhen validation is required or practical. - Update docs and CHANGELOG.md only when behavior, public contracts, or release-relevant metadata changed.
| Guide | Path |
|---|---|
| Agent rules | AGENTS.md |
| Claude Code | CLAUDE.md |
| Codex | CODEX.md |
| Copilot | COPILOT.md |
| Jules | JULES.md |
| Roadmap | ROADMAP.md |
| Todo | TODO.md |
| Changelog | CHANGELOG.md |
| Security | SECURITY.md |
@phcdevworks/spectre-base is the WordPress theme delivery layer
of the Spectre system for WordPress sites that consume Spectre tokens, Spectre
UI, and Spectre web components.
Maintained by PHCDevworks, it combines a standard WordPress theme directory with a Vite build pipeline, a TypeScript client entrypoint, and Tailwind CSS 4. It is for teams building custom WordPress themes that need modern frontend assets without moving design-system ownership into PHP templates.
Contributing | Code of Conduct | Changelog | Roadmap | Security Policy
spectre-theme/ is the deployable WordPress theme directory. src/ is the
build source. Everything in spectre-theme/dist/ is generated -- never edit
it directly.
| Layer | Path | Rule |
|---|---|---|
| Theme JS entry | src/js/main.ts |
Registers Spectre web components |
| Theme CSS entry | src/styles/main.css |
Shell styles using var(--sp-*) only |
| WordPress theme | spectre-theme/ |
Template hierarchy, asset loading, Gutenberg config |
| Theme metadata | spectre-theme/style.css and spectre-theme/readme.txt |
Keep version synced with package.json |
| Gutenberg tokens | spectre-theme/theme.json |
All values must come from var(--sp-*) |
| Build output | spectre-theme/dist/ |
Never edit directly -- regenerated by npm run build |
After any source change: run npm run build to regenerate output, then
npm run check to validate.
- The Vite build configuration for theme assets
- The TypeScript entrypoint in
src/js/main.ts - The CSS entrypoint in
src/styles/main.css - The WordPress theme files in
spectre-theme/, including asset loading infunctions.php - The compiled output for theme-owned assets in
spectre-theme/dist
The build compiles one JavaScript entry and one CSS entry. In production, the theme resolves those compiled assets from the Vite manifest and serves one JS bundle and one CSS bundle for the theme-owned frontend surface.
- Design token definitions. Those belong to
@phcdevworks/spectre-tokens. - Reusable UI component contracts and recipes. Those belong to
@phcdevworks/spectre-uiand@phcdevworks/spectre-components. - WordPress core installation, plugin management, or hosting concerns.
- Application state architecture beyond the theme entrypoint.
- Ships a deployable WordPress theme directory in
spectre-theme/ - Builds theme-owned CSS and JavaScript through Vite and TypeScript
- Switches between the Vite dev server in development and hashed assets in production
- Consumes Spectre tokens, Spectre UI, and Spectre web components without redefining their contracts
- Keeps PHP templates focused on WordPress structure and data delivery
- You are building a WordPress site and need Spectre tokens, UI, and web components delivered through a theme
- You want a Vite + TypeScript build pipeline for theme-owned assets without owning the design system itself
- You need hot module replacement in development and hashed production assets without writing the plumbing yourself
- You want to define design tokens, color scales, typography, or component
contracts -- those belong in
@phcdevworks/spectre-tokens,@phcdevworks/spectre-ui, and@phcdevworks/spectre-components - You need a WordPress plugin -- plugin logic belongs in a separate plugin
repository such as
spectre-icons - You are building a non-WordPress frontend -- this package is WordPress-specific
The CMS delivers; the design system defines. This theme is the delivery layer, not a second design system. WordPress owns template structure and data delivery; Spectre packages own visual meaning, styling contracts, and components.
- Use
var(--sp-*)tokens for all CSS values -- never hardcode hex, RGB, rem, or px - Use
<sp-button>,<sp-input>, and other<sp-*>components for controls - Keep PHP templates structural -- semantic shell classes and WordPress functions only
See AGENTS.md for the full shared edit boundaries and drift prevention rules that apply to all contributors and AI agents.
Prerequisites: Node.js ^22.12.0 || >=24.0.0, npm 11.14.1, PHP 8.2, and
ripgrep (required for
check:drift).
npm install-
Start the Vite dev server.
npm run dev
-
Make the theme available to WordPress by symlinking or copying
spectre-theme/into your local WordPress install.ln -s /path/to/spectre-base/spectre-theme /path/to/wordpress/wp-content/themes/spectre-theme
-
Set your WordPress environment to development mode so the theme loads assets from the Vite dev server instead of
spectre-theme/dist.define('WP_ENVIRONMENT_TYPE', 'development');
-
Build production assets when ready to deploy.
npm run build npm run check:assets
@phcdevworks/spectre-tokensprovides the design tokens consumed by the frontend layer@phcdevworks/spectre-uiprovides Spectre UI styles and primitives used by the theme layer@phcdevworks/spectre-componentsprovides the web components used directly in WordPress templates
This repository is where those frontend foundations are delivered through a WordPress theme. The theme should consume Spectre output, not redefine it.
By default, the theme stylesheet imports the Spectre UI default bundle, so a fresh install starts from Spectre UI instead of a generic Tailwind-only baseline.
The theme ships a complete WordPress template hierarchy. Each file handles a specific route:
| Template file | WordPress route |
|---|---|
index.php |
Catch-all fallback for all unmatched routes |
home.php |
Blog posts index (when a static front page is set) |
front-page.php |
Static front page |
single.php |
Single post |
page.php |
Static page |
archive.php |
Date, category, tag, and author archives |
search.php |
Search results |
404.php |
Not found |
header.php |
Shared header -- loaded via get_header() |
footer.php |
Shared footer -- loaded via get_footer() |
sidebar.php |
Sidebar -- loaded via get_sidebar() |
searchform.php |
Search form partial |
comments.php |
Comments section |
Template parts in spectre-theme/template-parts/:
| Part | Used by |
|---|---|
content-card.php |
index.php, home.php, archive.php |
content-single.php |
single.php |
content-page.php |
page.php, front-page.php |
content-none.php |
All list templates when no posts are found |
These CSS classes are defined in src/styles/main.css and are safe to use in
any PHP template. All values come from var(--sp-*) tokens.
| Class | Purpose |
|---|---|
spectre-site-container |
Centered, max-width container |
spectre-site-header |
Header shell with neutral background |
spectre-site-footer |
Footer shell with neutral background |
spectre-main |
Main content area with grid spacing |
spectre-main--spacious |
Variant with more block padding |
spectre-panel |
Bordered, padded surface (pages, 404) |
spectre-panel--roomy |
Panel with extra padding |
spectre-panel--centered |
Center-aligned panel |
spectre-panel--dashed |
Panel with dashed border (empty states) |
spectre-card |
Post card with hover shadow |
spectre-card__media |
Image area of a card |
spectre-card__body |
Content area of a card |
spectre-card__title |
Card headline |
spectre-card__excerpt |
Card excerpt text |
spectre-card__readmore |
Card "Read more" anchor |
spectre-post-grid |
Responsive auto-fit grid for cards |
spectre-section |
Content section with gap |
spectre-content |
Post body content area |
spectre-entry-meta |
Date and author metadata row |
spectre-eyebrow |
Small uppercase label |
spectre-title-lg |
Large heading |
spectre-title-xl |
Extra-large heading |
spectre-title-2xl |
2x extra-large heading |
spectre-muted |
Muted text color |
spectre-button |
Base anchor-as-button shell |
spectre-button--primary |
Primary filled button variant |
spectre-widget |
Sidebar widget wrapper |
spectre-widget-title |
Sidebar widget heading |
Fork or clone this repository to start a new Spectre-backed WordPress site. Minimum changes for a new site:
- Update
package.json-- setnameandversionfor your project. - Update the theme header in
spectre-theme/style.css--Theme Name,Theme URI,Author,Author URI,Description, andText Domain. - Update
spectre-theme/readme.txtto match. - Install dependencies:
npm install. - Symlink the theme and set
WP_ENVIRONMENT_TYPEinwp-config.php(see Quick start above). - Customize shell styles in
src/styles/main.cssusingvar(--sp-*)tokens only. - Register social icons via the
spectre_base_footer_social_iconsfilter (see Extension points below). - Build for production:
npm run build && npm run check:assets.
Do not rename PHP functions (spectre_base_*) without also updating
template calls and the text domain throughout. A project-wide search-and-replace
is the safest approach.
The theme exposes a documented set of action and filter hooks so an agency can
customize header, footer, navigation, and sidebar behavior from a child theme
or site plugin -- without copying or overriding the parent template files.
Each hook below is declared in the listed parent file; place your add_action
/ add_filter calls in your child theme's functions.php.
| Hook | Fires in | When |
|---|---|---|
spectre_base_before_header |
header.php |
Immediately before the <header> element |
spectre_base_before_site_branding |
header.php |
Inside .spectre-site-branding, before the logo/site title |
spectre_base_after_site_branding |
header.php |
Inside .spectre-site-branding, after the logo/site title |
spectre_base_after_header |
header.php |
Immediately after the </header> element |
spectre_base_before_footer |
footer.php |
Immediately before the <footer> element |
spectre_base_after_footer |
footer.php |
Immediately after the </footer> element |
spectre_base_before_sidebar($sidebar_id) |
sidebar.php |
Before the <aside> wrapper, only when the sidebar is active |
spectre_base_after_sidebar($sidebar_id) |
sidebar.php |
After the <aside> wrapper, only when the sidebar is active |
// Inject a promo banner just inside the header, in your child theme's functions.php:
add_action('spectre_base_before_site_branding', function () {
echo '<p class="spectre-eyebrow">' . esc_html__('Now booking 2026 projects', 'your-child-theme') . '</p>';
});These complement the core WordPress template-loading hooks that already fire
around these files: get_header, get_footer, and get_sidebar (fired by
get_header()/get_footer()/get_sidebar() before the file loads), plus
wp_head, wp_body_open, and wp_footer inside header.php/footer.php.
| Hook | Declared in | Purpose |
|---|---|---|
spectre_base_primary_nav_args |
header.php |
Filters the wp_nav_menu() args array for the primary navigation |
spectre_base_footer_nav_args |
footer.php |
Filters the wp_nav_menu() args array for the footer navigation |
spectre_base_footer_social_icons |
footer.php |
Filters the array of social icon entries rendered in the footer |
spectre_base_sidebar_id |
sidebar.php |
Filters which registered sidebar ID sidebar.php renders (default sidebar-main) |
// Swap the registered sidebar that sidebar.php renders:
add_filter('spectre_base_sidebar_id', fn () => 'sidebar-shop');
// Add a custom menu class to the primary navigation:
add_filter('spectre_base_primary_nav_args', function (array $args) {
$args['menu_class'] .= ' my-client-nav';
return $args;
});Add site-specific social icon links without modifying the theme directly:
// In your child theme's functions.php or a site plugin:
add_filter('spectre_base_footer_social_icons', function () {
return [
['name' => 'github', 'size' => '20', 'url' => 'https://github.com/yourorg'],
['name' => 'linkedin', 'size' => '20', 'url' => 'https://linkedin.com/company/yourco'],
];
});This requires the spectre-icons plugin to be active. If the plugin is not active the social row is not rendered regardless of the filter output.
For changes too large for a hook -- a fundamentally different header layout, for
example -- WordPress's standard child theme lookup already covers you: any file
a child theme provides under the same name (header.php, footer.php,
sidebar.php, template parts in template-parts/, etc.) takes priority over
the parent theme's copy. No filter is required to do this; it is core
get_header() / get_footer() / get_sidebar() / get_template_part()
behavior. Prefer the hooks above when possible -- they keep you on the parent
theme's update path.
Every --sp-* custom property consumed by this theme is owned and defined by
@phcdevworks/spectre-tokens (via @phcdevworks/spectre-ui). The theme itself
never declares a --sp-* custom property -- it only reads them with var() in
src/styles/main.css and theme.json.
Safe to consume (read-only): any --sp-* variable, in any child theme
stylesheet or theme.json, via var(--sp-...). See
Adding custom shell styles below.
Not safe to declare: do not define or redeclare a --sp-* custom property
in a child theme, site plugin, or theme.json. The --sp-* namespace is
reserved for the upstream Spectre token contract; locally redefining one of
these variables creates drift between this theme and the design system and
will be flagged by npm run check:drift.
To change a token's value for a client brand, do it through the upstream
contract -- override the relevant entries in theme.json's settings.color,
settings.typography, and settings.spacing palettes/presets (which already
reference var(--sp-*)), or configure @phcdevworks/spectre-tokens upstream.
Never hardcode a hex, rem, or px value in place of a token reference.
Add site-specific structural styles in a child theme or an additional CSS file.
Always use var(--sp-*) tokens:
/* child-theme/style.css or an additional import */
@layer components {
.my-hero {
background-color: var(--sp-surface-alternate);
padding-block: var(--sp-space-64);
}
}Agencies build client sites as WordPress child themes of spectre-base,
inheriting the build pipeline, templates, and token contract while keeping
client-specific branding isolated.
npm run create:child -- <client-name>This scaffolds spectre-child-<client-name>/ (git-ignored) with:
style.css-- WordPress child theme header declaringTemplate: spectre-theme, GPL license, and WP.org standard tagsfunctions.php-- enqueues the child stylesheet withspectre-base-styleas its dependency, so it loads after the parent bundletheme.json-- minimal, inherits the full parent token set and is ready for brand-specific overrides
The Template: spectre-theme header is what tells WordPress this is a child of
spectre-base -- it must match the parent theme's directory name exactly.
Override color, typography, and spacing presets in the child theme's
theme.json. Keep every value as a var(--sp-*) reference -- see
CSS custom property namespace above. Do not
introduce hex codes, raw px/rem values, or new custom properties.
- Full template/template-part overrides -- provide a same-named file
(
header.php,footer.php,template-parts/content-card.php, etc.) in the child theme directory; WordPress loads it instead of the parent's copy. - Targeted hook overrides -- prefer the PHP hook API for smaller customizations (injecting markup, filtering nav menu args, swapping the sidebar, registering social icons). Hooks keep the child theme on the parent theme's update path without forking template files.
Development -- symlink spectre-theme/ into WordPress and set
WP_ENVIRONMENT_TYPE=development (see Quick start). Assets stream from the
Vite dev server with HMR.
Production -- run npm run build, then copy or ZIP the entire spectre-theme/
directory (including dist/) to wp-content/themes/spectre-theme/ on the
server. The theme reads dist/.vite/manifest.json to enqueue hashed bundles.
Set WP_ENVIRONMENT_TYPE to anything other than development in wp-config.php.
# Build and verify before deploying
npm run check
# ZIP the deployable directory
zip -r spectre-theme.zip spectre-theme/The dist/ directory must be present in the ZIP. It is generated by the build
and is not committed to the repository.
Install dependencies, then run the full verification flow:
npm install
npm run checkThis project expects Node.js ^22.12.0 || >=24.0.0, npm 11.14.1, and
PHP 8.2.
CSS and JavaScript changes in src/ are reflected instantly in the browser via
HMR without a page reload. The Vite dev server runs on http://localhost:5173
by default. To use a different port, define the server URL in wp-config.php:
define('VITE_DEV_SERVER', 'http://localhost:5174');| Command | What it does |
|---|---|
npm run build |
TypeScript check + Vite production build |
npm run check |
Full validation gate -- must pass before any handoff |
npm run check:assets |
Validate Vite manifest and asset contract |
npm run check:drift |
Scan for hardcoded visual values and design-system drift |
npm run lint |
ESLint for TypeScript |
npm run lint:php |
PHP syntax validation |
npm run format |
Apply Prettier formatting |
src/js/main.ts-- theme JavaScript entrypointsrc/styles/main.css-- theme CSS entrypointspectre-theme/-- deployable WordPress theme directoryspectre-theme/functions.php-- asset enqueueing, theme setup, env-aware loadingspectre-theme/dist/-- Vite build output (never edit directly)vite.config.ts-- build and dev-server configuration
Run the full validation suite before handing off changes:
npm run checknpm run check is an alias for npm run validate. Both run in order:
TypeScript check, Vite build, asset contract, ESLint, PHP lint, and drift scan.
CI runs the same command.
check:drift expected output is empty or only token-backed references such as
var(--sp-shadow-*) and theme.json token presets. Any local visual value
must be removed or justified before merging.
This theme is compatible with the
spectre-icons WordPress plugin.
Once the plugin is installed and activated, the [spectre-icon] shortcode is
available in any template or content area.
The theme footer automatically renders icon links when the plugin is active:
[spectre-icon name="github" size="20"]
[spectre-icon name="twitter" size="20"]
[spectre-icon name="linkedin" size="20"]
To check availability before rendering icons in a custom template:
<?php if (spectre_base_has_icons()) : ?>
<?php echo do_shortcode('[spectre-icon name="arrow-right" size="16"]'); ?>
<?php endif; ?>This pattern works in both the classic editor and the block editor.
| Failure | Cause | Fix |
|---|---|---|
| Theme loads a blank page in production | Compiled manifest is missing or stale | Run npm run build then npm run check:assets and confirm spectre-theme/dist/.vite/manifest.json exists and lists src/js/main.ts as an entry |
| Styles not updating in development | Wrong environment or dev server not running | Confirm WP_ENVIRONMENT_TYPE=development in wp-config.php and npm run dev is running on the expected port |
check:drift reports unexpected matches |
Raw hex, pixel, rem, or Tailwind utility added to src/ or PHP |
Replace with a var(--sp-*) token or a Spectre component |
| PHP lint fails with syntax error | PHP syntax error in a template file | Fix the reported file, then rerun npm run lint:php (PHP 8.2 is the CI target) |
rg not found when running check:drift |
ripgrep not installed | Install ripgrep (brew install ripgrep on macOS, apt install ripgrep on Ubuntu) |
Claude Code (claude-sonnet-4-6) is the primary development agent for this
repository. Codex handles releases and production stabilization. Jules handles
small automated fixes and dependency updates. GitHub Copilot provides
development support.
Claude Code, Codex, and Copilot do not create git commits by default. Jules may
commit only bounded automated maintenance when the JULES.md scope and
validation gates pass. Final commit, merge, release, tag, and publishing
authority remains with Bradley Potts.
Protected from automated change: the Golden Rule (CMS delivers, design system defines -- no local token overrides or hardcoded values), PHP template structure, and the starter-theme boundary (no client-specific identities or brand values in templates). See AGENTS.md for full agent governance and boundary rules.
PHCDevworks maintains this package as part of the Spectre system.
When contributing:
- treat
spectre-theme/template files as structural -- no visual ownership - keep CSS token-driven using
var(--sp-*)only - never hand-edit
spectre-theme/dist/-- runnpm run buildinstead - run
npm run checkas the full validation gate before opening a pull request - keep version metadata synchronized across
package.json,spectre-theme/style.css, andspectre-theme/readme.txt
See CONTRIBUTING.md for the full workflow.
MIT © PHCDevworks. See LICENSE.