Today I delivered my first Single Block ( SB ) plugin to wordpress.org. It’s called SB Children block and it’s in the Block Directory.
I’ve written up some notes about the plugin. Suffice it to say there were a few challenges along the way. But I’ve left the details of these in the GitHub issues.
About the SB Children block plugin
- The plugin is called SB Children block – sb-children-block.
- It delivers a block called
Children
. - Which “lists children of the current content as links”.
- The core function it uses is
wp_list_pages
. - The internal block name is
oik-sb/children
.
The block is a rather simple Server Side Rendered (SSR) block that uses core WordPress logic to create the list, which can be shown to display various levels of descendent content, based on a Depth parameter.
Usage scenarios
- When you want to create a simple list of child pages for the current page.
- When you want to show the full hierarchy of descendants for the current page.
- When you want to do this for other hierarchical post types.
- To replace some shortcodes:
- I’ll use the block to replace some instances of my [bw_code bw_tree] and/or [bw_code bw_list] shortcodes.
- Other people may choose to switch from the shortcodes they’re using.
Finding and installing the Children block
Searching for sb-children-block v1.0.0
The Block Directory search will be delivered in WordPress 5.5. If you already have the latest version of Gutenberg or a Release Candidate of WordPress 5.5 installed then Block Directory search will be enabled.
You can therefore search for and install the Children block while using the editor.
In my local development environment I have Gutenberg 8.7.0
Search | Results |
---|---|
c | Quite a few results including Audio, File, Group and several others that don’t appear to have a c in them |
ch | Words with ch in them such as Search and Archives and Yoast SEO’s blocks that use the keyword Schema |
chi | Archives and Calendar, which has a keyword of Archive. |
chil | Goes away to search and returns “No blocks found in your library”. |
child | Finds Cornell Note, SB Children block and Paypal Donation Block. It’s not at all obvious why it found the other two. |
childr | Goes away to search and returns “No blocks found in your library”. |
childre | As above for chil and childr |
children | TADA! |

Why it found the other blocks
Cornell Notes Gutenberg Block contains the following text in the readme.txt
file.
Cornell Notes contains a second block – an Idea block – this block is only made available as a child of the Cornell Note block – and enables you to add as many ideas (key ideas and long-form notes) you require.
Paypal Donation Block contains the following text in the readme.txt
file.
[paypal_donation_block email ='yourpaypalemail@example.com' amount ='10' currency='USD' purpose='Charity for Child Health Care' ]
Searching for sb-children-block v1.0.1
In response to bobbingwide/sb-children-block#11 I updated the readme.txt
file. I added the substrings of children. This table summarises the new results performing the same searches.
Search | Results | Compare vs 1.0.0 |
---|---|---|
c | Quite a few results including Audio, File, Group and several others that don’t appear to have a c in them |
Same |
ch | Words with ch in them such as Search and Archives and Yoast SEO’s blocks that use the keyword Schema |
Same |
chi | Archives and Calendar, which has a keyword of Archive. | Same |
chil | Goes away to search and returns SB Children block | TADA! |
child | Finds Cornell Note, SB Children block and Paypal Donation Block. We now know why it found the other two | Same |
childr | Finds SB Children block | TADA! |
childre | Finds SB Children block | TADA! |
children | Finds SB Children block | TADA! |

Searching in other languages
In v1.0.1 I also added translations of children to the readme.txt
file.This table summarises the results of performing the search in different languages.
Language | Search | Results |
---|---|---|
French | Enfants | TADA! |
German | Kinder | TADA! |
Dutch | Kinderen | TADA! |
Italian | prole | TADA! |
Spanish | ninas or niñas, ninos or niños | TADA! |
These results suggest that we can search for any string in the readme.txt
file to get a result.
Searching for any old bollocks in the readme.txt
Let’s try some unexpected searches for strings in the readme.txt
file for v1.0.1.
Search | Results |
---|---|
5.5-RC2 | TADA! |
SB | TADA! |
Installation | 10 blocks but not SB Children block |
page-attributes | SB Children block and WooCommerce Product Table |
Some technical details
The plugin is a Single Block plugin initially created using the WordPress create-block package ( @wordpress/create-block ).
cd \apache\htdocs\wordpress\wp-content\plugins npx @wordpress/create-block
I then changed the generated code:
- To deliver a Server Side Rendered block.
- To internationalise the build for both the block editor and the server side code.
- To localise the language files into:
- UK English (
en_GB
locale ) - and my i18n test language bbboing (
bb_BB
locale ).
- UK English (
- and I added a custom
webpack.config.js
for peaceful coexistence with other single block plugins generated using the same tool.
Some of the source files
Configuration files
block.json
The block.json
file describes the block in a computer readable form.
{
"name": "oik-sb/children",
"title": "Children",
"category": "widgets",
"icon": "list-view",
"description": "List children of the current content as links.",
"textdomain": "sb-children-block",
"supports": {
"html": false
},
"editorScript": "file:./build/index.js",
"editorStyle": "file:./build/index.css",
"style": "file:./build/style-index.css"
}
- wordpress.org uses this, and other information from the plugin, to determine that it’s a single block plugin.
- This file is not currently used by the plugin code.
- The structure of this file is documented in an almost impossible to find block registration RFC.
- It’s partially explained as Block Type Metadata in block-metadata.md
- See https://github.com/WordPress/gutenberg/pull/23832 and https://github.com/WordPress/gutenberg/issues/16209
package.json
The package.json
file is used to control the build, using npm
( Node Package Manager).
{
"name": "sb-children-block",
"version": "1.0.0",
"description": "List children of the current content as links.",
"author": "bobbingwide",
"license": "GPL-2.0-or-later",
"main": "build/index.js",
"scripts": {
"build": "wp-scripts build",
"format:js": "wp-scripts format-js",
"lint:css": "wp-scripts lint-style",
"lint:js": "wp-scripts lint-js",
"start": "wp-scripts start",
"dev": "wp-scripts start",
"packages-update": "wp-scripts packages-update",
"makepot": "wp i18n make-pot . languages/sb-children-block.pot --exclude=node_modules,vendor,src",
"makejson": "wp i18n make-json languages --no-purge",
"l10n": "l10n sb-children-block"
},
"devDependencies": {
"@wordpress/scripts": "^12.1.1"
},
"dependencies": {}
}
- I added steps to run
makepot
,l10n
andmakejson
.makepot
uses a WP-CLI command to extract text strings for translationl10n
automatically translates these strings into UK English and bbboingmakejson
uses a WP-CLI command to produce the translation files required in the editor.
- I also added
dev
as an alias ofstart
- I haven’t used the other
npm run
commands
webpack.config.js
After many battles ( documented in a number of GitHub issues ), I added a special webpack configuration file to set a custom jsonpFunction
. Without this logic multiple single block plugin blocks which have been built using npm run build
do not coexist peacefully.
const config = require( '@wordpress/scripts/config/webpack.config' );
/**
* Because the block and the package have their own webpack configuration,
* they must provide a unique name for the global scope (which is used to lazy-load chunks),
* otherwise it throws a JS error when loading blocks compiled with `npm run build`
* @see https://github.com/WordPress/gutenberg/issues/23607
* @see https://webpack.js.org/configuration/output/#outputjsonpfunction
* @see https://github.com/WordPress/gutenberg/issues/24321
*/
// ------------------------------------------------------
config.output.jsonpFunction = 'sb-children-block';
// ------------------------------------------------------
module.exports = config;
JSX source files
index.js
, edit.js
and save.js
contain the JavaScript source of the block.
index.js
does the block registration for the editoredit.js
defines the editor interfacesave.js
just returns null; the block is Server Side Rendered by PHP code.
In each of these files WordPress components are imported from @wordpress/component-name
where component-name was often a best guess.
PHP files
The runtime PHP code is in build/index.asset.php
and sb-children-block.php
.
build/index.asset.php
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-editor', 'wp-element', 'wp-i18n', 'wp-polyfill'), 'version' => '7b0281db299adf72321e4f16c36f3025');
This file is generated by the wp-scripts
routine which is invoked by npm start
or npm run build
. It’s used by the logic in the main plugin file to automatically determine the block’s dependencies and its version.
If it doesn’t exist then your site crashes.
sb-children-block.php
The main plugin file registers scripts and styles needed for the block the registers the block itself.
register_block_type( 'oik-sb/children', array(
'editor_script' => 'sb-children-block-block-editor',
'editor_style' => 'sb-children-block-block-editor',
'style' => 'sb-children-block-block',
'render_callback'=>'sb_children_block_dynamic_block',
'attributes' => [
'depth' => [ 'type' => 'string'],
'className' => [ 'type' => 'string'],
]
) );
Most of the plugins’ logic is done by sb_children_block_block_init
in response to the init
hook. The code for localization of the block in the editor, that was missing from the generated plugin file is:
/*
* Localise the script by loading the required strings for the build/index.js file
* from the locale specific .json file in the languages folder
*/
$ok = wp_set_script_translations( 'sb-children-block-block-editor', 'sb-children-block' , $dir .'/languages' );
I was able to defer the logic to load the translation files to the actual logic that gets called to render the block
function sb_children_block_dynamic_block( $attributes ) {
load_plugin_textdomain( 'sb-children-block', false, 'sb-children-block/languages' );
$className = isset( $attributes['className']) ? $attributes['className'] : 'wp-block-oik-sb-children';
$depth = isset( $attributes['depth']) ? $attributes['depth'] : 0;
$post = get_post();
$args = [ 'child_of' => $post->ID, 'echo' => false, 'title_li' => null, 'depth' => $depth ];
$html = '<ul class="'. $className . '">';
$html .= wp_list_pages( $args );
$html .= '</ul>';
return $html;
}
Submitting a plugin to the block directory
Apart from step 1., sharing your Block with the World is now a lot easier than it used to be.
- Develop your plugin, on GitHub.
- Run the Block Plugin Checker. https://wordpress.org/plugins/developers/block-plugin-validator/
- When it works package it up into a .zip file.
- Submit your plugin’s .zip file at Add Your Plugin https://wordpress.org/plugins/developers/add/
- When it’s approved publish it on wordpress.org using SVN
- Wait a while and you’ll receive an email to say that your plugin has been added to the Block Directory. Here: https://wordpress.org/plugins/browse/block/.

Further reading
- To see all the source, and the issues I raised, against myself and Gutenberg, while developing the plugin, visit bobbingwide/sb-children-block.
- For my official documentation, with working examples, see https://www.oik-plugins.com/oik-plugins/sb-children-block/
- I’ve also catalogued this plugin and its block in blocks.wp-a2z.org
- To download the plugin sb-children-block.
- Read about the @wordpress/create-block package
- Read Share your Block with the World for guidelines on sharing your single block plugin on wordpress.org.
Some child pages plugins
Here’s a subset of plugins on wordpress.org that can be used to list child pages.
Plugin name and description | Plugin links | Version, total downloads, last update, tested |
---|---|---|
SB Children block List children of the current content as links. |
sb-children-block home |
1.2.0 2,071 August 19, 2022 6.0.5 |
oik lazy smart shortcodes for your WordPress website |
oik | 4.8.2 September 5, 2022 6.0.1 |
CC Child Pages Adds a responsive shortcode to list child and sibling pages. Pre-styled or specify your own CSS class for custom styling. Includes child pages widget. |
cc-child-pages home |
1.45 120,418 March 15, 2023 6.1.3 |
SB Child List The total in-page navigation solution for Wordpress. Using the shortcodes and widgets provided you can display navigation between your parent, child a … |
sb-child-list home |
4.5 37,145 May 13, 2019 |
Page-list [pagelist], [subpages], [siblings] and [pagelist_ext] shortcodes |
page-list home |
5.6 391,929 April 28, 2023 6.2.2 |
Notes:
- The oik plugin provides a number of shortcodes that can be used to list child content in a variety of forms.
- I wasn’t aware of sb-child-list until after I’d submitted my plugin.