Skip to content

Demo Project

studiometa/foehn-demo is every feature Føhn ships, in one working WordPress theme.

It exists to be read and to be run. It is also what the framework's end-to-end tests run against, so every attribute in it is exercised against a real WordPress rather than against function stubs — which means the examples here are known to work, not merely known to compile.

Starting a project? Use the starter instead. It is the same theme with the demonstrations taken out.

Running it

bash
composer create-project studiometa/foehn-demo foehn-demo
cd foehn-demo
ddev start
ddev launch

Admin at /wp/wp-admin, with admin / admin.

What is demonstrated where

AttributeFile
#[AsPostType]app/Models/Product.php, app/Models/Testimonial.php
#[AsPostMeta]app/Models/Product.phpprice, sale_price
#[AsTaxonomy]app/Taxonomies/
#[AsBlock]app/Blocks/ — a container, a sidebar-driven one, a DTO one
#[AsBlockBinding]app/Bindings/ReadingTime.php
#[AsSettingsPage]app/Settings/ThemeSettings.php, with a Twig form
#[AsRewriteRule]app/Routes/HealthCheckRoute.phpGET /_health
#[AsTemplateController]app/Controllers/
#[AsContextProvider]app/ContextProviders/
#[AsImageSize]app/ImageSizes/
#[AsMenu]app/Menus/
#[AsAction] / #[AsFilter]app/Hooks/ThemeHooks.php
Arrayable DTOsapp/Data/HeroContext.php

The theme's namespace is Demo\ rather than App\, which is the only thing in it you would not copy: App\ is what the starter uses and what a project of your own should.

What is not here

ACF. It needs ACF Pro, a paid plugin CI cannot install, so an ACF block here would be a path nothing ever runs — which is exactly what it was before the integration moved out. studiometa/foehn-acf carries its own examples.

The tests are the point

bash
composer test:demo                            # the PHP suite
npm run -w @studiometa/foehn-demo test:run    # browser tests
./tests/smoke/run.sh                          # against a started ddev

tests/smoke/ is what makes this package worth having. The PHP suites run against WordPress function stubs, so a discovery that registers nothing at all still passes them — on 2026-08-19 that was 1409 passing tests and a fatal error on every front-end page of the site.

The smoke test drives real requests against a real WordPress and asserts inside it: that the post types exist, that the meta is registered against the right subtype, that a bound block renders its computed value, that GET /_health reaches its handler, that the settings page appears under Appearance. CI runs it twice per change, on a cold discovery cache and again on a warm one, because restoring items and scanning them are different code paths.

Every assertion in it was checked to fail when its feature is removed. An assertion that cannot fail is worse than none.

Released under the MIT License.