You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何扩展Timber实现以句柄引用模板的Include功能?

Great question! I’ve worked on similar Timber/Twig setups before, so here’s how you can replicate Fractal’s convenient @handle include shortcut to clean up your template code:

Core Idea

We’ll create a custom Twig extension that intercepts {% include %} calls, detects when you’re using an @-prefixed handle, and maps it to the full path of your component template. This works seamlessly with Timber since it’s built on top of Twig.


Step 1: Build the Twig Extension

Add this code to your WordPress theme’s functions.php file or a custom plugin—it overrides Twig’s default include parser to handle @handles:

class FractalStyleHandleExtension extends \Twig\Extension\AbstractExtension {
    private $timber;

    public function __construct(\Timber\Timber $timber) {
        $this->timber = $timber;
    }

    public function getTokenParsers() {
        return [
            new class extends \Twig\TokenParser\IncludeTokenParser {
                public function parse(\Twig\Token $token) {
                    // Parse the original include expression
                    $expr = $this->parser->getExpressionParser()->parseExpression();
                    
                    // Check if we're dealing with an @handle
                    if ($expr instanceof \Twig\Node\Expression\ConstantExpression && str_starts_with($expr->getAttribute('value'), '@')) {
                        $handle = ltrim($expr->getAttribute('value'), '@');
                        // Map the handle to your component's template path
                        // Adjust this pattern to match your project's structure
                        $templatePath = "templates/components/{$handle}/{$handle}.twig";
                        
                        // Replace the @handle with the full path
                        $expr = new \Twig\Node\Expression\ConstantExpression($templatePath, $token->getLine());
                    }

                    // Handle remaining include logic (variables, only, ignore missing)
                    $variables = null;
                    $only = false;
                    $ignoreMissing = false;

                    if ($this->parser->getStream()->nextIf(\Twig\Token::NAME_TYPE, 'with')) {
                        $variables = $this->parser->getExpressionParser()->parseExpression();
                    }

                    if ($this->parser->getStream()->nextIf(\Twig\Token::NAME_TYPE, 'only')) {
                        $only = true;
                    }

                    if ($this->parser->getStream()->nextIf(\Twig\Token::NAME_TYPE, 'ignore missing')) {
                        $ignoreMissing = true;
                    }

                    $this->parser->getStream()->expect(\Twig\Token::BLOCK_END_TYPE);

                    return new \Twig\Node\IncludeNode($expr, $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
                }
            }
        ];
    }

    public function getName() {
        return 'fractal_style_handle_extension';
    }
}

// Register the extension with Timber
add_filter('timber/twig', function($twig) {
    $twig->addExtension(new FractalStyleHandleExtension(new \Timber\Timber()));
    return $twig;
});

Step 2: Customize Path Mappings (Optional)

If your component paths don’t follow a strict handle/handle.twig pattern (like your example where @basicteaser maps to templates/components/teaser/basicTeaser.twig), add a lookup array to handle exceptions:

Inside the parse() method, replace the $templatePath line with this:

// Define custom handle-to-path mappings
$handleMappings = [
    'basicteaser' => 'templates/components/teaser/basicTeaser.twig',
    'featured-card' => 'templates/components/cards/featured.twig',
    // Add more mappings as needed
];

// Use custom mapping if available, else fall back to default pattern
$templatePath = isset($handleMappings[$handle]) 
    ? $handleMappings[$handle] 
    : "templates/components/{$handle}/{$handle}.twig";

Step 3: Use the @handle Shortcut

Now you can clean up your includes just like in Fractal:

{# Before: long path #}
{% include 'templates/components/teaser/basicTeaser.twig' %}

{# After: clean @handle #}
{% include '@basicteaser' %}

{# Works with variables too! #}
{% include '@featured-card' with {title: 'My Featured Card', image: post.thumbnail} only %}

Key Notes

  • Handle Uniqueness: Just like Fractal, this relies on your component handles being unique—avoid duplicate @handles to prevent path conflicts.
  • Template Locations: Make sure your component paths align with where Timber searches for templates. If you’ve customized template directories via the timber/twig/template_dirs filter, adjust the $templatePath values accordingly.
  • Error Handling: For production, you might want to add checks for missing templates (e.g., throw a warning if the mapped path doesn’t exist) to catch typos early.

内容的提问来源于stack exchange,提问作者Sascha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:50:11