> For the complete documentation index, see [llms.txt](https://docs.acpt.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.acpt.io/integrations/gutenberg/repeater-and-flexible-content.md).

# Repeater & Flexible Content

The Repeater fields block

The **ACPT Repeater Loop** block allows you to render Repeater and Flexible Content fields directly inside the Gutenberg editor. It works by defining a template — a single "loop item" — that gets repeated once for every row of data stored in the field.

***

### Requirements

* ACPT **2.x** or later
* A **Meta Box** with at least one **Repeater** or **Flexible Content** field assigned to a post type
* The post type must use the **Gutenberg** editor

***

### Adding the block

1. Open the Gutenberg editor on any post.
2. Click **+** to add a new block and search for **"ACPT Repeater"**.
3. Insert the **ACPT Repeater Loop** block.
4. In the **Inspector Panel** (right sidebar), open **General settings**.
5. Use the **Field** dropdown to select a Repeater or Flexible Content field.
6. For **Flexible Content** fields, an additional **Block** dropdown will appear — select which layout block to render.

Once a field is selected, the block will generate a template automatically based on the field's structure.

***

### The loop template

The template is the single "row" that ACPT will repeat for each entry in the field. It is built inside the **Repeater Loop Item** inner block, which accepts any Gutenberg block (paragraphs, headings, images, buttons, third-party blocks, etc.).

Inside any block within the loop item, you reference field values using **tokens** — placeholders wrapped in double curly braces:

```
{{fieldName}}
```

When the page renders, ACPT replaces each token with the actual value for that row.

***

### Token syntax

#### Basic token

```
{{fieldName}}
```

Returns the default rendered output for the field type (e.g. a full `<a>` tag for URL fields, a formatted date for Date fields).

***

#### Dot notation — accessing sub-values

Many field types store structured data (a URL field stores both a URL and a label, an Image field stores a src, alt, title, etc.). You can target a specific property using **dot notation**:

```
{{fieldName.subKey}}
```

**Examples**

```
{{url.url}}       → the raw URL only
{{url.label}}     → the link label only

{{image.src}}     → the image src URL
{{image.alt}}     → the alt text
{{image.title}}   → the image title
{{image.id}}      → the attachment ID

{{phone.dial}}    → the dial code (e.g. +39)
{{phone.value}}   → the phone number only

{{currency.amount}}  → the numeric amount
{{currency.unit}}    → the currency code (e.g. EUR)

{{address.address}}  → street address only
{{address.city}}     → city only
{{address.country}}  → country only

{{dateRange.from}}   → start date
{{dateRange.to}}     → end date
```

***

#### Arguments — formatting modifiers

Some field types support additional formatting arguments separated by colons:

```
{{fieldName:arg1:arg2}}
```

**Date formatting**

```
{{date:d/m/Y}}         → 09/03/2026
{{date:F j, Y}}        → March 9, 2026
{{dateTime:Y-m-d:H:i}} → 2026-03-09 14:30
```

Accepts any valid [PHP date format string](https://www.php.net/manual/en/datetime.format.php).

**Number formatting**

```
{{price:2}}          → 1234.56   (2 decimal places)
{{price:2:,:. }}      → 1.234,56  (European format)
```

Arguments: `decimals : decimal_point : thousands_separator`

**List fields (Checkbox, Select Multi, List)**

```
{{tags}}             → default <ul> list
{{tags:string}}      → comma-separated string
{{tags:string:  / }} → slash-separated string
{{tags:ol}}          → ordered <ol> list
{{tags:0}}           → first item only
```

**Currency, Weight, Length**

```
{{price:symbol}}         → 42.00 €  (symbol instead of code)
{{price:value}}          → 42.00    (amount only)
{{price:full:,:.:after}} → 42,00 EUR (full with custom separators)
```

***

#### Raw modifier

Append `|raw` to any token to bypass default rendering and return the unformatted value:

```
{{url|raw}}     → raw URL string, no <a> tag
{{image|raw}}   → src URL only, no <img> tag
{{editor|raw}}  → raw HTML without shortcode processing
```

***

### Sub-key reference by field type

| Field type                  | Available sub-keys                                                                    |
| --------------------------- | ------------------------------------------------------------------------------------- |
| `URL`                       | `.url`, `.label`                                                                      |
| `Email`                     | *(none — use args: `:url`, `:link`)*                                                  |
| `Phone`                     | `.dial`, `.value`                                                                     |
| `Image` / `Video` / `Audio` | `.src`, `.url`, `.id`, `.alt`, `.title`, `.caption`, `.description`, `.href`, `.type` |
| `File`                      | `.src`, `.url`, `.id`, `.alt`, `.title`, `.label`                                     |
| `Gallery` / `Image Slider`  | `.src`, `.url`, `.id`, `.alt`, `.title` — or numeric index: `.0`, `.1`                |
| `Address`                   | `.address`, `.city`, `.country`                                                       |
| `Currency`                  | `.amount`, `.unit`                                                                    |
| `Weight`                    | `.weight`, `.unit`                                                                    |
| `Length`                    | `.length`, `.unit`                                                                    |
| `Date Range`                | `.from`, `.to`                                                                        |
| `Country`                   | `.country`                                                                            |
| `Post Object`               | *(none — use args: `:id`, `:title`)*                                                  |
| `Term Object`               | *(none — use args: `:id`, `:name`)*                                                   |
| `User`                      | *(none — use args: `:id`, `:name`)*                                                   |
| `QR Code`                   | `.url`, `.img`                                                                        |
| `Barcode`                   | `.text`, `.svg`, `.format`                                                            |

***

### Practical examples

#### Example 1 — Simple text repeater

A repeater with two child fields: `title` (Text) and `description` (Textarea).

**Template:**

```html
<h3>{{title}}</h3>
<p>{{description}}</p>
```

**Output (2 rows):**

```html
<h3>First item</h3>
<p>This is the first description.</p>
<h3>Second item</h3>
<p>This is the second description.</p>
```

***

#### Example 2 — URL field with dot notation

A repeater with a `link` field of type **URL** (stores both a URL and a label).

**Template:**

```html
<a href="{{link.url}}" class="btn">{{link.label}}</a>
```

**Output:**

```html
<a href="https://example.com" class="btn">Visit website</a>
<a href="https://another.com" class="btn">Read more</a>
```

Without dot notation, `{{link}}` would render the full default `<a>` tag. With `.url` and `.label` separately you have full control over the markup.

***

#### Example 3 — Image field inside a card

A repeater with `image` (Image), `name` (Text), and `role` (Text) fields.

**Template:**

```html
<div class="card">
    <img src="{{image.src}}" alt="{{image.alt}}" />
    <h4>{{name}}</h4>
    <span>{{role}}</span>
</div>
```

**Output:**

```html
<div class="card">
    <img src="https://site.com/wp-content/uploads/photo.jpg" alt="Jane Doe" />
    <h4>Jane Doe</h4>
    <span>Lead Developer</span>
</div>
```

***

#### Example 4 — Date field with custom format

A repeater with an `event_date` (Date) and `event_name` (Text) field.

**Template:**

```html
<p><strong>{{event_date:F j, Y}}</strong> — {{event_name}}</p>
```

**Output:**

```html
<p><strong>March 9, 2026</strong> — Annual Conference</p>
<p><strong>April 15, 2026</strong> — Workshop</p>
```

***

#### Example 5 — Currency with symbol

A repeater with a `price` (Currency) field.

**Template:**

```html
<span class="price">{{price:symbol}}</span>
```

**Output:**

```html
<span class="price">42.00 €</span>
```

***

#### Example 6 — Mixed token and raw modifier

A repeater with a `website` (URL) field used as a button `href`.

**Template:**

```html
<a href="{{website|raw}}" target="_blank" class="button">
    Visit {{website.label}}
</a>
```

`{{website|raw}}` returns the plain URL string suitable for an `href` attribute, while `{{website.label}}` returns just the label text.

***

#### Example 7 — Flexible Content

A **Flexible Content** field with a block called `feature` containing `icon` (Image) and `text` (Text) fields.

1. Select the **ACPT Repeater Loop** block.
2. Set **Field** → your Flexible Content field.
3. Set **Block** → `feature`.

**Template:**

```html
<div class="feature">
    <img src="{{icon.src}}" alt="{{icon.alt}}" width="48" height="48" />
    <p>{{text}}</p>
</div>
```

***

### Ghost preview

While editing in Gutenberg, the block renders a **ghost preview** — a dimmed preview of the actual data rows — below the template. This lets you verify that tokens are resolving correctly without leaving the editor.

The ghost preview updates automatically as you edit the template or add new blocks inside the loop item.

***

### Supported inner blocks

The loop item template supports any valid Gutenberg block, including:

* Core blocks: Paragraph, Heading, Image, List, Buttons, Columns, Group, Cover
* Third-party blocks: GenerateBlocks, Kadence, Stackable, and others

> **Note:** Some third-party blocks store field values in custom attributes rather than the standard `content` attribute. Token replacement works on the serialized block HTML, so tokens placed in any text or URL field of any block will be resolved correctly on the frontend.

***

### Troubleshooting

**Tokens are not replaced on the frontend** Make sure the token name exactly matches the child field name (case-insensitive). Check the field name in the ACPT Meta Box editor.

**The ghost preview is empty** The post must have saved data for the field. The preview fetches live data — if the field has no rows, the preview will be blank.

**A sub-key returns nothing** Not all field types support all sub-keys. Refer to the sub-key reference table above to confirm the sub-key is valid for your field type.

**The Block dropdown does not appear** The Block dropdown only appears for Flexible Content fields, not Repeater fields.

**The template resets after saving** The template is generated automatically when you first select a field. If you need to customise it, edit the inner blocks directly — your changes are preserved on save.
