You may know the content position setting in cover blocks to positioning the content inside the cover, which is horizontally and vertically centered by default. Since the group block can be used similar, and we used it inside a custom slider block, we wanted to have the identical settings for group blocks as well.

Content position for group block

First, we need to add the option itself to the group block’s toolbar. This can be done using the following code:

import assign from 'lodash.assign';
import {
	BlockControls,
	__experimentalBlockAlignmentMatrixControl as BlockAlignmentMatrixControl,
	store as blockEditorStore
} from '@wordpress/block-editor';
import { createHigherOrderComponent } from '@wordpress/compose';
import { useSelect } from '@wordpress/data';
import { addFilter } from '@wordpress/hooks';
import { __ } from '@wordpress/i18n';

const addAttributes = ( settings, name ) => {
	if ( name !== 'core/group' ) {
		return settings;
	}
	
	settings.attributes = assign( settings.attributes, {
		contentPosition: {
			default: 'top left',
			type: 'string',
		},
	} );
	
	return settings;
}

addFilter( 'blocks.registerBlockType', 'my-group/add-attributes', addAttributes );

const addControls = createHigherOrderComponent( ( BlockEdit ) => {
	return ( props ) => {
		if ( props.name !== 'core/group' ) {
			return ( <BlockEdit { ...props } /> );
		}
		
		const {
			attributes: {
				contentPosition,
			},
			clientId,
			setAttributes,
		} = props;
		const hasInnerBlocks = useSelect(
			( select ) =>
				select( blockEditorStore ).getBlock( clientId ).innerBlocks.length >
				0,
			[ clientId ]
		);
		
		return (
			<>
				<BlockEdit
					{ ...props }
				/>
				
				<BlockControls group="block">
					<BlockAlignmentMatrixControl
						label={ __( 'Change content position', 'textdomain' ) }
						value={ contentPosition }
						onChange={ ( nextPosition ) =>
							setAttributes( {
								contentPosition: nextPosition,
							} )
						}
						isDisabled={ ! hasInnerBlocks }
					/>
				</BlockControls>
			</>
		);
	};
}, 'addControls' );

addFilter( 'editor.BlockEdit', 'my-group/add-controls', addControls, 5 );

const addClass = createHigherOrderComponent( ( BlockListBlock ) => {
	return ( props ) => {
		const {
			attributes: {
				contentPosition,
			},
			name,
		} = props;
		
		if ( name !== 'core/group' || contentPosition === 'top left' ) {
			return ( <BlockListBlock { ...props } /> );
		}
		
		return (
			<BlockListBlock{ ...props }
				className={ 'is-custom-position is-position-' + contentPosition.replace( ' ', '-' ) }
			/>
		);
	};
},
'addClass' );
 
addFilter( 'editor.BlockListBlock', 'my-group/add-class', addClass );
Code language: JavaScript (javascript)

This first adds the ability to store the setting (line 12 – 27), then adds the control element to the toolbar (line 29 – 72) and then adds the class we use in SCSS later to reflect the changes made in the control element in the editor (line 74 – 96).

Then, we need said styling in SCSS:

.wp-block-group.is-custom-position {
	display: flex;
	flex-direction: column;
	height: 100%;
	margin-left: auto;
	margin-right: auto;
	
	// make sure centered aligned content is still centered
	> .has-text-align-center {
		width: 100%;
	}
	
	> .wp-block {
		margin-left: 0;
		margin-right: 0;
	}
	
	&.is-position-top-left {
		align-items: flex-start;
		justify-content: flex-start;
	}
	
	&.is-position-top-center {
		align-items: center;
		justify-content: flex-start;
	}
	
	&.is-position-top-right {
		align-items: flex-end;
		justify-content: flex-start;
	}
	
	&.is-position-center-left {
		align-items: flex-start;
		justify-content: center;
	}
	
	&.is-position-center-center {
		align-items: center;
		justify-content: center;
	}
	
	&.is-position-center-right {
		align-items: flex-end;
		justify-content: center;
	}
	
	&.is-position-bottom-left {
		align-items: flex-start;
		justify-content: flex-end;
	}
	
	&.is-position-bottom-center {
		align-items: center;
		justify-content: flex-end;
	}
	
	&.is-position-bottom-right {
		align-items: flex-end;
		justify-content: flex-end;
	}
}
Code language: SCSS (scss)

This SCSS can be used for the backend as well as the frontend.

For the frontend we also need to make sure that the custom class(es) will be added to the group block:

/**
 * Add group block content position class.
 * 
 * @param	string	$block_content The block content
 * @param	array	$block Block data
 * @return	string The updated block content
 */
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase, WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
function my_add_block_group_content_position( string $block_content, array $block ) {
	libxml_use_internal_errors( true );
	$dom = new DOMDocument();
	$dom->loadHTML(
		mb_convert_encoding(
			'<html>' . $block_content . '</html>',
			'HTML-ENTITIES',
			'UTF-8'
		),
		LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
	);
	
	foreach ( $dom->getElementsByTagName( 'div' ) as $div ) {
		// check for desired class name
		if ( strpos( $div->getAttribute( 'class' ), 'wp-block-group' ) === false ) {
			continue;
		}
		
		// check if we already processed this div
		if ( strpos( $div->getAttribute( 'class' ), 'is-position-' ) !== false ) {
			continue;
		}
		
		if ( empty( $block['attrs']['contentPosition'] ) ) {
			continue;
		}
		
		$div->setAttribute( 'class', $div->getAttribute( 'class' ) . ' is-position-' .str_replace( ' ', '-', $block['attrs']['contentPosition'] ) );
	}
	
	return str_replace(
		[
			'<html>',
			'</html>',
		],
		[
			'',
			'',
		],
		$dom->saveHTML( $dom->documentElement )
	);
}
// phpcs:enable

add_filter( 'render_block_core/group', 'my_add_block_group_content_position', 10, 2 );
Code language: PHP (php)

Note: If you want to make use of a custom vertical alignment, you need to set a custom height to your group blocks. Since they usually are only as high as their content, changing the vertical alignment has no effect, since there is no additional space that can be used for changing the alignment. However, if you set a minimum height of 400 px for your group blocks for instance and the content inside the group block is not that large, the vertical alignment works well.

Leave a Reply

Your email address will not be published. Required fields are marked *