> ## Documentation Index
> Fetch the complete documentation index at: https://docs.elasticfunnels.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Directives

> Backend template directives: @if, @else, @foreach, @set, session storage, @component, @extends, @block.

This page describes the **directives** the backend template engine understands. Use them in the page builder via the corresponding **backend** blocks, or write them directly in coded templates.

## Conditionals: `@if`, `@else`, `@elseif`, `@endif`

Show one block when a condition is true, optionally with else branches.

```html theme={null}
@if(article)
  <h1>{{ article.title }}</h1>
@else
  <p>Article not found.</p>
@endif
```

* **`@if(condition)`** — Renders the following content only when the condition is truthy.
* **`@else`** — Optional; rendered when the `@if` condition is false.
* **`@elseif(condition)`** — Optional; additional condition; first matching branch is used.
* **`@endif`** — Ends the conditional block.

### Conditions

You can use:

* **Word operators** (safe in HTML): `eq`, `neq`, `lt`, `lte`, `gt`, `gte`\
  Example: `@if(orders.length gt 0)`
* **Symbols** (where allowed): `===`, `!==`, `==`, `!=`, `<=`, `>=`, `<`, `>`
* **Logic:** `and`, `or`, unary `!`
* **Property checks:** `@if(article.author_avatar)`, `@if(related_articles && related_articles.length)`

Example with `@elseif` and array length:

```html theme={null}
@if(posts && posts.length)
  @foreach(post in posts)
    <article>…</article>
  @endforeach
@else
  <p>No posts yet.</p>
@endif
```

***

## Loops: `@foreach` … `@endforeach`

Repeat a block once per element in an array.

```html theme={null}
@foreach(post in posts)
  <article>
    <h3><a href="{{ post.details_url }}">{{ post.title }}</a></h3>
    <p>{{ post.excerpt | default:post.summary | default:'' | raw }}</p>
  </article>
@endforeach
```

* **`@foreach(item in array)`** — `item` is the variable name for the current element; `array` is an expression that must evaluate to an array (e.g. `posts`, `related_articles`).
* **`@endforeach`** — Required; ends the loop.

Inside the block you can use `{{ item.property }}`, `@if`, nested `@foreach`, and filters.

***

## Variables: `@set`

Define a variable for use later in the template.

```html theme={null}
@set(greeting = "Hello")
<p>{{ greeting }}, {{ name }}!</p>
```

Use when you need a reusable value or a clearer expression.

***

## Components: `@component`

Include a reusable component by name, with optional arguments.

```html theme={null}
@component("header", { title: "Home" })
```

The engine looks up the component by name and renders it with the given arguments in context.

***

## Inheritance: `@extends`, `@block`, and `@yield`

Use a **base template** and override only certain regions.

`@yield("name")` and `@block("name")…@endblock` both define named regions in a base layout that child templates can fill. The difference: `@yield` has no default content (renders empty if not overridden), while `@block` can include default content as a fallback.

### Base template (e.g. layout)

The base defines named **blocks** that child templates can override:

```html theme={null}
<!DOCTYPE html>
<html>
<head><title>Site</title></head>
<body>
  @block("content")
    Default content here.
  @endblock
</body>
</html>
```

### Child template

The child declares which base it extends and redefines one or more blocks:

```html theme={null}
@extends("layout")
@block("content")
<main>
  <h1>{{ article.title }}</h1>
  {{ article.body | raw }}
</main>
@endblock
```

* **`@extends("pageSlug")`** — Must be at the top; use the base page’s slug.
* **`@block("name")` … `@endblock`** in the child — Replaces the same-named `@block` or `@yield` in the base. Only the blocks you define are overridden; the rest of the base layout is used as-is.

### `@yield` vs `@block` — when to use which

`@yield("name")` is a slot with **no default content** — nothing renders if the child does not provide an override. `@block("name") default @endblock` has **optional default content** that renders when no child override is provided.

|                 | `@block("name") default @endblock`           | `@yield("name")`                                       |
| --------------- | -------------------------------------------- | ------------------------------------------------------ |
| Default content | Yes — rendered when child doesn't override   | No — renders empty                                     |
| Typical use     | Optional sections (header, sidebar, scripts) | Required slots (title, main content, page-level style) |

Example base layout using `@yield` for required slots and `@block` for optional ones:

```html theme={null}
<head>
  <title>@yield("title") · My Site</title>
  <style>@yield("style")</style>
</head>
<body>
  @block("header")<header><a href="/">Home</a></header>@endblock
  <main>@yield("content")</main>
  @block("scripts")@endblock
</body>
```

Child template:

```html theme={null}
@extends("layout")
@block("title")About@endblock
@block("style").about { padding: 80px 0; }@endblock
@block("content")<h1>About us</h1>@endblock
```

In the **page builder**, inheritance is supported with a read-only base layer: only the block regions are editable, and on save only the child source (extends + blocks) is stored.

***

## Session storage

You can store and read simple values in the visitor’s session from templates. Use this for things like remembering a choice across requests (e.g. a selected option, a flag) without using the frontend.

| Call                                | Purpose                                                                                 |
| ----------------------------------- | --------------------------------------------------------------------------------------- |
| **`@setSessionItem('key', value)`** | Store a value in the session. Use **`@setSessionItem('key', null)`** to clear that key. |
| **`{{ getSessionItem('key') }}`**   | Output the stored value, or empty if not set.                                           |
| **`@clearSessionItem('key')`**      | Remove the key from the session (same as setting it to null).                           |

**Rules:**

* **Keys** may only use letters, numbers, and underscores (`a–z`, `A–Z`, `0–9`, `_`). Other characters are stripped.
* **Values** are stored safely (encoded). You can pass strings or numbers; other types are JSON-serialized. There is a size limit per value (\~64 KB).
* **Clearing:** Passing `null` (or nothing) to `setSessionItem` removes the key, as does `@clearSessionItem('key')`.

**Session length and when it resets**

* **Lifetime:** Session data (including values you store with `setSessionItem`) lasts **3 hours** from when the session was first created. The timer does **not** reset on each page load—so after 3 hours the session expires and all stored values are gone.
* **When it resets:** The session is tied to the visitor’s session cookie. It is cleared when:
  * the 3-hour lifetime has passed,
  * the visitor clears their cookies,
  * or they use a different browser or device (new session).
* Use session storage for short-lived, per-visit state (e.g. “has seen this step”, “selected option for this visit”). For long-lived or cross-device data, use a different mechanism (e.g. customer account, database).

**Examples:**

```html theme={null}
@setSessionItem('selected_plan', 'premium')
<p>You chose: {{ getSessionItem('selected_plan') }}</p>
```

```html theme={null}
@if(getSessionItem('seen_intro'))
  <p>Welcome back.</p>
@else
  @setSessionItem('seen_intro', '1')
  <p>First time here? Read this…</p>
@endif
```

```html theme={null}
@clearSessionItem('cart_note')
@setSessionItem('cart_note', null)
```

***

## Summary

| Directive                                 | Purpose                                  |
| ----------------------------------------- | ---------------------------------------- |
| `@if(condition)` … `@endif`               | Conditional block                        |
| `@else` / `@elseif(condition)`            | Else branches                            |
| `@foreach(item in array)` … `@endforeach` | Loop                                     |
| `@set(variable = expression)`             | Set variable                             |
| `@setSessionItem('key', value)`           | Store (or clear with null) session value |
| `{{ getSessionItem('key') }}`             | Output session value                     |
| `@clearSessionItem('key')`                | Remove session value                     |
| `@component("name", args)`                | Include component                        |
| `@extends("pageSlug")`                    | Extend base template                     |
| `@block("name")` … `@endblock`            | Define/override block                    |

Next: [Variables and filters](/backend-template-engine/variables-and-filters).
