All add-ons currently require PHP 7.4 or greater.

On July 4th 2024 PHP 8.2 will be the new minimum requirement for all add-ons. Expect any add-on released after that date to require 8.2 or greater. Some releases may not immediately take advantage of 8.x specific features in PHP, which means you might, be able to continue using new releases in PHP 7.4, however, if you experience an error the first thing you should do is update to PHP 8.2 then create a support ticket if the error persists.

Publisher does not support the Fluid field type. Please do not contact asking when support will be available.

If you purchased an add-on from expressionengine.com, be sure to visit boldminded.com/claim to add the license to your account here on boldminded.com.

Ticket: speedy escaping doesn’t work where I think it should.

Status With Customer
Add-on / Version Speedy 1.9.2
Severity
EE Version 7.2.6

Paul Larson

May 03, 2024

Below is a template skeleton. Pretty simple sandwich of:

  • exp speedy fragment
  • exp channel entries
  • a few speedy:escapes
  • closing channel entries
  • closing fragment.

Yet, it doesn’t seem to be escaping. “I am in escape A” is present in the system/user/cache/speedy filesystem and I would expect that it shouldn’t be there.

File driver is default/file.

{layout='includes/_layout_2021'}

{exp:speedy:fragment ttl="43200"   global="no" key="{segment_2}-entry-contents"}

    {exp:channel:entries disable='member_data|pagination' limit="1" require_entry='yes' status='open|collection'}
    
        {exp:speedy:escape} {!-- ******* escape A --}
        
            <!-- ****** I am in escape A -->
            
            {layout:set name='seo'}
                <!-- lots of meta info -->
            {/layout:set}
        {/exp:speedy:escape} {!-- ******* end escape A --}      
        
        {exp:speedy:escape} {!-- ******* escape B --} 
        
            <!-- ******* I am in escape B -->
            
            {matrix_field}
                {embed="some/embed"}
            {/matrix_field}
            
        {/exp:speedy:escape} {!-- ******* end escape B --}      
        
    {/exp:channel:entries}
    
{/exp:speedy:fragment}
#1

Paul Larson

Comment has been marked private.

#2

Paul Larson

The TLDR is:

If File is cache method.

And I put {exp:speedy:escape} Hi I’m Fred Flintstone {/exp:speedy:escape}…

…I would think that text would not be in system/user/cache/speedy….

#3

Paul Larson

Hopefully an even simpler reduction template.

This has two escapes, #1 and #2. The content of both escapes appears in the stored cache file. That shouldn’t be the case, right? (for data I specifically don’t want cached?)

{exp:speedy:fragment ttl="43200" global="no" key="escape-test" driver="file"}

    {exp:channel:entries disable='member_data|pagination'  status='not derek'
    entry_id="10288" dynamic="no"}
    <h1>In entries loop</h1>

    {exp:speedy:escape}
        {layout:set name='seo'} THIS IS SEO-LAYOUT {/layout:set}
        {layout:set name="some_meta_data"}Some value here{/layout:set}
    {/exp:speedy:escape}

        <div class="cols2 product-header padding-top-60 margin-btm-60">
            <div class="col speedy-barstool_images_first">
                <h2>The title is {title}</h2>
                {exp:speedy:escape}
                    THIS IS HELLO-A
                {/exp:speedy:escape}
            </div>
        </div>

    {/exp:channel:entries}

{/exp:speedy:fragment}

screenshot

#4

BoldMinded (Brian)

Escaping means it should be saved in cache, it just remains unparsed. So when the cache item is printed back out to the page, if there are EE tags in there, they will get parsed live.

#5

BoldMinded (Brian)

For example, if you want to cache an item but show unique content to the logged in user, you might use an escape tag like this:

FWIW this is using the pre-escape method so early parsed global variables still work, but the same concept applies.

{exp:speedy:fragment key="one"}
{exp:channel:entries channel="pages" limit="1"}
    {title}

    {exp:speedy:escape:is_logged_in}
        {if logged_in}
            Logged in
        {if:else}
            Not logged in
        {/if}
    {/exp:speedy:escape:is_logged_in}

{/exp:channel:entries}
{/exp:speedy:fragment}
#6

Paul Larson

Let me ponder.

Ultimately I have an {embed} (a rather complicated one) that delivers a simple badge In Stock if a product is in stock.

But that embed seems to never parse, so it’s always showing an obsolete value. (That is: In Stock when the item is actually at zero inventory, or empty when it is in fact in stock)

With your advice I’m going to revisit that template (and the contents of the cache) to see if I can unravel it.

#7

Paul Larson

Brian,

In this example, shouldn’t my {current_time} tag remain unparsed, then? (instead of baking in the time from the last time the cache was saved?)

screenshot:

https://app.screencast.com/ifOJeChfxbA1i

Or below:

<iframe scrolling=’no’ frameborder=’0’ 2470px; height: 1944px; border:0;’ src=’https://app.screencast.com/ifOJeChfxbA1i/e’ allowfullscreen></iframe>

#8

Paul Larson

Maybe screenshots are overkill.

Template code:

{exp:speedy:fragment ttl="43200" global="no" key="escape-test" driver="file"}

    {exp:channel:entries disable='member_data|pagination'  status='not derek'
    entry_id="10288" dynamic="no"}
    <h1>In entries loop</h1>

    {exp:speedy:escape}
        {layout:set name='seo'} THIS IS SEO-LAYOUT {/layout:set}
        {layout:set name="some_meta_data"}Some value here{/layout:set}
    {/exp:speedy:escape}

        <div class="cols2 product-header padding-top-60 margin-btm-60">
            <div class="col speedy-barstool_images_first">
                <h2>The title is {title}</h2>
                {exp:speedy:escape}
                    THIS IS HELLO-A

                    The entry id is {entry_id} and the time is {current_time format="%D, %F %d, %Y - %g:%i:%s"}
                {/exp:speedy:escape}
            </div>
        </div>

    {/exp:channel:entries}

{/exp:speedy:fragment}

Cache result:

1715106480
1715149680
{!-- ra:00000000000016390000000000000000 --}
    <h1>In entries loop</h1>

    {layout:set name='seo'} THIS IS SEO-LAYOUT {/layout:set}
        {layout:set name="some_meta_data"}Some value here{/layout:set}

        <div class="cols2 product-header padding-top-60 margin-btm-60">
            <div class="col speedy-barstool_images_first">
                <h2>The title is 26424-MSR|DS22METZPEBB-B|ESPRESSO/SP-42</h2>
                THIS IS HELLO-A

                    The entry id is 10288 and the time is Tue, May 07, 2024 - 1:28:00
            </div>
        </div>
#9

BoldMinded (Brian)

current_time is already parsed when escape is getting called, so it will cache the result of the current_time variable. However, if you use a modifier the escape tag will parse earlier and it will escape the current_time var.

template:

{exp:speedy:fragment key="one"}
{exp:channel:entries channel="pages" limit="1"}
    {title}

    {exp:speedy:escape}
        Current Time A: {current_time}
    {/exp:speedy:escape}

    {exp:speedy:escape:time}
        Current Time B: {current_time}
    {/exp:speedy:escape:time}

    {exp:speedy:escape:is_logged_in}
        {if logged_in}
            Logged in
        {if:else}
            Not logged in
        {/if}
    {/exp:speedy:escape:is_logged_in}

    {exp:speedy:escape}
        {embed="embeds/switcher"}
    {/exp:speedy:escape}

{/exp:channel:entries}
{/exp:speedy:fragment}

Cached item:

{!-- ra:0000000000000b490000000000000000 --}    Testing non-Fluid dat

    Current Time A: 1715110104

    
        Current Time B: {current_time}
    

    
        {if logged_in}
            Logged in
        {if:else}
            Not logged in
        {/if}
    

    {embed="embeds/switcher"}
#10

BoldMinded (Brian)

The escape tag is working, I think you’re just running into parse order issues.

#11

Paul Larson

I understand parse order can be an issue.

But I don’t see that come to bear in this template. For this reduction template, the code I’m showing is literally the extent of the template. No partials, no embeds, no if_logged in.

I added a custom field {LONG_DESC} (just to avoid {title} and {current_time} getting special treatment), and even that is cached instead of remaining un-parsed.

{exp:speedy:escape}
                    THIS IS HELLO-A

                    The entry id is {entry_id} and the time is {current_time format="%D, %F %d, %Y - %g:%i:%s"}
                    

                    Let's try a custom field of {LONG_DESCR}
                {/exp:speedy:escape}
1715111715
1715154915
{!-- ra:00000000000016390000000000000000 --}
    <h1>In entries loop</h1>

    {layout:set name='seo'} THIS IS SEO-LAYOUT {/layout:set}
        {layout:set name="some_meta_data"}Some value here{/layout:set}

        <div class="cols2 product-header padding-top-60 margin-btm-60">
            <div class="col speedy-barstool_images_first">
                <h2>The title is 26424-MSR|DS22METZPEBB-B|ESPRESSO/SP-42</h2>
                THIS IS HELLO-A

                    The entry id is 10288 and the time is Tue, May 07, 2024 - 2:55:15
                    

                    Let's try a custom field of Monterra Urban Scale Swivel Rocker Lounge Chair
            </div>
        </div>

Should not ” Let’s try a custom field of {LONG_DESCR}” be stored un-parsed in cache?

I don’t see the normal parse order speed bump in this very basic template.

#12

BoldMinded (Brian)

The custom field should still getting parsed. If you escape it, then the cached version has no entries tag around it to parse it on output.

If you use the pre-escape option (exp:speedy:escape:modifier_here} then it won’t parse the custom field values.

The parsing of the fragment and escape tags have been unchanged basically since Speedy’s inception. I don’t know what else to say other than parse order is going to be a factor, and if the escape tag without the pre-escape modifier doesn’t work as expected, then to try the pre-escape modifiers.

#13

BoldMinded (Brian)

{exp:speedy:fragment key="one"}
{exp:channel:entries channel="pages" limit="1"}
    {title}

    {exp:speedy:escape}
        This is some random text. There is no reason to escape me, I won't be doing anything special when
        this cache item is rendered to the front-end.
    {/exp:speedy:escape}

{/exp:channel:entries}
{/exp:speedy:fragment}

Results in

{!-- ra:0000000000000b4a0000000000000000 --}    Testing non-Fluid dat

    This is some random text. There is no reason to escape me, I won't be doing anything special when
        this cache item is rendered to the front-end.
#14

Paul Larson

Ultimately, I have an “In Stock” icon that needs to display appropriately. It’s the output of an {embed}.

a) I’m just not sure, then, how to ensure the “In Stock” icon is always using live, instead of cached, data.

I thought :escape was the way to do this. Can I only escape outside of channel entries loops?

b) Just so I’m clear. Take my test template out of the picture. Generally speaking, if this code below is within exp:speedy:escape tags, what would you expect to be the default output? I can work backwards from there.

{exp:speedy:escape}
 Let's try a custom field of {LONG_DESCR}
{/exp:speedy:escape}
#15

BoldMinded (Brian)

I have some thoughts and I’ll try to elaborate on this more tomorrow when I’m at a computer. Thanks for the context, it helps to understand the situation.

As for that example I would expect it to cache and render exactly what you have there bc that variable is unparsed.

#16

Paul Larson

Thanks! I might make a simple (yet realistic) template with the embed just to provide more context.

#17

BoldMinded (Brian)

If you’re going to go with the embed route, then you might want to pass the entry ID so it is cached as

{embed="product/status" entry_id="{entry_id}"}

I tested this and it does parse the entry_id variable, but not the embed.

Another option is load the dynamic values with Ajax after the cached page is initially loaded, like demonstrated in the docs https://docs.boldminded.com/speedy/docs/static-caching/real-world-example. If you had a grid of 9 products you could figure out which entries are being displayed on the page, perhaps add all the entry ids onto a data attribute somewhere, then perform a single Ajax request to fetch the status of those entries, then update the DOM based on the Ajax response to indicate if a product is available or not. This would let you cache an entire section of the page, but then make real time updates of certain attributes of the products. This is mostly useful when using full page caching, but could be used with partial fragment caching too.

If you’re going to use an embed to get the status of each product, I’m not sure how much faster that will be since you’ll still have X embeds and X entries tags to get that info, which is why a single Ajax call to a template (or php based ACT endpoint) would be faster. Make the response a JSON object and javascript to perform the DOM updates.

#18

Paul Larson

Ok, here is the same template situation but much closer to what is actually employed on the site. Two exp:channel:loops, one with speedy escape, one without speedy of any kind.

{exp:speedy:fragment ttl="43200" global="no" key="escape-test" driver="file"}

    {exp:channel:entries disable='member_data|pagination'  status='not derek'
    entry_id="10288" dynamic="no"}
    
    <h2>A) Speedy fragment w/ escape</h2>
    <h3>The title is {title}</h3>

 {exp:speedy:escape}
    Stock value: "
  {embed='product/_in-stock-tag' ....
        "
 {/exp:speedy:escape}


    {/exp:channel:entries}

{/exp:speedy:fragment}

<hr><hr>

{exp:channel:entries disable='member_data|pagination'  status='not derek'
entry_id="10288" dynamic="no"}


 <h2>B) Outside speedy</h2>
 <h3>The title is {title}</h3>
 Stock value: "
  {embed='product/_in-stock-tag' .........
 "

{/exp:channel:entries}

As is, my {embed} already references the entry_id, so I believe it uses your last suggestion. “If you’re going to go with the embed route, then you might want to pass the entry ID…”

I still think what I have should work, with how I understand Speedy. I could absolutely be mistaken, though.

Here is the full embed, if it helps. It’s ugly, so I tried to spare you as long as possible.

{embed='product/_in-stock-tag'
        entry_id='{entry_id}'

        quantity="{parents field='PARENT_ITEM' limit='1' }{parents:QTY_AVAIL}{if parents:no_results}0{/if}{/parents}"
        brand_id="{categories style='linear' show_group='4|6|9|11|13|15|20|21|22|24|26|28|30|31' backspace='2'}{category_id}, {/categories}"
        type='{counterpoint_category_code}'
        sku='{tp_carc_entry_title}' {!-- formerly {title} which collides due to Assets --}
        yo='{tp_carc_entry_title}'
        channel='{channel_name}'
        show_as_in_stock='{show_as_in_stock}'
        out_of_stock='{out_of_stock}'
        align='left'
        }

I’ll follow up with a brief private video.

#19

Paul Larson

Comment has been marked private.

#20

BoldMinded (Brian)

That looks more like a cache clearing rules issue than an issue with fragments and escaping.

Login to reply