gutenbergGutenberg (Block Editor) Abilities
Block tree reads and writes, reusable blocks, block templates, patterns, and FSE global styles.
edit_theme_options 7delete_posts 1edit_posts 11read 2Available Tools (21)
blocks_get_post_treeRead-onlyRead a post or page as a structured Gutenberg block tree. Returns a flat list of blocks, each with its index path, block name, a plain-text snippet, and child count, far cheaper in tokens than fetching the full post_content. Use this first to find the path of the block you want to edit, then call blocks_get_block for full detail on one block. Works on any post type that stores block markup.
Parameter Schema3 parameters
{
"type": "object",
"properties": {
"post_id": {
"type": "integer",
"description": "Post or page ID."
},
"depth": {
"type": "integer",
"description": "How many levels of nesting to include. Default 10. Use 0 for top-level blocks only."
},
"snippet_length": {
"type": "integer",
"description": "Max characters of plain text per block. Default 160, max 1000."
}
},
"required": [
"post_id"
]
}blocks_get_blockRead-onlyGet one block from a post by its index path, including full attributes, raw inner HTML, and its serialized markup. Use after blocks_get_post_tree has told you which path you want.
Parameter Schema2 parameters
{
"type": "object",
"properties": {
"post_id": {
"type": "integer",
"description": "Post or page ID."
},
"path": {
"type": "string",
"description": "Dot-separated 0-based index path, e.g. \"0\" for the first top-level block or \"1.2\" for the third child of the second. Paths shift when siblings are inserted or removed. Always re-read the tree after a mutation rather than reusing an old path."
}
},
"required": [
"post_id",
"path"
]
}blocks_insertDestructiveInsert a new block into a post at a position relative to an existing block. Supply the block either as structured fields (block_name plus attributes and inner_html) or as raw markup. Set dry_run=true to preview the resulting tree without writing. Requires edit_post capability on the target post. Emits an undo token.
Parameter Schema9 parameters
{
"type": "object",
"properties": {
"post_id": {
"type": "integer",
"description": "Post or page ID."
},
"path": {
"type": "string",
"description": "Path of the reference block. Dot-separated 0-based index path, e.g. \"0\" for the first top-level block or \"1.2\" for the third child of the second. Paths shift when siblings are inserted or removed. Always re-read the tree after a mutation rather than reusing an old path."
},
"position": {
"type": "string",
"enum": [
"before",
"after",
"first_child",
"last_child"
],
"description": "Where to place the new block relative to the reference block."
},
"block_name": {
"type": "string",
"description": "Block type, e.g. \"core/paragraph\". Required unless markup is supplied."
},
"attributes": {
"type": "object",
"description": "Block attributes as a JSON object. Use blocks_get_type_schema to discover valid attributes."
},
"inner_html": {
"type": "string",
"description": "The block's saved HTML, e.g. \"<p>Hello</p>\" for a paragraph. Must match what the block's save() function would produce."
},
"markup": {
"type": "string",
"description": "Raw block markup as an alternative to the structured fields, e.g. \"<!-- wp:paragraph --><p>Hi</p><!-- /wp:paragraph -->\". Takes precedence over block_name/attributes/inner_html."
},
"expected_block_name": {
"type": "string",
"description": "Guard: abort unless the block at path has this name. Protects against a stale path pointing somewhere unintended."
},
"dry_run": {
"type": "boolean",
"description": "Preview the result without writing. Default false."
}
},
"required": [
"post_id",
"path",
"position"
]
}blocks_updateDestructiveUpdate the block at a given path: replace its attributes, its inner HTML, or both. Attributes are replaced wholesale, not merged: read the block first with blocks_get_block, then send the complete attribute set you want. Set dry_run=true to preview. Requires edit_post. Emits an undo token.
Parameter Schema6 parameters
{
"type": "object",
"properties": {
"post_id": {
"type": "integer",
"description": "Post or page ID."
},
"path": {
"type": "string",
"description": "Dot-separated 0-based index path, e.g. \"0\" for the first top-level block or \"1.2\" for the third child of the second. Paths shift when siblings are inserted or removed. Always re-read the tree after a mutation rather than reusing an old path."
},
"attributes": {
"type": "object",
"description": "Complete replacement attribute object. Omit to leave attributes unchanged."
},
"inner_html": {
"type": "string",
"description": "Replacement saved HTML for the block. Omit to leave unchanged. Ignored for blocks that have child blocks."
},
"expected_block_name": {
"type": "string",
"description": "Guard: abort unless the block at path has this name."
},
"dry_run": {
"type": "boolean",
"description": "Preview the result without writing. Default false."
}
},
"required": [
"post_id",
"path"
]
}blocks_deleteDestructiveDelete the block at a given path, including all of its children. Set dry_run=true to preview what would be removed. Requires edit_post. Emits an undo token that restores the full pre-deletion content.
Parameter Schema4 parameters
{
"type": "object",
"properties": {
"post_id": {
"type": "integer",
"description": "Post or page ID."
},
"path": {
"type": "string",
"description": "Dot-separated 0-based index path, e.g. \"0\" for the first top-level block or \"1.2\" for the third child of the second. Paths shift when siblings are inserted or removed. Always re-read the tree after a mutation rather than reusing an old path."
},
"expected_block_name": {
"type": "string",
"description": "Guard: abort unless the block at path has this name. Strongly recommended for deletes."
},
"dry_run": {
"type": "boolean",
"description": "Preview without writing. Default false."
}
},
"required": [
"post_id",
"path"
]
}blocks_moveDestructiveMove a block (with its children) from one path to another within the same post. The destination is resolved before the source is removed, so you can use the paths exactly as reported by blocks_get_post_tree without compensating for shifts. Requires edit_post. Emits an undo token.
Parameter Schema6 parameters
{
"type": "object",
"properties": {
"post_id": {
"type": "integer",
"description": "Post or page ID."
},
"from_path": {
"type": "string",
"description": "Path of the block to move. Dot-separated 0-based index path, e.g. \"0\" for the first top-level block or \"1.2\" for the third child of the second. Paths shift when siblings are inserted or removed. Always re-read the tree after a mutation rather than reusing an old path."
},
"to_path": {
"type": "string",
"description": "Path of the reference block at the destination."
},
"position": {
"type": "string",
"enum": [
"before",
"after",
"first_child",
"last_child"
],
"description": "Placement relative to the destination block."
},
"expected_block_name": {
"type": "string",
"description": "Guard: abort unless the block at from_path has this name."
},
"dry_run": {
"type": "boolean",
"description": "Preview without writing. Default false."
}
},
"required": [
"post_id",
"from_path",
"to_path",
"position"
]
}blocks_validate_markupedit_postsValidate Gutenberg block markup server-side and report a confidence level rather than a pass/fail. Checks delimiter balance, attribute JSON, block registration, attribute types against registered schemas, and nesting constraints. IMPORTANT: PHP cannot run a block's JavaScript save() function, which is what the editor actually compares against, so this cannot guarantee the editor will accept the markup, and a block that is not registered server-side is reported as "unknown", never as invalid. Use before writing hand-authored markup.
Parameter Schema1 parameter
{
"type": "object",
"properties": {
"markup": {
"type": "string",
"description": "Raw block markup to validate."
}
},
"required": [
"markup"
]
}blocks_list_typesedit_postsList Gutenberg block types registered on this site, with name, title, category, dynamic flag, and nesting constraints. Filter by category or search term. Note that blocks registered only in JavaScript do not appear: absence here does not mean a block is unavailable in the editor.
Parameter Schema2 parameters
{
"type": "object",
"properties": {
"category": {
"type": "string",
"description": "Filter by block category slug, e.g. \"text\", \"media\", \"design\"."
},
"search": {
"type": "string",
"description": "Case-insensitive substring match against block name and title."
}
}
}blocks_get_type_schemaedit_postsGet the full attribute schema for one block type: every attribute with its type and default, plus supports flags and registered variations. Call this before constructing a block with blocks_insert so the attributes you send match what the block actually accepts.
Parameter Schema1 parameter
{
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Fully-qualified block name, e.g. \"core/heading\"."
}
},
"required": [
"name"
]
}blocks_list_templatesedit_theme_optionsList site templates available for this theme. Returns each template's slug, title, description, and whether it was customized in the database or is still the theme-provided file. Works only when a block theme (Full Site Editing theme) is active. Filters by type (templates or template parts) and area.
Parameter Schema3 parameters
{
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"template",
"template_part"
],
"description": "Filter by type. Omit for both."
},
"area": {
"type": "string",
"description": "For template parts: filter by area (\"header\", \"footer\", \"uncategorized\"). For templates: omit."
},
"search": {
"type": "string",
"description": "Case-insensitive substring search on slug and title."
}
}
}blocks_get_templateedit_theme_optionsGet a single template by slug, returning its full block markup, content hash, and metadata. The slug is the name portion only, e.g. "single-post" for templates/single-post.html in the theme, or just "index" for the fallback index template. The tool resolves both theme-file and database-customized versions and tells you which you received.
Parameter Schema2 parameters
{
"type": "object",
"properties": {
"slug": {
"type": "string",
"description": "Template slug. For theme-provided templates this is the filename without extension, e.g. \"index\", \"single-post\", \"page\". For database-customizations the ID is theme//slug (e.g. \"flavor//single-post\"), which this tool resolves automatically."
},
"type": {
"type": "string",
"enum": [
"template",
"template_part"
],
"description": "Default \"template\"."
}
},
"required": [
"slug"
]
}blocks_update_templateDestructiveCreate or update a database customization of a theme template. Pass the slug (e.g. "single-post" or "header"). If the theme provides the template, the new content shadows it; if no theme template exists, a new custom template is created. The previous state is captured for undo.
Parameter Schema6 parameters
{
"type": "object",
"properties": {
"slug": {
"type": "string",
"description": "Template slug. For theme-provided templates this is the filename without extension, e.g. \"index\", \"single-post\", \"page\". For database-customizations the ID is theme//slug (e.g. \"flavor//single-post\"), which this tool resolves automatically."
},
"content": {
"type": "string",
"description": "The new block markup for the template body. Must be valid Gutenberg block markup. The title, description, and slug are derived automatically."
},
"title": {
"type": "string",
"description": "Optional human-readable title. Defaults to the slug title-cased."
},
"type": {
"type": "string",
"enum": [
"template",
"template_part"
],
"description": "Default \"template\"."
},
"area": {
"type": "string",
"description": "Template part area (\"header\", \"footer\", \"uncategorized\"). Only relevant when type is \"template_part\"."
},
"dry_run": {
"type": "boolean",
"description": "Preview what would be written without modifying the database."
}
},
"required": [
"slug",
"content"
]
}blocks_revert_templateDestructiveRemove a database customization, causing the theme-provided file to resurface. Pass the slug only: if a database post exists for that slug, it is deleted; if none exists, the tool reports that no customization was found and no changes were made. Captures the pre-deletion state for undo.
Parameter Schema3 parameters
{
"type": "object",
"properties": {
"slug": {
"type": "string",
"description": "Template slug. For theme-provided templates this is the filename without extension, e.g. \"index\", \"single-post\", \"page\". For database-customizations the ID is theme//slug (e.g. \"flavor//single-post\"), which this tool resolves automatically."
},
"type": {
"type": "string",
"enum": [
"template",
"template_part"
],
"description": "Default \"template\"."
},
"dry_run": {
"type": "boolean",
"description": "Preview what would be deleted without modifying the database."
}
},
"required": [
"slug"
]
}blocks_list_patternsedit_theme_optionsList registered block patterns available on this site. Read-only: patterns cannot be edited through this tool. Returns the pattern name, slug, category, description, and whether the pattern uses specific block types.
Parameter Schema2 parameters
{
"type": "object",
"properties": {
"category": {
"type": "string",
"description": "Filter by pattern category slug, e.g. \"buttons\", \"columns\", \"header\"."
},
"search": {
"type": "string",
"description": "Case-insensitive substring search on name and slug."
}
}
}blocks_list_reusableedit_postsList reusable blocks (the wp_block post type). Returns each block's ID, title, and a snippet of its content. Reusable blocks are global: updating one is reflected everywhere it is used.
Parameter Schema3 parameters
{
"type": "object",
"properties": {
"per_page": {
"type": "integer",
"description": "Number of reusable blocks per page. Default 20, max 100."
},
"page": {
"type": "integer",
"description": "Page number, 1-indexed. Default 1."
},
"search": {
"type": "string",
"description": "Case-insensitive substring search on the block title."
}
}
}blocks_get_reusableedit_postsGet a single reusable block by ID, returning its title, full block markup, and a token-budget-friendly summary of its internal block structure.
Parameter Schema1 parameter
{
"type": "object",
"properties": {
"reusable_id": {
"type": "integer",
"description": "The post ID of the reusable block (the wp_block post type)."
}
},
"required": [
"reusable_id"
]
}blocks_create_reusableDestructiveCreate a new reusable block. Requires edit_posts capability. Returns the new block's ID.
Parameter Schema2 parameters
{
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "Human-readable title for the reusable block."
},
"content": {
"type": "string",
"description": "Block markup for the reusable block. Must be valid Gutenberg block markup."
}
},
"required": [
"title",
"content"
]
}blocks_update_reusableDestructiveUpdate an existing reusable block's content. Reusable blocks are global: this change is reflected everywhere the block is embedded. Captures the previous content for undo. Requires edit_post capability on the wp_block post.
Parameter Schema4 parameters
{
"type": "object",
"properties": {
"reusable_id": {
"type": "integer",
"description": "The post ID of the reusable block to update."
},
"title": {
"type": "string",
"description": "New title for the block. Omit to leave unchanged."
},
"content": {
"type": "string",
"description": "New block markup. Required."
},
"dry_run": {
"type": "boolean",
"description": "Preview without writing. Default false."
}
},
"required": [
"reusable_id",
"content"
]
}blocks_delete_reusableDestructivePermanently delete a reusable block. All places where this block is embedded will fall back to rendering nothing. Captures the deleted content for undo. Requires delete_post capability on the wp_block post.
Parameter Schema2 parameters
{
"type": "object",
"properties": {
"reusable_id": {
"type": "integer",
"description": "The post ID of the reusable block to delete."
},
"dry_run": {
"type": "boolean",
"description": "Preview without deleting. Default false."
}
},
"required": [
"reusable_id"
]
}blocks_get_global_stylesedit_theme_optionsRead the site's global styles (theme.json): the colour palette, typography scale, spacing presets, layout widths, and per-block style overrides that a block theme renders from. This is the Site Editor's Styles sidebar, and the Gutenberg counterpart of elementor_get_kit. Pick which layer you want with origin: "user" (default) is what the Site Editor has saved and the only layer that is writable; "theme" is the active theme's own theme.json defaults; "merged" is what actually renders, after core, block, theme and user layers are combined in that priority order. IMPORTANT: by default this returns a KEY INDEX, not the values, because merged theme.json data on a real block theme carries a section per registered block and is larger than a single tool result allows. Pass keys:["settings.color.palette","styles.typography"] to read specific dot-paths, or include_all:true to force the whole object. Read the user layer before writing with blocks_update_global_styles, since a list-valued preset such as settings.color.palette is replaced wholesale rather than merged element by element. Requires edit_theme_options.
Parameter Schema3 parameters
{
"type": "object",
"properties": {
"origin": {
"type": "string",
"enum": [
"user",
"theme",
"merged"
],
"description": "Which layer to read. \"user\" (default) is the saved Site Editor customization and the only writable layer. \"theme\" is the theme's theme.json defaults, useful for discovering which preset slugs exist before overriding them. \"merged\" is the effective rendered result."
},
"keys": {
"type": "array",
"items": {
"type": "string"
},
"description": "Dot-paths to return the actual values for, e.g. \"settings.color.palette\", \"styles.color.background\", or a bare top-level key like \"settings\". A path that is absent from this layer is reported in unset_paths rather than returned as empty, because \"unset here\" and \"empty\" mean different things: an unset user value means the theme default still applies."
},
"include_all": {
"type": "boolean",
"description": "Return the complete theme.json object instead of the key index. Expect a very large response on the merged origin; prefer keys."
}
}
}blocks_update_global_stylesDestructiveWrite the site's user global styles (theme.json), which is what the Site Editor's Styles sidebar saves. IMPORTANT: the keys you send are MERGED into the existing user styles, not replaced, so sending only settings.color.palette leaves typography and every per-block override untouched. Nested objects merge recursively, but a LIST value (settings.color.palette, settings.typography.fontSizes, settings.spacing.spacingSizes) is replaced wholesale, the same rule as the Elementor kit repeaters: read the current list with blocks_get_global_styles keys:["settings.color.palette"] and send the full list back with your edits, or you will drop the entries you omitted. Pass replace_settings=true only for a deliberate wholesale swap, which discards every top-level key you do not send and reports what it removed. Accepts the "settings" and "styles" top-level keys; "version" and WordPress's isGlobalStylesUserThemeJSON marker are structural and written automatically (without that marker WordPress ignores the stored JSON entirely, so a write would succeed, read back correctly, and change nothing on the page). Set dry_run=true to preview a per-path diff without writing. After a write the response re-reads the stored value to confirm what landed, and the theme_json caches are invalidated so the next render picks the change up. Emits an undo token restoring the full pre-write user styles. Site-wide change. Requires edit_theme_options.
Parameter Schema4 parameters
{
"type": "object",
"properties": {
"settings": {
"type": "object",
"description": "theme.json \"settings\" subtree: presets and opt-ins such as color.palette, typography.fontSizes, spacing.spacingSizes, layout.contentSize. Merged recursively; list values replace wholesale."
},
"styles": {
"type": "object",
"description": "theme.json \"styles\" subtree: the applied values such as color.background, typography.fontFamily, elements.link, and per-block overrides under blocks. Merged recursively; list values replace wholesale."
},
"replace_settings": {
"type": "boolean",
"description": "Replace the whole user styles object instead of merging. Discards every top-level key you do not send. Default false."
},
"dry_run": {
"type": "boolean",
"description": "Report the per-path diff the call would apply without writing. Default false."
}
}
}