Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.x] Statamic Tag Blade Compiler #10967

Merged

Conversation

JohnathonKoster
Copy link
Contributor

@JohnathonKoster JohnathonKoster commented Oct 17, 2024

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:blog as="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:blog as="posts">
  @foreach ($posts as $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)
    <ul class="the-wrapper">
        @recursive_children
    </ul>
    @endif
</li>
</s:nav:main>
</ul>

-- or with an alias --

<ul>
  <s:nav:main as="the_items">
    @foreach ($the_items as $item)
      <li>{{ $item['title'] }} - {{ $item['depth'] }}</li>

      @if (isset($item['children']) && count($item['children']))
        <ul class="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):

@php
  use function Statamic\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:

@php
  use function Statamic\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:articles sort="date:asc|title:desc" limit="{display_all ? void : 3 }" }}
  <li>{{ title }}</li>
{{ /collection:articles }}

The above is equivalent to:

{{ if display_all }}
    {{ collection:articles sort="date:asc|title:desc" }}
        <li>{{ title }}</li>
    {{ /collection:articles }}
{{ else }}
    {{ collection:articles sort="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:

@php
  use function Statamic\View\Blade\{void};
@endphp

<s:collection:articles
  sort="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:

@php
  use function Statamic\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.

@JohnathonKoster JohnathonKoster changed the title Statamic Tag Blade Compiler [5.x] Statamic Tag Blade Compiler Oct 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
Copy link
Member

@jasonvarga jasonvarga left a comment

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:trans key="Hello" /> // works fine out here

<s:collection:articles>
  <s:trans key="Hello" /> // does nothing in here
</s:collection:articles>

@jasonvarga jasonvarga dismissed their stale review October 29, 2024 20:40

Changes were made

@daun
Copy link
Contributor

daun commented Oct 30, 2024

@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.

Copy link
Member

@jasonvarga jasonvarga left a comment

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>

Copy link
Member

@jasonvarga jasonvarga left a comment

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
Copy link
Contributor Author

JohnathonKoster commented Oct 30, 2024

@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 dismissed their stale review October 31, 2024 16:57

Did the thing

@jasonvarga jasonvarga merged commit 4ecdd9b into statamic:5.x Oct 31, 2024
16 checks passed
@admench
Copy link

admench commented Nov 2, 2024

Wow this is an amazing improvement! Thanks!

Sign up for free to 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