-
Notifications
You must be signed in to change notification settings - Fork 29
Open
Labels
Description
For static blocks we can use the registerBlockExtension to easily add additional classnames. Technically it also works for adding inline styles but we should use that sparingly because it may introduce block validation issues and deprecations.
Another issue is that the block extensions only apply to static blocks. When the rendering happens on the server in PHP it doesn't do anything.
To solve for all these usecases we can use the HTMLTagProcessor and the block render callbacks.
Here is a quick example for adding an animation extension:
JS that deals with the editor:
/**
* additional block attributes object
*/
const ANIMATION_ATTRIBUTES = {
animation: {
type: 'object',
default: {},
},
};
/**
* generateClassNames
*
* a function to generate the new className string that should get added to
* the wrapping element of the block.
*
* @param {object} attributes block attributes
* @returns {string} className string
*/
function generateClassNames(attributes) {
const { animation } = attributes;
if (!animation?.name) {
return '';
}
const classNames = [
'has-block-animation',
animation.name,
`duration-${animation?.duration || 300}`,
];
if (animation?.delay) {
classNames.push(`delay-${animation.delay}`);
}
if (animation?.easing) {
classNames.push(`timing-${animation.easing}`);
}
const classNameString = classNames.join(' ');
return classNameString;
}
registerBlockExtension(window.AnimateBlocks.blocks, {
extensionName: 'tenup/animate-blocks',
attributes: ANIMATION_ATTRIBUTES,
classNameGenerator: generateClassNames,
Edit: BlockEdit,
});PHP to register the additional attribute for all blocks
/**
* Register animation attribute to blocks
*/
function register_animation_attribute_for_blocks() {
$registered_blocks = \WP_Block_Type_Registry::get_instance()->get_all_registered();
foreach ( $registered_blocks as $name => $block ) {
$block->attributes['animation'] = array( 'type' => 'object' );
}
}
add_filter( 'wp_loaded', __NAMESPACE__ . '\\register_animation_attribute_for_blocks', 999 );PHP to add the actual output to the block on the server:
/**
* Append custom classes to the block frontend content.
*
* @since 1.0.0
*
* @param string $block_content The block frontend output.
* @param array $content_classes Custom classes to be added in array form.
* @return string Return the $block_content with the custom classes added.
*/
function append_content_classes( $block_content, $content_classes ) {
// If there are no content classes, return the original block content.
if ( empty( $content_classes ) ) {
return $block_content;
}
// Remove duplicate classes and turn into string.
$classes = array_unique( $content_classes );
$classes = array_map( 'sanitize_html_class', $classes );
$walker = new \WP_HTML_Tag_Processor( $block_content );
$walker->next_tag();
foreach ( $classes as $class ) {
$walker->add_class( $class );
}
return $walker->get_updated_html();
}
/**
* Check if the given block has animation settings.
*
* @since 1.0.0
*
* @param string $block_content The block frontend output.
* @param array $block The block info and attributes.
* @return mixed Return either the $block_content or nothing depending on animation settings.
*/
function render_with_animation( $block_content, $block ) {
$attributes = isset( $block['attrs']['animation'] )
? $block['attrs']['animation']
: null;
// Ensure the block actually has animation settings set. Otherwise, return
// the block content.
if ( ! isset( $attributes ) ) {
return $block_content;
}
// the add_custom_classes function here just generates an array of classes to be added based on the attributes
$content_classes = add_custom_classes( $attributes );
if ( ! empty( $content_classes ) ) {
$block_content = append_content_classes( $block_content, $content_classes );
}
return $block_content;
}
add_filter( 'render_block', __NAMESPACE__ . '\\render_with_animation', 10, 3 );