acf_register_block_type()
Registers a custom Gutenberg block through PHP (ACF).
It lets you add a block with its own ACF fields and render template directly from PHP.
After registration, the block can be specified in the ACF location (“Block”) parameter to attach fields to it:
'location' => [ [ [ 'param' => 'block', 'operator' => '==', 'value' => 'acf/hero-block', ], ], ],
Block output is handled through a PHP template or callback using get_field() and the_field().
Official documentation: https://www.advancedcustomfields.com/resources/acf_register_block_type/
Registration must take place on the acf/init hook.
Since ACF 6.0, it is recommended to register blocks using the new block.json syntax together with register_block_type().
The functionality described in this documentation may not work with modern WordPress versions.
Notes
-
For dynamic rendering, use
render_callback, especially when PHP logic is needed. -
Block previews can be enabled; see below.
- Nested blocks (innerBlocks) can be used; see below
Hooks from the function
Returns
(Array|false). An array of the validated settings for the registered block.
Usage
acf_register_block_type( $block );
- $block(array) (required)
Block registration arguments (correspond to registerBlockType() parameters in JS).
name(String): unique block identifier, for exampletestimonial.title(String): the display name in the editor.description(String): a short description.category(String): category (common,formatting,layout,widgets,embed).icon(String|Array): Dashicon or SVG; background and foreground colors can be set.keywords(Array): additional search words.post_types(Array): restricts post types.mode(String):auto,preview,edit— interface behavior.align,align_text,align_content(String): default alignment.render_template(String): path to the PHP render template.render_callback(Callable): function/method for rendering the block.enqueue_style,enqueue_script(String): paths to style/script files.enqueue_assets(Callable): function for dynamically registering assets.supports(Array): support options (align,mode,multiple,full_height,jsx, etc.).example(Array): template for a block-inserter preview.
Inner Blocks
<InnerBlocks /> enables nested content (blocks inside blocks).
Use the <InnerBlocks /> component in the block template. It creates an area for inserting nested blocks in the editor.
Important:
- Only one
<InnerBlocks />is permitted per block. - The block must be registered with JSX support —
'jsx' => true; otherwise the component will not work.
<InnerBlocks /> parameters
- allowedBlocks(array)
Limits the allowed blocks:
<?php $allowed_blocks = [ 'core/image', 'core/paragraph' ]; ?> <InnerBlocks allowedBlocks="<?= esc_attr( wp_json_encode( $allowed_blocks ) ) ?>" />
- template(array)
Creates the nested-block structure:
<?php $template = [ [ 'core/paragraph', [ 'placeholder' => 'Add a root-level paragraph' ] ], [ 'core/columns', [], [ [ 'core/column', [], [ [ 'core/image', [] ], ] ], [ 'core/column', [], [ [ 'core/paragraph', [ 'placeholder' => 'Add a inner paragraph' ] ], ] ], ] ], ]; ?> <InnerBlocks template="<?= esc_attr( wp_json_encode( $template ) ) ?>" templateLock="all" />
- templateLock(string)
Locks template content. Available settings:
all— the structure cannot be changed.insert— prevents removal but allows adding new blocks.
See the InnerBlocks component for more information.
Block registration example
add_action( 'acf/init', 'my_acf_init_blocks' );
function my_acf_init_blocks() {
acf_register_block_type( [
'name' => 'restricted',
'title' => 'Restricted',
'description' => 'A restricted content block.',
'category' => 'formatting',
'mode' => 'preview',
'render_template' => 'template-parts/blocks/restricted/restricted.php',
'supports' => [
'align' => true,
'mode' => false,
'jsx' => true,
],
] );
}
The restricted.php template example:
<?php
$classes = trim(
( $block['className'] ?? '' ) .
( ! empty( $block['align'] ) ? ' align' . $block['align'] : '' )
);
$start_date = get_field( 'start_date' );
$end_date = get_field( 'end_date' );
$start_ts = $start_date ? strtotime( $start_date ) : false;
$end_ts = $end_date ? strtotime( $end_date ) : false;
$notification = 'Content unrestricted.';
if ( $start_date || $end_date ) {
$notification = 'Content visible';
$notification .= $start_date ? " from $start_date" : '';
$notification .= $end_date ? " until $end_date" : '';
$notification .= '.';
}
?>
<div class="restricted-block <?= esc_attr( $classes ) ?>">
<span class="restricted-block-notification"><?= esc_html( $notification ) ?></span>
<InnerBlocks />
</div>
Block preview

To display a preview in the block inserter panel, add the example parameter when registering the block:
acf_register_block_type( [ 'name' => 'testimonial', 'title' => __( 'Testimonial' ), 'description' => __( 'A custom testimonial block.' ), 'example' => [ 'attributes' => [ 'mode' => 'preview', 'data' => [ 'testimonial' => 'Blocks are...', 'author' => 'Jane Smith', 'role' => 'Person', 'is_preview' => true, ], ], ], ] );
All values in the data array are available to the block template/handler through $block['data'] or get_field().
data— contains values available through$block['data']orget_field().is_preview— is not related to the block and can be used to display alternative markup.preview— the visual presentation mode of the block;editcan also be used, in which case fields associated with the block are displayed.
Changelog
| Since 5.8.0 | Introduced. |