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 classNames utility for PHP rendered blocks #13811

Closed
sirreal opened this issue Feb 11, 2019 · 12 comments
Closed

Add classNames utility for PHP rendered blocks #13811

sirreal opened this issue Feb 11, 2019 · 12 comments
Labels
[Feature] Block API API that allows to express the block paradigm. [Feature] Extensibility The ability to extend blocks or the editing experience

Comments

@sirreal
Copy link
Member

sirreal commented Feb 11, 2019

Is your feature request related to a problem? Please describe.

When rendering blocks in PHP using render_callback, blocks often wish to use the same classes as in the editor. This functionality is not provided in any way, so block authors end up re-implementing a solution that mirrors the JavaScript implementation.

An example is core's own Latest Posts block that dedicates these lines to matching the editor-side classes:

$class = 'wp-block-latest-posts';
if ( isset( $attributes['align'] ) ) {
$class .= ' align' . $attributes['align'];
}

if ( isset( $attributes['className'] ) ) {
$class .= ' ' . $attributes['className'];
}

It's easy to overlook part of this or get something subtle wrong. I can provide several examples across a project where dynamic blocks implement the same functionality as above. It seems clear that providing the base classes the way they would appear in the editor would be a helpful utility.

Describe the solution you'd like

Provide a way for PHP rendered blocks to get the same classes that would be provided in the editor based on block name, alignment, and custom or style variation classes. A simple function that takes a block name and attributes and returns the expected class name. One difficulty would be the fact that default attributes do not appear in attributes, so default alignment or className would need to be accounted for. Here's a initial implementation idea (inspired by @jeffersonrabb):

function block_classes( $name, $attributes = array() ) {
	$classes = array( 'wp-block-' . $name );
	if ( isset( $attributes['align'] && $attributes['align'] ) {
		array_push( $classes, 'align' . $attributes['align'] );
	}
	if ( isset( $attributes['className'] ) && $attributes['className'] ) {
		array_push( $classes, $attributes['className'] );
	}
	return implode( $classes, ' ' );
}

Describe alternatives you've considered

  • A base classes string could be provided as part of some block meta to the render callback.
@simison
Copy link
Member

simison commented Feb 11, 2019

One difficulty would be the fact that default attributes do not appear in attributes, so default alignment or className would need to be accounted for.

This might get solved by block RFC efforts? #13693

@gziolo gziolo added [Feature] Block API API that allows to express the block paradigm. [Feature] Extensibility The ability to extend blocks or the editing experience labels Feb 11, 2019
@gziolo
Copy link
Member

gziolo commented Feb 11, 2019

It's important to note here that this auto-generated class name is hookable on the client (https://github.com/WordPress/gutenberg/blob/master/docs/designers-developers/developers/filters/block-filters.md#blocksgetblockdefaultclassname), as well ass it can be disabled using supports and className (https://github.com/WordPress/gutenberg/blob/master/docs/designers-developers/developers/block-api/block-registration.md#supports-optional).

@nateplusplus
Copy link

nateplusplus commented Jun 11, 2019

Hi, I just wanted to note that this is also causing an issue for my use case where I would like to add style variations to a block which also uses a render_callback.

As far as I can tell, the render_callback can only accept attributes, but the block's generated className lives within props. I'm having trouble figuring out the most graceful way to pass the selected style variation to my render_callback.

In case anyone else is having this issue, my current workaround is to use the blocks.getSaveContent.extraProps hook in order to save whatever has been generated as the className into the attributes. Here is an example:

wp.domReady( function() {

	// Before saving, get the generated className for this block and save it into attributes

	function saveClassNameToAttributes( props ) {
		return lodash.assign( props, { attributes: { className: props.className } } );
	}
	wp.hooks.addFilter(
		'blocks.getSaveContent.extraProps',
		'plugin/my-block',
		saveClassNameToAttributes
	);
} );

@youknowriad
Copy link
Contributor

Dynamic blocks now automatically add the generated className (similar to frontend) when using get_block_wrapper_attributes. I think this can be close now.

@coreyworrell
Copy link
Contributor

@youknowriad How could one use get_block_wrapper_attributes() with a block that uses withColors HOC?

Example of a Card block:

registerBlockType('site/card', {
    edit: withColors('borderColor')(CardWithColorSettings),
    save: () => <InnerBlocks.Content/>,
})

If this wasn't a dynamic block, I could do:

registerBlockType('site/card', {
    edit: withColors('borderColor')(CardWithColorSettings),
    save({ attributes: { borderColor } }) {
        const className = borderColor ? getColorClassName('border-color', borderColor) : null

        return (
            <div { ...useBlockProps.save({ className }) }>
                <InnerBlocks.Content/>
            </div>
        )
    },
})

Right now I am doing this, but of course this isn't as good as using a built in function like getColorClassName() is.

function render(array $attributes, string $content): string
{
    $extra = [];

    if (!empty($attributes['borderColor'])) {
        $extra['class'] = 'has-'.$attributes['borderColor'].'-border-color';
    }

    return sprintf('<div %s>%s</div>', get_block_wrapper_attributes($extra), $content);
}

@youknowriad
Copy link
Contributor

Hi @coreymckrill

We do have an experimental "border" support flag that would allow you do just that (border color support for both static and dynamic blocks). At the moment though, it is still experimental but in it will be made stable in the next couple WP releases.

Your solution seems like a good temporary measure.

@coreymckrill
Copy link
Contributor

cc @coreyworrell

@youknowriad
Copy link
Contributor

oops sorry Corey for the wrong ping :)

@beatreichenbach
Copy link

beatreichenbach commented Aug 8, 2021

This doesn't add classes such as alignwide and alignfull that we can add with the support parameter:

registerBlockType( 'mypackage/myblock', {
    supports: {
        align: ['wide', 'full']
    }
}

I would expect get_block_wrapper_attributes() to output something like:
class="wp-block-mypackage-myblock alignfull" when using that feature.

edit: I just saw in the documentation:

Important: It doesn’t work with dynamic blocks yet.
(https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/)

@coreyworrell
Copy link
Contributor

@youknowriad how about PHP support for __experimentalSkipSerialization? If you have that applied to a block color support, how could you apply the classes in the render_callback function? Seems you would still need to build them as in my example above.

@youknowriad
Copy link
Contributor

Seems you would still need to build them as in my example above.

@coreymckrill yes, that's exactly the intent of __experimentalSkipSerialization. It means just store the value of the attribute but don't use it or inject any style automatically, I (block author) will be taking care of that manually.

@coreyworrell
Copy link
Contributor

coreyworrell commented Feb 8, 2022

@youknowriad right I understand that. But it would be helpful to have the PHP equivalent of __experimentalUseColorProps(), __experimentalGetColorClassesAndStyles(), and the other like functions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Block API API that allows to express the block paradigm. [Feature] Extensibility The ability to extend blocks or the editing experience
Projects
None yet
Development

No branches or pull requests

8 participants