1. Go to this page and download the library: Download studiometa/foehn library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
studiometa / foehn example snippets
declare(strict_types=1);
use Studiometa\Foehn\Kernel;
Kernel::boot(__DIR__ . '/app');
use Studiometa\Foehn\Attributes\AsAction;
use Studiometa\Foehn\Attributes\AsFilter;
final class ThemeHooks
{
#[AsAction('after_setup_theme')]
public function setup(): void
{
add_theme_support('post-thumbnails');
add_theme_support('title-tag');
}
#[AsFilter('excerpt_length')]
public function excerptLength(): int
{
return 30;
}
}
use Studiometa\Foehn\Attributes\AsPostType;
use Studiometa\Foehn\Models\Post;
#[AsPostType(
name: 'product',
singular: 'Product',
plural: 'Products',
public: true,
hasArchive: true,
menuIcon: 'dashicons-cart',
supports: ['title', 'editor', 'thumbnail'],
)]
final class Product extends Post
{
public function price(): ?float
{
return $this->meta('price') ? (float) $this->meta('price') : null;
}
}
use Studiometa\Foehn\Attributes\AsTaxonomy;
#[AsTaxonomy(
name: 'product_category',
singular: 'Category',
plural: 'Categories',
postTypes: ['product'],
hierarchical: true,
)]
final class ProductCategory {}
use Studiometa\Foehn\Attributes\AsAcfBlock;
use Studiometa\Foehn\Contracts\AcfBlockInterface;
use Studiometa\Foehn\Contracts\ViewEngineInterface;
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'))
->addImage('background')
->addWysiwyg('content')
->addLink('cta');
}
public function compose(array $block, array $fields): array
{
return [
'background' => $fields['background'] ?? null,
'content' => $fields['content'] ?? '',
'cta' => $fields['cta'] ?? null,
];
}
public function render(array $context, bool $isPreview = false): string
{
return $this->view->render('blocks/hero', $context);
}
}
use Studiometa\Foehn\Concerns\HasToArray;
use Studiometa\Foehn\Contracts\Arrayable;
use Studiometa\Foehn\Data\ImageData;
use Studiometa\Foehn\Data\LinkData;
final readonly class HeroContext implements Arrayable
{
use HasToArray;
public function __construct(
public string $title,
public ?ImageData $background = null,
public ?LinkData $cta = null,
public string $height = 'medium',
) {}
}
public function compose(array $block, array $fields): HeroContext
{
return new HeroContext(
title: $fields['title'] ?? '',
background: ImageData::fromAttachmentId($fields['background'] ?? null),
cta: LinkData::fromAcf($fields['cta_link'] ?? null),
height: $fields['height'] ?? 'medium',
);
}
use Studiometa\Foehn\Attributes\AsBlock;
use Studiometa\Foehn\Contracts\InteractiveBlockInterface;
use WP_Block;
#[AsBlock(
name: 'theme/accordion',
title: 'Accordion',
category: 'widgets',
interactivity: true,
)]
final readonly class AccordionBlock implements InteractiveBlockInterface
{
public static function attributes(): array
{
return [
'items' => ['type' => 'array', 'default' => []],
'allowMultiple' => ['type' => 'boolean', 'default' => false],
];
}
public static function initialState(): array
{
return [];
}
public function initialContext(array $attributes): array
{
return [
'openItems' => [],
'allowMultiple' => $attributes['allowMultiple'] ?? false,
];
}
public function render(array $attributes, string $content, WP_Block $block): string
{
// ...
}
}
use Studiometa\Foehn\Attributes\AsContextProvider;
use Studiometa\Foehn\Contracts\ContextProviderInterface;
#[AsContextProvider(templates: ['single', 'single-*'])]
final readonly class SingleContext implements ContextProviderInterface
{
public function provide(array $context): array
{
$post = $context['post'] ?? null;
$context['reading_time'] = $this->calculateReadingTime($post->content());
$context['related_posts'] = $this->getRelatedPosts($post);
return $context;
}
}
use Studiometa\Foehn\Attributes\AsTemplateController;
use Studiometa\Foehn\Contracts\ViewEngineInterface;
use Timber\Timber;
#[AsTemplateController('single', 'single-*')]
final readonly class SingleController
{
public function __construct(
private ViewEngineInterface $view,
) {}
public function __invoke(): string
{
$context = Timber::context();
return $this->view->renderFirst([
"pages/single-{$context['post']->post_type}",
'pages/single',
], $context);
}
}
use Studiometa\Foehn\Attributes\AsBlockPattern;
use Studiometa\Foehn\Contracts\BlockPatternInterface;
#[AsBlockPattern(
name: 'theme/hero-full-width',
title: 'Hero Full Width',
categories: ['heroes'],
)]
final readonly class HeroFullWidth implements BlockPatternInterface
{
public function compose(): array
{
return [
'heading' => __('Welcome', 'theme'),
'cta_text' => __('Learn more', 'theme'),
];
}
}
use Studiometa\Foehn\Attributes\AsRestRoute;
use WP_REST_Request;
final class ProductsApi
{
#[AsRestRoute('theme/v1', '/products', methods: ['GET'])]
public function index(WP_REST_Request $request): array
{
return ['products' => []];
}
#[AsRestRoute('theme/v1', '/products/(?P<id>\d+)', methods: ['GET'])]
public function show(WP_REST_Request $request): array
{
return ['product' => []];
}
}
use Studiometa\Foehn\Attributes\AsShortcode;
final class ButtonShortcode
{
#[AsShortcode('button')]
public function render(array $atts, ?string $content = null): string
{
$atts = shortcode_atts([
'url' => '#',
'style' => 'primary',
], $atts);
return sprintf(
'<a href="%s" class="btn btn--%s">%s</a>',
esc_url($atts['url']),
esc_attr($atts['style']),
esc_html($content)
);
}
}
use Studiometa\Foehn\Attributes\AsAction;
final readonly class NewsletterHooks
{
public function __construct(
private NewsletterService $newsletter,
private LoggerInterface $logger,
) {}
#[AsAction('user_register')]
public function onUserRegister(int $userId): void
{
$user = get_user_by('id', $userId);
$this->newsletter->subscribe($user->user_email);
$this->logger->info('User subscribed to newsletter', ['user_id' => $userId]);
}
}