Skip to content

Project Structure

A high-level map of what lives where and why.

  • Directorylumbermill/
    • Directoryacf-php/ ACF field group definitions (PHP)
    • Directoryapp/ Theme PHP application code
    • Directoryassets/src/ Frontend source files (JS, SCSS, fonts, images)
    • Directoryconfig/ Developer-facing configuration
    • Directorytemplates/ WordPress page templates (selectable in admin)
    • Directorytranslations/ JSON translation files (one per locale)
    • Directoryviews/ Twig templates
    • functions.php Theme bootstrap
    • front-page.php Front page WordPress template
    • page.php Default page WordPress template
    • single.php Single post WordPress template

All ACF field groups are defined in PHP here. Organise by context — each subfolder maps to a part of WordPress.

  • Directoryacf-php/
    • Directoryglobal/ Fields attached to all post types (e.g. featured image)
    • Directorypages/ Fields for specific WordPress pages (e.g. front-page)
    • Directorypost-types/ Fields for custom post types
    • Directorytemplates/ Fields for page templates
    • Directoryoption-pages/ Fields for ACF options pages
    • Directoryflex/ Flexible content layout definitions
    • Directoryhelpers/ Shared utilities (loadFieldGroup, advanced-link, etc.)
    • index.php Entry point — autoloads every nested index.php

See the ACF guide for how to create field groups.


PHP application code. Everything here is autoloaded under the App\ namespace.

  • Directoryapp/
    • DirectoryCache/ Cache driver implementations
    • DirectoryClassmap/ Timber class extensions (Post, Term, Menu, MenuItem)
    • DirectoryConstant/ String constants — PostTypeConstant, TaxonomyConstant, etc.
    • DirectoryEnum/ PHP enums
    • DirectoryHook/ WordPress hooks and filters
    • DirectoryLib/ Framework internals — do not modify
    • DirectoryUtil/ Reusable utility classes

Where does new code go?

What you’re buildingFolder
WordPress hook / filterapp/Hook/
Extending a Timber post/term/menuapp/Classmap/
A reusable helperapp/Util/
A post type or taxonomy slugapp/Constant/
An AJAX actionapp/Ajax/Action/ (see Ajax)
A REST endpointapp/RestAPI/ (see REST API)

Frontend source files processed by Vite.

  • Directoryassets/src/
    • Directoryjs/
      • Directorylib/ Shared JS utilities and helpers
      • Directorymodules/ Feature-specific JS modules
      • Directoryvendor/ Third-party scripts not managed by npm
      • site.js Main entrypoint
    • Directoryscss/
      • Directoryabstracts/ Variables, mixins, functions
      • Directorybase/ Reset, typography, global styles
      • Directorylayout/ Grid, containers, structural styles
      • Directorypages/ Page-specific styles
      • Directorypartials/ Component styles
      • Directoryvendor/ Third-party CSS overrides

Plain PHP arrays that control theme behaviour. Every file has a corresponding provider that acts on it at boot time. See the Config section for a full reference of each file.


WordPress page templates — selectable from the WordPress admin when editing a page. Each file here passes data to a Twig template in views/templates/.

See Page Templates for the full workflow.


All Twig templates. Never called directly — always rendered via Timber::render() in a PHP template.

  • Directoryviews/
    • Directorylayouts/ Base HTML layouts (base.twig)
    • Directorypartials/ Reusable includes (header, footer, head, buttons, images)
    • Directorytemplates/ Page-level templates, one per PHP template

The theme bootstrap. Loads config files and boots providers. The only things that belong here are:

  • Custom providers: $config->addProvider(new MyProvider);
  • Custom provider overrides: $config->replaceProvider(ThemeProvider::class, new MyThemeProvider);

Everything else should live in a provider or a hook class.