[5.x] Statamic Tag Blade Compiler - #10967

Merged
jasonvarga merged 41 commits into
statamic:5.xfrom
JohnathonKoster:statamic-antlers-blade-compiler
Oct 31, 2024
Merged

[5.x] Statamic Tag Blade Compiler#10967
jasonvarga merged 41 commits into
statamic:5.xfrom
JohnathonKoster:statamic-antlers-blade-compiler

Conversation

@JohnathonKoster

@JohnathonKosterJohnathonKoster commented Oct 17, 2024

Copy link
Copy Markdown
Contributor

Much more thorough documentation/information can be found over here: statamic/docs#1473

Overview

This PR adds a new tag compiler for Blade. Its primary goal is to make leveraging existing tags simpler when writing Blade templates. For example, in Antlers, you can use the collection tag like so:

{{ collection:blog }}
{{ title }}
{{ /collection:blog }}
{{ collection:blogas="posts" }}
{{ posts }}
{{ title }}
{{ /posts }}
{{ /collection:blog }}

with the changes in this PR, the following would now be possible in Blade:

<s:collection:blog>
{{$title}}
</s:collection:blog>
<s:collection:blogas="posts">
@foreach ($postsas$post)
{{$post->title}}@endforeach
</s:collection:blog>

The internal compiler will compile the custom <s: tags to PHP behind the scenes.

This PR also adds a new @recursive_children directive, which is only intended to be used within the <s:nav tag:

<ul>
<s:nav:main>
<li>
{{$title}} - {{$depth}}@if (count($children) >0)
<ulclass="the-wrapper">
@recursive_children
</ul>
@endif
</li>
</s:nav:main>
</ul>
-- or with an alias --
<ul>
<s:nav:mainas="the_items">
@foreach ($the_itemsas$item)
<li>{{$item['title'] }} - {{$item['depth'] }}</li>
@if (isset($item['children']) &&count($item['children']))
<ulclass="wrapper">
@recursive_children($item['children'])
</ul>
@endif@endforeach
</s:nav:main>
</ul>

Important: While they shares the same syntax as components, its important to think of these as "tags" and not traditional Blade components! For example, "slot" content shares the same scope as the outer template:

<?php$myVar=0; ?>
<s:collection:blog>
@php($myVar++)
</s:collection:blog>

Helper Functions

This PR also introduces a small number of namespaced helper functions. These can be imported at the top of a Blade template by using use function. Each helper function aims to reduce friction/help in a very specific way.

value

The first of these is the value helper function. It is intended to be used in conditions (and other similar scenarios). It resolves Value instances, and a few other things for you automatically so you don't have to remember to do it each time (or if something changes in the future where it now returns Value where it didn't before):

@phpusefunctionStatamic\View\Blade\{value};@endphp{{-- Always the the non-Value version --}}@if (value($theVariableName))
...
@endif

The value helper function will handle the following scenarios for you:

  • Statamic\Fields\Value objects (calls ->value())
  • Statamic\Fields\Values objects (calls ->all())
  • Statamic\Tags\FluentTag objects (calls ->fetch())
  • Statamic\Modifiers\Modify objects (calls ->fetch())

modify

The modify helper function is simply a shortcut to calling Statamic::modify. Once imported, you can replace all Statamic::modify calls with modify:

@phpusefunctionStatamic\View\Blade\{modify};@endphp{{modify('test')->stripTags()->backspace(1)->ensureRight('!!!') }}{{modify('test')->stripTags()->safeTruncate([42, '...']) }}

void

When using tags in Antlers, you can "remove" a parameter conditionally by using the void keyword:

{{ collection:articlessort="date:asc|title:desc"limit="{display_all ? void : 3 }" }}
<li>{{ title }}</li>
{{ /collection:articles }}

The above is equivalent to:

{{ ifdisplay_all }}
{{ collection:articlessort="date:asc|title:desc" }}
<li>{{ title }}</li>
{{ /collection:articles }}
{{ else }}
{{ collection:articlessort="date:asc|title:desc"limit="3" }}
<li>{{ title }}</li>
{{ /collection:articles }}
{{ /if }}

We can use the void() helper function to accomplish the same thing in Blade:

@phpusefunctionStatamic\View\Blade\{void};@endphp
<s:collection:articlessort="date:asc|title:desc":limit="$display_all ? void() : 3"
>
<ul>{{$title}}</ul>
</s:collection:articles>

Collecting them all

Just a quick example on what it'd look like if you wanted to collect all of the new Blade helper functions in your template:

@phpusefunctionStatamic\View\Blade\{value, modify, void};@endphp
// Hello there! Welcome to the world of HELPER FUNCTIONS!

Notes

  1. Most tags will be compatible with this syntax with no additional work. Docs will be coming for handling the edge cases/etc.
  2. Some tags may behave differently than they do in Antlers. This is largely due to how Antlers handles null/empty arrays. When used in Blade, tags that have different behaviors have been adapted to fit much more naturally in Blade. Docs for these scenarios is in progress.

@JohnathonKosterJohnathonKoster changed the title Statamic Tag Blade Compiler[5.x] Statamic Tag Blade CompilerOct 17, 2024
@JohnathonKoster
JohnathonKoster marked this pull request as draft October 17, 2024 03:51
@JohnathonKoster
JohnathonKoster marked this pull request as draft October 17, 2024 03:51
jasonvarga
jasonvarga previously requested changes Oct 29, 2024

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I've done something dumb, it seems that nested tags don't work.

<s:transkey="Hello" /> // works fine out here
<s:collection:articles>
<s:transkey="Hello" /> // does nothing in here
</s:collection:articles>

@jasonvarga
jasonvarga dismissed their stale reviewOctober 29, 2024 20:40

Changes were made

@daun

daun commented Oct 30, 2024

Copy link
Copy Markdown
Contributor

@JohnathonKoster This looks really neat. Would this in theory make it easier to integrate other templating engines as well or is this specifically tailored to Blade? There are addons for Twig and Latte and maybe this allows a few new tricks to make those integrations more seamless.

Comment threadtests/View/Blade/AntlersComponents/SelfClosingTagsTest.php

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that nested partials don't work.

one.blade.php
just some text
two.blade.php
{{ $slot }}
<s:partial:one /> this partial renders
<s:partial:two>
this text renders
<s:partial:one /> this partial doesnt render
</s:partial:two>

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That worked great, except now I'm noticing that slot content is escaped.

bar.blade.php
<b>text</b>
foo.blade.php
{{$slot}}
<s:partial:bar />
<s:partial:foo>
<s:partial:bar />
</s:partial:foo>

outputs

<b>text</b>
&lt;b&gt;text&lt;/b&gt;

When using Blade components, {{ $slot }} doesn't escape. It looks like they are dealing with Htmlable objects. (ComponentSlot)

@JohnathonKoster

JohnathonKoster commented Oct 30, 2024

Copy link
Copy Markdown
ContributorAuthor

@JohnathonKoster This looks really neat. Would this in theory make it easier to integrate other templating engines as well or is this specifically tailored to Blade? There are addons for Twig and Latte and maybe this allows a few new tricks to make those integrations more seamless.

The concept itself could be applied to other templating languages, but this implementation is tailored to Blade (interacting with Blade's loop variables, attribute/parameter syntax & behavior, slot behavior, etc.).

jasonvarga
jasonvarga previously requested changes Oct 31, 2024
Comment threadtests/View/Blade/AntlersComponents/PartialCompilerTest.php Outdated
@jasonvarga
jasonvarga dismissed their stale reviewOctober 31, 2024 16:57

Did the thing

@jasonvarga
jasonvarga merged commit 4ecdd9b into statamic:5.xOct 31, 2024
@admench

Copy link
Copy Markdown

Wow this is an amazing improvement! Thanks!

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@JohnathonKoster@daun@admench@jasonvarga
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[5.x] Statamic Tag Blade Compiler - #10967

Merged
jasonvarga merged 41 commits into
statamic:5.xfrom
JohnathonKoster:statamic-antlers-blade-compiler
Oct 31, 2024
Merged

[5.x] Statamic Tag Blade Compiler#10967
jasonvarga merged 41 commits into
statamic:5.xfrom
JohnathonKoster:statamic-antlers-blade-compiler

Conversation

@JohnathonKoster

@JohnathonKosterJohnathonKoster commented Oct 17, 2024

Copy link
Copy Markdown
Contributor

Much more thorough documentation/information can be found over here: statamic/docs#1473

Overview

This PR adds a new tag compiler for Blade. Its primary goal is to make leveraging existing tags simpler when writing Blade templates. For example, in Antlers, you can use the collection tag like so:

{{ collection:blog }}
{{ title }}
{{ /collection:blog }}
{{ collection:blogas="posts" }}
{{ posts }}
{{ title }}
{{ /posts }}
{{ /collection:blog }}

with the changes in this PR, the following would now be possible in Blade:

<s:collection:blog>
{{$title}}
</s:collection:blog>
<s:collection:blogas="posts">
@foreach ($postsas$post)
{{$post->title}}@endforeach
</s:collection:blog>

The internal compiler will compile the custom <s: tags to PHP behind the scenes.

This PR also adds a new @recursive_children directive, which is only intended to be used within the <s:nav tag:

<ul>
<s:nav:main>
<li>
{{$title}} - {{$depth}}@if (count($children) >0)
<ulclass="the-wrapper">
@recursive_children
</ul>
@endif
</li>
</s:nav:main>
</ul>
-- or with an alias --
<ul>
<s:nav:mainas="the_items">
@foreach ($the_itemsas$item)
<li>{{$item['title'] }} - {{$item['depth'] }}</li>
@if (isset($item['children']) &&count($item['children']))
<ulclass="wrapper">
@recursive_children($item['children'])
</ul>
@endif@endforeach
</s:nav:main>
</ul>

Important: While they shares the same syntax as components, its important to think of these as "tags" and not traditional Blade components! For example, "slot" content shares the same scope as the outer template:

<?php$myVar=0; ?>
<s:collection:blog>
@php($myVar++)
</s:collection:blog>

Helper Functions

This PR also introduces a small number of namespaced helper functions. These can be imported at the top of a Blade template by using use function. Each helper function aims to reduce friction/help in a very specific way.

value

The first of these is the value helper function. It is intended to be used in conditions (and other similar scenarios). It resolves Value instances, and a few other things for you automatically so you don't have to remember to do it each time (or if something changes in the future where it now returns Value where it didn't before):

@phpusefunctionStatamic\View\Blade\{value};@endphp{{-- Always the the non-Value version --}}@if (value($theVariableName))
...
@endif

The value helper function will handle the following scenarios for you:

  • Statamic\Fields\Value objects (calls ->value())
  • Statamic\Fields\Values objects (calls ->all())
  • Statamic\Tags\FluentTag objects (calls ->fetch())
  • Statamic\Modifiers\Modify objects (calls ->fetch())

modify

The modify helper function is simply a shortcut to calling Statamic::modify. Once imported, you can replace all Statamic::modify calls with modify:

@phpusefunctionStatamic\View\Blade\{modify};@endphp{{modify('test')->stripTags()->backspace(1)->ensureRight('!!!') }}{{modify('test')->stripTags()->safeTruncate([42, '...']) }}

void

When using tags in Antlers, you can "remove" a parameter conditionally by using the void keyword:

{{ collection:articlessort="date:asc|title:desc"limit="{display_all ? void : 3 }" }}
<li>{{ title }}</li>
{{ /collection:articles }}

The above is equivalent to:

{{ ifdisplay_all }}
{{ collection:articlessort="date:asc|title:desc" }}
<li>{{ title }}</li>
{{ /collection:articles }}
{{ else }}
{{ collection:articlessort="date:asc|title:desc"limit="3" }}
<li>{{ title }}</li>
{{ /collection:articles }}
{{ /if }}

We can use the void() helper function to accomplish the same thing in Blade:

@phpusefunctionStatamic\View\Blade\{void};@endphp
<s:collection:articlessort="date:asc|title:desc":limit="$display_all ? void() : 3"
>
<ul>{{$title}}</ul>
</s:collection:articles>

Collecting them all

Just a quick example on what it'd look like if you wanted to collect all of the new Blade helper functions in your template:

@phpusefunctionStatamic\View\Blade\{value, modify, void};@endphp
// Hello there! Welcome to the world of HELPER FUNCTIONS!

Notes

  1. Most tags will be compatible with this syntax with no additional work. Docs will be coming for handling the edge cases/etc.
  2. Some tags may behave differently than they do in Antlers. This is largely due to how Antlers handles null/empty arrays. When used in Blade, tags that have different behaviors have been adapted to fit much more naturally in Blade. Docs for these scenarios is in progress.

@JohnathonKosterJohnathonKoster changed the title Statamic Tag Blade Compiler[5.x] Statamic Tag Blade CompilerOct 17, 2024
@JohnathonKoster
JohnathonKoster marked this pull request as draft October 17, 2024 03:51
@JohnathonKoster
JohnathonKoster marked this pull request as draft October 17, 2024 03:51
jasonvarga
jasonvarga previously requested changes Oct 29, 2024

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I've done something dumb, it seems that nested tags don't work.

<s:transkey="Hello" /> // works fine out here
<s:collection:articles>
<s:transkey="Hello" /> // does nothing in here
</s:collection:articles>

@jasonvarga
jasonvarga dismissed their stale reviewOctober 29, 2024 20:40

Changes were made

@daun

daun commented Oct 30, 2024

Copy link
Copy Markdown
Contributor

@JohnathonKoster This looks really neat. Would this in theory make it easier to integrate other templating engines as well or is this specifically tailored to Blade? There are addons for Twig and Latte and maybe this allows a few new tricks to make those integrations more seamless.

Comment threadtests/View/Blade/AntlersComponents/SelfClosingTagsTest.php

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that nested partials don't work.

one.blade.php
just some text
two.blade.php
{{ $slot }}
<s:partial:one /> this partial renders
<s:partial:two>
this text renders
<s:partial:one /> this partial doesnt render
</s:partial:two>

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That worked great, except now I'm noticing that slot content is escaped.

bar.blade.php
<b>text</b>
foo.blade.php
{{$slot}}
<s:partial:bar />
<s:partial:foo>
<s:partial:bar />
</s:partial:foo>

outputs

<b>text</b>
&lt;b&gt;text&lt;/b&gt;

When using Blade components, {{ $slot }} doesn't escape. It looks like they are dealing with Htmlable objects. (ComponentSlot)

@JohnathonKoster

JohnathonKoster commented Oct 30, 2024

Copy link
Copy Markdown
ContributorAuthor

@JohnathonKoster This looks really neat. Would this in theory make it easier to integrate other templating engines as well or is this specifically tailored to Blade? There are addons for Twig and Latte and maybe this allows a few new tricks to make those integrations more seamless.

The concept itself could be applied to other templating languages, but this implementation is tailored to Blade (interacting with Blade's loop variables, attribute/parameter syntax & behavior, slot behavior, etc.).

jasonvarga
jasonvarga previously requested changes Oct 31, 2024
Comment threadtests/View/Blade/AntlersComponents/PartialCompilerTest.php Outdated
@jasonvarga
jasonvarga dismissed their stale reviewOctober 31, 2024 16:57

Did the thing

@jasonvarga
jasonvarga merged commit 4ecdd9b into statamic:5.xOct 31, 2024
@admench

Copy link
Copy Markdown

Wow this is an amazing improvement! Thanks!

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@JohnathonKoster@daun@admench@jasonvarga
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[5.x] Statamic Tag Blade Compiler - #10967

Merged
jasonvarga merged 41 commits into
statamic:5.xfrom
JohnathonKoster:statamic-antlers-blade-compiler
Oct 31, 2024
Merged

[5.x] Statamic Tag Blade Compiler#10967
jasonvarga merged 41 commits into
statamic:5.xfrom
JohnathonKoster:statamic-antlers-blade-compiler

Conversation

@JohnathonKoster

@JohnathonKosterJohnathonKoster commented Oct 17, 2024

Copy link
Copy Markdown
Contributor

Much more thorough documentation/information can be found over here: statamic/docs#1473

Overview

This PR adds a new tag compiler for Blade. Its primary goal is to make leveraging existing tags simpler when writing Blade templates. For example, in Antlers, you can use the collection tag like so:

{{ collection:blog }}
{{ title }}
{{ /collection:blog }}
{{ collection:blogas="posts" }}
{{ posts }}
{{ title }}
{{ /posts }}
{{ /collection:blog }}

with the changes in this PR, the following would now be possible in Blade:

<s:collection:blog>
{{$title}}
</s:collection:blog>
<s:collection:blogas="posts">
@foreach ($postsas$post)
{{$post->title}}@endforeach
</s:collection:blog>

The internal compiler will compile the custom <s: tags to PHP behind the scenes.

This PR also adds a new @recursive_children directive, which is only intended to be used within the <s:nav tag:

<ul>
<s:nav:main>
<li>
{{$title}} - {{$depth}}@if (count($children) >0)
<ulclass="the-wrapper">
@recursive_children
</ul>
@endif
</li>
</s:nav:main>
</ul>
-- or with an alias --
<ul>
<s:nav:mainas="the_items">
@foreach ($the_itemsas$item)
<li>{{$item['title'] }} - {{$item['depth'] }}</li>
@if (isset($item['children']) &&count($item['children']))
<ulclass="wrapper">
@recursive_children($item['children'])
</ul>
@endif@endforeach
</s:nav:main>
</ul>

Important: While they shares the same syntax as components, its important to think of these as "tags" and not traditional Blade components! For example, "slot" content shares the same scope as the outer template:

<?php$myVar=0; ?>
<s:collection:blog>
@php($myVar++)
</s:collection:blog>

Helper Functions

This PR also introduces a small number of namespaced helper functions. These can be imported at the top of a Blade template by using use function. Each helper function aims to reduce friction/help in a very specific way.

value

The first of these is the value helper function. It is intended to be used in conditions (and other similar scenarios). It resolves Value instances, and a few other things for you automatically so you don't have to remember to do it each time (or if something changes in the future where it now returns Value where it didn't before):

@phpusefunctionStatamic\View\Blade\{value};@endphp{{-- Always the the non-Value version --}}@if (value($theVariableName))
...
@endif

The value helper function will handle the following scenarios for you:

  • Statamic\Fields\Value objects (calls ->value())
  • Statamic\Fields\Values objects (calls ->all())
  • Statamic\Tags\FluentTag objects (calls ->fetch())
  • Statamic\Modifiers\Modify objects (calls ->fetch())

modify

The modify helper function is simply a shortcut to calling Statamic::modify. Once imported, you can replace all Statamic::modify calls with modify:

@phpusefunctionStatamic\View\Blade\{modify};@endphp{{modify('test')->stripTags()->backspace(1)->ensureRight('!!!') }}{{modify('test')->stripTags()->safeTruncate([42, '...']) }}

void

When using tags in Antlers, you can "remove" a parameter conditionally by using the void keyword:

{{ collection:articlessort="date:asc|title:desc"limit="{display_all ? void : 3 }" }}
<li>{{ title }}</li>
{{ /collection:articles }}

The above is equivalent to:

{{ ifdisplay_all }}
{{ collection:articlessort="date:asc|title:desc" }}
<li>{{ title }}</li>
{{ /collection:articles }}
{{ else }}
{{ collection:articlessort="date:asc|title:desc"limit="3" }}
<li>{{ title }}</li>
{{ /collection:articles }}
{{ /if }}

We can use the void() helper function to accomplish the same thing in Blade:

@phpusefunctionStatamic\View\Blade\{void};@endphp
<s:collection:articlessort="date:asc|title:desc":limit="$display_all ? void() : 3"
>
<ul>{{$title}}</ul>
</s:collection:articles>

Collecting them all

Just a quick example on what it'd look like if you wanted to collect all of the new Blade helper functions in your template:

@phpusefunctionStatamic\View\Blade\{value, modify, void};@endphp
// Hello there! Welcome to the world of HELPER FUNCTIONS!

Notes

  1. Most tags will be compatible with this syntax with no additional work. Docs will be coming for handling the edge cases/etc.
  2. Some tags may behave differently than they do in Antlers. This is largely due to how Antlers handles null/empty arrays. When used in Blade, tags that have different behaviors have been adapted to fit much more naturally in Blade. Docs for these scenarios is in progress.

@JohnathonKosterJohnathonKoster changed the title Statamic Tag Blade Compiler[5.x] Statamic Tag Blade CompilerOct 17, 2024
@JohnathonKoster
JohnathonKoster marked this pull request as draft October 17, 2024 03:51
@JohnathonKoster
JohnathonKoster marked this pull request as draft October 17, 2024 03:51
jasonvarga
jasonvarga previously requested changes Oct 29, 2024

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I've done something dumb, it seems that nested tags don't work.

<s:transkey="Hello" /> // works fine out here
<s:collection:articles>
<s:transkey="Hello" /> // does nothing in here
</s:collection:articles>

@jasonvarga
jasonvarga dismissed their stale reviewOctober 29, 2024 20:40

Changes were made

@daun

daun commented Oct 30, 2024

Copy link
Copy Markdown
Contributor

@JohnathonKoster This looks really neat. Would this in theory make it easier to integrate other templating engines as well or is this specifically tailored to Blade? There are addons for Twig and Latte and maybe this allows a few new tricks to make those integrations more seamless.

Comment threadtests/View/Blade/AntlersComponents/SelfClosingTagsTest.php

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that nested partials don't work.

one.blade.php
just some text
two.blade.php
{{ $slot }}
<s:partial:one /> this partial renders
<s:partial:two>
this text renders
<s:partial:one /> this partial doesnt render
</s:partial:two>

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That worked great, except now I'm noticing that slot content is escaped.

bar.blade.php
<b>text</b>
foo.blade.php
{{$slot}}
<s:partial:bar />
<s:partial:foo>
<s:partial:bar />
</s:partial:foo>

outputs

<b>text</b>
&lt;b&gt;text&lt;/b&gt;

When using Blade components, {{ $slot }} doesn't escape. It looks like they are dealing with Htmlable objects. (ComponentSlot)

@JohnathonKoster

JohnathonKoster commented Oct 30, 2024

Copy link
Copy Markdown
ContributorAuthor

@JohnathonKoster This looks really neat. Would this in theory make it easier to integrate other templating engines as well or is this specifically tailored to Blade? There are addons for Twig and Latte and maybe this allows a few new tricks to make those integrations more seamless.

The concept itself could be applied to other templating languages, but this implementation is tailored to Blade (interacting with Blade's loop variables, attribute/parameter syntax & behavior, slot behavior, etc.).

jasonvarga
jasonvarga previously requested changes Oct 31, 2024
Comment threadtests/View/Blade/AntlersComponents/PartialCompilerTest.php Outdated
@jasonvarga
jasonvarga dismissed their stale reviewOctober 31, 2024 16:57

Did the thing

@jasonvarga
jasonvarga merged commit 4ecdd9b into statamic:5.xOct 31, 2024
@admench

Copy link
Copy Markdown

Wow this is an amazing improvement! Thanks!

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@JohnathonKoster@daun@admench@jasonvarga
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[5.x] Statamic Tag Blade Compiler - #10967

Merged
jasonvarga merged 41 commits into
statamic:5.xfrom
JohnathonKoster:statamic-antlers-blade-compiler
Oct 31, 2024
Merged

[5.x] Statamic Tag Blade Compiler#10967
jasonvarga merged 41 commits into
statamic:5.xfrom
JohnathonKoster:statamic-antlers-blade-compiler

Conversation

@JohnathonKoster

@JohnathonKosterJohnathonKoster commented Oct 17, 2024

Copy link
Copy Markdown
Contributor

Much more thorough documentation/information can be found over here: statamic/docs#1473

Overview

This PR adds a new tag compiler for Blade. Its primary goal is to make leveraging existing tags simpler when writing Blade templates. For example, in Antlers, you can use the collection tag like so:

{{ collection:blog }}
{{ title }}
{{ /collection:blog }}
{{ collection:blogas="posts" }}
{{ posts }}
{{ title }}
{{ /posts }}
{{ /collection:blog }}

with the changes in this PR, the following would now be possible in Blade:

<s:collection:blog>
{{$title}}
</s:collection:blog>
<s:collection:blogas="posts">
@foreach ($postsas$post)
{{$post->title}}@endforeach
</s:collection:blog>

The internal compiler will compile the custom <s: tags to PHP behind the scenes.

This PR also adds a new @recursive_children directive, which is only intended to be used within the <s:nav tag:

<ul>
<s:nav:main>
<li>
{{$title}} - {{$depth}}@if (count($children) >0)
<ulclass="the-wrapper">
@recursive_children
</ul>
@endif
</li>
</s:nav:main>
</ul>
-- or with an alias --
<ul>
<s:nav:mainas="the_items">
@foreach ($the_itemsas$item)
<li>{{$item['title'] }} - {{$item['depth'] }}</li>
@if (isset($item['children']) &&count($item['children']))
<ulclass="wrapper">
@recursive_children($item['children'])
</ul>
@endif@endforeach
</s:nav:main>
</ul>

Important: While they shares the same syntax as components, its important to think of these as "tags" and not traditional Blade components! For example, "slot" content shares the same scope as the outer template:

<?php$myVar=0; ?>
<s:collection:blog>
@php($myVar++)
</s:collection:blog>

Helper Functions

This PR also introduces a small number of namespaced helper functions. These can be imported at the top of a Blade template by using use function. Each helper function aims to reduce friction/help in a very specific way.

value

The first of these is the value helper function. It is intended to be used in conditions (and other similar scenarios). It resolves Value instances, and a few other things for you automatically so you don't have to remember to do it each time (or if something changes in the future where it now returns Value where it didn't before):

@phpusefunctionStatamic\View\Blade\{value};@endphp{{-- Always the the non-Value version --}}@if (value($theVariableName))
...
@endif

The value helper function will handle the following scenarios for you:

  • Statamic\Fields\Value objects (calls ->value())
  • Statamic\Fields\Values objects (calls ->all())
  • Statamic\Tags\FluentTag objects (calls ->fetch())
  • Statamic\Modifiers\Modify objects (calls ->fetch())

modify

The modify helper function is simply a shortcut to calling Statamic::modify. Once imported, you can replace all Statamic::modify calls with modify:

@phpusefunctionStatamic\View\Blade\{modify};@endphp{{modify('test')->stripTags()->backspace(1)->ensureRight('!!!') }}{{modify('test')->stripTags()->safeTruncate([42, '...']) }}

void

When using tags in Antlers, you can "remove" a parameter conditionally by using the void keyword:

{{ collection:articlessort="date:asc|title:desc"limit="{display_all ? void : 3 }" }}
<li>{{ title }}</li>
{{ /collection:articles }}

The above is equivalent to:

{{ ifdisplay_all }}
{{ collection:articlessort="date:asc|title:desc" }}
<li>{{ title }}</li>
{{ /collection:articles }}
{{ else }}
{{ collection:articlessort="date:asc|title:desc"limit="3" }}
<li>{{ title }}</li>
{{ /collection:articles }}
{{ /if }}

We can use the void() helper function to accomplish the same thing in Blade:

@phpusefunctionStatamic\View\Blade\{void};@endphp
<s:collection:articlessort="date:asc|title:desc":limit="$display_all ? void() : 3"
>
<ul>{{$title}}</ul>
</s:collection:articles>

Collecting them all

Just a quick example on what it'd look like if you wanted to collect all of the new Blade helper functions in your template:

@phpusefunctionStatamic\View\Blade\{value, modify, void};@endphp
// Hello there! Welcome to the world of HELPER FUNCTIONS!

Notes

  1. Most tags will be compatible with this syntax with no additional work. Docs will be coming for handling the edge cases/etc.
  2. Some tags may behave differently than they do in Antlers. This is largely due to how Antlers handles null/empty arrays. When used in Blade, tags that have different behaviors have been adapted to fit much more naturally in Blade. Docs for these scenarios is in progress.

@JohnathonKosterJohnathonKoster changed the title Statamic Tag Blade Compiler[5.x] Statamic Tag Blade CompilerOct 17, 2024
@JohnathonKoster
JohnathonKoster marked this pull request as draft October 17, 2024 03:51
@JohnathonKoster
JohnathonKoster marked this pull request as draft October 17, 2024 03:51
jasonvarga
jasonvarga previously requested changes Oct 29, 2024

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I've done something dumb, it seems that nested tags don't work.

<s:transkey="Hello" /> // works fine out here
<s:collection:articles>
<s:transkey="Hello" /> // does nothing in here
</s:collection:articles>

@jasonvarga
jasonvarga dismissed their stale reviewOctober 29, 2024 20:40

Changes were made

@daun

daun commented Oct 30, 2024

Copy link
Copy Markdown
Contributor

@JohnathonKoster This looks really neat. Would this in theory make it easier to integrate other templating engines as well or is this specifically tailored to Blade? There are addons for Twig and Latte and maybe this allows a few new tricks to make those integrations more seamless.

Comment threadtests/View/Blade/AntlersComponents/SelfClosingTagsTest.php

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that nested partials don't work.

one.blade.php
just some text
two.blade.php
{{ $slot }}
<s:partial:one /> this partial renders
<s:partial:two>
this text renders
<s:partial:one /> this partial doesnt render
</s:partial:two>

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That worked great, except now I'm noticing that slot content is escaped.

bar.blade.php
<b>text</b>
foo.blade.php
{{$slot}}
<s:partial:bar />
<s:partial:foo>
<s:partial:bar />
</s:partial:foo>

outputs

<b>text</b>
&lt;b&gt;text&lt;/b&gt;

When using Blade components, {{ $slot }} doesn't escape. It looks like they are dealing with Htmlable objects. (ComponentSlot)

@JohnathonKoster

JohnathonKoster commented Oct 30, 2024

Copy link
Copy Markdown
ContributorAuthor

@JohnathonKoster This looks really neat. Would this in theory make it easier to integrate other templating engines as well or is this specifically tailored to Blade? There are addons for Twig and Latte and maybe this allows a few new tricks to make those integrations more seamless.

The concept itself could be applied to other templating languages, but this implementation is tailored to Blade (interacting with Blade's loop variables, attribute/parameter syntax & behavior, slot behavior, etc.).

jasonvarga
jasonvarga previously requested changes Oct 31, 2024
Comment threadtests/View/Blade/AntlersComponents/PartialCompilerTest.php Outdated
@jasonvarga
jasonvarga dismissed their stale reviewOctober 31, 2024 16:57

Did the thing

@jasonvarga
jasonvarga merged commit 4ecdd9b into statamic:5.xOct 31, 2024
@admench

Copy link
Copy Markdown

Wow this is an amazing improvement! Thanks!

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@JohnathonKoster@daun@admench@jasonvarga
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[5.x] Statamic Tag Blade Compiler - #10967

Merged
jasonvarga merged 41 commits into
statamic:5.xfrom
JohnathonKoster:statamic-antlers-blade-compiler
Oct 31, 2024
Merged

[5.x] Statamic Tag Blade Compiler#10967
jasonvarga merged 41 commits into
statamic:5.xfrom
JohnathonKoster:statamic-antlers-blade-compiler

Conversation

@JohnathonKoster

@JohnathonKosterJohnathonKoster commented Oct 17, 2024

Copy link
Copy Markdown
Contributor

Much more thorough documentation/information can be found over here: statamic/docs#1473

Overview

This PR adds a new tag compiler for Blade. Its primary goal is to make leveraging existing tags simpler when writing Blade templates. For example, in Antlers, you can use the collection tag like so:

{{ collection:blog }}
{{ title }}
{{ /collection:blog }}
{{ collection:blogas="posts" }}
{{ posts }}
{{ title }}
{{ /posts }}
{{ /collection:blog }}

with the changes in this PR, the following would now be possible in Blade:

<s:collection:blog>
{{$title}}
</s:collection:blog>
<s:collection:blogas="posts">
@foreach ($postsas$post)
{{$post->title}}@endforeach
</s:collection:blog>

The internal compiler will compile the custom <s: tags to PHP behind the scenes.

This PR also adds a new @recursive_children directive, which is only intended to be used within the <s:nav tag:

<ul>
<s:nav:main>
<li>
{{$title}} - {{$depth}}@if (count($children) >0)
<ulclass="the-wrapper">
@recursive_children
</ul>
@endif
</li>
</s:nav:main>
</ul>
-- or with an alias --
<ul>
<s:nav:mainas="the_items">
@foreach ($the_itemsas$item)
<li>{{$item['title'] }} - {{$item['depth'] }}</li>
@if (isset($item['children']) &&count($item['children']))
<ulclass="wrapper">
@recursive_children($item['children'])
</ul>
@endif@endforeach
</s:nav:main>
</ul>

Important: While they shares the same syntax as components, its important to think of these as "tags" and not traditional Blade components! For example, "slot" content shares the same scope as the outer template:

<?php$myVar=0; ?>
<s:collection:blog>
@php($myVar++)
</s:collection:blog>

Helper Functions

This PR also introduces a small number of namespaced helper functions. These can be imported at the top of a Blade template by using use function. Each helper function aims to reduce friction/help in a very specific way.

value

The first of these is the value helper function. It is intended to be used in conditions (and other similar scenarios). It resolves Value instances, and a few other things for you automatically so you don't have to remember to do it each time (or if something changes in the future where it now returns Value where it didn't before):

@phpusefunctionStatamic\View\Blade\{value};@endphp{{-- Always the the non-Value version --}}@if (value($theVariableName))
...
@endif

The value helper function will handle the following scenarios for you:

  • Statamic\Fields\Value objects (calls ->value())
  • Statamic\Fields\Values objects (calls ->all())
  • Statamic\Tags\FluentTag objects (calls ->fetch())
  • Statamic\Modifiers\Modify objects (calls ->fetch())

modify

The modify helper function is simply a shortcut to calling Statamic::modify. Once imported, you can replace all Statamic::modify calls with modify:

@phpusefunctionStatamic\View\Blade\{modify};@endphp{{modify('test')->stripTags()->backspace(1)->ensureRight('!!!') }}{{modify('test')->stripTags()->safeTruncate([42, '...']) }}

void

When using tags in Antlers, you can "remove" a parameter conditionally by using the void keyword:

{{ collection:articlessort="date:asc|title:desc"limit="{display_all ? void : 3 }" }}
<li>{{ title }}</li>
{{ /collection:articles }}

The above is equivalent to:

{{ ifdisplay_all }}
{{ collection:articlessort="date:asc|title:desc" }}
<li>{{ title }}</li>
{{ /collection:articles }}
{{ else }}
{{ collection:articlessort="date:asc|title:desc"limit="3" }}
<li>{{ title }}</li>
{{ /collection:articles }}
{{ /if }}

We can use the void() helper function to accomplish the same thing in Blade:

@phpusefunctionStatamic\View\Blade\{void};@endphp
<s:collection:articlessort="date:asc|title:desc":limit="$display_all ? void() : 3"
>
<ul>{{$title}}</ul>
</s:collection:articles>

Collecting them all

Just a quick example on what it'd look like if you wanted to collect all of the new Blade helper functions in your template:

@phpusefunctionStatamic\View\Blade\{value, modify, void};@endphp
// Hello there! Welcome to the world of HELPER FUNCTIONS!

Notes

  1. Most tags will be compatible with this syntax with no additional work. Docs will be coming for handling the edge cases/etc.
  2. Some tags may behave differently than they do in Antlers. This is largely due to how Antlers handles null/empty arrays. When used in Blade, tags that have different behaviors have been adapted to fit much more naturally in Blade. Docs for these scenarios is in progress.

@JohnathonKosterJohnathonKoster changed the title Statamic Tag Blade Compiler[5.x] Statamic Tag Blade CompilerOct 17, 2024
@JohnathonKoster
JohnathonKoster marked this pull request as draft October 17, 2024 03:51
@JohnathonKoster
JohnathonKoster marked this pull request as draft October 17, 2024 03:51
jasonvarga
jasonvarga previously requested changes Oct 29, 2024

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I've done something dumb, it seems that nested tags don't work.

<s:transkey="Hello" /> // works fine out here
<s:collection:articles>
<s:transkey="Hello" /> // does nothing in here
</s:collection:articles>

@jasonvarga
jasonvarga dismissed their stale reviewOctober 29, 2024 20:40

Changes were made

@daun

daun commented Oct 30, 2024

Copy link
Copy Markdown
Contributor

@JohnathonKoster This looks really neat. Would this in theory make it easier to integrate other templating engines as well or is this specifically tailored to Blade? There are addons for Twig and Latte and maybe this allows a few new tricks to make those integrations more seamless.

Comment threadtests/View/Blade/AntlersComponents/SelfClosingTagsTest.php

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that nested partials don't work.

one.blade.php
just some text
two.blade.php
{{ $slot }}
<s:partial:one /> this partial renders
<s:partial:two>
this text renders
<s:partial:one /> this partial doesnt render
</s:partial:two>

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That worked great, except now I'm noticing that slot content is escaped.

bar.blade.php
<b>text</b>
foo.blade.php
{{$slot}}
<s:partial:bar />
<s:partial:foo>
<s:partial:bar />
</s:partial:foo>

outputs

<b>text</b>
&lt;b&gt;text&lt;/b&gt;

When using Blade components, {{ $slot }} doesn't escape. It looks like they are dealing with Htmlable objects. (ComponentSlot)

@JohnathonKoster

JohnathonKoster commented Oct 30, 2024

Copy link
Copy Markdown
ContributorAuthor

@JohnathonKoster This looks really neat. Would this in theory make it easier to integrate other templating engines as well or is this specifically tailored to Blade? There are addons for Twig and Latte and maybe this allows a few new tricks to make those integrations more seamless.

The concept itself could be applied to other templating languages, but this implementation is tailored to Blade (interacting with Blade's loop variables, attribute/parameter syntax & behavior, slot behavior, etc.).

jasonvarga
jasonvarga previously requested changes Oct 31, 2024
Comment threadtests/View/Blade/AntlersComponents/PartialCompilerTest.php Outdated
@jasonvarga
jasonvarga dismissed their stale reviewOctober 31, 2024 16:57

Did the thing

@jasonvarga
jasonvarga merged commit 4ecdd9b into statamic:5.xOct 31, 2024
@admench

Copy link
Copy Markdown

Wow this is an amazing improvement! Thanks!

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@JohnathonKoster@daun@admench@jasonvarga
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[5.x] Statamic Tag Blade Compiler - #10967

Merged
jasonvarga merged 41 commits into
statamic:5.xfrom
JohnathonKoster:statamic-antlers-blade-compiler
Oct 31, 2024
Merged

[5.x] Statamic Tag Blade Compiler#10967
jasonvarga merged 41 commits into
statamic:5.xfrom
JohnathonKoster:statamic-antlers-blade-compiler

Conversation

@JohnathonKoster

@JohnathonKosterJohnathonKoster commented Oct 17, 2024

Copy link
Copy Markdown
Contributor

Much more thorough documentation/information can be found over here: statamic/docs#1473

Overview

This PR adds a new tag compiler for Blade. Its primary goal is to make leveraging existing tags simpler when writing Blade templates. For example, in Antlers, you can use the collection tag like so:

{{ collection:blog }}
{{ title }}
{{ /collection:blog }}
{{ collection:blogas="posts" }}
{{ posts }}
{{ title }}
{{ /posts }}
{{ /collection:blog }}

with the changes in this PR, the following would now be possible in Blade:

<s:collection:blog>
{{$title}}
</s:collection:blog>
<s:collection:blogas="posts">
@foreach ($postsas$post)
{{$post->title}}@endforeach
</s:collection:blog>

The internal compiler will compile the custom <s: tags to PHP behind the scenes.

This PR also adds a new @recursive_children directive, which is only intended to be used within the <s:nav tag:

<ul>
<s:nav:main>
<li>
{{$title}} - {{$depth}}@if (count($children) >0)
<ulclass="the-wrapper">
@recursive_children
</ul>
@endif
</li>
</s:nav:main>
</ul>
-- or with an alias --
<ul>
<s:nav:mainas="the_items">
@foreach ($the_itemsas$item)
<li>{{$item['title'] }} - {{$item['depth'] }}</li>
@if (isset($item['children']) &&count($item['children']))
<ulclass="wrapper">
@recursive_children($item['children'])
</ul>
@endif@endforeach
</s:nav:main>
</ul>

Important: While they shares the same syntax as components, its important to think of these as "tags" and not traditional Blade components! For example, "slot" content shares the same scope as the outer template:

<?php$myVar=0; ?>
<s:collection:blog>
@php($myVar++)
</s:collection:blog>

Helper Functions

This PR also introduces a small number of namespaced helper functions. These can be imported at the top of a Blade template by using use function. Each helper function aims to reduce friction/help in a very specific way.

value

The first of these is the value helper function. It is intended to be used in conditions (and other similar scenarios). It resolves Value instances, and a few other things for you automatically so you don't have to remember to do it each time (or if something changes in the future where it now returns Value where it didn't before):

@phpusefunctionStatamic\View\Blade\{value};@endphp{{-- Always the the non-Value version --}}@if (value($theVariableName))
...
@endif

The value helper function will handle the following scenarios for you:

  • Statamic\Fields\Value objects (calls ->value())
  • Statamic\Fields\Values objects (calls ->all())
  • Statamic\Tags\FluentTag objects (calls ->fetch())
  • Statamic\Modifiers\Modify objects (calls ->fetch())

modify

The modify helper function is simply a shortcut to calling Statamic::modify. Once imported, you can replace all Statamic::modify calls with modify:

@phpusefunctionStatamic\View\Blade\{modify};@endphp{{modify('test')->stripTags()->backspace(1)->ensureRight('!!!') }}{{modify('test')->stripTags()->safeTruncate([42, '...']) }}

void

When using tags in Antlers, you can "remove" a parameter conditionally by using the void keyword:

{{ collection:articlessort="date:asc|title:desc"limit="{display_all ? void : 3 }" }}
<li>{{ title }}</li>
{{ /collection:articles }}

The above is equivalent to:

{{ ifdisplay_all }}
{{ collection:articlessort="date:asc|title:desc" }}
<li>{{ title }}</li>
{{ /collection:articles }}
{{ else }}
{{ collection:articlessort="date:asc|title:desc"limit="3" }}
<li>{{ title }}</li>
{{ /collection:articles }}
{{ /if }}

We can use the void() helper function to accomplish the same thing in Blade:

@phpusefunctionStatamic\View\Blade\{void};@endphp
<s:collection:articlessort="date:asc|title:desc":limit="$display_all ? void() : 3"
>
<ul>{{$title}}</ul>
</s:collection:articles>

Collecting them all

Just a quick example on what it'd look like if you wanted to collect all of the new Blade helper functions in your template:

@phpusefunctionStatamic\View\Blade\{value, modify, void};@endphp
// Hello there! Welcome to the world of HELPER FUNCTIONS!

Notes

  1. Most tags will be compatible with this syntax with no additional work. Docs will be coming for handling the edge cases/etc.
  2. Some tags may behave differently than they do in Antlers. This is largely due to how Antlers handles null/empty arrays. When used in Blade, tags that have different behaviors have been adapted to fit much more naturally in Blade. Docs for these scenarios is in progress.

@JohnathonKosterJohnathonKoster changed the title Statamic Tag Blade Compiler[5.x] Statamic Tag Blade CompilerOct 17, 2024
@JohnathonKoster
JohnathonKoster marked this pull request as draft October 17, 2024 03:51
@JohnathonKoster
JohnathonKoster marked this pull request as draft October 17, 2024 03:51
jasonvarga
jasonvarga previously requested changes Oct 29, 2024

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I've done something dumb, it seems that nested tags don't work.

<s:transkey="Hello" /> // works fine out here
<s:collection:articles>
<s:transkey="Hello" /> // does nothing in here
</s:collection:articles>

@jasonvarga
jasonvarga dismissed their stale reviewOctober 29, 2024 20:40

Changes were made

@daun

daun commented Oct 30, 2024

Copy link
Copy Markdown
Contributor

@JohnathonKoster This looks really neat. Would this in theory make it easier to integrate other templating engines as well or is this specifically tailored to Blade? There are addons for Twig and Latte and maybe this allows a few new tricks to make those integrations more seamless.

Comment threadtests/View/Blade/AntlersComponents/SelfClosingTagsTest.php

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that nested partials don't work.

one.blade.php
just some text
two.blade.php
{{ $slot }}
<s:partial:one /> this partial renders
<s:partial:two>
this text renders
<s:partial:one /> this partial doesnt render
</s:partial:two>

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That worked great, except now I'm noticing that slot content is escaped.

bar.blade.php
<b>text</b>
foo.blade.php
{{$slot}}
<s:partial:bar />
<s:partial:foo>
<s:partial:bar />
</s:partial:foo>

outputs

<b>text</b>
&lt;b&gt;text&lt;/b&gt;

When using Blade components, {{ $slot }} doesn't escape. It looks like they are dealing with Htmlable objects. (ComponentSlot)

@JohnathonKoster

JohnathonKoster commented Oct 30, 2024

Copy link
Copy Markdown
ContributorAuthor

@JohnathonKoster This looks really neat. Would this in theory make it easier to integrate other templating engines as well or is this specifically tailored to Blade? There are addons for Twig and Latte and maybe this allows a few new tricks to make those integrations more seamless.

The concept itself could be applied to other templating languages, but this implementation is tailored to Blade (interacting with Blade's loop variables, attribute/parameter syntax & behavior, slot behavior, etc.).

jasonvarga
jasonvarga previously requested changes Oct 31, 2024
Comment threadtests/View/Blade/AntlersComponents/PartialCompilerTest.php Outdated
@jasonvarga
jasonvarga dismissed their stale reviewOctober 31, 2024 16:57

Did the thing

@jasonvarga
jasonvarga merged commit 4ecdd9b into statamic:5.xOct 31, 2024
@admench

Copy link
Copy Markdown

Wow this is an amazing improvement! Thanks!

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@JohnathonKoster@daun@admench@jasonvarga
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[5.x] Statamic Tag Blade Compiler - #10967

Merged
jasonvarga merged 41 commits into
statamic:5.xfrom
JohnathonKoster:statamic-antlers-blade-compiler
Oct 31, 2024
Merged

[5.x] Statamic Tag Blade Compiler#10967
jasonvarga merged 41 commits into
statamic:5.xfrom
JohnathonKoster:statamic-antlers-blade-compiler

Conversation

@JohnathonKoster

@JohnathonKosterJohnathonKoster commented Oct 17, 2024

Copy link
Copy Markdown
Contributor

Much more thorough documentation/information can be found over here: statamic/docs#1473

Overview

This PR adds a new tag compiler for Blade. Its primary goal is to make leveraging existing tags simpler when writing Blade templates. For example, in Antlers, you can use the collection tag like so:

{{ collection:blog }}
{{ title }}
{{ /collection:blog }}
{{ collection:blogas="posts" }}
{{ posts }}
{{ title }}
{{ /posts }}
{{ /collection:blog }}

with the changes in this PR, the following would now be possible in Blade:

<s:collection:blog>
{{$title}}
</s:collection:blog>
<s:collection:blogas="posts">
@foreach ($postsas$post)
{{$post->title}}@endforeach
</s:collection:blog>

The internal compiler will compile the custom <s: tags to PHP behind the scenes.

This PR also adds a new @recursive_children directive, which is only intended to be used within the <s:nav tag:

<ul>
<s:nav:main>
<li>
{{$title}} - {{$depth}}@if (count($children) >0)
<ulclass="the-wrapper">
@recursive_children
</ul>
@endif
</li>
</s:nav:main>
</ul>
-- or with an alias --
<ul>
<s:nav:mainas="the_items">
@foreach ($the_itemsas$item)
<li>{{$item['title'] }} - {{$item['depth'] }}</li>
@if (isset($item['children']) &&count($item['children']))
<ulclass="wrapper">
@recursive_children($item['children'])
</ul>
@endif@endforeach
</s:nav:main>
</ul>

Important: While they shares the same syntax as components, its important to think of these as "tags" and not traditional Blade components! For example, "slot" content shares the same scope as the outer template:

<?php$myVar=0; ?>
<s:collection:blog>
@php($myVar++)
</s:collection:blog>

Helper Functions

This PR also introduces a small number of namespaced helper functions. These can be imported at the top of a Blade template by using use function. Each helper function aims to reduce friction/help in a very specific way.

value

The first of these is the value helper function. It is intended to be used in conditions (and other similar scenarios). It resolves Value instances, and a few other things for you automatically so you don't have to remember to do it each time (or if something changes in the future where it now returns Value where it didn't before):

@phpusefunctionStatamic\View\Blade\{value};@endphp{{-- Always the the non-Value version --}}@if (value($theVariableName))
...
@endif

The value helper function will handle the following scenarios for you:

  • Statamic\Fields\Value objects (calls ->value())
  • Statamic\Fields\Values objects (calls ->all())
  • Statamic\Tags\FluentTag objects (calls ->fetch())
  • Statamic\Modifiers\Modify objects (calls ->fetch())

modify

The modify helper function is simply a shortcut to calling Statamic::modify. Once imported, you can replace all Statamic::modify calls with modify:

@phpusefunctionStatamic\View\Blade\{modify};@endphp{{modify('test')->stripTags()->backspace(1)->ensureRight('!!!') }}{{modify('test')->stripTags()->safeTruncate([42, '...']) }}

void

When using tags in Antlers, you can "remove" a parameter conditionally by using the void keyword:

{{ collection:articlessort="date:asc|title:desc"limit="{display_all ? void : 3 }" }}
<li>{{ title }}</li>
{{ /collection:articles }}

The above is equivalent to:

{{ ifdisplay_all }}
{{ collection:articlessort="date:asc|title:desc" }}
<li>{{ title }}</li>
{{ /collection:articles }}
{{ else }}
{{ collection:articlessort="date:asc|title:desc"limit="3" }}
<li>{{ title }}</li>
{{ /collection:articles }}
{{ /if }}

We can use the void() helper function to accomplish the same thing in Blade:

@phpusefunctionStatamic\View\Blade\{void};@endphp
<s:collection:articlessort="date:asc|title:desc":limit="$display_all ? void() : 3"
>
<ul>{{$title}}</ul>
</s:collection:articles>

Collecting them all

Just a quick example on what it'd look like if you wanted to collect all of the new Blade helper functions in your template:

@phpusefunctionStatamic\View\Blade\{value, modify, void};@endphp
// Hello there! Welcome to the world of HELPER FUNCTIONS!

Notes

  1. Most tags will be compatible with this syntax with no additional work. Docs will be coming for handling the edge cases/etc.
  2. Some tags may behave differently than they do in Antlers. This is largely due to how Antlers handles null/empty arrays. When used in Blade, tags that have different behaviors have been adapted to fit much more naturally in Blade. Docs for these scenarios is in progress.

@JohnathonKosterJohnathonKoster changed the title Statamic Tag Blade Compiler[5.x] Statamic Tag Blade CompilerOct 17, 2024
@JohnathonKoster
JohnathonKoster marked this pull request as draft October 17, 2024 03:51
@JohnathonKoster
JohnathonKoster marked this pull request as draft October 17, 2024 03:51
jasonvarga
jasonvarga previously requested changes Oct 29, 2024

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I've done something dumb, it seems that nested tags don't work.

<s:transkey="Hello" /> // works fine out here
<s:collection:articles>
<s:transkey="Hello" /> // does nothing in here
</s:collection:articles>

@jasonvarga
jasonvarga dismissed their stale reviewOctober 29, 2024 20:40

Changes were made

@daun

daun commented Oct 30, 2024

Copy link
Copy Markdown
Contributor

@JohnathonKoster This looks really neat. Would this in theory make it easier to integrate other templating engines as well or is this specifically tailored to Blade? There are addons for Twig and Latte and maybe this allows a few new tricks to make those integrations more seamless.

Comment threadtests/View/Blade/AntlersComponents/SelfClosingTagsTest.php

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that nested partials don't work.

one.blade.php
just some text
two.blade.php
{{ $slot }}
<s:partial:one /> this partial renders
<s:partial:two>
this text renders
<s:partial:one /> this partial doesnt render
</s:partial:two>

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That worked great, except now I'm noticing that slot content is escaped.

bar.blade.php
<b>text</b>
foo.blade.php
{{$slot}}
<s:partial:bar />
<s:partial:foo>
<s:partial:bar />
</s:partial:foo>

outputs

<b>text</b>
&lt;b&gt;text&lt;/b&gt;

When using Blade components, {{ $slot }} doesn't escape. It looks like they are dealing with Htmlable objects. (ComponentSlot)

@JohnathonKoster

JohnathonKoster commented Oct 30, 2024

Copy link
Copy Markdown
ContributorAuthor

@JohnathonKoster This looks really neat. Would this in theory make it easier to integrate other templating engines as well or is this specifically tailored to Blade? There are addons for Twig and Latte and maybe this allows a few new tricks to make those integrations more seamless.

The concept itself could be applied to other templating languages, but this implementation is tailored to Blade (interacting with Blade's loop variables, attribute/parameter syntax & behavior, slot behavior, etc.).

jasonvarga
jasonvarga previously requested changes Oct 31, 2024
Comment threadtests/View/Blade/AntlersComponents/PartialCompilerTest.php Outdated
@jasonvarga
jasonvarga dismissed their stale reviewOctober 31, 2024 16:57

Did the thing

@jasonvarga
jasonvarga merged commit 4ecdd9b into statamic:5.xOct 31, 2024
@admench

Copy link
Copy Markdown

Wow this is an amazing improvement! Thanks!

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@JohnathonKoster@daun@admench@jasonvarga
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[5.x] Statamic Tag Blade Compiler - #10967

Merged
jasonvarga merged 41 commits into
statamic:5.xfrom
JohnathonKoster:statamic-antlers-blade-compiler
Oct 31, 2024
Merged

[5.x] Statamic Tag Blade Compiler#10967
jasonvarga merged 41 commits into
statamic:5.xfrom
JohnathonKoster:statamic-antlers-blade-compiler

Conversation

@JohnathonKoster

@JohnathonKosterJohnathonKoster commented Oct 17, 2024

Copy link
Copy Markdown
Contributor

Much more thorough documentation/information can be found over here: statamic/docs#1473

Overview

This PR adds a new tag compiler for Blade. Its primary goal is to make leveraging existing tags simpler when writing Blade templates. For example, in Antlers, you can use the collection tag like so:

{{ collection:blog }}
{{ title }}
{{ /collection:blog }}
{{ collection:blogas="posts" }}
{{ posts }}
{{ title }}
{{ /posts }}
{{ /collection:blog }}

with the changes in this PR, the following would now be possible in Blade:

<s:collection:blog>
{{$title}}
</s:collection:blog>
<s:collection:blogas="posts">
@foreach ($postsas$post)
{{$post->title}}@endforeach
</s:collection:blog>

The internal compiler will compile the custom <s: tags to PHP behind the scenes.

This PR also adds a new @recursive_children directive, which is only intended to be used within the <s:nav tag:

<ul>
<s:nav:main>
<li>
{{$title}} - {{$depth}}@if (count($children) >0)
<ulclass="the-wrapper">
@recursive_children
</ul>
@endif
</li>
</s:nav:main>
</ul>
-- or with an alias --
<ul>
<s:nav:mainas="the_items">
@foreach ($the_itemsas$item)
<li>{{$item['title'] }} - {{$item['depth'] }}</li>
@if (isset($item['children']) &&count($item['children']))
<ulclass="wrapper">
@recursive_children($item['children'])
</ul>
@endif@endforeach
</s:nav:main>
</ul>

Important: While they shares the same syntax as components, its important to think of these as "tags" and not traditional Blade components! For example, "slot" content shares the same scope as the outer template:

<?php$myVar=0; ?>
<s:collection:blog>
@php($myVar++)
</s:collection:blog>

Helper Functions

This PR also introduces a small number of namespaced helper functions. These can be imported at the top of a Blade template by using use function. Each helper function aims to reduce friction/help in a very specific way.

value

The first of these is the value helper function. It is intended to be used in conditions (and other similar scenarios). It resolves Value instances, and a few other things for you automatically so you don't have to remember to do it each time (or if something changes in the future where it now returns Value where it didn't before):

@phpusefunctionStatamic\View\Blade\{value};@endphp{{-- Always the the non-Value version --}}@if (value($theVariableName))
...
@endif

The value helper function will handle the following scenarios for you:

  • Statamic\Fields\Value objects (calls ->value())
  • Statamic\Fields\Values objects (calls ->all())
  • Statamic\Tags\FluentTag objects (calls ->fetch())
  • Statamic\Modifiers\Modify objects (calls ->fetch())

modify

The modify helper function is simply a shortcut to calling Statamic::modify. Once imported, you can replace all Statamic::modify calls with modify:

@phpusefunctionStatamic\View\Blade\{modify};@endphp{{modify('test')->stripTags()->backspace(1)->ensureRight('!!!') }}{{modify('test')->stripTags()->safeTruncate([42, '...']) }}

void

When using tags in Antlers, you can "remove" a parameter conditionally by using the void keyword:

{{ collection:articlessort="date:asc|title:desc"limit="{display_all ? void : 3 }" }}
<li>{{ title }}</li>
{{ /collection:articles }}

The above is equivalent to:

{{ ifdisplay_all }}
{{ collection:articlessort="date:asc|title:desc" }}
<li>{{ title }}</li>
{{ /collection:articles }}
{{ else }}
{{ collection:articlessort="date:asc|title:desc"limit="3" }}
<li>{{ title }}</li>
{{ /collection:articles }}
{{ /if }}

We can use the void() helper function to accomplish the same thing in Blade:

@phpusefunctionStatamic\View\Blade\{void};@endphp
<s:collection:articlessort="date:asc|title:desc":limit="$display_all ? void() : 3"
>
<ul>{{$title}}</ul>
</s:collection:articles>

Collecting them all

Just a quick example on what it'd look like if you wanted to collect all of the new Blade helper functions in your template:

@phpusefunctionStatamic\View\Blade\{value, modify, void};@endphp
// Hello there! Welcome to the world of HELPER FUNCTIONS!

Notes

  1. Most tags will be compatible with this syntax with no additional work. Docs will be coming for handling the edge cases/etc.
  2. Some tags may behave differently than they do in Antlers. This is largely due to how Antlers handles null/empty arrays. When used in Blade, tags that have different behaviors have been adapted to fit much more naturally in Blade. Docs for these scenarios is in progress.

@JohnathonKosterJohnathonKoster changed the title Statamic Tag Blade Compiler[5.x] Statamic Tag Blade CompilerOct 17, 2024
@JohnathonKoster
JohnathonKoster marked this pull request as draft October 17, 2024 03:51
@JohnathonKoster
JohnathonKoster marked this pull request as draft October 17, 2024 03:51
jasonvarga
jasonvarga previously requested changes Oct 29, 2024

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I've done something dumb, it seems that nested tags don't work.

<s:transkey="Hello" /> // works fine out here
<s:collection:articles>
<s:transkey="Hello" /> // does nothing in here
</s:collection:articles>

@jasonvarga
jasonvarga dismissed their stale reviewOctober 29, 2024 20:40

Changes were made

@daun

daun commented Oct 30, 2024

Copy link
Copy Markdown
Contributor

@JohnathonKoster This looks really neat. Would this in theory make it easier to integrate other templating engines as well or is this specifically tailored to Blade? There are addons for Twig and Latte and maybe this allows a few new tricks to make those integrations more seamless.

Comment threadtests/View/Blade/AntlersComponents/SelfClosingTagsTest.php

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that nested partials don't work.

one.blade.php
just some text
two.blade.php
{{ $slot }}
<s:partial:one /> this partial renders
<s:partial:two>
this text renders
<s:partial:one /> this partial doesnt render
</s:partial:two>

@jasonvargajasonvarga left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That worked great, except now I'm noticing that slot content is escaped.

bar.blade.php
<b>text</b>
foo.blade.php
{{$slot}}
<s:partial:bar />
<s:partial:foo>
<s:partial:bar />
</s:partial:foo>

outputs

<b>text</b>
&lt;b&gt;text&lt;/b&gt;

When using Blade components, {{ $slot }} doesn't escape. It looks like they are dealing with Htmlable objects. (ComponentSlot)

@JohnathonKoster

JohnathonKoster commented Oct 30, 2024

Copy link
Copy Markdown
ContributorAuthor

@JohnathonKoster This looks really neat. Would this in theory make it easier to integrate other templating engines as well or is this specifically tailored to Blade? There are addons for Twig and Latte and maybe this allows a few new tricks to make those integrations more seamless.

The concept itself could be applied to other templating languages, but this implementation is tailored to Blade (interacting with Blade's loop variables, attribute/parameter syntax & behavior, slot behavior, etc.).

jasonvarga
jasonvarga previously requested changes Oct 31, 2024
Comment threadtests/View/Blade/AntlersComponents/PartialCompilerTest.php Outdated
@jasonvarga
jasonvarga dismissed their stale reviewOctober 31, 2024 16:57

Did the thing

@jasonvarga
jasonvarga merged commit 4ecdd9b into statamic:5.xOct 31, 2024
@admench

Copy link
Copy Markdown

Wow this is an amazing improvement! Thanks!

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@JohnathonKoster@daun@admench@jasonvarga