oofbar / craft-twig-toolbox
创建自己的 Twig 辅助工具。
Requires
- craftcms/cms: ^4.0.0 || ^5.0.0
README
将业务逻辑从您的 Twig 模板中分离出来的最简单方法。
此插件所做的只是注册一个 Twig 扩展——其余的都由您自己决定!使用 Twig Toolbox,您终于可以开始清理每个模板顶部的混乱...
用法
Twig Toolbox 允许您将自定义过滤器、函数、全局变量和测试注入到 Craft 的模板引擎中。
要开始使用,请从 Craft 插件商店安装插件,或使用 Composer
composer require oofbar/craft-twig-toolbox php craft plugins/install twig-toolbox
然后,将以下内容复制到 config/twig-toolbox.php
<?php return [ 'filters' => [], 'functions' => [], 'globals' => [], 'tests' => [], ];
💡 如果你想挑战自己,编写 自己的 Twig 扩展 是了解自定义模块开发的好方法。
让我们看看每个语言特性如何使用的一些示例。
过滤器
→ 关于 Twig 过滤器 的文档
filters
键应包含字母数字键,其值可以是 函数 或 可调用。过滤器 始终 至少有一个参数!
示例
<?php return [ 'filters' => [ 'salePrice' => function(float $price): float { return $price * 0.9; }, ], ];
<div class="product"> <div class="sku">{{ product.sku }}</div> <span class="price price--default">{{ product.price | money }}</span> <span class="price price--members">{{ product.price | salePrice | money }}</span> </div>
函数
→ 关于 Twig 函数 的文档
functions
数组中的每个项目都应该有一个字母数字键,以及一个 函数 作为其值。函数需要声明预期的参数,并在适当的情况下明确返回一个值。
😄 您可以在函数中使用几乎任何 Craft API!
示例
<?php return [ 'functions' => [ 'getDeals' => function(): array { return Entry::find() ->section('products') ->onSale(true) ->all(); }, 'log' => function(mixed $message): void { Craft::getLogger()->log($message); }, ], ];
{# Use to fetch data for a loop... #} {% for deal in getDeals() %} <div class="deal"> <div class="title">{{ deal.title }}</div> <div class="expiry">{{ deal.saleEndDate | date('short') }}</div> </div> {% else %} {# ...or just do something silently! #} {% do log('We didn’t show a user any deals!') %} <div class="empty">Sorry, there is nothing on sale right now.</div> {% endfor %}
全局变量
→ 关于 Twig 全局变量 的文档
全局变量最好少用,并且只用于简单的值。Craft 4 中的新 自定义配置 几乎是等效的!
⚠️ 注意您分配给全局变量的内容!调用某些 Craft 或插件 API 可能会在系统初始化时导致竞争条件。
示例
<?php return [ 'globals' => [ 'cutoffTime' => (new \DateTime)->modify('midnight'), ], ];
<h2>Prices are valid until {{ cutoffTime | date }}!</h2>
测试
→ 关于 Twig 测试 的文档
测试有点像函数,但仅在使用 Twig 的 is
操作符时可用。它们可以极大地提高模板的可读性——尤其是当逻辑很复杂时。
示例
<?php use craft\elements\User; return [ 'tests' => [ 'expensive' => function(float $value): bool { return $value > 10.0; }, 'member' => function(User $user): bool { return $user->isInGroup('members'); }, ], ];
{% set image = product.image.one() %} {% if product.price is expensive %} <img src="{{ image.url }}" class="shiny-effect"> {% else %} <img src="{{ image.url }}"> {% endif %}
技巧 + 技巧
可调用
PHP 有一个特殊的“类型”用于 可调用 值。这包括我们之前使用的匿名函数或“闭包”,以及一些使添加代理到原生 PHP 和 Craft 函数变得简单的其他语法。
use craft\helpers\Number; return [ 'filters' => [ // Built-in PHP functions: 'chunk' => 'array_chunk', // Craft helper proxy: 'roman' => [Number::class, 'upperRoman'], ], ];
处理类型
一些上述功能可以通过接受特殊的 mixed
类型或联合类型来变得更加灵活。例如,expensive
测试可以像这样进行一些类型检查和标准化...
<?php use craft\elements\Entry; return [ 'tests' => [ 'expensive' => function(float|Entry $value): bool { // Normalize an Entry into a scalar field value: if ($value instanceof Entry) { $value = $value->price; } return $value > 10.0; }, ], ];
...然后,模板可以读取得更加流畅
{% if product is not expensive %} <button>Buy two!</button> {% endif %}
参数化
filters
和 functions
可以接受参数来定制它们的行为。如果你发现自己正在添加许多类似的辅助工具,请花点时间考虑如何使用一个或多个参数将它们合并和参数化。
HTML 辅助工具
考虑一下,Twig 如何帮助你生成 HTML,而不是试图自己构建它!
<?php return [ 'functions' => [ 'bem' => function(string $base, array $flags): string { $classNames = [$base]; // Create BEM-style class names, ignoring empty flags: foreach (array_filter($flags) as $flag) { $classNames[] = "{$base}--{$flag}"; } return join(' ', array_unique($classNames)); }, ], ];
<div class="{{ bem('product', [ product is expensive ? 'expensive' : null, currentUser is member ? 'member-pricing' : null, ]) }}"> {{ product.title }} </div>
帮助 + 支持
如果你在开始时遇到困难,请在 GitHub 上创建一个问题,我们会尽力帮助你!如果你需要关于特定项目任务的支持(如找到合适的 Craft API),我们建议你在 更广泛的社区 中提出。