Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a guide for extending a dynamic block using the HTMLTagProcessor #134

Open
fabiankaegy opened this issue May 17, 2023 · 1 comment
Open
Labels
Good First Issue Good for newcomers Guide

Comments

@fabiankaegy
Copy link
Member

fabiankaegy commented May 17, 2023

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 );
@fabiankaegy fabiankaegy added Good First Issue Good for newcomers Guide labels May 17, 2023
@Aryan123-rgb
Copy link

Aryan123-rgb commented May 17, 2023

@fabiankaegy Hii, I was looking through your code and I am interested in contributing. I have a basic understanding of js but I have no prior knowledge of php so I am unable to understand the entire codebase . Please help me out here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Good First Issue Good for newcomers Guide
Projects
None yet
Development

No branches or pull requests

2 participants