Register custom Gutenberg blocks with block.json — static saves HTML, dynamic renders via PHP callback.
Gutenberg Custom Blocks
// block.json
{
"apiVersion": 2,
"name": "my-plugin/callout",
"title": "Callout Box",
"category": "text",
"icon": "megaphone",
"editorScript": "file:./index.js",
"style": "file:./style.css"
}
// Register block (PHP)
function register_my_blocks() {
register_block_type(__DIR__ . '/blocks/callout');
}
add_action('init', 'register_my_blocks');
// Dynamic block (PHP renders each page load)
register_block_type('my-plugin/latest-posts', [
'render_callback' => 'render_latest_posts',
]);
function render_latest_posts($attrs) {
$posts = get_posts(['numberposts' => 5]);
$html = '';
foreach ($posts as $p)
$html .= '- ' . esc_html($p->post_title) . '
';
return $html . '
';
}