Hooks reference

This page lists the public filters and actions in Anansi SEO 0.5.11, grouped by feature. For each hook it says when it runs, what it receives and what it should return. Most page-output filters run only when Anansi builds that output: when it is in charge (live mode, no other SEO plugin) or on a signed preview request. Many hooks have a Rank Math twin that Anansi fires with the same arguments; those are listed in Rank Math compatibility hooks at the end.

Hooks marked low-level mirror a Rank Math hook of the same shape. They work, but they are close to Anansi’s internals and are more likely to change than the others.

Contents


Head and page output

anansi/head/tags (filter)

Collects the tags for Anansi’s head block. Runs once per page while Anansi builds its wp_head output.

ParameterTypeDescription
$tagsarray[]Each item: 'order' => int (lower prints first, default 50) and 'html' => string (already escaped).

Returns array[].

Anansi’s own tags use these orders: <title> 1, description 6, robots 10, canonical 20, prev/next 21 and 22, Open Graph and Twitter 30, verification tags 90. Items with empty html are dropped.

add_filter( 'anansi/head/tags', function ( $tags ) {
    $tags[] = array(
        'order' => 25,
        'html'  => '<meta name="theme-color" content="#0f172a" />',
    );
    return $tags;
} );

Escape everything you put in html. Anansi prints it as given.

anansi/head (action)

Fires inside Anansi’s head block, after the tags from anansi/head/tags and before the closing marker. Anansi’s JSON-LD prints here at priority 90.

ParameterTypeDescription
$previewbooltrue on a signed preview request.
add_action( 'anansi/head', function ( $preview ) {
    echo '<link rel="author" href="' . esc_url( home_url( '/humans.txt' ) ) . '" />' . "\n";
} );

anansi/title_raw (filter)

The page title before escaping. Runs after Anansi resolved the template and variables (and capitalised it, if that setting is on), before the page number is added.

ParameterTypeDescription
$titlestringPlain-text title.

Returns string. Return '' to leave WordPress’s own title.

Rank Math twin: rank_math/frontend/title.

add_filter( 'anansi/title_raw', function ( $title ) {
    if ( is_singular( 'event' ) ) {
        $title .= ' | Tickets';
    }
    return $title;
} );

anansi/title/add_page_number (filter)

Whether to add “Page N of M” to the title of page 2 and later when the title does not already show it.

ParameterTypeDescription
$addboolDefault true.
$titlestringTitle so far.
$pageintCurrent page number (2 or more).

Returns bool.

anansi/title (filter)

The plain-text title Anansi hands to WordPress through pre_get_document_title (priority 15) in live mode, for themes that call wp_get_document_title(). Anansi fills it from its own title at default priority.

ParameterTypeDescription
$titlestringTitle, '' before Anansi’s own callback runs.

Returns string. To change the title, prefer anansi/title_raw, which also changes the <title> tag in Anansi’s head block.

anansi/title_separator (filter)

The separator used for %sep%.

ParameterTypeDescription
$sepstringFrom the Titles setting title_separator (default -).

Returns string.

anansi/description (filter)

The meta description before escaping.

ParameterTypeDescription
$descriptionstringPlain text, '' when Anansi has none.

Returns string. Return '' for no description tag.

Rank Math twin: rank_math/frontend/description.

anansi/robots (filter)

The robots directives for the page.

ParameterTypeDescription
$robotsarrayKeyed list, for example array( 'index' => 'index', 'follow' => 'follow' ). Possible keys: index, follow, noarchive, noimageindex, nosnippet.

Returns array.

Rank Math twin: rank_math/frontend/robots.

add_filter( 'anansi/robots', function ( $robots ) {
    if ( is_tag() ) {
        $robots['index']  = 'noindex';
        $robots['follow'] = 'follow';
    }
    return $robots;
} );

anansi/advanced_robots (filter)

The max-* directives. Runs only when the page is indexable and not nosnippet.

ParameterTypeDescription
$robotsarrayKeyed list, for example array( 'max-snippet' => 'max-snippet:-1', 'max-image-preview' => 'max-image-preview:large' ).

Returns array. The result is merged into the robots list.

Rank Math twin: rank_math/frontend/advanced_robots.

anansi/canonical (filter)

The canonical URL. Anansi prints no canonical on noindex pages.

ParameterTypeDescription
$urlstringCanonical URL.

Returns string. Return '' for no canonical tag.

Rank Math twin: rank_math/frontend/canonical.

The full <link rel="prev"> / <link rel="next"> tag HTML on paginated pages.

ParameterTypeDescription
$htmlstringTag HTML.

Returns string. Return '' to drop it. Only <link> tags with href and rel survive.

Rank Math twins: rank_math/frontend/prev_rel_link, rank_math/frontend/next_rel_link.

ParameterTypeDescription
$disableboolDefault false.

Returns bool. true turns off rel prev/next.

add_filter( 'anansi/disable_adjacent_rel_links', '__return_true' );

anansi/meta/sources (filter)

The meta keys Anansi reads for a field, in order. Runs every time Anansi reads a post, term or user field.

ParameterTypeDescription
$keysstring[]Default array( '_anansi_{key}', 'rank_math_{key}' ).
$typestringpost, term or user.
$keystringShort field key: title, description, robots, canonical_url, focus_keyword, breadcrumb_title, facebook_image_id, primary_category, …

Returns string[]. The first stored, non-empty value wins.

add_filter( 'anansi/meta/sources', function ( $keys, $type, $key ) {
    if ( 'post' === $type && 'title' === $key ) {
        $keys[] = '_mytheme_seo_title';
    }
    return $keys;
}, 10, 3 );

See theme-integration.md.

anansi/disable_primary_term (filter)

When Anansi is in charge it moves a post’s primary term to the front of get_the_terms() results.

ParameterTypeDescription
$disableboolDefault false.

Returns bool. true keeps WordPress’s order.

anansi/webmaster/{id} (filter)

The content of one site verification tag on the front page. {id} is one of google_verify, bing_verify, baidu_verify, yandex_verify, pinterest_verify, norton_verify.

ParameterTypeDescription
$contentstringThe code from General settings.

Returns string. '' prints no tag.

Rank Math twin: rank_math/webmaster/{id}.


Title variables

anansi/vars/replacements (filter)

All variable replacements for one template, just before they are applied.

ParameterTypeDescription
$replacementsarrayToken => value, for example '%title%' => 'Hello world'.
$objectWP_Post\|WP_Term\|WP_User\|nullWhat the template is about.

Returns array.

anansi/vars/{name} (filter)

Value for a variable Anansi does not know. {name} is the lower-case variable name without percent signs.

ParameterTypeDescription
$valuestring\|nullnull.
$argsstring\|nullText inside parentheses for %name(args)%, else null.
$objectmixedPost, term, user or null.

Returns string\|null. null becomes an empty string.

// %price% and %price(EUR)% in any title or description template.
add_filter( 'anansi/vars/price', function ( $value, $args, $object ) {
    if ( ! $object instanceof WP_Post ) {
        return $value;
    }
    $price = get_post_meta( $object->ID, '_price', true );
    return '' === $price ? $value : trim( ( $args ? $args : '$' ) . ' ' . $price );
}, 10, 3 );

Open Graph and Twitter

All of these run while Anansi builds its social tags. Each has a Rank Math twin with the rank_math/ prefix instead of anansi/ (for example rank_math/opengraph/facebook/og_title).

anansi/opengraph/{network}/{property} (filter)

One filter per tag value. {network} is facebook, twitter or slack. {property} is the tag name with : changed to _.

NetworkProperties
facebookog_locale, og_type, og_title, og_description, og_url, og_site_name, article_publisher, article_author, article_tag, article_section, og_updated_time, fb_app_id, fb_admins, og_image, og_image_secure_url, og_image_width, og_image_height, og_image_alt, og_image_type, og_video, video_duration, article_published_time, article_modified_time
twittertwitter_card, twitter_title, twitter_description, twitter_site, twitter_creator, twitter_image
slacktwitter_label1, twitter_data1, twitter_label2, twitter_data2, …
ParameterTypeDescription
$contentstring\|intTag value.

Returns scalar. An empty value drops the tag.

add_filter( 'anansi/opengraph/facebook/og_title', function ( $title ) {
    return is_front_page() ? 'Acme: tools for makers' : $title;
} );

Other Open Graph filters

HookParametersReturnsPurpose
anansi/opengraph/twitter_cardbool $on (default true)boolfalse drops all Twitter tags.
anansi/opengraph/typestring $type (website, article, profile)stringThe og:type value.
anansi/opengraph/urlstring $urlstringThe og:url value (the canonical URL).
anansi/opengraph/twitter/card_typestring $cardstringTwitter card type. Allowed: summary, summary_large_image, app, player; anything else becomes summary.
anansi/opengraph/pre_set_featured_imagebool $skip (false), int $post_idboolReturn anything other than false to skip the featured image.
anansi/opengraph/pre_set_content_imagebool $skip (false), int $post_idboolSame, for the first image in the content.
anansi/opengraph/pre_set_default_imagebool $skip (false)boolSame, for the site’s default image.
anansi/opengraph/attachment_idint $idintAttachment used for an image.
anansi/opengraph/image_sizesstring[] $sizes (full, large, medium_large)string[]Sizes tried, in order. The first between 200 and 2000 px wins.
anansi/opengraph/{network}/imagestring $url ('' when Anansi found no image)stringImage URL. A different URL replaces the image and skips the file-type check. Runs for facebook and twitter.
anansi/opengraph/{network}/image_arrayarray $image (url, id, width, height, type, alt)arrayFull image data. Return an array without url to drop it.
anansi/opengraph/slack_enhanced_dataarray $data (label => value)arrayLabel/data pairs printed as twitter:label{n} / twitter:data{n}.
anansi/frontend/time_to_read_contentstring $contentstringText used for the reading time.
anansi/frontend/time_to_read_wpmint $wpm (200)intWords per minute.
// Use a branded image when a page has none.
add_filter( 'anansi/opengraph/facebook/image', function ( $url ) {
    return '' === $url ? get_theme_file_uri( 'assets/share.png' ) : $url;
} );

Schema (JSON-LD graph)

Anansi prints one <script type="application/ld+json" class="anansi-schema"> with an @graph, on the anansi/head action at priority 90.

anansi/json_ld (filter)

Builds the graph. Your callback gets the graph so far and returns it.

ParameterTypeDescription
$dataarrayGraph nodes, keyed.
$jsonldAnansi_SchemaThe schema object. Public properties: $post (WP_Post\|null), $post_id (int), $parts (array: title, url, canonical, modified, published, excerpt, desc, author). Public method: can_add_global_entities( $data ).

Returns array.

Anansi’s own steps run on the same hook:

PriorityStepKeys it adds
8Rank Math FAQ and HowTo blocksFAQPage and HowTo nodes
9Publisherpublisher (Organization or Person)
10Page contextWebSite, primaryImage, BreadcrumbList, WebPage, ProfilePage, richSnippet (default Article)
10Stored schemasschema-{meta_id}
30Video schemaVideoObject nodes
99LinkingAdds @id, isPartOf, publisher, image, inLanguage to schema-* and richSnippet nodes; links a howto node to the WebPage; folds the first FAQPage node into WebPage

Callbacks added to rank_math/json_ld run in the same chain (see the compatibility section). Keys are dropped when the graph is printed. Nodes that only have @type, and empty values, are removed.

Run at priority 20 to see Anansi’s main nodes. Give your own nodes an @id; the linking step at 99 only touches schema-* and richSnippet.

add_filter( 'anansi/json_ld', function ( $data, $jsonld ) {
    if ( ! is_singular( 'product' ) ) {
        return $data;
    }
    $url = get_permalink();
    $data['acmeProduct'] = array(
        '@type' => 'Product',
        '@id'   => $url . '#product',
        'name'  => get_the_title(),
        'url'   => $url,
    );
    if ( isset( $data['publisher']['@id'] ) ) {
        $data['acmeProduct']['brand'] = array( '@id' => $data['publisher']['@id'] );
    }
    return $data;
}, 20, 2 );

A full example is in theme-integration.md.

anansi/schema/validated_data (filter)

The whole graph after empty values were removed, just before printing.

ParameterTypeDescription
$dataarrayGraph nodes.

Returns array.

Other schema filters

All have a rank_math/ twin with the same name after the prefix.

HookParametersReturnsPurpose
anansi/schema/languagestring $langstringinLanguage value.
anansi/schema/add_global_entitiesbool $add, Anansi_Schema $jsonldboolWhether Organization, WebSite and WebPage nodes are added.
anansi/snippet/remove_taxonomy_databool $remove, string $taxonomyboolOn term archives: drop the global nodes.
anansi/json_ld/breadcrumbs_enabledbool $onboolAdd the BreadcrumbList node.
anansi/json_ld/disable_searchbool $disable (true except on the front page)boolLeave out the WebSite SearchAction.
anansi/json_ld/search_urlstring $url (/?s={search_term_string})stringSearchAction target.
anansi/snippet/breadcrumbarray $nodearrayThe BreadcrumbList node.
anansi/schema/article_entityarray $entityarrayEvery Article node (default or stored). Rank Math twin: rank_math/snippet/rich_snippet_article_entity.
anansi/snippet/rich_snippet_{type}false, array $parts, array $datamixedReturn anything but false to replace a node of this type with your own (see next row). {type} is the lower-case schema type; blogposting and newsarticle map to article, music types to music, event types to event.
anansi/snippet/rich_snippet_{type}_custom_entityarray $node (empty)arrayYour replacement node when the previous filter did not return false.
anansi/snippet/rich_snippet_{type}_entityarray $schemaarrayOne stored node of that type (not Article: Article uses anansi/schema/article_entity).
anansi/snippet/rich_snippet_entityarray $nodearrayEvery stored node, last step.
anansi/schema/default_typestring $type, string $post_type, int $post_idstringDefault Article type (Article, BlogPosting, NewsArticle) for a post type set to Article.
// News posts are NewsArticle by default.
add_filter( 'anansi/schema/default_type', function ( $type, $post_type, $post_id ) {
    return has_category( 'news', $post_id ) ? 'NewsArticle' : $type;
}, 10, 3 );

Video schema

HookParametersReturnsPurpose
anansi/video/sourcesstring[] $urls, string $contentstring[]Video URLs found in a post (YouTube and Vimeo are parsed). Runs when a post is scanned.
anansi/video/youtube_api_keystring $keystringYouTube Data API key (from settings). Return '' to use oEmbed only.
anansi/video/nodearray $node, array $video, WP_Post $postarrayOne VideoObject node. Return an empty value to drop it.
anansi/video/creator_typestring $type (Person), array $videostringPerson or Organization for the channel.
add_filter( 'anansi/video/creator_type', function () {
    return 'Organization';
} );

Content blocks

These run for Rank Math’s FAQ (rank-math/faq-block) and HowTo (rank-math/howto-block) blocks, which Anansi supports after Rank Math is gone. The Rank Math twins of the schema/block/* and schema/nested_blocks filters run without Rank Math’s own callbacks.

HookParametersReturnsPurpose
anansi/schema/block/before_filterarray $blocks (from parse_blocks())arrayBlocks before Anansi looks for Rank Math blocks.
anansi/schema/nested_blocksstring[] $names (core/group, core/columns, core/column)string[]Container blocks searched for nested Rank Math blocks.
anansi/schema/block/{name}array $data, array $blockarrayGraph after one Rank Math block was handled. {name} is the block name without rank-math/, for example faq-block.
anansi/schema/block/faq/contentstring $html, string[] $parts, array $attributesstringFront-end HTML of the FAQ block (when Rank Math is inactive).
anansi/schema/block/howto/contentstring $html, string[] $parts, array $attributesstringSame for HowTo.
anansi/blocks/{block}/title_wrapperstring $tagstringHeading tag for questions or steps. {block} is faq or howto. Allowed: h2–h6, p, div.
anansi/block/preserve_line_breaksbool $keep (true), string $blockboolPassed to wpautop() for answer and step text.
anansi/preferred_source/domainstring $domainstringDomain sent to Google’s preferred-source page.
anansi/preferred_source/urlstring $url, string $domainstringLink target of the preferred-source block and [anansi_preferred_source] shortcode.

Breadcrumbs are on when the General setting is on, or when the theme declares add_theme_support( 'anansi-breadcrumbs' ) or add_theme_support( 'rank-math-breadcrumbs' ).

anansi/breadcrumb/items (filter)

The breadcrumb trail. Used for the BreadcrumbList schema and the compatibility breadcrumb functions.

ParameterTypeDescription
$crumbsarrayEach crumb: array( 0 => string $label, 1 => string $url, 'hide_in_schema' => bool ).
$breadcrumbsAnansi_BreadcrumbsThe builder.

Returns array. Crumbs with an empty URL or hide_in_schema are left out of the schema.

Rank Math twin: rank_math/frontend/breadcrumb/items.

add_filter( 'anansi/breadcrumb/items', function ( $crumbs ) {
    if ( is_singular( 'docs' ) ) {
        array_splice( $crumbs, 1, 0, array( array( 'Docs', home_url( '/docs/' ), 'hide_in_schema' => false ) ) );
    }
    return $crumbs;
} );

anansi/breadcrumb/main_term (filter)

The term shown for a post when its post type uses a primary taxonomy.

ParameterTypeDescription
$termWP_TermFirst term (the primary term comes first).
$termsWP_Term[]All the post’s terms in that taxonomy.

Returns WP_Term. Anything else drops the term crumbs.

Rank Math twin: rank_math/frontend/breadcrumb/main_term.

anansi/breadcrumb/html (filter)

The HTML printed by the compatibility functions and shortcodes (see functions.md).

ParameterTypeDescription
$htmlstringBreadcrumb HTML in Rank Math’s markup.
$crumbsarrayThe trail.
$argsarraywrap_before, wrap_after, before, after.

Returns string.


Sitemaps

Anansi serves /sitemap_index.xml, /{type}-sitemap.xml, /{type}-sitemap{n}.xml and the stylesheet when it is in charge. Every anansi/sitemap/{x} filter below has a Rank Math twin rank_math/sitemap/{x}.

anansi/sitemap/index/entry (filter)

One entry in the sitemap index.

ParameterTypeDescription
$entryarrayloc (URL) and lastmod (date string, may be '@' + timestamp for authors).
$kindstringpost, term or author.
$objectstring\|WP_UserPost type name, taxonomy name, or the first user of that author sitemap page.

Returns array\|false. A falsy value removes the entry.

// No author sitemap in the index.
add_filter( 'anansi/sitemap/index/entry', function ( $entry, $kind ) {
    return 'author' === $kind ? false : $entry;
}, 10, 2 );

anansi/sitemap/entry (filter)

One URL in a post, term or author sitemap (also used to filter HTML sitemap items).

ParameterTypeDescription
$urlarrayloc (URL), mod (last-modified date), images (array of array( 'src' => URL )).
$kindstringpost, term or user.
$objectWP_Post\|WP_Term\|WP_UserThe object.

Returns array\|false. An empty value removes the URL.

anansi/sitemap/index (filter)

Raw XML added at the end of the sitemap index, before </sitemapindex>. Anansi’s news sitemap uses it.

ParameterTypeDescription
$xmlstring''.

Returns string of <sitemap>…</sitemap> elements.

anansi/sitemap/{type}/content (filter)

Body of a sitemap type that no built-in provider handles, for example /custom-sitemap.xml ({type} = custom). Anansi adds the XML declaration and stylesheet line in front.

ParameterTypeDescription
$xmlstring''.

Returns string, a full <urlset>…</urlset>. '' gives a 404.

See theme-integration.md for a full example.

Exclusions

HookParametersReturnsPurpose
anansi/sitemap/exclude_post_typebool $exclude (false), string $post_typeboolLeave a post type out.
anansi/sitemap/exclude_taxonomybool $exclude (false), string $taxonomyboolLeave a taxonomy out.
anansi/sitemap/posts_to_excludeint[] $idsint[]Post IDs left out (from the “Exclude posts” setting).
anansi/sitemap/include_noindexbool $include (false), string $kind (post or term)boolList noindex content anyway.
anansi/sitemap/exclude_empty_termsbool $hide (true), array $taxonomiesboolHide terms with no posts.
anansi/sitemap/exlude_posts_with_canonical_urlsbool $exclude (false), string\|string[] $post_typeboolLeave out posts with a custom canonical URL. The misspelling is Rank Math’s and is kept on purpose.
anansi/sitemap/author/queryarray $argsarrayget_users() arguments for the author sitemap.
anansi/excluded_post_typesarray $types (name => name)arrayPost types the sitemaps consider at all. Rank Math twin: rank_math/excluded_post_types.
anansi/excluded_taxonomiesarray $taxonomies (name => WP_Taxonomy)arraySame for taxonomies. Rank Math twin: rank_math/excluded_taxonomies.
add_filter( 'anansi/sitemap/exclude_taxonomy', function ( $exclude, $taxonomy ) {
    return 'post_tag' === $taxonomy ? true : $exclude;
}, 10, 2 );

URLs and images

HookParametersReturnsPurpose
anansi/sitemap/xml_post_urlstring $url, WP_Post $poststringURL listed for a post.
anansi/sitemap/post_type_archive_linkstring\|false $url, string $post_typestring\|falseArchive URL listed first in a post type sitemap.
anansi/sitemap/post_objectWP_Post $postWP_Post\|falsePost before its entry is built. false skips it.
anansi/sitemap/urlimagesarray $images, int $post_idarrayAll images for one post.
anansi/sitemap/xml_img_srcstring $src, WP_Post $poststringOne image URL. '' skips it.
anansi/sitemap/xml_imgarray $image (src), WP_Post $postarrayOne image entry.
anansi/sitemap/content_before_parse_html_imagesstring $content, int $post_idstringContent scanned for images.
anansi/sitemap/include_external_imagebool $include (false)boolList images on other hosts.
anansi/links/is_externalnull, array $parts (from wp_parse_url())bool\|nullWhether a post URL is external (external URLs are not listed). null lets Anansi decide. Rank Math twin: rank_math/links/is_external.

Caching and response

HookParametersReturnsPurpose
anansi/sitemap/enable_cachingbool $onboolUse the sitemap cache (only when the “Cache sitemaps” setting is on). rank_math/sitemap/enable_caching runs first, when Rank Math is not active.
anansi/sitemap/cache_thisbool $cache (true), string $type ('1' = index), int $pageboolReturn false for sitemaps whose content changes with time.
anansi/sitemap/http_headersarray $headers, bool $is_xslarrayResponse headers (name => value).
anansi/sitemap/remove_creditbool $remove (false)boolDrop the “generated by Anansi SEO” comment.
anansi/sitemap/maybe_redirectbool $redirect (true)bool302 from {type}-sitemap.xml to {type}-sitemap1.xml when a type needs several pages, and back when it fits on one.

The cache never serves stale copies: any change to posts, terms, users, SEO meta or settings starts a new cache generation. wp anansi sitemap flush clears it by hand.

HTML sitemap

HookParametersReturnsPurpose
anansi/sitemap/html_sitemap_post_typesstring[] $typesstring[]Post types listed.
anansi/sitemap/html_sitemap_taxonomiesarray $taxonomiesarrayTaxonomies listed.
anansi/sitemap/html_sitemap_post_statusesstring[] $statuses (publish), string $post_typestring[]Statuses listed.
anansi/sitemap/html_sitemap/sort_itemsarray $sort (field, order), string $kind (posts or terms), string $typearraySort field and ASC/DESC.
anansi/html_sitemap/get_posts/joinstring $sql (''), string $post_typestringExtra SQL JOIN. Rank Math twin: rank_math/html_sitemap/get_posts/join.
anansi/html_sitemap/get_posts/wherestring $sql (''), string $post_typestringExtra SQL WHERE. Rank Math twin: rank_math/html_sitemap/get_posts/where.

Low-level sitemap hooks

These mirror Rank Math’s sitemap internals one to one.

HookParametersReturnsPurpose
anansi/sitemap/providersobject[] $providers ([])object[]Extra sitemap providers. An object needs handles_type( $type ), get_index_links( $max ) and get_sitemap_links( $type, $max, $page ).
anansi/sitemap/build_typestring $typestringSitemap type being built ('1' = index).
anansi/sitemap/{type}_urlsetstring $xmlstringOpening <urlset> tag.
anansi/sitemap/{type}_sitemap_urlarray $url, generatorstringWhen used, builds each <url> element yourself.
anansi/sitemap/{type}_contentstring $xml ('')stringXML added at the end of page 1 of a sitemap type.
anansi/sitemap/urlstring $xml, array $urlstringOne finished <url> element.
anansi/sitemap/{type}_stylesheet_urlstring $linestringThe <?xml-stylesheet ?> line.
anansi/sitemap/{context}/join, anansi/sitemap/{context}/wherestring $sql (''), string $post_typestringRaw SQL for post queries. {context} is post_count or get_posts. Returned SQL is used as is.
anansi/sitemap/base_urlstring $basestringPath prefix for sitemap URLs.
anansi/sitemap/index/slugstring $slug (sitemap_index)stringFile name of the index.
anansi/sitemap/{type}/slugstring $slugstringFile name part for a type (used for author).
anansi/sitemap/xsl_{type} (action)string $title, string $kml_title—Print a stylesheet other than main. Anansi exits after the action.

News sitemap

anansi/news_sitemap/items (filter)

The posts listed in /news-sitemap.xml, after Anansi’s checks (last 48 hours, eligible post types, not excluded).

ParameterTypeDescription
$itemsWP_Post[]Posts, newest first.

Returns WP_Post[].

add_filter( 'anansi/news_sitemap/items', function ( $items ) {
    return array_filter( $items, function ( $post ) {
        return ! has_tag( 'sponsored', $post );
    } );
} );

Redirects and 404 log

Redirects run on the front end when Anansi is in charge.

HookTypeParametersReturnsPurpose
anansi/redirection/pre_searchfilternull, string $uri, string $full_uriarray\|nullDecide the redirect yourself before stored redirects are checked. Return array( 'url_to' => URL, 'header_code' => 301 ), or null to continue.
anansi/redirection/get_clean_patternfilterstring $cleaned, string $pattern, string $comparisonstringPattern used for matching. Using it turns off the combined regex pre-check, so matching is slower.
anansi/redirection/fallback_exclude_locationsfilterstring[] $paths (login, admin, dashboard)string[]Paths the “404 fallback” setting never redirects.
anansi/redirection/add_query_stringfilterbool $add (true), array $rowboolPass the request’s query string on to the destination.
anansi/redirection/add_redirect_headerfilterbool $add (true)boolX-Redirect-By: Anansi SEO (else WordPress).
anansi/redirection/cache_controlfilterstring $value, int $code, array $rowstringCache-Control header (max-age=3600 for 301/308, no-cache, no-store, max-age=0 otherwise). '' sends none.
anansi/redirection/auto_createdactionint $redirect_id, int $object_id, string $type (post or term)—A redirect was created or extended after a slug change.
anansi/redirects/changedactionint[] $ids—Redirects were added, edited, had their status changed, or were deleted.
anansi/404_monitor/per_minutefilterint $budget (120)intMost 404 hits logged per minute (only with a persistent object cache). 0 or less removes the limit.

The Rank Math twins of pre_search and get_clean_pattern only run when Rank Math is not active.

// Send every old /shop/ URL to the new store.
add_filter( 'anansi/redirection/pre_search', function ( $pre, $uri ) {
    if ( null === $pre && 0 === strpos( $uri, 'shop/' ) ) {
        return array( 'url_to' => 'https://store.example.com/', 'header_code' => 301 );
    }
    return $pre;
}, 10, 2 );

HookParametersReturnsPurpose
anansi/links/post_typesstring[] $typesstring[]Post types that can be suggested (from settings, default post).
anansi/links/editor_enabledbool $on (true), string $post_typeboolShow the suggestions panel for a post type.
anansi/links/excludebool $exclude (false), int $post_id, string $urlboolNever suggest this post. The redirects module uses it to skip URLs that redirect.
anansi/links/scorefloat $score (0–1), int $post_id, array $signals, array $argsfloatFinal score of one suggestion. $signals keys: semantic, words, taxonomy, keyword, title.
anansi/links/min_scorefloat $min (0.15)floatLowest score shown.
anansi/links/weightsarray $weights, bool $semanticarrayBlend weights: semantic, words, taxonomy, keyword, title, pillar, related.
anansi/links/cache_ttlint $seconds (300)intHow long one suggestion result is cached.
anansi/links/voyage_modelsarray $models (id => label)arrayChoices for the Voyage AI model setting.
anansi/links/voyage_daily_capint $cap (from settings)intVoyage AI requests per day. 0 or less means no cap.
anansi/links/voyage_user_rateint $max (30)intDraft embedding requests per user in 10 minutes.
// Never suggest posts in the "Archive" category.
add_filter( 'anansi/links/exclude', function ( $exclude, $post_id ) {
    return $exclude || has_category( 'archive', $post_id );
}, 10, 2 );

Crawlers, llms.txt and IndexNow

robots.txt and AI crawlers

HookParametersReturnsPurpose
anansi/crawlers/ai_botsarray $botsarrayKnown AI crawlers: user-agent token => array( 'group' => 'training'\|'search'\|'user', 'vendor' => string, 'note' => string ).
anansi/crawlers/blocked_botsstring[] $tokensstring[]Tokens robots.txt disallows, after the preset and per-bot choices.
anansi/crawlers/post_indexablebool $indexable, WP_Post $postboolWhether a post counts as indexable for llms.txt and IndexNow.
anansi/crawlers/term_indexablebool $indexable, WP_Term $termboolSame for terms (llms.txt).
anansi/nosnippet/blocksstring[] $blocksstring[]Blocks that get the “Hide from snippets” block style.
add_filter( 'anansi/crawlers/ai_bots', function ( $bots ) {
    $bots['ExampleBot'] = array( 'group' => 'training', 'vendor' => 'Example Inc.', 'note' => '' );
    return $bots;
} );

llms.txt

llms.txt is served at /llms.txt when Anansi is in charge and the setting is on. The Rank Math twins (rank_math/llms_txt/…) run only when Rank Math is not active.

HookTypeParametersReturnsPurpose
anansi/llms_txt/sitemap_urlfilterstring $urlstringSitemap URL listed ('' for none). Has no Rank Math twin.
anansi/llms_txt/posts_query_argsfilterarray $argsarrayWP_Query arguments per post type.
anansi/llms_txt/postsfilterWP_Post[] $posts, array $argsarrayPosts found for one query.
anansi/llms_txt/post_descriptionfilterstring $description, WP_Post $poststringText after a post’s link.
anansi/llms_txt/termsfilterWP_Term[] $terms, string $taxonomyarrayTerms listed for a taxonomy.
anansi/llms_txt/extra_contentfilterstring $textstringText added at the end.
anansi/llms_txt/remove_creditfilterbool $remove (false)boolDrop the credit line.
anansi/llms_txt/before_outputaction——Just before the body is printed.
anansi/llms_txt/after_outputaction——Just after the body is printed.

The llms.txt body is cached. Saving General or Crawlers settings clears it.

IndexNow

HookParametersReturnsPurpose
anansi/indexnow/keystring $keystringIndexNow API key.
anansi/indexnow/key_locationstring $url, string $context (serve, payload or admin)stringKey file URL.
anansi/indexnow/hoststring $hoststringhost value sent to IndexNow.
anansi/indexnow/publish_urlstring\|false $url, WP_Post $poststring\|falseURL queued when a post changes. false cancels. Rank Math twin: rank_math/instant_indexing/publish_url.
anansi/indexnow/submit_urlsstring[] $urls, bool $manualstring[]URLs about to be sent. [] cancels. Rank Math twin: rank_math/instant_indexing/submit_url.

Editor

HookParametersReturnsPurpose
anansi/editor/enabledbool $on (true)boolShow Anansi’s editor: sidebar, meta box, term and user fields, list columns.
anansi/editor/post_typesstring[] $types (public types except attachments)string[]Post types that get the editor and registered _anansi_* meta.
anansi/editor/taxonomiesstring[] $taxonomiesstring[]Taxonomies that get SEO fields.
anansi/admin_bar/noindex_badgebool $show (true)boolShow the noindex badge in the admin bar.
anansi/editor/dataarray $data, WP_Post $postarrayData the block editor sidebar and classic meta box get (window.anansiEditor). The schema builder adds schemaRows (with status) and schemaBuild (where to load the modal).
anansi/editor/metabox_schema (action)WP_Post $post—Prints the schema rows part of the classic meta box’s Schema tab. When nothing is hooked, the read-only list is shown.

Schema builder

HookParametersReturnsPurpose
anansi/schema_builder/typesarray $specs (slug => spec from includes/modules/schema-builder/types/*.json)arrayAdd, change or remove schema editor types. A spec has type, label, description, rich, groups[].fields[] (key, label, kind, level, default, options, when, unless, requiredWith), objects (path => nested @type) and anyOf. The same specs drive the form, the checks and the server-side cleaning.
anansi/schema_builder/saved (action)int $post_id—After a post’s schema rows were saved in the schema editor (REST or classic meta box).
// Add a "Course" form to the schema editor.
add_filter( 'anansi/schema_builder/types', function ( $specs ) {
    $specs['course'] = array(
        'type'        => 'Course',
        'label'       => 'Course',
        'description' => 'A course you teach.',
        'rich'        => false,
        'groups'      => array(
            array(
                'label'  => 'Basics',
                'fields' => array(
                    array( 'key' => 'name', 'label' => 'Name', 'kind' => 'text', 'level' => 'required', 'default' => '%title%' ),
                    array( 'key' => 'provider.name', 'label' => 'Provider', 'kind' => 'text', 'default' => '%org_name%' ),
                ),
            ),
        ),
        'objects'     => array( 'provider' => 'Organization' ),
    );
    return $specs;
} );
// Hide Anansi's editor for a post type that is never public in search.
add_filter( 'anansi/editor/post_types', function ( $types ) {
    return array_values( array_diff( $types, array( 'landing' ) ) );
} );

Tweaks

Unless noted, each has a rank_math/ twin with the same name after the prefix.

HookParametersReturnsPurpose
anansi/lock_modified_datebool $allow (true)boolfalse turns the “lock modified date” feature off.
anansi/tweaks/lock_for_savebool $locked, int $post_id, array $postarrboolFinal lock decision for one save. No Rank Math twin.
anansi/frontend/attachment/redirect_urlstring $url, WP_Post $attachmentstringWhere an attachment page redirects.
anansi/frontend/rss/include_footerbool $include (true), string $context (full or excerpt)boolAdd the RSS before/after text.
anansi/frontend/rss/before_contentstring $textstringText before each feed item.
anansi/frontend/rss/after_contentstring $textstringText after each feed item.
anansi/frontend/rss/nofollow_linksbool $nofollow (true)boolrel="nofollow" on links in that text.
anansi/frontend/add_ugc_attributebool $add (true)boolrel="ugc" on comment links.
anansi/frontend/remove_reply_to_combool $remove (true)boolRemove ?replytocom from reply links.
anansi/tweaks/category_base_handled_elsewherebool $otherboolTell Anansi another plugin or the theme already strips /category/. No Rank Math twin.

Last updated line

The optional “Last updated” line (Titles & Meta → Last updated line). It prints only while Anansi is in charge, on the singular page’s own post in the main loop. Feeds, REST, admin, excerpts and password-protected posts never get it. The date is the post’s modified date (never earlier than the publish date), the same date as the Article schema’s dateModified, so “Lock modified date” also keeps the line’s date. No Rank Math twins.

HookParametersReturnsPurpose
anansi/last_updated/showbool $show, WP_Post $postboolShow the line on this post. $show already reflects the settings (switch, content types, “only changed posts”) and the password check.
anansi/last_updated/htmlstring $html, WP_Post $post, string $date (local MySQL datetime)stringThe line’s markup. Default: <p class="anansi-last-updated"><em>Last updated: <time datetime="…">14 October 2026</time></em></p>.
// Hide the line on one category.
add_filter( 'anansi/last_updated/show', function ( $show, $post ) {
    return $show && ! has_category( 'news', $post );
}, 10, 2 );

Admin screens and dashboard

anansi/admin/sections (filter)

Adds or changes sections on an Anansi settings page.

ParameterTypeDescription
$sectionsarraySection id => array( 'title' => string, 'desc' => string, 'links' => array( array( label, url ) ), 'fields' => array[] ).
$pagestringtitles, social, general or sitemaps.

Returns array.

A field is an array with key (required), type and label, plus optional help, default, options (for select, radio, chips), option (store in another option; it is registered and saved with the page), placeholder, min, max, rows and show_if. Types include text, textarea, number, url, email, switch (alias toggle), select, radio, chips, code, lines, media and heading. Values are sanitised by type. When two sections define the same option key, the first one wins.

add_filter( 'anansi/admin/sections', function ( $sections, $page ) {
    if ( 'general' !== $page ) {
        return $sections;
    }
    $sections['acme'] = array(
        'title'  => 'Acme add-on',
        'desc'   => 'Settings for the Acme integration.',
        'fields' => array(
            array(
                'key'     => 'acme_enabled',
                'option'  => 'acme_seo',
                'type'    => 'switch',
                'default' => 'off',
                'label'   => 'Add Acme data to the schema',
            ),
        ),
    );
    return $sections;
}, 10, 2 );

anansi/admin/sanitized (filter)

Values about to be saved from an Anansi settings page, per option.

ParameterTypeDescription
$storedarraySanitised values.
$optionstringOption name.

Returns array.

anansi/dashboard/cards (action)

Fires on the Anansi dashboard (needs manage_options) inside the main column, above the page preview card. Print your own card markup. The Google module uses it.

add_action( 'anansi/dashboard/cards', function () {
    echo '<section class="an-card"><h2>Acme</h2><p>All good.</p></section>';
} );

Settings export, import and snapshots

HookParametersReturnsPurpose
anansi/settings_io/importablestring[] $optionsstring[]Options a settings file may write. Default: anansi_titles, anansi_general, anansi_sitemap, anansi_settings, anansi_crawlers, anansi_links. Each must hold an array.
anansi/settings_io/excludedbool $excluded (false), string $optionboolLeave an option out of export and import.
anansi/import/snapshot/fetchnull, string $urlarray\|nullAnswer a snapshot fetch yourself (tests, or a site behind auth). Return array( 'status' => int, 'location' => string, 'body' => string ).

Activation

anansi/activate (action)

Fires when Anansi is activated, after its settings are seeded and before rewrite rules are flushed. Modules create tables and add rewrite rules here. No parameters.

add_action( 'anansi/activate', function () {
    // Anansi was just activated: set up the add-on's defaults.
    add_option( 'acme_seo', array( 'acme_enabled' => 'off' ) );
} );

It runs in the request that activates Anansi, so only code that is already loaded then (another active plugin, or the active theme) can hook it.


Abilities

anansi/abilities/post_updated (action)

Fires after the anansi/update-post-seo ability changed at least one field.

ParameterTypeDescription
$post_idintPost ID.
$changedstring[]Field keys that changed: title, description, focus_keyword, robots.
add_action( 'anansi/abilities/post_updated', function ( $post_id, $changed ) {
    error_log( sprintf( 'AI tool changed %s on post %d', implode( ', ', $changed ), $post_id ) );
}, 10, 2 );

See rest-and-abilities.md.


Google module

The Google module (Search Console and the YouTube Data API) has no public filters or actions. It adds its dashboard card through anansi/dashboard/cards and two REST routes, documented in rest-and-abilities.md.


Rank Math compatibility hooks

Code written for Rank Math often hooks rank_math/… filters. So that this code keeps working after the switch, Anansi fires the matching Rank Math hook right after its own, with the same arguments. Your anansi/… callback runs first, then the rank_math/… callbacks see the result.

When the Rank Math name is fired depends on the hook:

  • Rank Math not active, or a signed preview request. This covers most output hooks, so a preview shows what your Rank Math code will do after the switch.
  • Rank Math not active only. These hooks change things outside the page head (files, requests, redirects), so they never run twice while Rank Math still runs.
  • Merged into Anansi’s graph. Callbacks on rank_math/json_ld run inside Anansi’s schema graph.

If a Rank Math hook is not listed here, Anansi does not fire it.

Fired when Rank Math is not active, or on a preview request

Rank Math hookAnansi hook
rank_math/frontend/titleanansi/title_raw
rank_math/frontend/descriptionanansi/description
rank_math/frontend/robotsanansi/robots
rank_math/frontend/advanced_robotsanansi/advanced_robots
rank_math/frontend/canonicalanansi/canonical
rank_math/frontend/prev_rel_link, rank_math/frontend/next_rel_linkanansi/prev_rel_link, anansi/next_rel_link
rank_math/frontend/breadcrumb/itemsanansi/breadcrumb/items
rank_math/frontend/breadcrumb/main_termanansi/breadcrumb/main_term
rank_math/opengraph/{network}/{property} and every other rank_math/opengraph/… filter in the Open Graph sectionanansi/opengraph/…
rank_math/frontend/time_to_read_content, rank_math/frontend/time_to_read_wpmanansi/frontend/time_to_read_…
rank_math/schema/language, rank_math/schema/validated_data, rank_math/schema/add_global_entitiesanansi/schema/…
rank_math/json_ld/breadcrumbs_enabled, rank_math/json_ld/disable_search, rank_math/json_ld/search_urlanansi/json_ld/…
rank_math/snippet/remove_taxonomy_data, rank_math/snippet/breadcrumb, rank_math/snippet/rich_snippet_{type}, …_custom_entity, …_entity, rank_math/snippet/rich_snippet_entityanansi/snippet/…
rank_math/snippet/rich_snippet_article_entityanansi/schema/article_entity
rank_math/schema/default_typeanansi/schema/default_type
rank_math/webmaster/{id}anansi/webmaster/{id}
rank_math/sitemap/{x} for every anansi/sitemap/{x} filter and the xsl_{type} actionanansi/sitemap/{x}
rank_math/sitemap/enable_caching (fired before Anansi’s)anansi/sitemap/enable_caching
rank_math/excluded_post_types, rank_math/excluded_taxonomiesanansi/excluded_post_types, anansi/excluded_taxonomies
rank_math/html_sitemap/get_posts/join, rank_math/html_sitemap/get_posts/whereanansi/html_sitemap/get_posts/…
rank_math/links/is_externalanansi/links/is_external
rank_math/lock_modified_dateanansi/lock_modified_date
rank_math/frontend/attachment/redirect_url, rank_math/frontend/rss/…, rank_math/frontend/add_ugc_attribute, rank_math/frontend/remove_reply_to_comanansi/frontend/…

Fired only when Rank Math is not active

Rank Math hookAnansi hook
rank_math/redirection/pre_search (only if the Anansi filter returned null)anansi/redirection/pre_search
rank_math/redirection/get_clean_patternanansi/redirection/get_clean_pattern
rank_math/instant_indexing/publish_urlanansi/indexnow/publish_url
rank_math/instant_indexing/submit_urlanansi/indexnow/submit_urls
rank_math/llms_txt/{name} (filters and the two actions)anansi/llms_txt/{name}

Content blocks

Anansi registers its own renderer for Rank Math’s FAQ and HowTo blocks only while Rank Math is not active. Inside it, these always fire:

Rank Math hookAnansi hook
rank_math/blocks/{block}/title_wrapperanansi/blocks/{block}/title_wrapper
rank_math/block/preserve_line_breaksanansi/block/preserve_line_breaks
rank_math/schema/block/faq/content, rank_math/schema/block/howto/contentanansi/schema/block/…/content

rank_math/schema/block/before_filter, rank_math/schema/nested_blocks and rank_math/schema/block/{name} run inside Anansi’s graph without Rank Math’s own callbacks, so a preview never adds the same FAQ twice.

Schema graph: rank_math/json_ld

Anansi does not fire rank_math/json_ld as a separate filter. When it builds its graph, it takes every callback on rank_math/json_ld and every callback on anansi/json_ld, at their own priorities, and runs them in one chain. Callbacks that belong to Rank Math’s own classes are skipped, because Anansi does that work itself. The second argument is Anansi’s schema object, which has the can_add_global_entities() method and the public $post, $post_id and $parts properties that Rank Math callbacks commonly read.

Action: rank_math/head

After its head block, Anansi fires do_action( 'rank_math/head' ) when the request is not a preview and Rank Math is not active. Nothing is printed. Themes that check did_action( 'rank_math/head' ) to see whether an SEO plugin printed the tags will then step aside.

The external-links tweak reads wp_helpers_is_affiliate_link (bool $is_affiliate, string $url), the shared filter Rank Math and affiliate plugins use, to spot affiliate links.