Gutenberg – change block output using PHP or JS

If you’re a PHP developer like me, the Block Editor is like a whole new frontier for coding. It’s hard to get your bearings to know where to begin. Thankfully, now that Gutenberg is a part of WP Core, some of the documentation is improving enough that you don’t have to wade through the code on GitHub just to figure out what’s possible.

There are some things you can do with good old PHP. I’m still learning what’s good to do in PHP, and what may be better suited to JS, so hop in in the comments if you can offer better ways of accomplishing the same goals.

Change the way a block renders on the front end

If you just want to change how a block appears on the front end without changing any of the actual block editing or saving process, you can use PHP in either a plugin or a theme. This feels like a safe way to experiment with how your blocks are rendering, without destroying any of the underlying Core functionality within the Editor or even when the content gets saved to the database. Everything will work as usual on the back end – you’re just manipulating the content after the fact, right at the time it’s being displayed, as with any other filter that processes content at the time of rendering.

The render_block hook is the one we’re looking for.

Removing inline styles with PHP

One thing I really dislike about Core Blocks is that users can add inline styles. It seems to me as though it would have been better to define some Core CSS classes that themes could choose to use however they wanted, rather than adding inline styles that override everything except !important, which is always a last resort for me.

Since I have not found a way to actually remove the Text Alignment controls for the Core heading and paragraph block, I tried filtering how they were output, and I was able to remove the inline styles.

add_filter('render_block', function($block_content, $block) {
	// Only affect Core Heading and Core Paragraph blocks
	if('core/heading' === $block['blockName'] || 'core/paragraph' === $block['blockName']) {
		$block_content = str_replace('text-align:left', '', $block_content);
		$block_content = str_replace('text-align:right', '', $block_content);
		$block_content = str_replace('text-align:center', '', $block_content);
	}
	// Always return the content
	return $block_content;
}, 10, 2);

The closest I’ve come to removing the alignment tools entirely, so editors aren’t confused when they set alignment in the editor and then it doesn’t work on the front end, is to use CSS to hide just those alignment buttons.

Here’s how to enqueue the CSS so it only applies to the editor, not the front end:

add_action('init', 'css_hide_alignment_buttons');
function css_hide_alignment_buttons() {
	'hide-alignment-buttons', // unique handle
	plugins_url('/hide-alignment-buttons.css', dirname(__FILE__)),
	array('wp-edit-blocks'), // dependency - so our CSS will apply after Core CSS
	null
}

And the CSS:

.components-toolbar button[aria-label="Align text left"],
.components-toolbar button[aria-label="Align text center"],
.components-toolbar button[aria-label="Align text right"] {
	display:none;
}

If your site is set to use a different language, you would have to update this to use your translated text, since the Core developers didn’t give us a unique class or ID to identify these specific buttons or this toolbar group. Both the PHP and the CSS feel awfully hacky, so I’d love to hear if there’s another way to get this done.

If you’re building your own block using WP components, you can disable the toolbar or only enable specific buttons. Here’s how:

Let’s say you’re using a RichText component.

<RichText
    tagName="p"
    value={ paratext }
    onChange={ ( paratext ) => { setAttributes( { paratext } ) } }
/>

You can add formattingControls and set them to an empty array to remove the default bold, italic, strikethrough, and link buttons:

<RichText
    tagName="p"
    value={ paratext }
    onChange={ ( paratext ) => { setAttributes( { paratext } ) } }
    formattingControls={ [] }
/>

Or you can enable just the specific buttons you like. This would enable a link, but nothing else:

<RichText
    tagName="p"
    value={ paratext }
    onChange={ ( paratext ) => { setAttributes( { paratext } ) } }
    formattingControls={ ['link'] }
/>

Adding a CSS class to a block with PHP or JS

Something that feels a little more in line with the “WordPress Way” is adding a class to a block. You have a couple of choices here: one, use PHP to filter just the front end, or two, use JS to change the block itself.

Here’s the PHP way first – it’s very similar to the way we stripped inline styles above.

add_filter('render_block', function($block_content, $block) {
	// Only add a class to Core List blocks
	if('core/list' === $block['blockName']) {
		$block_content = str_replace('ul', 'ul class="my-custom-class"', $block_content);
	}
	// Always return the content
	return $block_content;
}, 10, 2);

This will add “my-custom-class” to the list block. The downside is, if anything else ever adds a CSS class to the list block, you will end up with a <ul> that has two class attributes. Also, if you’re using the new class to apply styling, that class won’t exist in the Editor, so the Editor view won’t match the front end. But the bright side is, you’re not changing anything about the way the block is edited or saved. If you ever remove this code, your blocks will just have the default class (or default lack of class), and will not fail validation.

That brings us to the JS way. The bright side of this method is that it actually affects the block right in the Editor, so if you’re using the class to enable certain styles and you’re wanting to apply those styles in the Editor as well as the front end, your users will be able to see those styles right in the Editor. The downside is that you’re editing a Core block fundamentally. If you already have List blocks on your website, and you later add this JS to add a CSS class to them, all of your old List blocks will fail validation because they don’t have the class. Only List blocks created after this code is added will validate. Likewise, if you ever remove this code from your site, all of your old List blocks will have the class and will fail validation because it is not from Core. So, you may end up manually combing through a lot of blocks to fix them if you don’t think this through before you start building them.

Another downside, at least for me, is that when you use this type of JS, you aren’t just creating a file and saving it. You have to set up Webpack and build it. So far, because that’s pretty foreign to me, I have used Create Guten Block for this purpose. It adds an awful lot of files for accomplishing such a trivial task, so I’d like to find a simpler, “here’s the least amount of code required” way. In any case, if you use Create Guten Block and just replace the contents of block.js with this JS, as long as you’re running npm so it can watch and build the output files, this does work:

wp.hooks.addFilter(
	'blocks.getSaveContent.extraProps',
	'namespace/gute-change-core-blocks',
	guteAddBlockClass
);

function guteAddBlockClass( props, blockType) {
	/* Only add a class to Core List blocks */
	if(blockType.name === 'core/paragraph') {
		return Object.assign( props, { class: 'my-custom-class' } );
	}
}

I’m fairly sure it would be possible to write this JS in a way that doesn’t require Webpack and building, but all the other pros and cons would remain, so my current preference is to use the PHP option instead and not affect what happens in the Editor unless it becomes critical for styling reasons.

Leave a Reply

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