Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors

Spacing_Preprocessor::add_block_gapsprivateWC 1.0

Adds spacing to blocks: margin-top for vertical gaps, horizontal padding for column gaps, and root padding for children of root-level containers.

Root padding is distributed from the outer email wrapper to individual block wrappers. Container blocks (groups, post-content) at the root level delegate padding to their children instead of taking it themselves. This enables alignfull blocks to skip root padding and span the full email width.

Container padding works similarly: when a template group wrapping post-content has its own horizontal padding, that padding is distributed per-block alongside root padding. Alignfull blocks skip both padding types and span the full contentSize. The template group gets a suppress-horizontal-padding flag so its renderer omits horizontal padding from its own CSS output.

Blocks fall into three categories for root padding:

  • Zero padding (has_zero_padding): skip root padding entirely — edge-to-edge intent.
  • Non-zero explicit padding (has_own_padding, !has_zero_padding): receive root padding on top of their own padding. Their own padding is internal content spacing; root padding ensures inset from the email edge. These blocks also stop delegation.
  • No explicit padding: receive root padding if delegated, or delegate if a container.

Method of the class: Spacing_Preprocessor{}

No Hooks.

Returns

Array.

Usage

// private - for code of main (parent) class only
$result = $this->add_block_gaps( $parsed_blocks, $gap, $parent_block, $root_padding, $apply_root_padding, $container_padding ): array;
$parsed_blocks(array) (required)
Parsed blocks.
$gap(string)
Gap.
Default: ''
$parent_block(array|null)
Parent block.
Default: null
$root_padding(array)
Root horizontal padding with 'left' and 'right' keys.
Default: array()
$apply_root_padding(true|false)
Whether this block should receive root padding (delegated by parent container).
Default: false
$container_padding(array)
Container horizontal padding with 'left' and 'right' keys.
Default: array()

Spacing_Preprocessor::add_block_gaps() code WC 10.7.0

private function add_block_gaps( array $parsed_blocks, string $gap = '', $parent_block = null, array $root_padding = array(), bool $apply_root_padding = false, array $container_padding = array() ): array {
	foreach ( $parsed_blocks as $key => $block ) {
		$block_name        = $block['blockName'] ?? '';
		$parent_block_name = $parent_block['blockName'] ?? '';
		// Ensure that email_attrs are set.
		$block['email_attrs'] = $block['email_attrs'] ?? array();

		/**
		 * Do not add a gap to:
		 * - first child
		 * - parent block is a buttons block (where buttons are side by side).
		 */
		if ( 0 !== $key && $gap && 'core/buttons' !== $parent_block_name ) {
			$block['email_attrs']['margin-top'] = $gap;
		}

		// Handle horizontal gap for columns: apply padding-left to column children (except the first).
		if ( 'core/columns' === $parent_block_name && 0 !== $key && null !== $parent_block ) {
			$columns_gap = $this->get_columns_block_gap( $parent_block, $gap );
			if ( $columns_gap ) {
				$block['email_attrs']['padding-left'] = $columns_gap;
			}
		}

		// Distribute root horizontal padding.
		// Container blocks (group, post-content) at root level do NOT get padding;
		// they delegate it to their children. Non-container blocks at root level
		// (e.g., columns, paragraph) get padding directly.
		// Blocks flagged with $apply_root_padding (children of root containers)
		// also get padding, unless they are post-content or a container wrapping
		// post-content (both delegate further down the tree).
		// Blocks that explicitly define their own horizontal padding are managing
		// their own layout and skip root padding entirely. Containers with explicit
		// padding also stop delegation so their children follow the container's padding.
		$is_root_level      = null === $parent_block;
		$is_container       = in_array( $block_name, self::CONTAINER_BLOCKS, true );
		$alignment          = $block['attrs']['align'] ?? null;
		$has_zero_padding   = $this->has_zero_horizontal_padding( $block );
		$has_own_padding    = $this->has_explicit_horizontal_padding( $block );
		$wraps_post_content = $apply_root_padding && $is_container && $this->contains_post_content( $block );
		$should_apply       = $apply_root_padding || ( $is_root_level && ! $is_container ) || ( $is_root_level && $is_container && $has_own_padding );

		$post_content_block_names = $this->get_post_content_block_names();
		if ( $should_apply && ! $has_zero_padding && 'full' !== $alignment && ! in_array( $block_name, $post_content_block_names, true ) && ! $wraps_post_content && ! empty( $root_padding ) ) {
			$block['email_attrs']['root-padding-left']  = $root_padding['left'];
			$block['email_attrs']['root-padding-right'] = $root_padding['right'];
		}

		// Apply container padding (from template group wrapping post-content).
		// Alignfull blocks skip both root and container padding.
		if ( $should_apply && ! $has_zero_padding && 'full' !== $alignment && ! in_array( $block_name, $post_content_block_names, true ) && ! $wraps_post_content && ! empty( $container_padding ) ) {
			$block['email_attrs']['container-padding-left']  = $container_padding['left'];
			$block['email_attrs']['container-padding-right'] = $container_padding['right'];
		}

		// Determine whether children should receive root padding delegation.
		// Root-level containers delegate to their children.
		// Post-content blocks that received delegation also pass it through.
		// Containers wrapping post-content that received delegation also delegate,
		// so that user blocks inside post-content get padding individually.
		// Containers with explicit horizontal padding stop delegation — they
		// manage their own layout.
		$children_apply         = false;
		$children_container_pad = $container_padding;
		if ( $is_root_level && $is_container && ! $has_own_padding ) {
			$children_apply = true;
		} elseif ( $apply_root_padding && in_array( $block_name, $post_content_block_names, true ) ) {
			$children_apply = true;
		} elseif ( $wraps_post_content ) {
			$children_apply = true;

			// When a container wrapping post-content has its own non-zero
			// horizontal padding, distribute it as container-padding to
			// descendant blocks and suppress the container's own CSS padding.
			$block_padding = $this->get_block_horizontal_padding( $block );
			if ( ! empty( $block_padding ) ) {
				$children_container_pad                              = $block_padding;
				$block['email_attrs']['suppress-horizontal-padding'] = true;
			}
		} elseif ( $is_root_level && $is_container && $has_own_padding && ! $has_zero_padding && $this->contains_post_content( $block ) ) {
			// Root-level container with own padding that wraps post-content:
			// distribute its padding as container-padding and suppress its own CSS.
			$children_apply = true;
			$block_padding  = $this->get_block_horizontal_padding( $block );
			if ( ! empty( $block_padding ) ) {
				$children_container_pad                              = $block_padding;
				$block['email_attrs']['suppress-horizontal-padding'] = true;
			}

			// This container also should not receive root padding itself
			// (it delegates everything to children).
			unset( $block['email_attrs']['root-padding-left'], $block['email_attrs']['root-padding-right'] );
		}

		$block['innerBlocks']  = $this->add_block_gaps( $block['innerBlocks'] ?? array(), $gap, $block, $root_padding, $children_apply, $children_container_pad );
		$parsed_blocks[ $key ] = $block;
	}

	return $parsed_blocks;
}