From d5099f62a6d7a3a383ec91e6a107e2659ab3fdfd Mon Sep 17 00:00:00 2001 From: John Koster Date: Wed, 19 Aug 2026 23:22:19 -0500 Subject: [PATCH] Docs! --- content/collections/tags/include-exists.md | 41 ++ content/collections/tags/include-if-exists.md | 65 +++ content/collections/tags/include.md | 543 ++++++++++++++++++ 3 files changed, 649 insertions(+) create mode 100644 content/collections/tags/include-exists.md create mode 100644 content/collections/tags/include-if-exists.md create mode 100644 content/collections/tags/include.md diff --git a/content/collections/tags/include-exists.md b/content/collections/tags/include-exists.md new file mode 100644 index 000000000..2aebe2cd0 --- /dev/null +++ b/content/collections/tags/include-exists.md @@ -0,0 +1,41 @@ +--- +id: 5821391e-fc26-4a44-9a14-9893c86f0387 +title: 'Include:Exists' +description: 'Checks if a view exists.' +intro: 'Checks if a view exists.' +parameters: + - + name: src + type: string + required: true + description: | + The name of the view to check for. Example: `src="cards/author_bio"` or `:src="var_name"`. +--- +## Overview + +You can use this tag to check if a view exists. Useful if you have some sort of dynamic loop. + +::tabs + +::tab antlers +```antlers +{{ if {include:exists src="myview"} }} + It exists. +{{ else }} + It doesn't. +{{ /if }} +``` +::tab blade +```blade +@if (Statamic::tag('include:exists')->src('myview')->fetch()) + It exists. +@else + It doesn't. +@endif +``` +:: + +## Related Reading + +This tag goes hand in hand with the [`include`](/tags/include) tag. +You may be interested in the [`include:if_exists`](/tags/include-if-exists) tag to simplify your template. diff --git a/content/collections/tags/include-if-exists.md b/content/collections/tags/include-if-exists.md new file mode 100644 index 000000000..61d17a41e --- /dev/null +++ b/content/collections/tags/include-if-exists.md @@ -0,0 +1,65 @@ +--- +id: 702a89b4-ff3e-4f29-b9cd-5343c4e7d34f +title: 'Include:If_Exists' +description: 'Renders a view if it exists.' +intro: 'Renders a view if it exists.' +parameters: + - + name: src + type: string + required: true + description: | + The name of the view to render. Example: `src="cards/author_bio"` or `:src="var_name"`. + - + name: when + type: string + description: | + Render the view only if a condition is met. + - + name: unless + type: string + description: | + The converse of `when`. + - + name: cascade + type: boolean + description: | + When `true`, the [Cascade](/content-modeling/data-inheritance) is made available inside the view. Defaults to `false`. + - + name: params + type: array + description: | + An associative array whose entries become variables in the view. Any parameter you set directly on the tag overrides a matching key. + - + name: handle_prefix + type: string|array + description: | + A prefix, or array of prefixes, to strip from the keys in `params`. With `handle_prefix="hero_"`, a `hero_title` entry is also available as `{{ title }}`. + - + name: "*" + type: mixed + description: | + Any other parameter you create will be passed through to the view as a variable. +--- +## Overview + +You can use this tag to output a view if it exists. If the view doesn't exist, nothing is output instead of throwing a "view not found" exception. Useful if you have some sort of dynamic loop. + +::tabs + +::tab antlers +```antlers +{{ include:if_exists src="myview" }} +``` +::tab blade +```blade + +``` +:: + +This tag accepts everything the [`include`](/tags/include) tag does, including [slots](/tags/include#slots) and the same [scope rules](/tags/include#scope-isolation). + +## Related Reading + +This tag goes hand in hand with the [`include`](/tags/include) tag. +You may be interested in the [`include:exists`](/tags/include-exists) tag if you need to do a more complicated conditional check in your template. diff --git a/content/collections/tags/include.md b/content/collections/tags/include.md new file mode 100644 index 000000000..66510beef --- /dev/null +++ b/content/collections/tags/include.md @@ -0,0 +1,543 @@ +--- +title: Include +description: Renders another view with strict, predictable scoping +intro: The include tag renders another [view](/views), like the [partial](/tags/partial) tag, but with stricter variable scope rules and support for scoped slots. +parameters: + - + name: src + type: string + description: | + You can pass the name of the view with a parameter instead of the tag argument. Example: `src="cards/author_bio"` or `:src="var_name"`. + - + name: when + type: string + description: | + Render the view only if a condition is met. + - + name: unless + type: string + description: | + The converse of `when`. + - + name: cascade + type: boolean + description: | + When `true`, the [Cascade](/content-modeling/data-inheritance) is made available inside the view. Defaults to `false`. + - + name: params + type: array + description: | + An associative array whose entries become variables in the view. Any parameter you set directly on the tag overrides a matching key. + - + name: handle_prefix + type: string|array + description: | + A prefix, or array of prefixes, to strip from the keys in `params`. With `handle_prefix="hero_"`, a `hero_title` entry is also available as `{{ title }}`. + - + name: "*" + type: mixed + description: | + Any other parameter you create will be passed through to the view as a variable. +id: d2bb11fc-5acf-44f4-b134-7a27b9f0dc78 +--- +## Overview + +The `include` tag renders another [view](/views), just like the [partial](/tags/partial) tag, but the two differ in how variables are passed in and general scoping rules. A `partial` inherits your template's data automatically. An `include` sees only what you pass it, its own front-matter, and the Cascade if you opt in. + +::tabs + +::tab antlers +```antlers +{{# Import /resources/views/blog/_card.antlers.html #}} +{{ include:blog/card }} +``` +::tab blade +```blade +{{-- This will import /resources/views/blog/_card.antlers.html --}} + +``` +:: + +## Scope Isolation + +The `include` tag has stricter scope than `partial`. Below, _your template_ is the file calling the tag, and _the view_ is the file being included: + +1. Views receive no data from your template. Only tag parameters, [`params`](#passing-lots-of-data) entries, and the view's own front-matter are available. +2. Variables assigned _inside_ a view don't leak back to your template, even when both use the same name. +3. Reassigning a variable you passed in won't leak the new value back to your template. +4. The [Cascade](/content-modeling/data-inheritance) is unavailable unless you opt in with `cascade="true"`. +5. Nested includes do not inherit the variables of their parent includes. +6. Slot content uses the variables of your template. + +The difference between the two tags is easiest to see side by side: + +::tabs +::tab include +```antlers +{{ title = "Dashboard" }} + +{{ include:widget }} + +Result: {{ title }} +``` + +```antlers +{{# _widget.antlers.html #}} +

{{ title }}

+{{ title = "Widget" }} +``` + +```output +

+ +Result: Dashboard +``` +::tab partial +```antlers +{{ title = "Dashboard" }} + +{{ partial:widget }} + +Result: {{ title }} +``` + +```antlers +{{# _widget.antlers.html #}} +

{{ title }}

+{{ title = "Widget" }} +``` + +```output +

Dashboard

+ +Result: Widget +``` +:: + +:::tip +Scope isolation applies to your data, not to cross-template features. Stacks, [sections](/tags/section), and the [scope](/tags/scope) tag all still work from inside an included view, and are the intended way to send something back out. +::: + +### The Cascade + +The [Cascade](/content-modeling/data-inheritance) is not available inside an included view by default, including globals, `current_user`, and URL segments. You may opt in with `cascade="true"`: + +::tabs +::tab antlers +```antlers +{{ include:header cascade="true" }} + +{{# Inside `header.antlers.html` #}} +Welcome back, {{ current_user:name }} +``` +::tab blade +```blade + + +{{-- Inside `header.blade.php` --}} +Welcome back, {{ $current_user['name'] }} +``` +:: + +The Cascade is opt-in per include, and nested includes don't inherit it. + +### Front-Matter Defaults + +Included views can define default values with [YAML front-matter](/variables/overview#view-front-matter), just like partials. Parameters you pass override the defaults. + +::tabs + +::tab antlers +```antlers +{{ include:card author="David Hasselhoff" }} +``` + +```antlers +--- +author: Jack McDade +image: https://example.com/placeholder.png +--- + + +

Written by {{ view:author }}

+``` +::tab blade +```blade + +``` + +```blade +@frontmatter([ + 'author' => 'Jack McDade', + 'image' => 'https://example.com/placeholder.png', +]) + + +

Written by {{ $view['author'] }}

+``` +:: + +```html + +

Written by David Hasselhoff

+``` + +Unlike partials, each include's `view` data is not merged into other nested includes. + +## Passing Data + +You must pass data into an included view explicitly: + +::tabs + +::tab antlers +```antlers +{{ include:list header="favorite ice cream flavors" :items="flavors" }} + +{{# Inside `list.antlers.html` #}} +

These are my {{ header }}

+{{ items | ul }} +``` +::tab blade +```blade + + +{{-- Inside `list.blade.php` --}} +

These are my {{ $header }}

+{!! Statamic::modify($items)->ul() !!} +``` +:: + +```html +

These are my favorite ice cream flavors

+
    +
  • Chocolate Chip Cookie Dough
  • +
  • Mint Chocolate Chip
  • +
  • Neon Mind Melter
  • +
+``` + +### Passing Lots of Data + +Rather than listing out one parameter per variable, use `params`. It takes an associative array and spreads each entry into the view as its own variable, which is handy for something like a [Replicator](/fieldtypes/replicator) set. + +::tabs + +::tab antlers +```antlers +{{ include:card :params="author" }} + +{{# Inside `card.antlers.html` #}} +

{{ name }}

+ +``` +::tab blade +```blade + + +{{-- Inside `card.blade.php` --}} +

{{ $name }}

+ +``` +:: + +Parameters set directly on the tag override matching keys in the array: + +::tabs +::tab antlers +```antlers +{{ include:card :params="author" name="A different name" }} +``` +::tab blade +```blade + +``` +:: + +Passing anything other than an associative array to `params` will throw an exception. + +:::tip +A `params` variable is also made available to you within the view. The `params` variable will contain _all_ parameters set on the `include` tag (not just those passed to `params`). This can be useful to check if something was actually explicitly set on the tag. +::: + +::tabs +::tab antlers +```antlers +{{ include:card :params="author" role="Editor" }} + +{{# Inside `card.antlers.html` #}} +{{ params:name }} {{# From the params array #}} +{{ params:role }} {{# From the parameter set on the tag #}} +``` +::tab blade +```blade + + +{{-- Inside `card.blade.php` --}} +{{ $params['name'] }} {{-- From the params array --}} +{{ $params['role'] }} {{-- From the parameter set on the tag --}} +``` +:: + +You may also use the `params` parameter to pass data that has the same name as a reserved parameter, such as `src`, `when`, `cascade`, etc. + +### Variable Prefixing + +When your data shares a common prefix, such as fields from an imported fieldset, use `handle_prefix` to remove the prefix from variables within the included view. With `handle_prefix="hero_"`, a `hero_title` entry becomes available as `{{ title }}`. + +::tabs +::tab antlers +```antlers +{{ include:hero :params="entry" handle_prefix="hero_" }} + +{{# Inside `hero.antlers.html` #}} +

{{ title }}

+

{{ subtitle }}

+``` +::tab blade +```blade + + +{{-- Inside `hero.blade.php` --}} +

{{ $title }}

+

{{ $subtitle }}

+``` +:: + +Prefixed variables are _added_, not renamed. A `hero_title` entry is available as both `{{ title }}` and `{{ hero_title }}`. + +You may also pass an array, such as `:handle_prefix="['hero_', 'banner_']"`. Prefixes are checked in order, and the first to produce a given name wins. + +:::tip +When the same variable name comes from more than one place, this is the order of priority (highest first): + +1. A prefixed parameter set directly on the tag (`hero_title`) +2. A plain parameter set directly on the tag (`title`) +3. A prefixed key from `params` (`hero_title`) +4. A plain key from `params` (`title`) +::: + +## Slots + +To pass a chunk of markup into a view, use the include tag as a pair. Everything between the tags becomes the `{{ slot }}` variable: + +::tabs +::tab antlers +```antlers +{{# In your template #}} +{{ include:modal title="Confirmation" }} +
+ +

Are you sure you want to delete your collection of WWE wrestling figures?

+
+{{ /include:modal }} + +{{# _modal.antlers.html #}} +
+

{{ title }}

+ {{ slot }} + +
+``` +::tab blade +```blade +{{-- In your template --}} + +
+ +

Are you sure you want to delete your collection of WWE wrestling figures?

+
+
+ +{{-- _modal.blade.php --}} +
+

{{ $title }}

+ {!! $slot !!} + +
+``` +:: + +Slots are _lazily_ evaluated when using the include tag. They render only when the view outputs them. Slot content uses your template's variables plus the include's [`params`](#passing-lots-of-data). + +### Named Slots + +A view can have more than one slot. Define them in your template with `slot:name` pairs, and output them in the view the same way as the default slot: + +::tabs +::tab antlers +```antlers +{{ include:card }} + {{ slot:header }}

Welcome

{{ /slot:header }} + + This is the default slot. +{{ /include:card }} + +{{# _card.antlers.html #}} +
{{ slot:header }}
+
{{ slot }}
+``` +::tab blade +```blade + +

Welcome

+ + This is the default slot. +
+ +{{-- _card.blade.php --}} +
+
{{ $slot }}
+``` +:: + +### Fallback Content + +Render default content when a slot wasn't provided. Checking a slot tests for its presence without forcing a render: + +::tabs +::tab antlers +```antlers +{{# Inside the view #}} +{{ if slot:header }} +
{{ slot:header }}
+{{ else }} +
Default heading
+{{ /if }} +``` +::tab blade +```blade +{{-- Inside the view --}} +
Default heading
+``` +:: + +### Scoped Slots + +Add parameters to a slot's output tag and they become variables inside the slot's content. This is ideal for loops, where each iteration passes the slot its own values: + +::tabs +::tab antlers +```antlers +{{# In your template #}} +{{ include:list :rows="people" }} + {{ slot:row }} + {{ name }} - #{{ index }} + {{ /slot:row }} +{{ /include:list }} + +{{# In _list.antlers.html #}} +{{ rows }} + {{ slot:row :name="name" :index="count" }} +{{ /rows }} +``` +::tab blade +```blade +{{-- In your template --}} + + {{ $name }} - #{{ $index }} + + +{{-- In _list.blade.php --}} +@foreach ($rows as $person) + +@endforeach +``` +:: +```output +Alice - #1 +Bob - #2 +Carol - #3 +``` + +This also works with the default slot: + +::tabs +::tab antlers +```antlers +{{# In your template #}} +{{ include:list :rows="people" }} + {{ name }} - #{{ index }} +{{ /include:list }} + +{{# In _list.antlers.html #}} +{{ rows }} + {{ slot :name="name" :index="count" /}} +{{ /rows }} +``` +::tab blade +```blade +{{-- In your template --}} + + {{ $name }} - #{{ $index }} + + +{{-- In _list.blade.php --}} +@foreach ($rows as $person) + +@endforeach +``` +:: +```output +Alice - #1 +Bob - #2 +Carol - #3 +``` + +Inside the slot, these parameters take precedence over variables of the same name from your template. + +### Forwarding Slots + +A slot is just a value, so a view can pass one it received to another include, either as a parameter or wrapped in a new pair: + +```antlers +{{# _card.antlers.html forwards its slot to _panel.antlers.html #}} +{{ include:panel :slot="slot" }} + +{{# Or, wrap it with more content along the way #}} +{{ include:panel }}

{{ title }}

{{ slot }}{{ /include:panel }} +``` + +## Conditional Rendering + +Render a view only if a condition is met with `when`, or its converse, `unless`. + +::tabs +::tab antlers +```antlers +{{ include:components/subtitle :when="subtitle" }} + {{ subtitle }} +{{ /include:components/subtitle }} +``` +::tab blade +```blade + + {{ $subtitle }} + +``` +:: + +## Using With Modifiers + +Because `include` is a tag and not a variable, you can't pipe it through [modifiers](/modifiers) directly. Wrap it in a [sub-expression](/antlers#sub-expressions) using curly braces to apply modifiers to its output. + +```antlers +{{ {include:component} | spaceless }} +``` + +In Blade, render the view and pass the result through `Statamic::modify()`: + +```blade +{!! Statamic::modify(Statamic::tag('include:component')->fetch())->spaceless() !!} +``` + +## Related Reading + +If you haven't read up on [views](/views) yet, you should. It's considered fundamental knowledge, like knowing that seals are just dog mermaids. 🐕 🧜‍♀️ + +The [partial](/tags/partial) tag covers the same ground with inherited scoping. Reach for it when you want the surrounding data to flow in automatically. + +You may also be interested in the [`include:exists`](/tags/include-exists) or [`include:if_exists`](/tags/include-if-exists) tags.