Repository navigation
Theme shell extensibility and distribution
Contract change type: breaking
Added
- Added
spectre-theme/LICENSE.txt(full GPL-2.0-or-later text) and
spectre-theme/NOTICE.txt(MIT attribution for bundled Spectre packages)
so the deployable WordPress theme package carries its own license
independently of the MIT-licensed repository. - Added
npm run package:theme, which assembles a marketplace-ready
spectre-theme.zipfrom thespectre-theme/directory. - Added
npm run check:license(part ofnpm run check), which fails the
build if repository license metadata, theme metadata, or theme license
notices drift from the MIT repo / GPL-2.0-or-later theme package boundary. - Added
spectre_base_register_cascade_layers()infunctions.php, which
unconditionally establishes thewp-global-stylescascade-layer order
(below Spectre'scomponents/utilitieslayers) on every request via a
src-less style handle, independent of the Vite manifest, dev/prod asset
mode, and whether WordPress has global-styles content to wrap. Documented
the resulting@layer wp-global-styles { ... }contract in README.md
"Adding custom shell styles" so a child theme's own global heading CSS
(e.g. plainh1-h6rules instyle.css) can opt into the same
precedence guarantee as the parent theme's compiledtheme.jsonheading
defaults, without overriding an explicit<sp-text level="h1" size="*">
recipe or requiring the child theme to target[data-sp-text-native],
.sp-text, or another rendered implementation detail. - Added regression coverage in
scripts/check-style-precedence.ts(run via
npm run check:styles, part of thewordpress-smoke.ymlCI workflow)
confirming a child theme's own CSS wrapped in@layer wp-global-styles
still loses to an explicit Spectre text recipe even when WordPress's
global-styleshandle has no content to wrap on that request. - Redesigned
footer.phpas a marketplace-ready four-column footer: a brand
column (site logo/title, tagline, social icons, and inline contact info)
and three nav columns (newfooter-secondaryandfooter-tertiarymenu
locations alongside the existingfooterlocation, each rendered via
spectre_base_footer_nav_column()). Contact details come from the
spectre_base_footer_contact_itemsfilter, rendered inline in the brand
column viaspectre_base_footer_contact_info()rather than as their own
grid column. Columns lay out via<sp-grid columns="4">(collapsing
responsively to one column on mobile) using only existingspectre-ui
footer recipe classes (sp-footer__heading,sp-footer__text,
sp-footer__muted,sp-footer__links,sp-footer__link,
sp-footer__chip,sp-footer__divider) -- no new design values. The
copyright bar now surfaces a Privacy Policy link automatically via
WordPress core'sget_privacy_policy_url()when a privacy policy page is
configured. A nav column with no menu assigned is simply omitted. - Added filter hooks
spectre_base_footer_secondary_nav_args,
spectre_base_footer_tertiary_nav_args,spectre_base_footer_nav_heading,
andspectre_base_footer_contact_items, documented in README.md "PHP Hook
API" alongside the existing footer hooks. - Added header and footer extension seams so a child theme can drop its
header.php/footer.phpforks and keep the shell's skip link and main
landmark. Sites that use none of them render the same markup as before.spectre_base_site_brandingandspectre_base_primary_navfilters:
return a markup string to replace the branding or primary-nav contents
(for example a bundled logo, or top-level items rendered as
<sp-dropdown mega>). The region wrappers and the branding actions stay.spectre_base_header_actionsaction: a slot after the primary nav for a
header CTA.spectre_base_header_layoutfilter:inline(default) or
edge-fluid-edge, a three-region branding/nav/actions grid on
spectre-ui'ssp-grid-template--edge-fluid-edgeutility.spectre_base_header_container_classfilter: utility classes for the
header container's inner element.sp-relativemakes the container the
anchor for mega panels.spectre_base_main_startaction: fires first inside
<main id="spectre-main-content">in every public template, so a page
hero renders inside the landmark without the child opening<main>.spectre_base_footer_surface(page|card|subtle|inverse|
hero) andspectre_base_footer_appearance(dark|light|
system) filters, passed to thespectre-components1.22.0sp-footer
surfaceandappearanceoptions. The child no longer has to select
.sp-footeror[data-sp-footer-native].spectre_base_iconfilter andspectre_base_icon()helper: an icon
provider for footer social and contact icons. The spectre-icons
shortcode stays the default provider, and a child can return its own
markup (such as a bundled inline SVG) without the plugin.
npm run check:driftnow enforces the 8px layout grid (owner-confirmed
2026-10-03). It fails onsp-*padding, margin, gap, and space utilities
(including responsive prefixes) and--sp-space-*references whose step is
not 0, 4, or a multiple of 8. README.md "8px Layout Grid" documents the
rule, thexl-4xllayout steps, and thesp-sectionhero/attached
options.
Changed
-
Raised the Spectre dependency ranges to
@phcdevworks/spectre-tokens
^4.12.0,@phcdevworks/spectre-ui^5.4.0, and
@phcdevworks/spectre-components^1.22.0. -
Social icons no longer require the spectre-icons plugin: the row renders
each entry that some icon provider (the plugin shortcode or the
spectre_base_iconfilter) has markup for, and skips the rest. -
Replaced the off-grid
sp-12andsp-20block editor spacing presets in
theme.jsonwithsp-64,sp-80, andsp-96. Content that used the
removed presets loses that spacing value and needs a new preset picked in
the editor. -
Standardized the package summary against the approved PHCDevworks product
description. -
Documented the MIT (repository/framework) vs. GPL-2.0-or-later (deployable
spectre-theme/package) licensing boundary in the root and theme
README.mdfiles. -
Updated the pinned GitHub Actions major versions used by the CI, dependency
report, and WordPress smoke workflows:actions/checkoutv4 to v7 and
actions/setup-nodev4 to v7.shivammathur/setup-phpstays on v2, which is
still its current major. -
Updated
scripts/create-child-theme.tsto include a commented example of
the@layer wp-global-stylescontract in the generated child theme
style.css. -
Added block editor canvas spacing: the post title and content are
centered at the container max width with inline padding, and the title is
separated from the body by a--sp-surface-dividerrule and a
--sp-space-32gap. Rules are scoped to.editor-styles-wrapperin
src/styles/main.cssand do not affect the front end. -
Rebuilt the footer on the
spectre-components1.21.0 /spectre-ui5.3.0
footer contract:<sp-footer>is nowborderedwith a brand top accent
rail (newspectre_base_footer_accent/spectre_base_footer_accent_color
filters), the grid is sized to the columns actually rendered so missing
nav menus no longer leave empty columns, the current page's footer link
gets thesp-footer__link--activestate, and the copyright bar splits into
the copyright notice (left) and a newspectre_base_footer_legal_links
filter (right, defaulting to the privacy policy link). Social icons gain a
labelaccessible name for icon-only links, and unlinked icons render as
<sp-footer-chip>. Social and legal-link rendering moved into
spectre_base_footer_social_icons()/spectre_base_footer_legal_links()
infunctions.php. -
Added a Footer menus Customizer setting (Appearance > Customize >
Footer, 1-4, default 3) that controls how many footer menu locations the
theme registers and renders, including a new fourthfooter-quaternary
location with its ownspectre_base_footer_quaternary_nav_argsfilter.
The footer grid now puts the brand column in the first third and the menu
columns in a nested grid across the remaining two thirds, since
sp-gridhas no five-column layout for brand plus four menus. -
Footer nav column headings now default to the assigned menu's name from
Appearance > Menus instead of the theme-authored "Explore",
"Services", and "Resources" labels, so no site content ships from the
theme.spectre_base_footer_nav_headingstill overrides it, and an empty
heading omits the heading element (the nav is then labelled by its menu
location). -
Added a site-wide Color Mode Customizer setting (Appearance >
Customize > Color Mode): Light (default), Dark, or System, which follows
each visitor's device setting and updates live. The theme sets
data-spectre-themeon<html>(server-side for Light/Dark, a pre-paint
inline script for System) plus a matching<meta name="color-scheme">,
so every Spectre component switches through its published mode-aware
tokens with no theme-defined colors. -
Every page now fills at least the full viewport height, so the header
sits at the top and the footer at the bottom even on short or empty pages:
<html>getssp-h-full,<body>getssp-min-h-full sp-flex sp-flex-col(via thebody_classfilter), and<sp-footer>gets
sp-mt-auto. Longer pages scroll as before. -
Removed card framing from every page template: single posts, post-list
items (content-card.php), the front page content, comments, the
previous/next post links, the 404 page, and sidebar widgets now render on
the page surface as plain<article>/<section>/<nav>elements instead
of<sp-card>. Comments share the post's.sp-content-flowmeasure. -
Restyled the site header to match the footer:
<sp-nav>is now full-width,
bordered, and sticky with a brand top accent rail (new
spectre_base_header_accent/spectre_base_header_accent_colorfilters),
its container spans the full layout width, primary menu links render with
thesp-nav__linkrecipe andsp-nav__link--activeon the current page,
and the site title uses thesp-heading--h6type preset. The primary menu
now renders top-level items only (depth1), and the no-menu fallback
lists pages with the same recipe classes and no duplicate Home link. -
Generalized the menu link-class hook to a
spectre_link_class
wp_nav_menu()arg, shared by the header and footer menus.
Fixed
- Fixed centered text in post, page, comment, and post-card content: their
sp-stacks now usealign="stretch"instead of the default reflected
align="center", which browsers treat as legacytext-align: center. - Fixed page and post titles rendering at body text size; they now use the
sp-textpreset="heading"scale, and on pages and single posts share the
.sp-content-flowmeasure with the body so they line up with it. - Fixed page content sitting flush against the header: each template's
<sp-container>now carriessp-py-32spacing. - Fixed an empty previous/next navigation block on single posts with no
adjacent post. - Fixed the site title rendering as an
<h1>on every page, duplicating each
template's own page-title<h1>; it is now a heading-styled link. - Fixed nested navigation landmarks: the primary menu no longer adds its own
<nav>inside the<sp-nav>landmark, which is now labelled "Primary". - Fixed the footer content shrinking to its intrinsic width at the left of
the page:.sp-footeris a flex row, so its<sp-container>child now
stretches via the footer'ssp-flex-col sp-items-stretchutilities. - Fixed footer text centering (link columns, and the copyright bar once it
wraps):sp-stackreflects its defaultalign="center"as an HTML
attribute, which browsers treat as legacytext-align: center. Footer
stacks now usealign="stretch". - Fixed the block editor loading none of the theme's CSS on hosts that
cannot reach their own public URL (e.g. Docker port mapping).
spectre_base_add_editor_styles()now passesadd_editor_style()a
theme-relative path, which WordPress reads from disk, instead of an
absolute URL, which the block editor fetches server-side via
wp_remote_get()and silently drops on failure -- leaving every
var(--sp-*)value intheme.jsonunresolved in the editor canvas.