Where WordPress Stores Block Attributes

Where WordPress Stores Block Attributes — WP Block Suite

WordPress stores block attributes according to each attribute’s declared source. Unsourced attributes enter the block’s comment JSON. Sourced attributes are extracted from saved HTML.

Some modern blocks can also read separate entity data through bindings. Defaults may not be stored anywhere. Nested blocks remain document structure, not ordinary attributes.

Therefore, there is no universal block-attribute table. Most instance data travels inside post_content. Its exact representation depends on the attribute definition.

The storage map

DefinitionStored locationTypical use
No sourceDelimiter JSONSettings and identifiers
attributeHTML attributeURLs, labels, dimensions
textElement textPlain visible content
htmlElement inner HTMLFormatted rich text
queryRepeated markupStructured item arrays
The source tells WordPress where parsing should recover each value.

Definition and instance are different

block.json defines the attribute schema for a block type. It describes keys, types, sources, selectors, defaults, and allowed values.

A saved block instance contains actual selected values. The definition tells WordPress how to recover them. It does not store every instance itself. The step-by-step is in replacing a block across a site.

Think of metadata as a map. Think of post_content as the journey record. Parsing combines both into the editor’s attribute object.

Our block.json guide covers the wider metadata contract. This guide follows one instance through storage and retrieval.

A complete storage example

"attributes": {
  "tone": { "type": "string", "default": "neutral" },
  "message": {
    "type": "string",
    "source": "html",
    "selector": ".message"
  },
  "url": {
    "type": "string",
    "source": "attribute",
    "selector": "a",
    "attribute": "href"
  }
}

The tone has no source. WordPress stores a changed tone inside delimiter JSON. Message and URL are recovered from saved markup. The answer is in what a block contains and stores.

<!-- wp:acme/notice {"tone":"warning"} -->
<aside class="wp-block-acme-notice">
  <p class="message">Read the migration notes.</p>
  <a href="/notes/">Open notes</a>
</aside>
<!-- /wp:acme/notice -->

One instance uses three storage positions. Parsing returns one attribute object. The edit component need not care where each value lived.

Attributes without a source use comment JSON

An attribute without source is serialized inside the opening delimiter. This works well for settings without a natural HTML representation.

Examples include item counts, selected modes, internal identifiers, and boolean options. The JSON stays invisible. Rendering code can still read the parsed value.

The saved object only needs non-default values in many cases. WordPress can supply the declared default during parsing. Missing JSON therefore does not always mean missing data.

Comment JSON should not duplicate visible content needlessly. Saved HTML provides better fallback for meaningful words. It also reduces hidden serialized data.

The attribute source reads HTML attributes

The attribute source reads one HTML attribute from a selected element. Common targets include src, href, alt, and data-* values.

The selector identifies an element inside saved markup. The attribute field names the HTML attribute. Parsing returns its stored string value.

The saving function must output that element and value. WordPress does not insert sourced data automatically. Missing markup produces missing or default attributes later.

Boolean HTML attributes need special care. Presence and textual values differ. Test exact parsing behaviour for each declared type.

The text source reads plain text

The text source reads text content from a matching element. It does not preserve nested formatting markup. This suits short plain labels.

Suppose a caption contains emphasis. A text source returns textual content without preserving that emphasis. An HTML source may fit better.

Choose selectors that remain stable across versions. A renamed class breaks extraction. Semantic tags alone can also match unintended elements.

Whitespace and entities deserve fixtures. Browser-like parsing can normalise them. Compare round trips using realistic punctuation and multilingual text.

The html source reads formatted content

The html source reads inner HTML from a selected element. RichText commonly uses it. Formatting elements can therefore survive editing.

The source includes markup within the selected element. The outer element remains part of the saving contract. Changing either structure can affect validation.

Saved rich content still needs sanitisation. Allowed formats depend on editor configuration and user capabilities. Do not render arbitrary HTML without appropriate escaping.

Use HTML storage when formatting is meaningful fallback content. Use comment storage for non-visible configuration. That boundary improves portability.

The query source reads repeated structures

The query source extracts an array from repeated matching elements. A nested definition describes fields within each matched item.

It can represent image lists, cards, or other repeated markup. Each item may combine text, HTML, and element attributes.

Query sources become fragile when markup changes substantially. Ordering is part of the saved meaning. Missing selectors can silently drop individual fields.

InnerBlocks may be better for independently editable complex items. Query attributes suit controlled repeated markup. Choose based on editing behaviour and migration needs.

The old meta source is deprecated

The legacy meta attribute source stored values in post meta. WordPress now marks that source as deprecated. Avoid it for new blocks.

Modern entity data can use registered meta and Block Bindings. That architecture separates the external value from ordinary block serialization.

Post meta requires server registration, types, REST visibility, and permissions. One post-level value can also serve several blocks. That differs from instance-owned data.

Do not migrate blindly from comment attributes into post meta. Multiple block instances may hold different values. A single post field cannot represent them directly.

Defaults may exist without saved values

An attribute definition can declare a default. Parsing supplies it when stored data is absent. The default therefore lives in registration, not necessarily content.

Changing a default can alter old unsaved instances after an update. No content migration occurred. The same stored block now receives different fallback behaviour.

Defaults should remain stable after release. When visual change is required, plan migration deliberately. Test examples lacking explicit values.

An empty string, zero, false, and absence are different states. Avoid truthiness shortcuts. Define and test each intended meaning.

Types determine whether values are accepted

Attribute definitions can require strings, numbers, booleans, arrays, objects, or null. An enum can restrict accepted values further.

Parsing extracts a candidate and checks its type. A mismatched candidate may not populate the attribute. The default may appear instead.

Form controls often return strings. A numeric attribute needs deliberate conversion. Otherwise, the editor can remain dirty after saving.

The official Attributes reference documents types and sources. Test against the current supported WordPress versions.

Block supports add their own attributes

Standard supports can extend a block’s attributes automatically. Colour presets may create named attributes. Custom design values often enter the shared style object.

The style object can contain nested colour, spacing, typography, border, and dimension values. It usually appears within delimiter JSON.

Developers should not redeclare generated attributes casually. Conflicting schemas create parsing differences. Use the standard support APIs where they fit.

InnerBlocks are not ordinary attributes

Nested blocks appear inside the parent’s serialized boundaries. WordPress parses them into an inner block tree. They are not simply another JSON attribute.

This distinction preserves independent editing, identity, and validation for children. A parent can still influence children through templates, context, and allowed-block rules.

Dynamic blocks using InnerBlocks must save their inner content. Returning completely empty saved output can discard the children’s serialized representation.

Dynamic blocks still need stored attributes

Dynamic blocks commonly save only a self-closing comment. Unsourced attributes remain inside that delimiter. The server callback receives parsed values during rendering.

Attributes may describe a query rather than its current results. Store filters, counts, or identifiers. Query changing records when rendering.

Do not store sensitive credentials inside block attributes. Editors, APIs, revisions, and exports may expose content. Use secured server configuration instead.

How setAttributes changes editor state

The edit component receives current attributes and setAttributes. Calling it updates the block’s editor state. WordPress later serializes that state during saving.

Recent APIs can accept updater functions for derived changes. This helps avoid stale values. Support depends on the project’s WordPress baseline.

Updating nested objects needs deliberate immutability. Mutating an existing object can hide changes. Create the required replacement shape instead.

How copying and duplication affect storage

Duplicating a block copies its serialized attributes and inner content. External entity references may still point toward the same record. Instance identifiers may also duplicate.

Do not assume every identifier should remain unique after copying. Some represent shared resources intentionally. Others require regeneration when creating a new instance.

Test copy, paste, duplication, reusable patterns, and transforms. Storage designs often behave correctly only during direct editing. Alternative creation paths reveal ownership mistakes.

Attribute changes need migrations

Renaming a key makes older stored values invisible to the new definition. Changing sources moves the expected location. Changing types can reject historical values.

Static blocks can provide deprecated definitions and migration functions. Those definitions recognise older markup. Migration converts attributes into the current shape.

Keep fixtures for every released format. Parse them with current code. Confirm editing and resaving preserve intended content.

Server-rendered blocks avoid static markup validation. They still need attribute compatibility. Old delimiter JSON continues reaching current callbacks.

Security and privacy boundaries

Block attributes are content, not trusted configuration. Sanitize values during saving where appropriate. Escape them again for their output context.

Post content can appear through REST responses, exports, revisions, and backups. Avoid storing secrets, private tokens, or unrestricted executable code.

External entity data also needs permission checks. A binding should not bypass normal access rules. Validate both reading and editing capabilities.

Why database searches can mislead you

A database search may find visible text without identifying its block. Sourced attributes appear as ordinary HTML. Comment attributes appear as escaped JSON nearby.

Serialized values can use escaped characters or normalised entities. Searching the displayed form may return nothing. Parse content before drawing conclusions.

One value can also appear twice intentionally. Comment JSON stores the setting. Saved markup expresses its rendered consequence.

For example, an alignment attribute can accompany a matching CSS class. They support parsing and fallback differently. Removing either copy can break validation.

Database tools should report affected post identifiers before changing anything. Export those records first. Then transform parsed blocks and preserve unrelated HTML.

How revisions record attribute changes

Post revisions capture earlier serialized content. They therefore capture most instance attribute changes. Separate external entities may follow different revision policies.

Restoring a post can restore delimiter JSON and sourced HTML together. It may not restore changed post meta. Check every external dependency separately.

A debugging workflow for missing attributes

  1. Inspect the current attribute definition.
  2. Copy one affected block as raw markup.
  3. Locate comment JSON and matching saved elements.
  4. Confirm selectors match exactly one intended target.
  5. Check extracted values against declared types.
  6. Compare defaults with explicit saved values.
  7. Inspect the saving function’s current output.
  8. Test the oldest supported block fixture.
  9. Disable filters altering registration or content.
  10. Save only after preserving a revision.

Start with raw evidence. Sidebar controls can display defaults that were never stored. The delimiter and markup reveal actual persistence.

A storage design checklist

  • Store meaningful visible content inside durable HTML.
  • Store non-visible instance settings inside delimiter JSON.
  • Use stable selectors for sourced values.
  • Keep defaults stable after public release.
  • Convert control values into declared types.
  • Use InnerBlocks for independently editable child content.
  • Use external entities only for genuinely shared data.
  • Never place credentials inside block attributes.
  • Test copying, transforms, imports, and deactivation.
  • Maintain fixtures and migrations for old schemas.

The best storage mirrors ownership. Instance settings belong with the instance. Shared records belong outside it. Visible meaning deserves durable fallback markup.

Frequently asked questions

Where are WordPress block attributes stored?

Most live inside post_content, using delimiter JSON or saved HTML. The declared source decides.

Are block attributes stored in post meta?

Usually not. The legacy meta source is deprecated. Modern bindings can read registered external data.

What happens when a block attribute has no source?

WordPress serializes its non-default value inside the block’s opening comment JSON.

Are InnerBlocks stored as attributes?

No. They are nested serialized blocks with independent names, attributes, content, and validation.

Can changing an attribute default affect old blocks?

Yes. Older blocks lacking explicit values receive the new default during parsing.

The verdict

Transparent storage makes block plugins easier to leave. Some advanced features still require provider code. Test WP Block Suite’s free plugins before deciding. Then compare the $299 lifetime suite for several matching Pro needs.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *