Attributes are the data your block stores. In Part 3 we declared three: title, body, calloutType. This tutorial covers how they actually work.
Attribute types
The supported type values are: string, number, integer, boolean, array, object, null. Use the most specific type — it drives validation and the editor’s behavior.
"attributes": {
"title": { "type": "string", "default": "Heads up" },
"dropCap": { "type": "boolean", "default": false },
"fontSize": { "type": "integer", "default": 16 },
"items": { "type": "array", "default": [] },
"metadata": { "type": "object", "default": {} }
}
Attribute sources
source tells WordPress where in the saved HTML to find an attribute. Without a source, the attribute is stored in the block comment as JSON. With a source, it’s extracted from the rendered HTML on parse.
| Source | When to use | Stores in |
|---|---|---|
| (none) | Most cases — simple, fast, fully controlled | Block comment JSON |
attribute | Reading from an HTML attribute (e.g., href, src) | The HTML attribute |
html | Storing rich text content directly in the HTML | Element innerHTML |
text | Storing plain text (no formatting) | Element textContent |
meta (deprecated) | Reading from post_meta | wp_postmeta table |
"linkUrl": {
"type": "string",
"source": "attribute",
"selector": "a",
"attribute": "href"
}
That declaration tells WordPress: “the linkUrl attribute value is the href of the <a> element in this block’s saved HTML.”
Why sources matter
Without a source, your block comment looks like this:
<!-- wp:my-plugin/callout {"title":"Heads up","body":"Body text"} -->
<div class="my-callout">
<h4 class="my-callout-title">Heads up</h4>
<p class="my-callout-body">Body text</p>
</div>
<!-- /wp:my-plugin/callout -->
The attributes are in the comment AND duplicated in the HTML. That’s fine — slightly redundant but simple.
With sources, attributes are NOT in the comment — only in the HTML:
<!-- wp:my-plugin/callout -->
<div class="my-callout">
<h4 class="my-callout-title">Heads up</h4>
<p class="my-callout-body">Body text</p>
</div>
<!-- /wp:my-plugin/callout -->
Smaller post_content, single source of truth. Worth doing for blocks where the HTML is the canonical representation.
Defaults matter
When a user inserts a fresh block, the editor uses the default value for each attribute. Set sensible defaults so the inserted block isn’t a sea of “Untitled” placeholders.
Deprecations — evolving attributes safely
When you change a Save function or attribute schema, existing saved content stops validating. To keep it working, register a deprecation:
import { registerBlockType } from '@wordpress/blocks';
registerBlockType(metadata.name, {
edit: Edit,
save: Save,
deprecated: [
{
attributes: oldAttributes,
save: OldSave,
migrate: (oldAttributes) => ({
...oldAttributes,
// map old shape → new shape
calloutType: oldAttributes.style ?? 'info',
}),
},
],
});
The deprecation array lets WordPress recognize old saved HTML as a valid (but old) version of the block, then migrate it forward when the user re-edits.
Verification
In the editor, switch to Code editor (top-right menu in wp-admin) and inspect your block’s serialized HTML. Confirm attributes show up where you expect them — comment vs HTML.
What’s next
Part 5 adds inspector controls (the sidebar panel) so users can change calloutType without typing into the block.
Get the next one in your inbox. Practical tips, no fluff.
More tutorials
View all- WordPress
How to Prepare Your Plugin or Theme for WordPress 7.0
A step-by-step compatibility process for shipping a WordPress 7.0-ready release — set up a test site, audit your blocks, fix the breaking changes, and ship with confidence.
22 min
- WordPress
WordPress 7.0 for Block Developers: Breaking Changes
WordPress 7.0 enforces the iframed editor, broadens contentOnly mode, and drops PHP 7.3. Here are the breaking changes block and plugin developers must fix before users upgrade.
25 min
- WordPress
WordPress 7.0 AI: Client, Abilities & Connectors
The headline feature of WordPress 7.0 is native AI in Core. Here is what the WP AI Client, the Abilities API, and the Connectors system actually mean for plugin developers.
25 min