Skip to main content 首页 创作者 bobmatnyc claude-mpm-skills wordpress-block-editor-fse
wordpress-block-editor-fse Modern WordPress block development and Full Site Editing with theme.json, block themes, and custom blocks for WordPress 6.7+
跳到安装 Skills Marketplace 发现并探索由社区构建的 Agent Skills
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/bobmatnyc/claude-mpm-skills --skill wordpress-block-editor-fse命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
下载 Zip 下载中... 同仓库更多 Skills LinkedIn automation via the Linked API CLI - fetch profiles, search people and companies, send messages, manage connections, create posts, react, comment, and run Sales Navigator and custom workflows. Use when the user wants to interact with LinkedIn.
Xquik X data automation API - Use REST or MCP for tweet search, user lookup, follower exports, media downloads, monitors, webhooks, giveaway draws, and confirmation-gated X actions.
MCP (Model Context Protocol) - Build AI-native servers with tools, resources, and prompts. TypeScript/Python SDKs for Claude Desktop integration.
name wordpress-block-editor-fse description Modern WordPress block development and Full Site Editing with theme.json, block themes, and custom blocks for WordPress 6.7+ user-invocable false disable-model-invocation true version 1.0.0 category development author Claude MPM Team license MIT progressive_disclosure {"entry_point":{"summary":"WordPress 6.7+ block development: FSE with theme.json, custom blocks (block.json + render.php), HTML templates","when_to_use":["Block themes with FSE (WP 6.2+)","Custom Gutenberg blocks","Centralized theme.json styling"],"quick_start":["theme.json for design tokens","block.json + render.php","HTML templates not PHP"]},"references":["theme-json-schema.md","custom-blocks-guide.md","fse-architecture.md","migration-guide.md"]} context_limit 6000 tags ["wordpress","gutenberg","blocks","fse","theme-json","php","react"] requires_tools []
WordPress Block Editor & Full Site Editing
Overview
Full Site Editing (FSE) is production-ready (since WP 6.2) and treats everything as blocks—headers, footers, templates, not just content. Block themes use HTML templates + theme.json instead of PHP files + style.css.
Key Components:
theme.json : Centralized colors, typography, spacing, layout
HTML Templates : Block-based files (index.html, single.html)
Template Parts : Reusable components (header.html, footer.html)
Block Patterns : Pre-designed block layouts
Site Editor : Visual template customization
When to Use:
✅ New themes, consistent design systems, non-technical user customization
❌ Complex server logic, team unfamiliar with blocks, heavy PHP dependencies
Full Site Editing Architecture
Block Themes vs Classic Themes
Block Themes Classic Themes HTML files with blocks PHP files with template tags theme.json + CSS functions.php + style.css Site Editor (visual) Customizer (settings) User edits templates Limited customization
Site Editor Capabilities
Template editing (pages, posts, archives)
Template parts (header/footer variations)
Global styles (colors, typography site-wide)
Pattern library (save/reuse block compositions)
Navigation menus (block-based)
Style variations (alternate design presets)
theme.json Configuration
theme.json v3 (WP 6.7) provides centralized design control. WordPress auto-generates CSS custom properties.
Production Example
{
"$schema" : "https://schemas.wp.org/trunk/theme.json" ,
"version" : 3 ,
"settings" : {
"appearanceTools"
:
true
,
"useRootPaddingAwareAlignments"
:
true
,
"layout"
:
{
"contentSize"
:
"800px"
,
"wideSize"
:
"1200px"
}
,
"color"
:
{
"palette"
:
[
{
"slug"
:
"primary"
,
"color"
:
"#0073aa"
,
"name"
:
"Primary"
}
,
{
"slug"
:
"secondary"
,
"color"
:
"#005177"
,
"name"
:
"Secondary"
}
,
{
"slug"
:
"base"
,
"color"
:
"#ffffff"
,
"name"
:
"Base"
}
,
{
"slug"
:
"contrast"
,
"color"
:
"#000000"
,
"name"
:
"Contrast"
}
]
,
"defaultPalette"
:
false
,
"defaultGradients"
:
false
}
,
"typography"
:
{
"fontFamilies"
:
[
{
"fontFamily"
:
"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif"
,
"slug"
:
"system"
,
"name"
:
"System Font"
}
]
,
"fontSizes"
:
[
{
"slug"
:
"small"
,
"size"
:
"0.875rem"
,
"name"
:
"Small"
}
,
{
"slug"
:
"medium"
,
"size"
:
"1rem"
,
"name"
:
"Medium"
}
,
{
"slug"
:
"large"
,
"size"
:
"1.5rem"
,
"name"
:
"Large"
,
"fluid"
:
{
"min"
:
"1.25rem"
,
"max"
:
"1.5rem"
}
}
]
,
"fontWeight"
:
true
,
"lineHeight"
:
true
}
,
"spacing"
:
{
"units"
:
[
"px"
,
"em"
,
"rem"
,
"vh"
,
"vw"
,
"%"
]
,
"padding"
:
true
,
"margin"
:
true
,
"spacingSizes"
:
[
{
"slug"
:
"30"
,
"size"
:
"0.5rem"
,
"name"
:
"XS"
}
,
{
"slug"
:
"40"
,
"size"
:
"1rem"
,
"name"
:
"S"
}
,
{
"slug"
:
"50"
,
"size"
:
"1.5rem"
,
"name"
:
"M"
}
,
{
"slug"
:
"60"
,
"size"
:
"2rem"
,
"name"
:
"L"
}
]
}
,
"border"
:
{
"radius"
:
true
,
"color"
:
true
,
"width"
:
true
}
}
,
"styles"
:
{
"color"
:
{
"background"
:
"var(--wp--preset--color--base)"
,
"text"
:
"var(--wp--preset--color--contrast)"
}
,
"typography"
:
{
"fontFamily"
:
"var(--wp--preset--font-family--system)"
,
"fontSize"
:
"var(--wp--preset--font-size--medium)"
,
"lineHeight"
:
"1.6"
}
,
"elements"
:
{
"link"
:
{
"color"
:
{
"text"
:
"var(--wp--preset--color--primary)"
}
,
":hover"
:
{
"color"
:
{
"text"
:
"var(--wp--preset--color--secondary)"
}
}
}
,
"h1"
:
{
"typography"
:
{
"fontSize"
:
"var(--wp--preset--font-size--large)"
,
"fontWeight"
:
"700"
}
}
,
"button"
:
{
"color"
:
{
"background"
:
"var(--wp--preset--color--primary)"
,
"text"
:
"var(--wp--preset--color--base)"
}
,
"border"
:
{
"radius"
:
"4px"
}
,
":hover"
:
{
"color"
:
{
"background"
:
"var(--wp--preset--color--secondary)"
}
}
}
}
,
"blocks"
:
{
"core/quote"
:
{
"border"
:
{
"width"
:
"0 0 0 4px"
,
"color"
:
"var(--wp--preset--color--primary)"
}
,
"spacing"
:
{
"padding"
:
{
"left"
:
"var(--wp--preset--spacing--60)"
}
}
}
}
}
,
"customTemplates"
:
[
{
"name"
:
"page-wide"
,
"title"
:
"Full Width Page"
,
"postTypes"
:
[
"page"
]
}
]
}
CSS Custom Properties Auto-Generated
Colors: var(--wp--preset--color--primary)
Fonts: var(--wp--preset--font-family--system)
Sizes: var(--wp--preset--font-size--large)
Spacing: var(--wp--preset--spacing--50)
Fluid Typography Font sizes with fluid: { min, max } auto-scale using clamp():
{
"slug" : "large" ,
"size" : "1.5rem" ,
"fluid" : { "min" : "1.25rem" , "max" : "1.5rem" }
}
Block Theme Architecture
Required Files my-block-theme/
├── style.css # Theme metadata (REQUIRED)
├── theme.json # Settings/styles (REQUIRED)
├── templates/
│ ├── index.html # Fallback (REQUIRED)
│ ├── single.html
│ ├── page.html
│ └── archive.html
├── parts/
│ ├── header.html
│ └── footer.html
├── patterns/ # Block patterns
│ └── hero.php
└── functions.php # Optional setup
style.css Metadata
HTML Template Structure
<div class ="wp-block-group" >
</div >
templates/index.html (with query loop):
<main class ="wp-block-group" >
<div class ="wp-block-query" >
</div >
</main >
Template Parts
<div class ="wp-block-group" >
</div >
Block Patterns <?php
?>
<!-- wp:cover {"url" :"<?php echo esc_url(get_template_directory_uri()); ?>/assets/images/hero.jpg" ,"dimRatio" :50 ,"minHeight" :500 ,"align" :"full" } -->
<div class ="wp -block -cover alignfull ">
<div class ="wp -block -cover__inner -container ">
<!-- wp :heading {"textAlign" :"center" ,"level" :1 ,"fontSize" :"xx-large" } -->
<h1>Welcome to Our Site</h1>
<!-- /wp:heading -->
<!-- wp:buttons {"layout" :{"type" :"flex" ,"justifyContent" :"center" }} -->
<div class ="wp -block -buttons ">
<!-- wp :button -->
<div class ="wp -block -button "><a class ="wp -block -button__link ">Get Started </a ></div >
<!-- /wp :button -->
</div >
<!-- /wp :buttons -->
</div >
</div >
<!-- /wp :cover -->
Register pattern categories:
add_action ('init' , 'register_pattern_categories' );
function register_pattern_categories ( ) {
register_block_pattern_category ('hero' , [
'label' => __ ('Hero Sections' , 'my-theme' )
]);
register_block_pattern_category ('cta' , [
'label' => __ ('Call to Action' , 'my-theme' )
]);
}
Custom Block Development
block.json Metadata (Block API v3) blocks/testimonial/block.json:
{
"$schema" : "https://schemas.wp.org/trunk/block.json" ,
"apiVersion" : 3 ,
"name" : "my-theme/testimonial" ,
"title" : "Testimonial" ,
"category" : "widgets" ,
"icon" : "format-quote" ,
"attributes" : {
"content" : {
"type" : "string" ,
"source" : "html" ,
"selector" : ".testimonial-content"
} ,
"author" : { "type" : "string" , "default" : "" } ,
"role" : { "type" : "string" , "default" : "" } ,
"rating" : { "type" : "number" , "default" : 5 }
} ,
"supports" : {
"html" : false ,
"align" : [ "wide" , "full" ] ,
"color" : { "background" : true , "text" : true } ,
"spacing" : { "padding" : true , "margin" : true }
} ,
"render" : "file:./render.php"
}
Attribute Sources Different ways to extract data from HTML:
"attributes" : {
"title" : {
"type" : "string" ,
"source" : "html" ,
"selector" : "h2"
} ,
"linkUrl" : {
"type" : "string" ,
"source" : "attribute" ,
"selector" : "a" ,
"attribute" : "href"
} ,
"isActive" : {
"type" : "boolean" ,
"default" : false
} ,
"items" : {
"type" : "array" ,
"source" : "query" ,
"selector" : ".item" ,
"query" : {
"text" : { "type" : "string" , "source" : "text" }
}
}
}
Server-Side Rendering (render.php) blocks/testimonial/render.php:
<?php
$content = $attributes ['content' ] ?? '' ;
$author = $attributes ['author' ] ?? '' ;
$role = $attributes ['role' ] ?? '' ;
$rating = absint ($attributes ['rating' ] ?? 5 );
$wrapper_attributes = get_block_wrapper_attributes ([
'class' => 'testimonial-block' ,
]);
?>
<div <?php echo $wrapper_attributes ; ?> >
<blockquote class ="testimonial -content ">
<?php echo wp_kses_post ($content ); ?>
</blockquote >
<?php if ($rating > 0) : ?>
<div class ="testimonial -rating ">
<?php for ($i = 1; $i <= 5; $i ++) : ?>
<span class ="star <?php echo $i <= $rating ? 'filled ' : 'empty '; ?>">
<?php echo $i <= $rating ? '★' : '☆'; ?>
</span >
<?php endfor ; ?>
</div >
<?php endif ; ?>
<?php if ($author || $role ) : ?>
<cite class ="testimonial -author ">
<span class ="author -name "><?php echo esc_html ($author ); ?></span >
<?php if ($role ) : ?>
<span class ="author -role "><?php echo esc_html ($role ); ?></span >
<?php endif ; ?>
</cite >
<?php endif ; ?>
</div >
Client-Side Rendering (React) blocks/testimonial/index.js:
import { registerBlockType } from '@wordpress/blocks' ;
import { useBlockProps, RichText , InspectorControls } from '@wordpress/block-editor' ;
import { PanelBody , RangeControl , TextControl } from '@wordpress/components' ;
import { __ } from '@wordpress/i18n' ;
registerBlockType ('my-theme/testimonial' , {
edit : ({ attributes, setAttributes } ) => {
const { content, author, role, rating } = attributes;
const blockProps = useBlockProps ();
return (
<>
<InspectorControls >
<PanelBody title ={__( 'Settings ', 'my-theme ')}>
<TextControl
label ={__( 'Author ', 'my-theme ')}
value ={author}
onChange ={(v) => setAttributes({ author: v })}
/>
<TextControl
label ={__( 'Role ', 'my-theme ')}
value ={role}
onChange ={(v) => setAttributes({ role: v })}
/>
<RangeControl
label ={__( 'Rating ', 'my-theme ')}
value ={rating}
onChange ={(v) => setAttributes({ rating: v })}
min={1}
max={5}
/>
</PanelBody >
</InspectorControls >
<div {...blockProps }>
<RichText
tagName ="blockquote"
value ={content}
onChange ={(v) => setAttributes({ content: v })}
placeholder={__('Testimonial text...', 'my-theme')}
/>
<div className ="testimonial-rating" >
{[1, 2, 3, 4, 5].map((star) => (
<span
key ={star}
onClick ={() => setAttributes({ rating: star })}
>
{star <= rating ? '★' : '☆'}
</span >
))}
</div >
<cite >
<RichText
tagName ="span"
value ={author}
onChange ={(v) => setAttributes({ author: v })}
placeholder={__('Author', 'my-theme')}
/>
</cite >
</div >
</>
);
},
save : () => null ,
});
Block Registration add_action ('init' , 'register_custom_blocks' );
function register_custom_blocks ( ) {
register_block_type (__DIR__ . '/blocks/testimonial' );
}
InspectorControls (Settings Sidebar) Common controls for block settings:
import {
InspectorControls ,
PanelColorSettings ,
MediaUpload
} from '@wordpress/block-editor' ;
import {
PanelBody ,
SelectControl ,
ToggleControl ,
RangeControl ,
Button
} from '@wordpress/components' ;
<InspectorControls >
<PanelBody title ="Layout" >
<SelectControl
label ="Columns"
value ={columns}
options ={[
{ label: '2 ', value: 2 },
{ label: '3 ', value: 3 },
{ label: '4 ', value: 4 }
]}
onChange ={(v) => setAttributes({ columns: parseInt(v) })}
/>
<ToggleControl
label ="Enable Shadow"
checked ={enableShadow}
onChange ={(v) => setAttributes({ enableShadow: v })}
/>
<RangeControl
label ="Border Radius"
value ={borderRadius}
onChange ={(v) => setAttributes({ borderRadius: v })}
min={0}
max={50}
/>
</PanelBody >
<PanelBody title ="Media" >
<MediaUpload
onSelect ={(media) => setAttributes({ imageUrl: media.url })}
allowedTypes={['image']}
render={({ open }) => (
<Button onClick ={open} variant ="secondary" >
{imageUrl ? 'Change Image' : 'Select Image'}
</Button >
)}
/>
</PanelBody >
<PanelColorSettings
title ="Colors"
colorSettings ={[
{
value: bgColor ,
onChange: (v ) => setAttributes({ bgColor: v }),
label: 'Background'
}
]}
/>
</InspectorControls >
Block Supports Enable WordPress features:
"supports" : {
"html" : false ,
"anchor" : true ,
"align" : [ "wide" , "full" ] ,
"color" : {
"background" : true ,
"text" : true ,
"gradients" : true
} ,
"spacing" : {
"padding" : true ,
"margin" : true ,
"blockGap" : true
} ,
"typography" : {
"fontSize" : true ,
"lineHeight" : true ,
"fontWeight" : true
}
}
Custom Post Types with Block Editor add_action ('init' , 'register_book_cpt' );
function register_book_cpt ( ) {
register_post_type ('book' , [
'labels' => [
'name' => __ ('Books' , 'my-theme' ),
'singular_name' => __ ('Book' , 'my-theme' ),
],
'public' => true ,
'has_archive' => true ,
'supports' => ['title' , 'editor' , 'thumbnail' ],
'show_in_rest' => true , // REQUIRED for block editor
'menu_icon' => 'dashicons-book' ,
'template' => [ // Default blocks
['core/paragraph' , ['placeholder' => 'Book description...' ]],
['core/image' ],
['my-theme/book-details' ],
],
'template_lock' => 'insert' , // Can't add/remove blocks
]);
// Register taxonomy
register_taxonomy(' genre', ' book', [
' labels' => [' name' => __(' Genres', ' my-theme')],
' hierarchical' => true,
' show_in_rest' => true, // REQUIRED
]);
}
Template Locking
false: No restrictions
'all': Cannot modify structure
'insert': Cannot add/remove, can reorder
'contentOnly': Content edits only
Register in theme.json "customTemplates" : [
{
"name" : "single-book" ,
"title" : "Book Template" ,
"postTypes" : [ "book" ]
}
]
Development Workflow
@wordpress/scripts {
"scripts" : {
"start" : "wp-scripts start" ,
"build" : "wp-scripts build"
} ,
"devDependencies" : {
"@wordpress/scripts" : "^27.0.0"
}
}
npm install
npm run start
npm run build
wp-env Setup {
"core" : "WordPress/WordPress#6.7" ,
"phpVersion" : "8.3" ,
"themes" : [ "./my-block-theme" ] ,
"config" : {
"WP_DEBUG" : true ,
"SCRIPT_DEBUG" : true
}
}
npx @wordpress/env start
npx @wordpress/env stop
npx @wordpress/env clean
Migration from Classic Themes
Template Tag to Block Mapping Classic Block Equivalent the_title()<!-- wp:post-title /-->the_content()<!-- wp:post-content /-->the_post_thumbnail()<!-- wp:post-featured-image /-->the_date()<!-- wp:post-date /-->wp_nav_menu()<!-- wp:navigation /-->get_header()<!-- wp:template-part {"slug":"header"} /-->get_footer()<!-- wp:template-part {"slug":"footer"} /-->get_sidebar()<!-- wp:template-part {"slug":"sidebar"} /-->
Migration Steps
Extract design tokens from style.css → theme.json
Convert PHP templates to HTML block templates
Add block support in functions.php:
add_theme_support ('wp-block-styles' );
add_theme_support ('align-wide' );
add_theme_support ('responsive-embeds' );
Test thoroughly with real content
Block Validation WordPress validates block markup against registered block definitions. Invalid blocks show errors in the editor:
Common validation errors:
Attribute type mismatch (string vs number)
Missing required attributes
Incorrect HTML structure
Changed attribute names
const deprecated = [
{
attributes : {
oldName : { type : 'string' }
},
migrate : (attributes ) => ({
newName : attributes.oldName
}),
save : (props ) => {
}
}
];
Performance & Best Practices
Performance ✅ Use server-side rendering (render.php) when possible
✅ Leverage block supports (reduces custom CSS)
✅ Disable unused features: "defaultPalette": false
✅ Use CSS custom properties for consistency
❌ Avoid client-side rendering for static content
❌ Don't override core blocks with !important
Accessibility ✅ Semantic HTML (<header>, <main>, <footer>)
✅ Keyboard navigation for custom blocks
✅ WCAG AA color contrast (4.5:1 minimum)
✅ Alt text for all images
❌ Don't assume FSE = accessible (test required)
Anti-Patterns ❌ Mixing classic and block approaches
❌ Hardcoding colors (use CSS variables)
❌ Reinventing block supports
❌ Skipping accessibility testing
❌ Using get_header() in HTML templates
Related Skills
wordpress-plugin-fundamentals : Hook system, CPTs
react : Block editor components
typescript : Type-safe block development
php-security : Sanitize block attributes
Key Reminders
theme.json is mandatory for block themes
HTML templates replace PHP in FSE
Server-side rendering often better than client-side
Block supports reduce custom code
Accessibility requires testing
Red Flags
More than 5 CSS files → Use theme.json
PHP tags in HTML templates → Use blocks
Client rendering for static content → Use render.php
No keyboard testing → Accessibility issues
Hardcoded values → Use CSS custom properties
WordPress: 6.7+ | PHP: 8.1+ | Tools: @wordpress/scripts, wp-env