render_blockfilter-hookWP 5.0.0

Allows changing the HTML of every block after it is rendered.

The filter is called in WP_Block::render() for static and dynamic blocks, including nested ones. For a dynamic block, render_callback has already run by this point.

After it, the render_block_(name) filter is called for the specific block type. Changes affect the output but not the saved post content.

If block rendering is interrupted through pre_render_block, the filter is not called for that block.

To change one block type, it is more convenient to use render_block_(name), for example, render_block_core/image.

To change data before rendering, use render_block_data; to skip rendering or replace the result in advance, use pre_render_block.

Usage

add_filter( 'render_block', 'wp_kama_render_block_filter', 10, 3 );

/**
 * Function for `render_block` filter-hook.
 * 
 * @param string   $block_content The block content.
 * @param array    $block         The full block, including name and attributes.
 * @param WP_Block $instance      The block instance.
 *
 * @return string
 */
function wp_kama_render_block_filter( $block_content, $block, $instance ){
	// filter...
	return $block_content;
}
$block_content(string)

Block HTML after rendering, including processing by previous callbacks of this filter.

Return the modified string or the original value. An empty string '' removes the current HTML from the output, but the cost of rendering has already been incurred. Subsequent filters can add content again.

$block(array)

Data for the block being processed.

  • blockName(string|null)
    Full block name, for example, core/image. It can be null for freeform HTML outside blocks.

  • attrs(array)
    Attributes from the block's HTML comment. Attributes extracted from HTML through source can be absent.

  • innerBlocks(array of arrays)
    Nested blocks. Each item has the same structure as $block.

  • innerHTML(string)
    HTML from the parsed block markup without the HTML of nested blocks. This is not the finished rendering result.

  • innerContent(array)
    HTML fragments and null values marking where nested blocks are inserted.
$instance(WP_Block)
Current WP_Block{} object.

Examples

#1 Add a class to paragraphs and headings

Add the article-text class to the first HTML tag of core/paragraph and core/heading blocks.

add_filter( 'render_block', 'my_add_text_block_class', 10, 2 );

function my_add_text_block_class( $block_content, $block ) {

	if ( ! in_array( $block['blockName'], [ 'core/paragraph', 'core/heading' ], true ) ) {
		return $block_content;
	}

	$processor = new WP_HTML_Tag_Processor( $block_content );

	if ( $processor->next_tag() ) {
		$processor->add_class( 'article-text' );
	}

	return $processor->get_updated_html();
}

#2 Add a wrapper to blocks with a specified class

In the additional settings of the required block, specify the needs-wrapper CSS class. On output, wrap such a block in a container.

add_filter( 'render_block', 'my_wrap_marked_block', 10, 2 );

function my_wrap_marked_block( $block_content, $block ) {
	if ( ! $block_content ) {
		return $block_content;
	}

	$classes = preg_split( '/\s+/', $block['attrs']['className'] ?? '' );

	if ( ! in_array( 'needs-wrapper', $classes, true ) ) {
		return $block_content;
	}

	return '<div class="block-wrapper">' . $block_content . '</div>';
}

Changelog

Since 5.0.0 Introduced.
Since 5.9.0 The $instance parameter was added.

Where the hook is called

WP_Block::render()
render_block
wp-includes/class-wp-block.php 717
$block_content = apply_filters( 'render_block', $block_content, $this->parsed_block, $this );

Where the hook is used in WordPress

wp-includes/block-supports/background.php 131
add_filter( 'render_block', 'wp_render_background_support', 10, 2 );
wp-includes/block-supports/block-style-variations.php 269
add_filter( 'render_block', 'wp_render_block_style_variation_class_name', 10, 2 );
wp-includes/block-supports/block-visibility.php 132
add_filter( 'render_block', 'wp_render_block_visibility_support', 10, 2 );
wp-includes/block-supports/custom-css.php 153
add_filter( 'render_block', 'wp_render_custom_css_class_name', 10, 2 );
wp-includes/block-supports/dimensions.php 187
add_filter( 'render_block', 'wp_render_dimensions_support', 10, 2 );
wp-includes/block-supports/duotone.php 44
add_filter( 'render_block', array( 'WP_Duotone', 'render_duotone_support' ), 10, 3 );
wp-includes/block-supports/elements.php 307
add_filter( 'render_block', 'wp_render_elements_class_name', 10, 2 );
wp-includes/block-supports/layout.php 1450
add_filter( 'render_block', 'wp_render_layout_support_flag', 10, 2 );
wp-includes/block-supports/position.php 151
add_filter( 'render_block', 'wp_render_position_support', 10, 2 );
wp-includes/block-supports/settings.php 151
add_filter( 'render_block', '_wp_add_block_level_presets_class', 10, 2 );
wp-includes/block-supports/states.php 749
add_filter( 'render_block', 'wp_render_block_states_support', 10, 2 );
wp-includes/blocks/navigation.php 1726
add_filter( 'render_block', 'block_core_navigation_add_support_classes_to_container', 11, 2 );
wp-includes/default-filters.php 788
add_filter( 'render_block', 'wp_render_typography_support', 10, 2 );
wp-includes/default-filters.php 791
add_filter( 'render_block', 'wp_strip_inline_note_markers' );
wp-includes/script-loader.php 3456
add_filter( 'render_block', $callback_separate, 10, 2 );