For years, mastering Gutenberg block construction required an in-depth understanding of technologies similar to React and Node.js, along with sophisticated assemble steps and JavaScript equipment.
On the other hand, WordPress construction is evolving, and also you’ll have the ability to now assemble and prepare Gutenberg blocks completely in PHP.
This is in particular in point of fact useful for developers who prefer to avoid React and server-side JavaScript (JS) construction. It lowers the learning curve, streamlines the developer revel in, and lets in higher potency by means of getting rid of needless front-end script overhead.
Inside the following sections, you’ll learn how to profit from the ones new choices to build PHP-only Gutenberg blocks. Along the easiest way, you’ll learn how to create leaner, faster, and easier-to-maintain WordPress web websites.
Reasonably exciting, right kind? Let’s get started.
What are PHP-only blocks and why do they subject?
Creating a Gutenberg block traditionally required complicated server-side JavaScript and React coding skills. This acted as a barrier to the adoption of the block editor by means of longtime WordPress developers who would perhaps not have the necessary React and Node.js knowledge.
Problems are changing now. Starting with Gutenberg 21.8, you’ll have the ability to join Gutenberg blocks the use of no longer anything else alternatively PHP. This avoids the complexities of setting up a Node.js environment for individuals who don’t artwork with server-side JavaScript.
With PHP-only block registration, you’ll have the ability to join and display blocks in every the editor and frontend the use of the identical PHP code. This encourages web sites the use of hybrid topic issues or standard PHP functions and shortcodes to adopt and develop on the block editor.
For individuals who want to learn about further, listed here are the main GitHub PRs dedicated to PHP-only blocks.
- Permit registering PHP-only blocks: This PR implements automatic server-side block registration and renames the
auto_ssrreinforce toauto_register. - PHP-only blocks: Cross all metadata from PHP registration to the buyer: PHP-only blocks with
auto_registerreinforce now transfer all metadata to the consumer from the PHP registration. - PHP-only blocks: Generate inspector controls from attributes: This PR introduces automatic era of the UI (Inspector Controls) in step with the attributes declared on the server.
How you’ll be able to assemble your first PHP-only Gutenberg block
When a block is registered only on the server facet — without JS knowledge — and the new auto_register reinforce flag is ready to true, the editor routinely uses the ServerSideRender phase to enroll the block on the shopper facet and display the block preview. In essence, the block’s content material subject material is now generated without delay from the PHP code in every the editor and the frontend.
For instance, proper right here is an easy PHP example that registers a block the use of the PHP-only method.
/**
* Render callback (frontend and editor)
*/
function my_php_only_block_render( $attributes ) {
return '
🚀 PHP-only Block
This block used to be as soon as created with only PHP!
';
}
/**
* Signal within the block on the 'init' hook.
*/
add_action( 'init', function() {
register_block_type( 'my-plugin/php-only-test-block', array(
'determine' => 'My PHP-only Block',
'icon' => 'welcome-learn-more',
'elegance' => 'text',
'render_callback' => 'my_php_only_block_render',
'is helping' => array(
// Automatically registers the block inside the Editor JS (up to now auto_ssr)
'auto_register' => true,
),
) );
});
You’ll take a look at this code by means of copying and pasting it into the main report of a custom designed plugin. After activating the plugin, you will have to see the “My PHP-Most straightforward Block” inside the block inserter.

The register_block_type serve as registers a block kind on the server. It now contains the brand new auto_register improve, teaching Gutenberg to transport metadata from the PHP registration.
The function accepts two arguments:
- The determine of the block kind, at the side of the namespace. In this example, the block determine is
my-plugin/php-only-test-block. - An array of arguments for the block kind. Inside the code above, we set
determine,icon,elegance,render_callback, andis helping. Another time, for PHP-only block types, theis helpingarray must include'auto_register' => true.
At the side of simplifying the creation of custom designed block types and making them easy to mix into hybrid topic issues, PHP-only blocks can be used as wrappers for legacy PHP functions and shortcodes. Moreover, the use of PHP-only blocks opens the door to new possible choices for custom designed integrations and server-side capacity.
In line with Héctor Priethor,
A pure-PHP registration type would simplify the minimum must haves for block construction, making them available to a much broader developer target market, and have the same opinion increase the block ecosystem previous complicated JavaScript usage.
The usage of attributes to build the block settings UI
PR 74102 lets in the automatic era of inspector controls from block feature definitions. This allows shoppers to configure the appearance and capacity of your PHP-only blocks like all Gutenberg block registered by way of JavaScript.
In the past, you had to manually create an edit.js report in React and description fairly numerous environment controls the use of React portions.
Now, Gutenberg reads the feature definitions and routinely generates the corresponding input fields inside the WordPress editor.
The machine maps the data types defined inside the attributes array to DataForm field definitions.
'kind' => 'string'generates a text field.'kind' => 'amount'generates a number field.'kind' => 'integer'generates an integer field.'kind' => 'boolean'generates a checkbox.'kind' => 'string'with'enum' => array()generates a make a choice field.
You’re going to note that you just’ll have the ability to only use a few controls. If you need explicit controls, similar to RichText, RangeControl, or ToggleControl, you’re going to however wish to opt for the JS/React manner.
On the other hand, this addition has in point of fact in depth advantages. Barriers to get admission to are decreased further, and likewise you won’t wish to learn about React, Webpack, or NPM to create custom designed blocks with simple editable alternatives.
Inside the following example, we extend the development block confirmed inside the previous segment by means of together with some attributes.
/**
* 1. Define the block's HTML output.
*/
function my_php_only_block_render( $attributes ) {
// Extract attributes
$determine = esc_html( $attributes['blockTitle'] );
$rely = intval( $attributes['itemCount'] );
$enabled = $attributes['isEnabled']; // Boolean from the ToggleControl
$duration = esc_attr( $attributes['displaySize'] );
// Get began development the output
$output = sprintf( '',
$duration === 'huge' ? '20px' : ($duration === 'small' ? '12px' : '16px')
);
$output .= sprintf( '🚀 %s
', $determine );
// If the toggle is ON, show the report. If OFF, show a fallback message.
if ( $enabled ) {
$output .= '';
for ( $i = 1; $i <= $rely; $i++ ) {
$output .= sprintf( '- Products %d
', $i );
}
$output .= '
';
} else {
$output .= 'The report is not too long ago disabled.
';
}
$output .= '';
return $output;
}
/**
* 2. Signal within the block on 'init'.
*/
add_action( 'init', function() {
register_block_type( 'my-plugin/php-only-test-block', array(
'determine' => 'My PHP-only Block',
'icon' => 'welcome-learn-more',
'elegance' => 'text',
'render_callback' => 'my_php_only_block_render',
// Attributes used to generate the Inspector UI
'attributes' => array(
'blockTitle' => array(
'kind' => 'string',
'default' => 'PHP-only Block',
),
'itemCount' => array(
'kind' => 'integer',
'default' => 3,
),
'isEnabled' => array(
'kind' => 'boolean',
'default' => true,
),
'displaySize' => array(
'kind' => 'string',
'enum' => array( 'small', 'medium', 'huge' ),
'default' => 'medium',
),
),
'is helping' => array(
'auto_register' => true,
),
) );
});
A quick check out this code unearths how easy it’s to enroll a custom designed block with all its configuration settings the use of the new API. Attributes this present day are used not only to store user-entered knowledge however along with define the UI schema. The code above does the following:
- The
register_block_typefunction registers the block kindmy-plugin/php-only-test-block. - The second argument passed to the function is an array containing the following portions:
determine,icon,elegance,render_callback,attributes, andis helping. - The
attributesarray incorporates the block’s attributes. Inside the above example, the array comprises the elementsblockTitle,itemCount,isEnabled, anddisplaySize. 'auto_register' => truelets in server-side automatic registration.
Right here’s what the callback function my_php_only_block_render does:
- First, the function extracts the feature values from the
$attributesarray and assigns them to the$determine,$rely,$enabled, and$durationvariables. - Then, it generates the block’s content material subject material.
Proper right here’s the result on show:

A real-world example of PHP-only blocks
While there are many scenarios where JavaScript is still required, you’ll have the ability to already do such a lot with PHP-only blocks, in particular when used with block props.
Inside the following example, we use the get_block_wrapper_attributes() serve as, which generates a string of attributes to the current block being rendered. The block will routinely download the user-set colors, borders, and shadows, and apply the corresponding sorts to the main container. This fashion, the block is customizable by means of Gutenberg’s native equipment, very similar to a React-based block.
To see it at artwork, create a smart-pricing-widget folder for your pc. In this folder, create a style.css report with the following CSS code:
/* style.css */
.pricing-card {
display: flex;
flex-direction: column;
align-items: middle;
text-align: middle;
box-sizing: border-box;
}
.pricing-card h3 {
margin: 0;
font-size: 1.5rem;
}
.pricing-card .price-value {
font-size: 3.5rem;
font-weight: 800;
margin: 15px 0;
}
.pricing-card ul {
list-style: none;
padding: 25px 0;
margin: 20px 0;
width: 100%;
border-top: 1px solid rgba(128,128,128,0.3);
display: flex;
flex-direction: column;
hollow: 12px;
}
.pricing-card li {
display: flex;
align-items: middle;
justify-content: middle;
hollow: 10px;
}
.pricing-card .cta-button {
margin-top: auto;
padding: 15px 25px;
border-radius: 8px;
text-decoration: none;
font-weight: bold;
transition: opacity 0.2s;
}
.pricing-card .cta-button:hover {
opacity: 0.8;
}
/* Theme Permutations */
.pricing-card.theme-light { background-color: #ffffff; colour: #000000; }
.pricing-card.theme-light .cta-button { background-color: #21759b; colour: #ffffff; }
.pricing-card.theme-dark { background-color: #1a1a1a; colour: #ffffff; }
.pricing-card.theme-dark .cta-button { background-color: #ffffff; colour: #1a1a1a; }
.pricing-card.theme-blue { background-color: #21759b; colour: #ffffff; }
.pricing-card.theme-blue .cta-button { background-color: #000000; colour: #ffffff; }
/* Tool Classes */
.pricing-card .is-full-width {
width: 100%;
display: block;
align-self: stretch;
}
We will not commentary on this code as it is a simple stylesheet for your widget block.
Now, create the main report for your plugin, determine it smart-pricing-widget.php, and paste the following code:
"pricing-card theme-{$theme}",
) ) );
$output = sprintf( '', $wrapper_attributes );
$output .= sprintf( '%s
', $plan_name );
$output .= sprintf( '€%d', $rate );
if ( ! empty( $features_array ) ) {
$output .= '';
foreach ( $features_array as $serve as ) {
$is_checked = strpos( $serve as, '+' ) === 0;
$clean_text = esc_html( ltrim( $serve as, '+- ' ) );
$icon = $is_checked ? '✅' : '❌';
$style = $is_checked ? '' : 'style="opacity: 0.6;"';
$output .= sprintf( '- %s %s
', $style, $icon, $clean_text );
}
$output .= '
';
}
$btn_class = 'cta-button' . ( $btn_size === 'entire' ? ' is-full-width' : '' );
$output .= sprintf( '%s', esc_attr( $btn_class ), $btn_text );
$output .= '';
return $output;
}
/**
* Check in Assets and Block
*/
add_action( 'init', function() {
// 1. Signal within the CSS report
wp_register_style(
'smart-pricing-style',
plugins_url( 'style.css', __FILE__ ),
array(),
'1.2.0'
);
// 2. Signal within the Block
register_block_type( 'instructional/smart-pricing', array(
'api_version' => 3,
'determine' => 'Pricing Card',
'icon' => 'cart',
'elegance' => 'widgets',
'render_callback' => 'render_smart_pricing_block',
// Link the registered style preserve proper right here
'style' => 'smart-pricing-style',
'attributes' => array(
'planName' => array( 'kind' => 'string', 'default' => 'Professional' ),
'rate' => array( 'kind' => 'integer', 'default' => 49 ),
'buttonText' => array( 'kind' => 'string', 'default' => 'Make a choice Plan' ),
'buttonSize' => array( 'kind' => 'string', 'enum' => array( 'auto', 'entire' ), 'default' => 'auto' ),
'blockTheme' => array( 'kind' => 'string', 'enum' => array( 'gentle', 'dark', 'blue' ), 'default' => 'gentle' ),
'featuresList' => array( 'kind' => 'string', 'default' => "+ Strengthen, + Updates, - Space" ),
),
'is helping' => array(
'auto_register' => true,
'colour' => array( 'background' => true, 'text' => true ),
'spacing' => array( 'margin' => true, 'padding' => true ),
'typography' => array( 'fontSize' => true ),
'shadow' => true,
'__experimentalBorder' => array( 'colour' => true, 'radius' => true, 'style' => true, 'width' => true ),
'border' => array( 'colour' => true, 'radius' => true, 'style' => true, 'width' => true ),
),
) );
});
This script comprises two functions. The register_block_type() function is the engine of your plugin. Listed here are its primary portions:
- The principle argument is the block identifier, at the side of the namespace (
instructional/smart-pricing). - The second argument is an array of arguments. Inside the code above, now we now have set the API style, determine, icon, elegance, render callback, style, attributes, and helps.
- The attributes inside the array generate the controls that buyers will use so to upload content material subject material and configure the block. The
kindphase specifies the type of keep an eye on so to upload to the block inspector. In this example, the ones are text fields ('kind’ => 'string’), an integer ('kind’ => 'integer’), and a couple of drop-down menus ('kind’ => 'string’, 'enum’ => array()). - The
is helpingarray items add choices that make the block style customizable. As we mentioned earlier, the only reinforce required in a PHP-only block isauto_register, which permits automatic UI era for custom designed attributes. The other is helping declared above include colour, spacing, typography, shadow, and border.
The callback function render_smart_pricing_block() generates the block’s HTML. Right here’s an in depth description of what this function does:
- It extracts and sanitizes the block attributes, then supplies the CSS code that generates the block’s glance inside the frontend and editor.
- The choices to be displayed inside the block (
$attributes['featuresList'];) are handled separately. At the moment, it’s no longer imaginable so to upload complicated controls to the block settings sidebar. To create a listing, similar to a listing of choices, you’ll have the ability to only use a simple text field. In this example, you must manually enter the product choices, separated by means of commas. - The
$wrapper_attributesvariable is a container for the wrapper attributes provided by means of theget_block_wrapper_attributesserve as. This function does not merely add the kinds specified inside the code (pricing-card theme-{$theme}), alternatively routinely retrieves all the style customizations that the shopper gadgets inside the block inspector, at the side of colors, borders, padding, margin, shadow, typography, and the standard block classes (wp-block-tutorial-smart-pricing). wp_kses_datapromises there aren’t any malicious tags or scripts (XSS) inside the string.- The rest of the code generates the block content material subject material.
Flip at the plugin and create a brand spanking new post or internet web page. Open the block inserter and scroll proper right down to the Widgets segment. Proper right here, you will have to see your “Pricing Card” block known by means of a purchasing groceries cart icon.

The image above presentations the block with the default gentle theme.
Inside the image underneath, you’ll have the ability to see the dark style of the block and the settings you declared for your plugin.

The following image presentations the way controls you added with the block is helping.

It’s normally payment noting that sorts added by means of is helping override the block theme sorts. This allows for higher customization of the block’s glance, as confirmed inside the following image:

Convert legacy shortcodes to Gutenberg blocks with herbal PHP
One of the vital necessary direct uses of PHP blocks is as shortcode wrappers. With Gutenberg, you’ll have the ability to however use shortcodes for your content material subject material, alternatively it’s a will have to to manually insert your shortcode proper right into a Shortcode block, which isn’t some of the stress-free revel in.
Think you’ll have the following shortcode:
function my_custom_alert_shortcode( $atts ) {
$alternatives = shortcode_atts( array(
'kind' => 'knowledge',
'message' => 'Default alert message',
), $atts );
$sorts = array(
'knowledge' => 'background: #d1ecf1; colour: #0c5460; border-color: #bee5eb;',
'warning' => 'background: #fff3cd; colour: #856404; border-color: #ffeeba;',
'error' => 'background: #f8d7da; colour: #721c24; border-color: #f5c6cb;'
);
$style = $sorts[ $options['type'] ] ?? $sorts['info'];
return sprintf(
'
%s: %s
',
esc_attr( $style ),
esc_html( $alternatives['type'] ),
esc_html( $alternatives['message'] )
);
}
add_shortcode( 'sc_alert', 'my_custom_alert_shortcode' );
This code generates a simple box that you just’ll have the ability to insert into your content material subject material with the following shortcode:
[sc_alert type="alert" message="Hello"]
In Gutenberg, you’re going to make use of a Shortcode block to insert the sphere into your content material subject material, as confirmed inside the following image:

The placement changes totally with PHP-only blocks. Now you’ll have the ability to wrap your shortcode in a PHP-only Gutenberg block and configure it at some stage in the UI controls. Right here’s the code so to upload for your plugin:
/**
* Rendering callback
*/
function render_shortcode_alert_wrapper_block( $attributes ) {
$kind = esc_attr( $attributes['alertType'] );
$message = esc_attr( $attributes['alertMessage'] );
$shortcode_string = sprintf( '[sc_alert type="%s" message="%s"]', $kind, $message );
$wrapper_attributes = wp_kses_data( get_block_wrapper_attributes( array(
'class' => 'wp-block-shortcode-alert-wrapper',
) ) );
return sprintf(
'%s',
$wrapper_attributes,
do_shortcode( $shortcode_string )
);
}
/**
* Signal within the block kind on the server
*/
add_action( 'init', function() {
register_block_type( 'instructional/alert-wrapper', array(
'api_version' => 3,
'determine' => 'Alert (Shortcode wrapper)',
'icon' => 'feedback',
'elegance' => 'widgets',
'render_callback' => 'render_shortcode_alert_wrapper_block',
'attributes' => array(
'alertType' => array(
'kind' => 'string',
'enum' => array( 'knowledge', 'warning', 'error' ),
'default' => 'knowledge',
),
'alertMessage' => array(
'kind' => 'string',
'default' => 'Sort your alert message proper right here...',
),
),
'is helping' => array(
'auto_register' => true,
'spacing' => array( 'margin' => true, 'padding' => true ),
'typography' => array( 'fontSize' => true ),
),
) );
});
The code above is similar to the code inside the previous segment. What changes right here’s the rendering callback.
$shortcode_stringstores the shortcode string ([sc_alert type="%s" message="%s"]).- The function returns the HTML of the block container and the built-in shortcode (
do_shortcode( $shortcode_string )).
Now, open the block inserter and seek for the “Shortcode wrapper” block a number of the widgets. Insert it into your content material subject material and configure it from the block settings bar. The block will appear identical in every the editor and the frontend.

How is WordPress construction changing with PHP-only blocks?
As problems stand, herbal PHP blocks are in an experimental section and now have limited options. Gutenberg supplies further powerful choices, similar to block patterns and block permutations, which give all the editing choices of native Gutenberg blocks and custom designed blocks in-built JavaScript. However there are scenarios where PHP blocks offer necessary possible choices.
First, PHP-only blocks will have to encourage wider adoption of the block editor, in particular among WordPress developers who’re a lot much less oriented towards server-side JavaScript construction.
Additionally, they’re splendid wrappers for custom designed functions and shortcodes, as confirmed inside the example in this article. In addition to, they enable for easy integration with external services.
And we will moreover rather expect longer term improvements and feature additions, further configuration controls, and integrations with present Gutenberg equipment.
One thing is keep in mind that: with PHP-only blocks, development Gutenberg blocks has become so much more practical.
If WordPress construction is your job, Kinsta provides the developer gear you want, enabling you to be aware of WordPress construction, getting rid of the need for sophisticated configurations and tedious maintenance tasks: SSH, SFTP, Git integration, computerized updates, one-click staging, a built-in native building software, and much more. Check it out firsthand with your first month unfastened.
The post How you can construct PHP-only Gutenberg blocks appeared first on Kinsta®.


0 Comments