Block Contains unexpected or Invalid content
-
Dynamic Block Shows Validation Error Only in FSE, Works Fine in Post Editor
I’m facing a frustrating issue with a custom dynamic block that shows “Block contains unexpected or invalid content” error, but only in the Full Site Editor (FSE). The exact same block works perfectly without any errors in the regular post/page editor.
The block is a simple social sharing widget registered as a dynamic block with
save: () => nullin JavaScript and arender.phpfile for server-side rendering. It’s properly registered in PHP usingregister_block_type()with the block.json file. The attributes are three boolean values for showing/hiding different social platforms.What’s puzzling is that in the FSE template code editor, the block appears correctly as a self-closing comment
<!-- wp:estylish/estylish-share /-->, which is the expected format for dynamic blocks. However, FSE still throws the validation error and shows “Attempt recovery” button. When I click it, nothing changes – the error persists.I’ve tried everything I can think of: cleared all caches, fixed character encoding issues, added deprecations, verified the save function returns null, ensured PHP and JS registrations match, deleted and re-added the block in templates, set html support to false in block.json, and rebuilt the project multiple times. The error only appears in FSE templates and template parts, never in regular posts or pages.
Has anyone encountered this issue where a dynamic block validates correctly in the post editor but fails validation in FSE? Is there something different about how FSE handles dynamic blocks compared to the regular editor? I’m wondering if this could be a bug in WordPress or if there’s some undocumented requirement for dynamic blocks in FSE that I’m missing.
Any help or insights would be greatly appreciated as I’ve been stuck on this for days and it’s blocking our theme development.
// ============================================
// FILE: index.js
// ============================================import { registerBlockType } from “@wordpress/blocks”;
import { useBlockProps, InspectorControls } from “@wordpress/block-editor”;
import { PanelBody, ToggleControl } from “@wordpress/components”;
import { __ } from “@wordpress/i18n”;
import metadata from “./block.json”;// Register the block
registerBlockType(metadata.name, {
// Explicitly set all properties to match block.json
title: metadata.title,
description: metadata.description,
category: metadata.category,
icon: metadata.icon,
supports: metadata.supports,
attributes: metadata.attributes,
example: metadata.example,edit: ({ attributes, setAttributes }) => { const { showTwitter, showFacebook, showPinterest } = attributes; const blockProps = useBlockProps({ className: 'estylish-share-editor' }); return ( <> <InspectorControls> <PanelBody title={__('Social Platforms', 'estylish')}> <ToggleControl label={__('Show Twitter', 'estylish')} checked={showTwitter} onChange={(value) => setAttributes({ showTwitter: value })} /> <ToggleControl label={__('Show Facebook', 'estylish')} checked={showFacebook} onChange={(value) => setAttributes({ showFacebook: value })} /> <ToggleControl label={__('Show Pinterest', 'estylish')} checked={showPinterest} onChange={(value) => setAttributes({ showPinterest: value })} /> </PanelBody> </InspectorControls> <div {...blockProps}> <div className="sonchor" style={{ padding: "20px", backgroundColor: "#f5f5f5" }} > <div className="share"> <span>—</span> {__('Share', 'estylish')} </div> <div style={{ marginTop: "10px" }}> {showTwitter && ( <span style={{ marginRight: "10px" }}> {__('Twitter', 'estylish')} </span> )} {showFacebook && ( <span style={{ marginRight: "10px" }}> {__('Facebook', 'estylish')} </span> )} {showPinterest && ( <span>{__('Pinterest', 'estylish')}</span> )} </div> <p style={{ fontSize: "12px", color: "#666", marginTop: "10px" }}> {__('Social share buttons will display on frontend', 'estylish')} </p> </div> </div> </> ); }, // Dynamic block - must return null save: () => null});
// ============================================
// FILE: block.json
// ============================================
/*
{
“$schema”: “https://schemas.wp.org/trunk/block.json”,
“apiVersion”: 3,
“name”: “estylish/estylish-share”,
“version”: “1.0.0”,
“title”: “Estylish Share”,
“category”: “widgets”,
“icon”: “share”,
“description”: “Social sharing widget with Twitter, Facebook and Pinterest”,
“keywords”: [“share”, “social”, “twitter”, “facebook”, “pinterest”],
“textdomain”: “estylish”,
“example”: {
“attributes”: {
“showTwitter”: true,
“showFacebook”: true,
“showPinterest”: true
}
},
“supports”: {
“html”: false,
“align”: false,
“anchor”: false,
“customClassName”: false,
“className”: false,
“reusable”: true,
“inserter”: true
},
“attributes”: {
“showTwitter”: {
“type”: “boolean”,
“default”: true
},
“showFacebook”: {
“type”: “boolean”,
“default”: true
},
“showPinterest”: {
“type”: “boolean”,
“default”: true
}
},
“editorScript”: “file:./index.js”,
“render”: “file:./render.php”
}
*/// ============================================
// FILE: render.php
// ============================================
/*
<?php
/**- Estylish Share Block – Server-side rendering
- @package Estylish
- Available variables:
- $attributes (array): Block attributes
- $content (string): Block inner content
- $block (WP_Block): Block instance
*/
// Ensure we’re in WordPress context
if (!defined(‘ABSPATH’)) {
exit;
}// Get attributes with proper defaults
$show_twitter = isset($attributes[‘showTwitter’]) ? (bool) $attributes[‘showTwitter’] : true;
$show_facebook = isset($attributes[‘showFacebook’]) ? (bool) $attributes[‘showFacebook’] : true;
$show_pinterest = isset($attributes[‘showPinterest’]) ? (bool) $attributes[‘showPinterest’] : true;// Get current post data safely
$post_id = get_the_ID();
if (!$post_id) {
// If no post context, don’t render
return ”;
}$post_url = esc_url(get_permalink($post_id));
$post_title = get_the_title($post_id);
$post_thumbnail_url = get_the_post_thumbnail_url($post_id, ‘large’);// Build sharing URLs
$twitter_url = add_query_arg([
‘url’ => $post_url,
‘text’ => $post_title
], ‘https://twitter.com/intent/tweet’);$facebook_url = add_query_arg([
‘u’ => $post_url
], ‘https://www.facebook.com/sharer/sharer.php’);$pinterest_url = add_query_arg([
‘url’ => $post_url,
‘media’ => $post_thumbnail_url ?: ”,
‘description’ => $post_title
], ‘https://pinterest.com/pin/create/button/’);// Start output
?>—
*/
- Estylish Share Block – Server-side rendering
You must be logged in to reply to this topic.