The question:
I’m building a dynamic block in a custom plugin that shows code in my blog posts. I’m struggling with this bug where the output of the render_callback
function gets echoed out to the WP dashboard when editing that post.
Here’s what the HTML (just the top) of the post edit page looks like:
test (frontend)test (frontend)test (frontend)<!DOCTYPE html>
<html class="wp-toolbar"
lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /
This is what my init.php file looks like (my render_code_block function at the end of the file):
<?php
/** * Blocks Initializer * * Enqueue CSS/JS of all the blocks. *
* @since 1.0.0 * @package CGB */
// Exit if accessed directly. if (!defined('ABSPATH')) { exit; }
/** * Enqueue Gutenberg block assets for both frontend + backend. *
* Assets enqueued: * 1. blocks.style.build.css - Frontend + Backend. * 2. blocks.build.js - Backend. * 3. blocks.editor.build.css - Backend. * * @uses {wp-blocks} for block type registration & related functions. * @uses {wp-element} for WP Element abstraction — structure of blocks. * @uses {wp-i18n} to internationalize the block's text. * @uses {wp-editor} for WP editor styles. * @since
1.0.0 */ function fe24_post_blocks_cgb_block_assets() { // phpcs:ignore // Register block styles for both frontend + backend. wp_register_style(
'fe24_post_blocks-cgb-style-css', // Handle.
plugins_url('dist/blocks.style.build.css', dirname(__FILE__)), // Block style CSS.
is_admin() ? array('wp-editor') : null, // Dependency to include the CSS after it.
null // filemtime( plugin_dir_path( __DIR__ ) . 'dist/blocks.style.build.css' ) // Version: File modification time. );
// Register block editor script for backend. wp_register_script(
'fe24_post_blocks-cgb-block-js', // Handle.
plugins_url('/dist/blocks.build.js', dirname(__FILE__)), // Block.build.js: We register the block here. Built with Webpack.
array('wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor'), // Dependencies, defined above.
null, // filemtime( plugin_dir_path( __DIR__ ) . 'dist/blocks.build.js' ), // Version: filemtime — Gets file modification time.
true // Enqueue the script in the footer. );
// Register block editor styles for backend. wp_register_style(
'fe24_post_blocks-cgb-block-editor-css', // Handle.
plugins_url('dist/blocks.editor.build.css', dirname(__FILE__)), // Block editor CSS.
array('wp-edit-blocks'), // Dependency to include the CSS after it.
null // filemtime( plugin_dir_path( __DIR__ ) . 'dist/blocks.editor.build.css' ) // Version: File modification time. );
// WP Localized globals. Use dynamic PHP stuff in JavaScript via `cgbGlobal` object. wp_localize_script(
'fe24_post_blocks-cgb-block-js',
'cgbGlobal', // Array containing dynamic data for a JS Global.
[
'pluginDirPath' => plugin_dir_path(__DIR__),
'pluginDirUrl' => plugin_dir_url(__DIR__),
// Add more data here that you want to access from `cgbGlobal` object.
] );
/** * Register Gutenberg block on server-side. * * Register the block on server-side to ensure that the block * scripts and styles for both frontend and backend are * enqueued when the editor loads. * * @link https://wordpress.org/gutenberg/handbook/blocks/writing-your-first-block-type#enqueuing-block-scripts
* @since 1.16.0 */ register_block_type(
'fe24/fe24-code-block',
array(
// Enqueue blocks.style.build.css on both frontend & backend.
'style' => 'fe24_post_blocks-cgb-style-css',
// Enqueue blocks.build.js in the editor only.
'editor_script' => 'fe24_post_blocks-cgb-block-js',
// Enqueue blocks.editor.build.css in the editor only.
'editor_style' => 'fe24_post_blocks-cgb-block-editor-css',
'render_callback' => 'render_code_block'
) ); }
function render_code_block($attributes) {
// $content = $attributes['code'];
// echo "<pre><code>$content</pre></code>";
echo 'test (frontend)'; }
// Hook: Block assets.
add_action('init', 'fe24_post_blocks_cgb_block_assets');
And finally my block.js:
/**
* BLOCK: fe24-post-blocks
*
* Registering a basic block with Gutenberg.
* Simple block, renders and saves the same content without any interactivity.
*/
// Import CSS.
import "./editor.scss";
import "./style.scss";
const { __ } = wp.i18n; // Import __() from wp.i18n
const { registerBlockType } = wp.blocks; // Import registerBlockType() from wp.blocks
const { RichText, InspectorControls } = wp.blockEditor;
const {
ToggleControl,
PanelBody,
PanelRow,
CheckboxControl,
SelectControl,
ColorPicker,
} = wp.components;
registerBlockType("fe24/fe24-code-block", {
// Block name. Block names must be string that contains a namespace prefix. Example: my-plugin/my-custom-block.
title: __("fe24 code block"), // Block title.
icon: "editor-code", // Block icon from Dashicons → https://developer.wordpress.org/resource/dashicons/.
category: "common", // Block category — Group blocks together based on common traits E.g. common, formatting, layout widgets, embed.
keywords: [__("fe24 code block"), __("code"), __("fe24")],
attributes: {
// languages: {
// type: "array",
// },
selectedLanguage: {
type: "string",
},
code: {
type: "string",
},
},
edit: (props) => {
const languages = ["javascript", "css", "html", "php"];
return (
<div>
<InspectorControls>
<PanelBody title="Fe24 Code Block Settings" initialOpen={true}>
<PanelRow>
<SelectControl
label="Language"
value={props.attributes.selectedLanguage}
options={languages.map((language) => {
return { label: language, value: language };
})}
onChange={(newval) => {
props.setAttributes({ selectedLanguage: newval })
console.log(newval);
}
}
/>
</PanelRow>
</PanelBody>
</InspectorControls>
<RichText
tagName="code"
placeholder="Insert your code"
value={props.attributes.code}
onChange={(newval) => {
console.log(newval);
props.setAttributes({ code: newval });
}}
/>
</div>
);
},
save: () => {
return null;
},
});
The Solutions:
Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.
Method 1
Excerpt from “Creating dynamic blocks” in the block editor handbook:
The server-side rendering is a function taking the block and the block
inner content as arguments, and returning the markup (quite
similar to shortcodes)
So despite the “render” as in render_callback
, a block render callback should not actually echo anything (and neither call any functions that echo something) and instead, return the output — which will later be automatically echoed by WordPress. Therefore in your render_code_block()
function, you need to replace the echo
with return
, i.e. use return 'test (frontend)';
..
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0