ttempleton/craft-nocache

一个用于在缓存块内避免缓存的Twig扩展

安装次数: 44 000

依赖项: 1

建议者: 0

安全: 0

星标: 46

关注者: 3

分支: 6

开放问题: 1

类型:craft-plugin

3.0.4 2024-09-24 09:31 UTC

This package is auto-updated.

Last update: 2024-09-24 09:32:55 UTC


README

Craft CMS的Twig扩展,用于在缓存块内避免缓存

{% cache %}
    This will be cached
    {% nocache %}
        This won't be
    {% endnocache %}
{% endcache %}

当禁用包含文件的缓存时,它也可以正常工作

{% cache %}
    This will be cached
    {% include 'template' %}
{% endcache %}

template.twig

{% nocache %}
    This won't be
{% endnocache %}

如果您需要在nocache标签外部引用变量,您需要传递一个上下文——这就像在传递变量时include标签的工作方式一样。请注意,您不必传递全局变量,例如craftcurrentUser,但您将不得不再次导入您的宏。

{% set variable = 5 %}
{% nocache with {x: variable} %}
    The following value should be 5: {{ x }}
{% endnocache %}

要求

No-Cache需要Craft CMS 4.0.0或更高版本。

安装

No-Cache可以从Craft Plugin Store或使用Composer安装。

Craft Plugin Store

打开您的项目控制面板,转到插件商店,搜索No-Cache并点击安装。

Composer

打开您的终端,转到您的项目根目录并运行以下命令

composer require ttempleton/craft-nocache

然后打开您的项目控制面板,转到设置→插件,找到No-Cache并点击安装。

示例:用户信息

假设您有一个产品列表,您想在页面上显示这些产品。在每个产品下面,您想要一个“添加到购物车”按钮。但是,您只想在用户登录时显示此按钮。不仅如此,如果用户已经在他们的购物车中有此按钮,您还想禁用该按钮。不幸的是,您正在每页输出20个产品及其图像,因此缓存列表似乎是个明智的选择。

{% cache %}
{% for product in craft.entries().section('products').limit(20).all() %}
    <article>
        <figure>{{ product.image.one().img }}</figure>
        <h1>{{ product.title }}</h1>
        {% if currentUser %}
            <button{{ currentUser.cart.id(product.id).count() > 0 ? ' disabled' }}>Add to cart</button>
        {% endif %}
    </article>
{% endfor %}
{% endcache %}

现在我们遇到了一个问题。围绕产品列表的缓存会导致currentUser逻辑几乎不起作用,因为它们将与产品一起被缓存。您不能通过将事物分开成多个缓存块来隔离用户逻辑,因为您在一个循环中,整个目的就是为了缓存获取产品条目的数据库调用。因此,您必须在JavaScript中应用您的用户检查(这远非理想),或者完全放弃缓存。

有了nocache标签,您可以非常容易地解决这个问题

{% cache %}
{% for product in craft.entries().section('products').limit(20).all() %}
    <article>
        <figure>{{ product.image.one().img }}</figure>
        <h1>{{ product.title }}</h1>
        {% nocache with {productId: product.id} %}
        {% if currentUser %}
            <button{{ currentUser.cart.id(productId).count() > 0 ? ' disabled' }}>Add to cart</button>
        {% endif %}
        {% endnocache %}
    </article>
{% endfor %}
{% endcache %}

nocache块将允许您缓存整个产品列表,但仍然可以在缓存之外执行您的用户逻辑。它还允许传递上下文,因此您仍然可以在nocache块内引用产品和条目,并访问它们的属性,而无需任何额外的数据库调用。

示例:CSRF令牌

这是一个出色的安全功能,但它基本上使得使用缓存变得不可能。您可能会发现自己在前端输出一个表单,但它在模板包含和宏的堆栈中嵌得很深。在这个堆栈的顶部,您方便地围绕它包裹了一个缓存标签。

现在,您的CSRF令牌将被缓存,您基本上对此无能为力。使用nocache标签,这个问题就不再存在了

<form>
    {% nocache %}{{ csrfInput() }}{% endnocache %}
    ...
</form>

现在您可以在模板中的任何地方包含这个表单,而不用担心您的CSRF令牌被缓存。作为附带说明,是的,nocache标签确实会在它们不在缓存块内时工作(尽管请尽量避免这样做,因为nocache标签确实会增加一些开销)。

注意

nocache块内的内容将比正常情况下渲染得略有不同。在nocache块外部声明的变量实际上会在缓存块期间保留其值。

这会在以下情况中引起问题

{% set article = craft.entries().section('news').one() %}
{% cache %}
    ...
    {% nocache with {article: article} %}
        {{ article.title }}
    {% endnocache %}
{% endcache %}

您可能期望,如果您更改文章的标题,它将在nocache块内更新。但这并不成立,因为由于缓存块的存在,文章本身会被缓存。

有几种解决方法。您可以将{% set articles %}语句移动到缓存块内部,这样更新文章就会导致缓存失效。在您在缓存内(但不在nocache块内)使用文章的情况下,这是一种首选方法,因为您不需要在nocache块内进行数据库调用以获取文章。

{% cache %}
    {% set article = craft.entries().section('news').one() %}
    ...
    {% nocache with {article: article} %}
        {{ article.title }}
    {% endnocache %}
{% endcache %}

另一种选择是在nocache块内查询文章。这可能比上述解决方案更好,因为更新文章标题不会导致缓存失效。在这种情况下,区别在于nocache块的内容现在将导致数据库调用。

{% cache %}
    ...
    {% nocache %}
        {% set article = craft.entries().section('news').one() %}
        {{ article.title }}
    {% endnocache %}
{% endcache %}

每种情况都不同,所以请根据您的最佳判断来使用。

非常感谢Ben Fleming创建No-Cache,并允许我接管它。