studiometa / foehn
🍃 A modern WordPress framework powered by Tempest, featuring attribute-based auto-discovery for hooks, post types, blocks, and more.
Installs: 2
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 1
pkg:composer/studiometa/foehn
Requires
- php: ^8.4
- tempest/framework: ^2.14
- timber/timber: ^2.0
Requires (Dev)
- carthage-software/mago: 1.4.1
- pestphp/pest: ^3.0
- php-stubs/acf-pro-stubs: ^6.5
- php-stubs/wordpress-stubs: *
- php-stubs/wp-cli-stubs: ^2.12
- stoutlogic/acf-builder: ^1.12
This package is auto-updated.
Last update: 2026-02-04 23:21:03 UTC
README
A modern WordPress framework powered by Tempest, featuring attribute-based auto-discovery for hooks, post types, blocks, and more.
Warning
AI-Generated Project — This project was primarily built by AI coding agents (Claude). While functional and tested, it may contain bugs, security issues, or unexpected behavior. Use at your own risk, especially in production environments.
Features
- 🚀 Zero configuration - Auto-discovery of components via PHP 8 attributes
- 🎯 Modern DX - Type-safe, IDE-friendly, testable
- 🔌 WordPress native - Works with Timber, ACF, and Gutenberg blocks
- ⚡ Minimal boilerplate - One line to boot your theme
Requirements
- PHP 8.4+
- WordPress 6.4+
- Composer
Installation
composer require studiometa/foehn
Quick Start
1. Boot the kernel
<?php // functions.php use Studiometa\Foehn\Kernel; Kernel::boot(__DIR__ . '/app');
2. Create a post type
<?php // app/Models/Product.php namespace App\Models; use Studiometa\Foehn\Attributes\AsPostType; use Timber\Post; #[AsPostType( name: 'product', singular: 'Product', plural: 'Products', public: true, hasArchive: true, menuIcon: 'dashicons-cart', )] final class Product extends Post { public function price(): ?float { return $this->meta('price') ? (float) $this->meta('price') : null; } }
3. Register hooks
<?php // app/Hooks/ThemeHooks.php namespace App\Hooks; use Studiometa\Foehn\Attributes\AsAction; use Studiometa\Foehn\Attributes\AsFilter; final class ThemeHooks { #[AsAction('after_setup_theme')] public function setupTheme(): void { add_theme_support('post-thumbnails'); add_theme_support('title-tag'); } #[AsFilter('excerpt_length')] public function excerptLength(): int { return 30; } }
4. Create an ACF block
<?php // app/Blocks/Hero/HeroBlock.php namespace App\Blocks\Hero; use Studiometa\Foehn\Attributes\AsAcfBlock; use Studiometa\Foehn\Contracts\AcfBlockInterface; use StoutLogic\AcfBuilder\FieldsBuilder; #[AsAcfBlock( name: 'hero', title: 'Hero Banner', category: 'layout', icon: 'cover-image', )] final readonly class HeroBlock implements AcfBlockInterface { public function __construct( private ViewEngineInterface $view, ) {} public static function fields(): FieldsBuilder { return (new FieldsBuilder('hero')) ->addWysiwyg('content') ->addImage('background'); } public function compose(array $block, array $fields): array { return [ 'content' => $fields['content'] ?? '', 'background' => $fields['background'] ?? null, ]; } public function render(array $context): string { return $this->view->render('blocks/hero', $context); } }
Available Attributes
| Attribute | Description |
|---|---|
#[AsAction] |
Register a WordPress action hook |
#[AsFilter] |
Register a WordPress filter hook |
#[AsPostType] |
Register a custom post type |
#[AsTaxonomy] |
Register a custom taxonomy |
#[AsBlock] |
Register a native Gutenberg block |
#[AsAcfBlock] |
Register an ACF block |
#[AsBlockPattern] |
Register a block pattern |
#[AsViewComposer] |
Add data to specific views |
#[AsTemplateController] |
Handle template rendering |
#[AsShortcode] |
Register a shortcode |
#[AsRestRoute] |
Register a REST API endpoint |
#[AsCliCommand] |
Register a WP-CLI command |
#[AsTimberModel] |
Register a Timber class map |
Documentation
Contributing
Contributions are welcome! Please read our contributing guidelines before submitting a PR.
License
MIT License - see LICENSE for details.
Credits
- Tempest Framework by Brent Roose
- Timber by Upstatement
- Inspired by Acorn by Roots