WordPress: How to modify Core blocks with PHP
You may not or be a fan of the new Gutenberg in WordPress. This feature is an important improvement when you compare it to a WYSIWYG editor. This new editor makes writing content for blogs with columns, tables, images, and galleries.
What are some of the improvements with Gutenberg editor?
- Page builder
- Embed videos
- Create columns
- Galleries
- Reusable blocks
- …
In this article I will not explain the basics of Gutenberg, you are also required to have some basic knowledge about PHP and the internal workings of WordPress.
In the past
Before working with Gutenberg, writing articles was a bit different, especially when you wanted to use columns in your editor. Most of the time you used a WYSIWYG editor or you had to create custom fields for a specific page template.
Now with Gutenberg, is has become much easier to create content with columns, videos or even galleries.
Past
In the past you needed a plugin like ACF PRO or in Drupal something like Paragraphs or a page-builder . In the worst case you had to write custom HTML-code in the source code of your WYSIWYG.
The new way
Now it has become much easier to create content with columns or create custom blocks; this can be done by writing custom javascript or using third-party plugins like ACF PRO
The problem with WYSIWYG editors
Again, in the past, you had to write text or custom HTML code using a Wysiwyg editor like TinyMCE. The problem with these out-dated editors is that they look Libre Office.
These editors gave a lot of problems every-time you copy-pasted text.
- Wysiwyg editors have their limitations
- Creating columns or something fancy requires front-end knowledge
Is Gutenberg an improvement?
Yes, Gutenberg is definitely a huge improvement that makes resizing images easier.
- Create columns
- Group content
- Create image galleries
- Embed content of YouTube, Vimeo or a lot of services
Even the Drupal community is making a module that is similar to that of WordPress Gutenberg.
Benefits
This is an improvement like I mentioned above. The biggest benefit of this lets you concentrate more on development.
But more importantly, you can delegate creating pages to the most simple soul (sarcasm). Yes, this is a cruel comment, but this is a reality :) Customers will appreciate this and be more happy a more user friendly implementation.
The most common blocks are paragraphs, headings, embeds, lists, etc …
But WordPress also allows ways to modify the existing HTML (with some limitations) by using WordPress Filter hooks.
Note: The following code is written in PHP 7.4 and will not work in lower versions of PHP.
You can write a filter hook to modify the HTML.
Inside my hook I am using conditions to avoid storing my modified code in the database.
- Target the type of block (group, image)
- Only render in the front-end
- Don’t alter the HTML in wp-json
$block attributes
Every blocks contains properties which are important, to fetch values CSS-classes or titles.
BlockName
This property explains the type of block and is important to target a specific block.
Variable $block
This is the most important variable, it explains and contains information about background-color or alignment.
'blockName' => string 'core/paragraph' (length=14)
'attrs' =>
array (size=0)
empty
'innerBlocks' =>
array (size=0)
empty
'innerHTML' => string '...'(length=...)
'innerContent' =>
array (size=1)
0 => string '...'(length=...)
attrs:
- className
- backgroundColor
- align
innerBlocks: this property is empty most of the time, but isn’t empty when you use core/columns and core/group
innerHTML: is a string generated by WordPress core
innerContent: is an array of HTML strings
InnerHTML
This is the original HTML generated by WordPress, notice that this string does not include the HTML of the innerBlocks attribute.
Get the ID attribute
Unfortunately for you getting the ID is weird. Because it does not appear in the attribute attrs, you need to use a regular expression. You can also use the technique below to retrieve attributes like href, rel, and so on.
You need to use innerHTML, because $block_content may include child blocks; columns, rows, groups.
Inner blocks
As mentioned above you can use inner_blocks, to modify the CSS-classes of columns. For example you want to change the CSS-class wp-block-column into the bootstrap .col CSS-class.
Groups
This block typically contains your child-blocks like paragraphs, images, headings, or any other type of block-like columns.
Inside your hook you can use the php function var_dump to inspect your child blocks.
The output should look like this when you have a paragraph inside a group or a column.
array (size=1)
0 =>
array (size=5)
'blockName' => string 'core/paragraph' (length=14)
'attrs' =>
array (size=0)
empty
'innerBlocks' =>
array (size=0)
empty
'innerHTML' => string '<p>A paragraph inside a group</p>'(length=...)
'innerContent' =>
array (size=1)
0 => string '<p>A paragraph inside a group</p>'(length=...)
A group rendered in the front-end, it will look like this:
<div class="wp-block-group">
<div class="wp-block-group__inner-container">
<div class="wp-block-columns">
<div class="wp-block-column">
<p>A paragraph inside a group</p>
</div>
...
</div>
</div>
</div>
Let’s change the existing CSS-classes
The simplest solution for changing some CSS-classes, is by doing the following (core/group).
$block['attrs']['className'] = str_replace('wp-block-group', 'group', $block['attrs']['className']);
And for rows (bootstrap):
// rows
$block['attrs']['className'] = str_replace('wp-block-columns', 'row', $block['attrs']['className']);
Now you should start seeing the pattern, that we looping to each block and replacing the default WordPress CSS-classes.
The total picture looks like this for rendering columns.
This can be useful when you want to alter the CSS class names, while you want to use a specific CSS framework, or you are a person who writes everything from scratch without a framework.
But you can basically alter the output and make your HTML resemble that of Bootstrap. Basically when you inspect the code of WordPress inside the directory wp-includes/, you’ll notice that the function the_content parses everything and loops through each block with the function render_block.
Filter render block
You can use the filter render_block, to hook in altering the existing HTML
Inside your hook, you can use a for-each on the attribute innerBlocks, to render the columns or sub-blocks.
Basically you can use this hook, to alter your HTML that uses the syntax of your favourite framework like Bootstrap or Foundation Sites.
Default CSS-classes for background colour
WordPress has the functionality to add background or text colours, and WordPress would append CSS-classes like this.
<div class="... has-background has-vivid-cyan-blue-background-color">...</div>
Unfortunately it is impossible at this moment — to alter these class names with a build-in WordPress hook. If you really want to alter the CSS class names, I would recommend using a Filter Hook and returning a different output.
$block['attrs']['className'] = str_replace('has-vivid-cyan-blue-background-color', 'bg-cyan-blue', $block['attrs']['className'] ?? '');
Solution block core/group
The group is an interesting block, it is ideal for turning Gutenberg in a full fledged page builder. The most important usage is of course grouping content and giving it a background colour, anchor link, …
The index className only includes CSS class(es) that have been filled in the drop-down advanced when you select block.
As long as the input-field “Additional CSS class(es)” is empty, the PHP-index will also not exists. That is why it is important to use the PHP function isset or the syntax ??= to detect if the attribute exists. Else you’ll encounter internal server errors.
<?php// Add background colour of core/group
$block['attrs']['className'] .= ' group--' . ($block['attrs']['backgroundColor'] ?? 'white');
Solution for blocks like heading, paragraphs, lists, etc …
Paragraphs, heading, etc require a totally different solution because WordPress already generates these HTML tags and a problem is that WordPress doesn’t include everything in $block[‘attrs’].
Both solutions also work when you want to change the defaults, while aligning the content centred or to the right.
<?php$block_content = str_replace(
'has-' . ($block['attrs']['backgroundColor'] ?? 'white') . '-background-color',
'bg--' . ($block['attrs']['backgroundColor'] ?? 'white'),
$block_content
);
These missing attributes
When you debug the attributes of a block, you’ll notice that properties like an anchor tag isn’t included in your array.
This is a work around is by using regular expressions, because there is no attribute target inside the variable $block.
// Always use the index innerHTML and never $block_content
preg_match('/id="(.+?)"/', $block['innerHTML'], $id_matches); // Values ['id="anchor-tag", 'anchor-tag']$html .= '<div class="... ' . $block['attrs']['className'] . '" ' . ($id_matches[0] ?? '') . '>' . "\n";
Text colour
The solution is almost the same as with background colours, instead we are replacing a string with another string by using the PHP function str_replace.
<?php
// Alter text colour of core/group
$block['attrs']['className'] .= ' text-color---' . ($block['attrs']['backgroundColor'] ?? 'white');
Alter background names
By default WordPress comes with a lot of background colour names, like pink and orange. But sometimes you want to disable this to limit the editors to make weird colour changes to the website.
- Limit the amount of colours by settings your custom colors
- Disable custom colours
This result can easily be achieved by creating an action hook that uses “after_setup_theme”. An action hook is a bit different than a filter, where a filter hook can be used to alter passed data like arrays or strings.
When are action hooks interesting?
Action hooks are instead used to register post types, style sheets, scripts, categories or render HTML in de head tag or render a re-captcha at the WordPress login form.
- Register post type
- Register taxonomy
- Add style-sheet or script
- Add HTML in the head or beginning or end of the body tag
- Enable support for thumbnails / featured image
- Remove or disable functionality of WordPress like XMLRCP that have security issues
- Disable editing theme files through the back-office
Now let’s not get off track. You will probably find the following snippet interesting. This way you can write your custom colour styles and remove the colour choise like pink.
Note: WordPress generates a bunch of code and also includes an extra stylesheet in the background.
Remove Gutenberg Stylesheet
When you inspect your network panel in WordPress or view the source of the page you’ll see this stylesheet popping-up in the HTML.
<link rel='stylesheet' id='wp-block-library-css' href='.../wp-includes/css/dist/block-library/style.min.css?ver=5.4.1' type='text/css' media='all' />
Luckily for this you can use the function wp_deregister_style and remove that stylesheet from all of your pages. This reduces the amount of stylesheets that are loaded on a page and this way you’ll have faster loading speeds.
add_action('init', static function () {
wp_deregister_style('wp-block-library-css');
});
Debugging
This is the simplest and most basic way to debug data from a block coming through a hook. It can easily be done by writing the following code.
<?php
if (
$block['blockName'] === 'core/group' &&
!is_admin() &&
!wp_is_json_request()
) {
// Detect the block you want and only render in the front-endvar_dump($block);
}
By this simple trick you can see which properties the variable $block contains.
Disable blocks
Ok, most of the time you to give your customers full access to every block type. But sometimes it’s better to disable certain block types like file, video file, …
This to avoid having users upload tons of native video’s weighting several hundreds megabytes (because the customer didn’t compress them). Then complain his limit is used up or have to pay more for more space.
You can add the following code in your functions.php
Tutorial: https://wpdevelopment.courses/articles/a-list-of-all-default-gutenberg-blocks-in-wordpress-5-0/
Let’s be honest and my opinion (2020)
OK, I agree that Gutenberg is a huge improvement compared to a classic editor. The writing experience comes very close of that of medium.com.
Positive
- It’s much easier to write content
- Creating columns, galleries is so simple that even a customer knows how to add a random gallery to a page. No longer you have to use ACF PRO to create a repeater field or install an additional plug-in with possible security issues.
- It’s lean and fast
Negatives
Because Gutenberg isn’t that old yet, the problem arrives when you want to write custom blocks. But the the existing API and documentation is rather confusing and incomplete at the moment. Also a lot of existing tutorials online are in its early stages, that is why they aren’t that helpful or don’t work.
- WordPress needs to develop a framework or tool to compile a Typescript / React code to Native JS. Something similar like Laravel Mix.
- A default framework would make it easier to use React, instead of Native JS / ES Next
Could be improved (written in 2020)
I really like where WordPress is going and I fully support the idea of developing pages with Gutenberg.
I was developing a platform and infrastructere for a company that needs to be reused for multiple websites, where the customer can update or add new pages to their website.
What was wonderful about Gutenberg is that you don’t have to create new page templates for each page lay-out (home, about, products, contact).
You can just drag and drop blocks.
https://developer.wordpress.org/themes/template-files-section/page-template-files/
Have more attributes to work with
But it would be a huge help if certain properties like ID, target would also appear in the variable $block.
At the moment you have to write complicated code (regular expressions) to retrieve specific HTML attributes.
<?php
// Extract the anchor of a core/group, core/heading and
// exclude anchor attributes from inner blocks.
preg_match('/id="(.+?)"/', $block['innerHTML'], $id_matches);$html.= '<div ... ' . ($id_matches[1] ?? '') . '>';
It would be much easier if I could write something like this.
<?php
$html.= '<div class="' . ($block['attrs']['id'] ?? '') . '">
Question mark syntax:
https://www.tutorialspoint.com/php7/php7_coalescing_operator.htm