Skip to content

ContextProviderInterface

Interface for context providers that add data to templates.

Signature

php
<?php

namespace Studiometa\Foehn\Contracts;

use Studiometa\Foehn\Views\TemplateContext;

interface ContextProviderInterface
{
    /**
     * Provide additional data for the view context.
     *
     * @param TemplateContext $context Current template context
     * @return TemplateContext Modified context with additional data
     */
    public function provide(TemplateContext $context): TemplateContext;
}

Methods

provide(TemplateContext $context)

Receives the current template context and returns a modified context with additional data. The context is immutable - use with(), merge(), or withDto() to add data.

php
public function provide(TemplateContext $context): TemplateContext
{
    // Add new data (immutable)
    return $context
        ->with('site_name', get_bloginfo('name'))
        ->with('related_posts', $this->getRelatedPosts($context->post));
}

TemplateContext API

The TemplateContext object provides typed access and immutable updates:

php
// Typed properties
$context->post;   // ?Post
$context->posts;  // ?PostCollectionInterface
$context->site;   // Site
$context->user;   // ?User

// Post type casting
$product = $context->post(Product::class); // ?Product

// Dynamic keys
$context->get('key');           // mixed
$context->get('key', 'default'); // with default
$context->has('key');           // bool

// Immutable updates
$context = $context->with('key', $value);
$context = $context->merge(['a' => 1, 'b' => 2]);
$context = $context->withDto($myDto);

Usage

php
<?php

namespace App\ContextProviders;

use Studiometa\Foehn\Attributes\AsContextProvider;
use Studiometa\Foehn\Contracts\ContextProviderInterface;
use Studiometa\Foehn\Views\TemplateContext;

#[AsContextProvider('*')]
final class GlobalContextProvider implements ContextProviderInterface
{
    public function provide(TemplateContext $context): TemplateContext
    {
        return $context
            ->with('current_year', date('Y'))
            ->with('is_home', is_front_page());
    }
}

With Dependency Injection

php
<?php

namespace App\ContextProviders;

use App\Services\CartService;
use Studiometa\Foehn\Attributes\AsContextProvider;
use Studiometa\Foehn\Contracts\ContextProviderInterface;
use Studiometa\Foehn\Views\TemplateContext;

#[AsContextProvider('*')]
final class CartContextProvider implements ContextProviderInterface
{
    public function __construct(
        private readonly CartService $cart,
    ) {}

    public function provide(TemplateContext $context): TemplateContext
    {
        return $context->with('cart', [
            'count' => $this->cart->getItemCount(),
            'total' => $this->cart->getTotal(),
        ]);
    }
}

With Post Type Casting

php
use App\Models\Product;

#[AsContextProvider('single-product')]
final class ProductContextProvider implements ContextProviderInterface
{
    public function provide(TemplateContext $context): TemplateContext
    {
        $product = $context->post(Product::class);

        if (!$product) {
            return $context;
        }

        return $context
            ->with('related', $product->relatedProducts(4))
            ->with('categories', $product->categories());
    }
}

With Typed DTO

php
use Studiometa\Foehn\Contracts\Arrayable;
use Studiometa\Foehn\Concerns\HasToArray;

final readonly class ArchiveData implements Arrayable
{
    use HasToArray;

    public function __construct(
        public int $foundPosts,
        public int $currentPage,
    ) {}
}

#[AsContextProvider('archive-*')]
final class ArchiveContextProvider implements ContextProviderInterface
{
    public function provide(TemplateContext $context): TemplateContext
    {
        return $context->withDto(new ArchiveData(
            foundPosts: WP::query()->found_posts,
            currentPage: max(1, get_query_var('paged')),
        ));
    }
}

Released under the MIT License.