Skip to main content

Yoast SEO Abilities - Term's SEO data

Yoast SEO registers two abilities to work with the SEO data of individual taxonomy terms (categories, tags, and any custom taxonomies): one to read it and one to update it.

AbilityTypeReturns
yoast-seo/get-term-seo-dataRead-onlyThe SEO data object for the matched term
yoast-seo/update-term-seo-dataWriteThe updated SEO data object for the term

Permissions​

Like the Post's SEO data abilities, these two abilities are gated behind the advanced metadata capability (wpseo_edit_advanced_metadata), the same capability that gates the advanced and schema fields in the editor. On top of that, per-term edit access is always enforced: only terms the current user is allowed to edit are ever returned or updated.

Annotations​

Each ability declares a set of behavior annotations as hints for AI agents and other MCP clients:

AbilityRead-onlyDestructiveIdempotent
yoast-seo/get-term-seo-dataYesNoYes
yoast-seo/update-term-seo-dataNoNot declared (null)Yes

update-term-seo-data only edits Yoast's SEO metadata fields and never touches the term's name, slug, or description.

Identifying the term​

Both abilities accept a term_id (an integer of 1 or higher) or a permalink (the term archive's URL) to locate the term. At least one identifier is required.

Term IDs are unique across taxonomies in WordPress, so the ID alone is always sufficient to identify a term. A permalink is matched exactly against the permalink Yoast SEO has stored for the term, without any WordPress URL resolution, so it must be the term archive's exact URL. A permalink that belongs to a post, author, or other archive returns a not-found error.

Unlike get-post-seo-data, neither ability accepts a title search: both always target a single term.

Identifier precedence​

When both identifiers are provided, term_id wins and permalink is ignored: it is not cross-checked, even when it points to a different term, and a term_id that doesn't resolve returns a not-found error without falling back to the permalink. To avoid editing the wrong term, send a single identifier per request.

get-term-seo-data​

Reads the SEO data for a single taxonomy term.

Input​

Provide at least one of the following:

  • term_id – the ID of the term to retrieve. An integer of 1 or higher.
  • permalink – the permalink (URL) of the term archive to retrieve.

Output​

Returns a single term SEO data object. Unlike get-post-seo-data, the object is not wrapped in an array.

Usage​

Send a GET request to the ability's /run endpoint. To retrieve the SEO data of the term with ID 7:

/wp-json/wp-abilities/v1/abilities/yoast-seo/get-term-seo-data/run?input[term_id]=7

To retrieve the same term by its archive permalink instead, pass the archive's full URL (URL-encoded) as permalink:

/wp-json/wp-abilities/v1/abilities/yoast-seo/get-term-seo-data/run?input[permalink]=https%3A%2F%2Fexample.com%2Fcategory%2Frecipes%2F

Doing so might yield the following result:

{
"term_id": 7,
"term_name": "Recipes",
"permalink": "https://example.com/category/recipes/",
"taxonomy": "category",
"seo_title": null,
"seo_title_rendered": "Recipes - My Site",
"meta_description": "Browse all our recipe posts.",
"meta_description_rendered": "Browse all our recipe posts.",
"focus_keyphrase": null,
"canonical": null,
"canonical_rendered": "https://example.com/category/recipes/",
"is_cornerstone": false,
"noindex": null,
"open_graph_title": null,
"open_graph_title_rendered": "Recipes",
"open_graph_description": null,
"open_graph_description_rendered": "Browse all our recipe posts.",
"twitter_title": null,
"twitter_title_rendered": "Recipes",
"twitter_description": null,
"twitter_description_rendered": "Browse all our recipe posts.",
"seo_score": "na",
"readability_score": "na",
"inclusive_language_score": "na"
}

update-term-seo-data​

Updates the SEO data for a single taxonomy term.

Only the fields you provide are changed; every other field is left untouched. A provided empty value ("" or null, depending on the field) clears that field and lets Yoast SEO fall back to its default.

Input​

Identify the term with term_id or permalink, then provide any of the writable fields you want to change:

  • seo_title – the custom SEO title. A string, or null to clear it and fall back to the default template.
  • meta_description – the custom meta description. A string, or null to clear it.
  • canonical – the custom canonical URL. A string, or null or an empty string to remove it and fall back to the default canonical.
  • is_cornerstone – whether the term is marked as cornerstone content. A boolean.
  • noindex – whether search engines should be told not to index this term archive. true sets noindex (the archive is excluded from search results); false forces the archive to be indexed; null clears the setting and falls back to the taxonomy default.
  • open_graph_title – the custom Open Graph title. A string, or null to clear it.
  • open_graph_description – the custom Open Graph description. A string, or null to clear it.
  • twitter_title – the custom X title. A string, or null to clear it.
  • twitter_description – the custom X description. A string, or null to clear it.
note

Terms support fewer SEO metadata fields than posts. The advanced robots flags (nofollow, noimageindex, noarchive, nosnippet) and the Schema.org page and article type overrides are not available for terms.

Output​

Returns the single, updated term SEO data object, reflecting the state of the term after the update. This is the same shape as the get-term-seo-data response, so you can immediately confirm what was written.

On sites without Yoast SEO Premium, the response may also carry an extra ai_generate_hint field when a title or description field is updated.

Usage​

Send a POST request to the ability's /run endpoint with an input object in the body. To mark the category with ID 7 as noindex:

/wp-json/wp-abilities/v1/abilities/yoast-seo/update-term-seo-data/run
{
"input": {
"term_id": 7,
"noindex": true
}
}

You can identify the term by its archive permalink instead, and change several fields at once:

{
"input": {
"permalink": "https://example.com/category/recipes/",
"seo_title": "All Recipes - My Site",
"meta_description": "Browse all our tested and approved recipes.",
"is_cornerstone": true
}
}

The term SEO data object​

Both abilities return the same object. Its fields are:

FieldTypeDescription
term_idintegerThe term ID.
term_namestring | nullThe term's breadcrumb title: the custom breadcrumb title when set, otherwise the term name.
permalinkstring | nullThe term archive's permalink (URL).
taxonomystringThe taxonomy slug, such as category or post_tag.
seo_titlestring | nullThe custom SEO title, or null when none is set.
seo_title_renderedstring | nullThe SEO title as output on the front end, with the default template applied and snippet variables expanded.
meta_descriptionstring | nullThe custom meta description, or null when none is set.
meta_description_renderedstring | nullThe meta description as output on the front end.
focus_keyphrasestring | nullThe focus keyphrase, or null when none is set.
canonicalstring | nullThe custom canonical URL, or null when none is set.
canonical_renderedstring | nullThe canonical URL as output on the front end: the custom value when set, otherwise the term archive permalink.
is_cornerstonebooleanWhether the term is marked as cornerstone content.
noindexboolean | nullWhether search engines are told not to index this term archive. true means noindex, false forces indexing, null means the taxonomy default applies.
open_graph_titlestring | nullThe custom Open Graph title.
open_graph_title_renderedstring | nullThe Open Graph title as output on the front end.
open_graph_descriptionstring | nullThe custom Open Graph description.
open_graph_description_renderedstring | nullThe Open Graph description as output on the front end.
twitter_titlestring | nullThe custom X title.
twitter_title_renderedstring | nullThe X title as output on the front end.
twitter_descriptionstring | nullThe custom X description.
twitter_description_renderedstring | nullThe X description as output on the front end.
seo_scorestringThe result of the SEO analysis when the term was last saved: one of na, bad, ok, or good.
readability_scorestringThe result of the readability analysis when the term was last saved.
inclusive_language_scorestringThe result of the inclusive language analysis when the term was last saved.

The *_rendered companion of a field carries the value as actually output on the front end: the global default template applied where no custom value is set, with snippet variables expanded. It is null when nothing is output. This lets you distinguish a field the user left empty (a null stored value with a non-null rendered value) from what visitors and search engines actually see.

Full definition​

A GET request to /wp-json/wp-abilities/v1/abilities returns the complete definition of each ability:

{
"name": "yoast-seo/get-term-seo-data",
"label": "Get Term SEO Data",
"description": "Get the SEO data for a single taxonomy term, such as a category or a tag. Identify the term by term_id or by permalink (URL). Only terms the current user is allowed to edit are returned.",
"category": "yoast-seo",
"input_schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"term_id": {
"type": "integer",
"description": "The ID of the term to retrieve.",
"minimum": 1
},
"permalink": {
"type": "string",
"description": "The permalink (URL) of the term archive to retrieve."
}
}
},
"output_schema": {
"type": "object",
"properties": {
"term_id": { "type": "integer" },
"term_name": { "type": ["string", "null"] },
"permalink": { "type": ["string", "null"] },
"taxonomy": { "type": "string" },
"seo_title": { "type": ["string", "null"] },
"seo_title_rendered": { "type": ["string", "null"] },
"meta_description": { "type": ["string", "null"] },
"meta_description_rendered": { "type": ["string", "null"] },
"focus_keyphrase": { "type": ["string", "null"] },
"is_cornerstone": { "type": "boolean" },
"open_graph_title": { "type": ["string", "null"] },
"open_graph_title_rendered": { "type": ["string", "null"] },
"open_graph_description": { "type": ["string", "null"] },
"open_graph_description_rendered": { "type": ["string", "null"] },
"twitter_title": { "type": ["string", "null"] },
"twitter_title_rendered": { "type": ["string", "null"] },
"twitter_description": { "type": ["string", "null"] },
"twitter_description_rendered": { "type": ["string", "null"] },
"seo_score": { "type": "string", "enum": ["na", "bad", "ok", "good"] },
"readability_score": { "type": "string", "enum": ["na", "bad", "ok", "good"] },
"inclusive_language_score": { "type": "string", "enum": ["na", "bad", "ok", "good"] },
"canonical": {
"type": ["string", "null"],
"description": "The custom canonical URL as stored for the term. Null when no custom value is set; the rendered companion field carries what is actually output."
},
"canonical_rendered": {
"type": ["string", "null"],
"description": "The canonical URL as output on the front end: the custom value when set, otherwise the permalink of the term. Null when nothing is output."
},
"noindex": {
"type": ["boolean", "null"],
"description": "Whether search engines are told not to index this term archive. true means noindex (the archive is excluded from search results); false means the archive is forced to be indexed; null means no setting is stored and the taxonomy default applies."
}
}
},
"meta": {
"annotations": {
"readonly": true,
"destructive": false,
"idempotent": true
},
"show_in_rest": true,
"mcp": {
"public": true
}
}
}

The update definition above is the one returned on a site without Yoast SEO Premium. With Premium active, the ai_generate_hint property is absent from the output schema.

How to disable them programmatically​

You can unregister either of these abilities through the WordPress-native wp_abilities_api_init action. Remove a name from the array to keep that ability enabled:

<?php
add_action( 'wp_abilities_api_init', function() {
$abilities = [
'yoast-seo/get-term-seo-data',
'yoast-seo/update-term-seo-data',
];
foreach ( $abilities as $ability ) {
if ( wp_has_ability( $ability ) ) {
wp_unregister_ability( $ability );
}
}
}, 20 ); // Run after Yoast SEO registers at default priority 10