The whole theme sorts into nine categories. Each has a one-line definition and a fixed home. Learn the nine and any file's purpose is legible from its path.
Everything front-end lives under resources/public/, split into the two mirrored halves
introduced in the Overview:
resources/public/
├── views/ ← PHP: markup
│ ├── modules/ Module views (kebab-case: intro.php)
│ ├── components/ Component views (kebab-case: content-stack.php)
│ ├── layouts/ Layout views (header-bar.php, footer-top.php)
│ ├── templates/ Template views (one-fold.php)
│ └── widgets/ Widget views (lightbox.php)
│
└── assets/ ← JS + SCSS: behaviour & style
├── modules/ Module assets (PascalCase folder: Intro/Intro.js + Intro.scss)
├── components/ Component assets (Border/, Image/, Navigation/…)
├── layouts/ Layout assets (HeaderBar/, Footer/, CookieComplianceBanner/…)
├── templates/ Template assets (OneFold/, SinglePost/)
├── global/ The two Globals (Crucial/, Deferred/)
├── utilities/ Utilities (Instantiable/, Traits/, AssetLoader/, Observers/…)
├── vendors/ Vendors (Splide/, Fancybox/, MapLibre/, FontAwesome/…)
└── lib/ Shared SCSS (rhythm.scss, animate.scss)
The nine categories
One line each; the fixed home for every one is in the tree above.
| Category | What it is | Examples |
|---|---|---|
| Global | One of two body-mounted orchestrators that own the two-phase boot — the kernel, exactly one of each, no view. |
Crucial, Deferred |
| Layout | Site chrome emitted by the page shell, gated only by global settings — a property of the site, not any one page. | HeaderBar, Footer, CookieComplianceBanner |
| Template | A WordPress page template that owns the module region — whether it exists and how Modules compose into it. | OneFold, SinglePost |
| Module | Top-level, author-placeable content block that owns a page region — an App\Modules\* class registered in config/modules.php, backed by an ACF group. |
Intro, Hero, Gallery, Reviews |
| Component | Reusable block rendered inside a Module via View::component(), never author-placeable; view-only or view + behaviour (a HasX trait lazy-loads the behaviour). |
content-stack, navigation, rich-media |
| Widget | A literal WordPress widget (the WP widget API), under views/widgets/ — distinct from a Component. |
lightbox |
| Utility | A JS primitive not tied to an element — the theme's standard library of cross-cutting logic, no view. | Instantiable, Traits, AssetLoader, Observers |
| Vendor | The single sanctioned thin lining around a third-party library, behind one import. | Splide, Fancybox, MapLibre |
| lib | Shared SCSS only — mixins, functions, variables; aliased lib/ in Vite, no JS. |
rhythm, animate |
The distinguishing question for the big four is authorial placeability. A Module is dropped into page content by an author. A Component is placed by a developer inside a Module. A Layout is site chrome the author only configures, never places. A Template owns the region Modules go into. Complexity and whether something ships JS are irrelevant to the category.
Colocation and naming
Two conventions hold everywhere:
- The view half and the asset half share a name. The Module rendered by
views/modules/intro.phphas its behaviour inassets/modules/Intro/. Find one, you know where the other is. - Views are kebab-case files; assets are PascalCase folders.
content-stack.phppairs withassets/components/ContentStack/. The asset folder holds the colocated.jsand.scssfor that one thing and nothing else.
widget means a WordPress widget here, nothing else. For a reusable UI piece inside a
Module, the word is Component — never "widget," "partial," or "element."
Related
- A page's life — how these pieces load and run together.
- Building Blocks — how to author each type in the taxonomy.
- Traits — how a Module composes many capabilities at once.