Block attributes define the data structure and persistence layer for your blocks. They specify what data your block stores and how that data is extracted from saved post content.
Attribute Definition
Attributes are defined in the attributes object of your block configuration. Each attribute has a key and a definition object:
attributes : {
url : {
type : 'string' ,
source : 'attribute' ,
selector : 'img' ,
attribute : 'src' ,
},
title : {
type : 'string' ,
},
size : {
enum : [ 'large' , 'small' ],
},
}
Attribute Properties
Type Validation
Specifies the data type. Must be one of:
null
boolean
object
array
string
integer
number (same as integer)
attributes : {
title : {
type : 'string' ,
},
count : {
type : 'number' ,
},
isActive : {
type : 'boolean' ,
},
items : {
type : 'array' ,
},
settings : {
type : 'object' ,
},
}
Enum Validation
Restricts the attribute to a fixed set of allowed values
attributes : {
size : {
enum : [ 'large' , 'small' , 'tiny' ]
},
direction : {
type : 'string' ,
enum : [ 'ltr' , 'rtl' ]
}
}
Default Value
Default value used when no matching content is found
attributes : {
dropCap : {
type : 'boolean' ,
default : false
},
tagName : {
type : 'string' ,
enum : [ 'a' , 'button' ],
default : 'a'
},
isStackedOnMobile : {
type : 'boolean' ,
default : true
}
}
Role
Designates the conceptual purpose of the attribute:
content - User-editable content (enables content-only editing)
local - Temporary, non-persistable data (not saved to post content)
attributes : {
content : {
type : 'rich-text' ,
source : 'rich-text' ,
selector : 'p' ,
role : 'content' , // Marks as user content
},
tempData : {
type : 'string' ,
role : 'local' , // Not saved to database
}
}
Attribute Sources
The source field determines where and how attribute values are stored and extracted.
When no source is specified, data is stored in the block’s comment delimiter:
attributes : {
title : {
type : 'string' ,
// No source - stored in comment
}
}
Saved as:
<!-- wp:my-plugin/book {"title":"Hello World"} -->
< div class = "wp-block-my-plugin-book" > Content </ div >
<!-- /wp:my-plugin/book -->
Attribute Source
Extract values from HTML element attributes:
Must be used with selector and attribute fields
attributes : {
url : {
type : 'string' ,
source : 'attribute' ,
selector : 'img' ,
attribute : 'src' ,
},
alt : {
type : 'string' ,
source : 'attribute' ,
selector : 'img' ,
attribute : 'alt' ,
}
}
Extracts from:
< img src = "https://example.com/image.jpg" alt = "Description" />
Results in:
{
url : "https://example.com/image.jpg" ,
alt : "Description"
}
Boolean Attributes
For existence checks (e.g., disabled attribute), use type: 'boolean':
attributes : {
disabled : {
type : 'boolean' ,
source : 'attribute' ,
selector : 'button' ,
attribute : 'disabled' ,
}
}
Text Source
Extract inner text content using textContent :
attributes : {
caption : {
type : 'string' ,
source : 'text' ,
selector : 'figcaption' ,
}
}
Extracts from:
< figure >
< img src = "/image.jpg" />
< figcaption > The inner text of the figcaption element </ figcaption >
</ figure >
Results in:
{ caption : "The inner text of the figcaption element" }
HTML Source
Extract inner HTML using innerHTML :
attributes : {
content : {
type : 'string' ,
source : 'html' ,
selector : 'figcaption' ,
}
}
Extracts from:
< figcaption > The inner text of the < strong > figcaption </ strong > element </ figcaption >
Results in:
{ content : "The inner text of the <strong>figcaption</strong> element" }
Rich-Text Source
For RichText components that support formatting:
attributes : {
content : {
type : 'rich-text' ,
source : 'rich-text' ,
selector : 'p' ,
role : 'content'
}
}
Query Source
Extract arrays of objects by matching multiple elements:
attributes : {
images : {
type : 'array' ,
source : 'query' ,
selector : 'img' ,
query : {
url : {
type : 'string' ,
source : 'attribute' ,
attribute : 'src' ,
},
alt : {
type : 'string' ,
source : 'attribute' ,
attribute : 'alt' ,
},
}
}
}
Extracts from:
< div >
< img src = "https://example.com/large.jpg" alt = "large image" />
< img src = "https://example.com/small.jpg" alt = "small image" />
</ div >
Results in:
{
images : [
{ url: "https://example.com/large.jpg" , alt: "large image" },
{ url: "https://example.com/small.jpg" , alt: "small image" }
]
}
Real-World Examples
Paragraph Block Attributes
From packages/block-library/src/paragraph/block.json:
{
"attributes" : {
"content" : {
"type" : "rich-text" ,
"source" : "rich-text" ,
"selector" : "p" ,
"role" : "content"
},
"dropCap" : {
"type" : "boolean" ,
"default" : false
},
"placeholder" : {
"type" : "string"
},
"direction" : {
"type" : "string" ,
"enum" : [ "ltr" , "rtl" ]
}
}
}
From packages/block-library/src/button/block.json:
{
"attributes" : {
"text" : {
"type" : "rich-text" ,
"source" : "rich-text" ,
"selector" : "a,button" ,
"role" : "content"
},
"url" : {
"type" : "string" ,
"source" : "attribute" ,
"selector" : "a" ,
"attribute" : "href" ,
"role" : "content"
},
"linkTarget" : {
"type" : "string" ,
"source" : "attribute" ,
"selector" : "a" ,
"attribute" : "target" ,
"role" : "content"
},
"rel" : {
"type" : "string" ,
"source" : "attribute" ,
"selector" : "a" ,
"attribute" : "rel" ,
"role" : "content"
},
"backgroundColor" : {
"type" : "string"
},
"textColor" : {
"type" : "string"
},
"gradient" : {
"type" : "string"
}
}
}
Group Block Attributes
From packages/block-library/src/group/block.json:
{
"attributes" : {
"tagName" : {
"type" : "string" ,
"default" : "div"
},
"templateLock" : {
"type" : [ "string" , "boolean" ],
"enum" : [ "all" , "insert" , "contentOnly" , false ]
}
}
}
Using Attributes in Components
In Edit Function
export default function Edit ( { attributes , setAttributes } ) {
const { content , alignment , fontSize } = attributes ;
return (
< RichText
value = { content }
onChange = { ( newContent ) => setAttributes ( { content: newContent } ) }
style = { {
textAlign: alignment ,
fontSize: fontSize + 'px'
} }
/>
);
}
In Save Function
export default function save ( { attributes } ) {
const blockProps = useBlockProps . save ();
return (
< div { ... blockProps } >
< img src = { attributes . url } alt = { attributes . alt } />
< p className = "book-author" > { attributes . author } </ p >
</ div >
);
}
Meta attributes are deprecated. Use EntityProvider and related hooks from @wordpress/core-data instead.
Old approach (deprecated):
attributes : {
author : {
type : 'string' ,
source : 'meta' ,
meta : 'author'
},
}
New approach:
import { useEntityProp } from '@wordpress/core-data' ;
function Edit () {
const [ meta , setMeta ] = useEntityProp ( 'postType' , 'post' , 'meta' );
const author = meta . author ;
const updateAuthor = ( newAuthor ) => {
setMeta ( { ... meta , author: newAuthor } );
};
}
Attribute Selectors
The selector field uses CSS selectors to target elements:
// Tag selector
selector : 'img'
// Class selector
selector : '.book-author'
// ID selector
selector : '#unique-element'
// Attribute selector
selector : 'img[data-id]'
// Descendant selector
selector : '.wp-block-image img'
// Multiple selectors
selector : 'a,button'
Best Practices
Use source whenever possible
Store data in HTML markup rather than comment delimiters. This makes blocks more portable and reduces database overhead.
Always specify the type field to ensure proper validation and prevent data corruption.
Use role for content attributes
Mark user-editable content with role: 'content' to enable content-only editing modes.
Provide sensible defaults
Use the default field to ensure your block works even when attributes are undefined.
Use enum for fixed values
When an attribute should only accept specific values, use enum for validation.
TypeScript Support
interface BookBlockAttributes {
title : string ;
author : string ;
pages : number ;
isAvailable : boolean ;
tags : string [];
}
import type { BlockEditProps } from '@wordpress/blocks' ;
export default function Edit ( {
attributes ,
setAttributes
} : BlockEditProps < BookBlockAttributes > ) {
// TypeScript now knows the shape of attributes
const { title , author , pages } = attributes ;
}
Migration and Deprecation
When changing attributes, use block deprecation to migrate old content:
deprecated : [
{
attributes: {
// Old attribute definition
oldName: {
type: 'string' ,
},
},
migrate ( attributes ) {
return {
// Map to new attribute
newName: attributes . oldName ,
};
},
save () {
// Old save function
},
},
]
Next Steps
Block Supports Enable automatic attributes for common features
Inner Blocks Build blocks that contain other blocks