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.


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.


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.

En example used in the filter hook “render_block” of targeting a specific type

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.


This property explains the type of block and is important to target a specific block.

Detect the name of a block inside a hook

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)
'innerBlocks' =>
array (size=0)
'innerHTML' => string '...'(length=...)
'innerContent' =>
array (size=1)
0 => string '...'(length=...)


  • 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


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.


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)
'innerBlocks' =>
array (size=0)
'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>

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.

Guternberg dropdown to add a CSS-class
This collapse menu appears in the right when you select a 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'),

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.

An example of the Gutenberg sidebar and marking the anchor field.
This part doesn’t appear in $block[attrs’], but is generated in the original HTML.

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.

// 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
Colour palette

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 () {   


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.

if (
$block['blockName'] === 'core/group' &&
!is_admin() &&
) {
// Detect the block you want and only render in the front-end

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.


  • 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


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.


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.

// 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.

$html.= '<div class="' . ($block['attrs']['id'] ?? '') . '">

Question mark syntax:

Gutenberg resources:

Senior back-end developer in Ghent who likes writing sometimes weird / creative solutions to a specific problem.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store