The wptPanels key in block.json is how a block opts into the registry. It controls which panels appear in the block’s inspector and allows per-block default overrides.
Option 1: Full Registry (Recommended)
"wptPanels": {
"structure": true,
"spacing": true,
"layout": true
}
true means: use this panel, pull all options and defaults from the registry. When the admin changes registry options, this block gets the changes on next re-registration. This is the correct default for all new blocks.
Option 2: Disable a Panel
"wptPanels": {
"structure": true,
"spacing": false,
"layout": false
}
false means: do not register any attributes or render any inspector panel for this panel group. Use this for blocks that genuinely do not need spacing or visibility control, for example, a simple inline element or a block that manages its own layout entirely.
Option 3: Override Specific Defaults
"wptPanels": {
"structure": {
"headingLevel": "h3",
"semanticRole": "article"
},
"spacing": {
"blockPadding": "xl"
},
"layout": true
}
An object overrides the default values for the fields you specify. The available options still come from the registry, so if the admin adds a new spacing value, it appears in this block’s dropdown too. Only the starting default is changed.
This is ideal for blocks that are semantically always a certain type, a team member card is always an article, for example, so its default semanticRole should be article.
The object override changes defaults only, not available options. To restrict available options for a specific block, you need to declare the controls manually in
index.jsinstead of using the registry for that field.
Reading the Registry in index.js
( function () {
'use strict';
var REGISTRY = window.wptPanelRegistry || {};
// Build SelectControl options from a registry field
function registryOptions( panel, fieldKey ) {
var fields = REGISTRY[panel] && REGISTRY[panel].fields ? REGISTRY[panel].fields : [];
for ( var i = 0; i < fields.length; i++ ) {
if ( fields[i].key === fieldKey && fields[i].options ) {
return fields[i].options.map( function(v) { return { label: v, value: v }; } );
}
}
return [];
}
// Build all option arrays upfront
var HEADING_OPTIONS = registryOptions( 'structure', 'headingLevel' );
var ROLE_OPTIONS = registryOptions( 'structure', 'semanticRole' );
var PADDING_OPTIONS = registryOptions( 'spacing', 'blockPadding' );
var GAP_OPTIONS = registryOptions( 'spacing', 'blockGap' );
var MB_OPTIONS = registryOptions( 'spacing', 'spacingBottom' );
var ALIGN_OPTIONS = registryOptions( 'layout', 'textAlign' );
// Use in SelectControl
el( SelectControl, {
label: 'Heading Level',
value: attributes.headingLevel,
options: HEADING_OPTIONS,
onChange: function(v) { setAttributes({ headingLevel: v }); }
})
}() );
Falls back to an empty array if the registry is unavailable. The block still renders; no JS crash.