Render Templates

  • JNext lesson
  • KPrevious lesson
  • FSearch lessons
  • EscClear search

Template Variables

Every block render template receives four variables from ACF:

Every ACF block render template receives the same four variables, and once you know them you can read or write any template in the plugin: the block settings array, content, preview state, and post ID. This lesson documents each and the theme-override lookup that makes customization update-safe.

  • $block (array) – The block settings and attributes. Contains $block['id'] (unique block instance ID), $block['name'] (e.g. acf/accordion), $block['className'] (additional CSS classes), $block['style'] (style variation), and $block['data'] (flat ACF field values).

  • $content (string) – The rendered InnerBlocks HTML. Only populated for blocks with "jsx": true in their block.json supports.

  • $is_preview (bool) – true when the block is being rendered inside the editor as an AJAX preview. Useful for disabling interactive JavaScript or showing placeholder content.

  • $post_id (int) – The ID of the post being edited or displayed.

Reading Field Values

Templates should use the compatibility helper functions instead of calling get_field() directly. This ensures fields work correctly across all ACF versions, including ACF 6.7+ where get_field() behavior changed for block data.

Single Fields

$title = acf_blocks_get_field( 'field_name', $block );

This calls get_field() first. If it returns false/null/empty, it falls back to reading from $block['data']['field_name'].

Repeater Fields

$items = acf_blocks_get_repeater( 'items', array(
    'item_title',
    'item_description',
    'item_icon',
), $block );

The second argument is an array of sub-field names. You can also pass an associative array to specify field types for special handling:

$products = acf_blocks_get_repeater( 'products', array(
    'product_name'  => 'text',
    'product_image' => 'image',
    'product_link'  => 'link',
    'is_featured'   => 'bool',
    'price'         => 'number',
), $block );

Supported types:

  • text (default) – Returns the raw string value.
  • image – If the value is a numeric attachment ID, returns an array with ID, url, and alt.
  • image_url – If the value is a numeric attachment ID, returns just the URL string.
  • link – Handles serialized link arrays and normalizes to title, url, target.
  • bool – Casts to boolean.
  • int / number – Casts to integer.

The function handles three data formats transparently:

  1. Native ACF arrays (when get_field() works normally).
  2. Flat indexed keys like items_0_item_title, items_1_item_title (REST API save format).
  3. Nested row-0, row-1 format (ACF 6.7+ block comment format).

Nested Repeaters

For repeaters inside repeaters (e.g. the Compare block where each product has a sub-repeater of features):

$features = acf_blocks_get_nested_repeater(
    'products_' . $i . '_features',
    array( 'feature_name', 'feature_value' ),
    $block['data']
);

The first argument is the full flat key prefix. The third argument is the raw $block['data'] array (not the $block array itself).

Icon Markup

The helper function acf_blocks_get_icon_markup() handles icon field values:

echo acf_blocks_get_icon_markup( $icon_value );

If the value looks like a CSS class string (contains hyphens or spaces, no emoji), it outputs <i class="..." aria-hidden="true"></i>. Otherwise it outputs the value as escaped text (for emoji or text icons).

A backward-compatible alias md_get_icon_markup() is available.

InnerBlocks

Blocks with "jsx": true in their block.json supports can use InnerBlocks. The $content variable contains the rendered InnerBlocks HTML. Templates typically output it like:

<div class="acf-hero-content">
    <InnerBlocks />
    <?php echo $content; ?>
</div>

The <InnerBlocks /> tag is replaced by the editor with the InnerBlocks editing interface. On the frontend, $content contains the rendered output.

Some blocks (like Hero) check whether $content is empty and fall back to legacy ACF field values when it is. This provides backward compatibility with content created before InnerBlocks support was added.

Preview Detection

Use $is_preview to adjust rendering for the editor:

if ( $is_preview ) {
    // Show a simplified version for the editor
} else {
    // Full frontend rendering with interactive JS
}

This is commonly used to skip loading frontend JavaScript (like the star rating submission handler) in the editor preview.

Inline Styles

Some blocks generate per-instance inline CSS. The Section Block uses md_store_block_css() to collect CSS during rendering, then md_output_stored_block_css() outputs it all in wp_footer. The Post Display block outputs a <style> tag directly within its render template.

For inline CSS, the utility function acf_blocks_minify_css() strips comments, collapses whitespace, and removes trailing semicolons:

$css = acf_blocks_minify_css( $raw_css );

Quick answers to common questions:

How do I customize a block’s HTML output?

Copy the block’s template into your theme at the documented override path and edit there. The renderer checks the theme first, so your version wins and survives plugin updates. Never edit templates inside the plugin directory.

What is $is_preview used for in templates?

It’s true when the block renders inside the editor, letting templates show placeholder content or skip expensive operations during editing. The published page always renders with it false.