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
- Title variables
- Open Graph and Twitter
- Schema (JSON-LD graph)
- Video schema
- Content blocks
- Breadcrumbs
- Sitemaps
- News sitemap
- Redirects and 404 log
- Internal link suggestions
- Crawlers, llms.txt and IndexNow
- Editor
- Tweaks
- Last updated line
- Admin screens and dashboard
- Settings export, import and snapshots
- Activation
- Abilities
- Google module
- Rank Math compatibility hooks
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.
| Parameter | Type | Description |
|---|---|---|
$tags | array[] | 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.
| Parameter | Type | Description |
|---|---|---|
$preview | bool | true 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.
| Parameter | Type | Description |
|---|---|---|
$title | string | Plain-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.
| Parameter | Type | Description |
|---|---|---|
$add | bool | Default true. |
$title | string | Title so far. |
$page | int | Current 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.
| Parameter | Type | Description |
|---|---|---|
$title | string | Title, '' 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%.
| Parameter | Type | Description |
|---|---|---|
$sep | string | From the Titles setting title_separator (default -). |
Returns string.
anansi/description (filter)
The meta description before escaping.
| Parameter | Type | Description |
|---|---|---|
$description | string | Plain 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.
| Parameter | Type | Description |
|---|---|---|
$robots | array | Keyed 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.
| Parameter | Type | Description |
|---|---|---|
$robots | array | Keyed 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.
| Parameter | Type | Description |
|---|---|---|
$url | string | Canonical URL. |
Returns string. Return '' for no canonical tag.
Rank Math twin: rank_math/frontend/canonical.
anansi/prev_rel_link and anansi/next_rel_link (filters)
The full <link rel="prev"> / <link rel="next"> tag HTML on paginated pages.
| Parameter | Type | Description |
|---|---|---|
$html | string | Tag 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.
anansi/disable_adjacent_rel_links (filter)
| Parameter | Type | Description |
|---|---|---|
$disable | bool | Default 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.
| Parameter | Type | Description |
|---|---|---|
$keys | string[] | Default array( '_anansi_{key}', 'rank_math_{key}' ). |
$type | string | post, term or user. |
$key | string | Short 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.
| Parameter | Type | Description |
|---|---|---|
$disable | bool | Default 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.
| Parameter | Type | Description |
|---|---|---|
$content | string | The 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.
| Parameter | Type | Description |
|---|---|---|
$replacements | array | Token => value, for example '%title%' => 'Hello world'. |
$object | WP_Post\|WP_Term\|WP_User\|null | What 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.
| Parameter | Type | Description |
|---|---|---|
$value | string\|null | null. |
$args | string\|null | Text inside parentheses for %name(args)%, else null. |
$object | mixed | Post, 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 _.
| Network | Properties |
|---|---|
facebook | og_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 |
twitter | twitter_card, twitter_title, twitter_description, twitter_site, twitter_creator, twitter_image |
slack | twitter_label1, twitter_data1, twitter_label2, twitter_data2, … |
| Parameter | Type | Description |
|---|---|---|
$content | string\|int | Tag 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
| Hook | Parameters | Returns | Purpose |
|---|---|---|---|
anansi/opengraph/twitter_card | bool $on (default true) | bool | false drops all Twitter tags. |
anansi/opengraph/type | string $type (website, article, profile) | string | The og:type value. |
anansi/opengraph/url | string $url | string | The og:url value (the canonical URL). |
anansi/opengraph/twitter/card_type | string $card | string | Twitter card type. Allowed: summary, summary_large_image, app, player; anything else becomes summary. |
anansi/opengraph/pre_set_featured_image | bool $skip (false), int $post_id | bool | Return anything other than false to skip the featured image. |
anansi/opengraph/pre_set_content_image | bool $skip (false), int $post_id | bool | Same, for the first image in the content. |
anansi/opengraph/pre_set_default_image | bool $skip (false) | bool | Same, for the site’s default image. |
anansi/opengraph/attachment_id | int $id | int | Attachment used for an image. |
anansi/opengraph/image_sizes | string[] $sizes (full, large, medium_large) | string[] | Sizes tried, in order. The first between 200 and 2000 px wins. |
anansi/opengraph/{network}/image | string $url ('' when Anansi found no image) | string | Image URL. A different URL replaces the image and skips the file-type check. Runs for facebook and twitter. |
anansi/opengraph/{network}/image_array | array $image (url, id, width, height, type, alt) | array | Full image data. Return an array without url to drop it. |
anansi/opengraph/slack_enhanced_data | array $data (label => value) | array | Label/data pairs printed as twitter:label{n} / twitter:data{n}. |
anansi/frontend/time_to_read_content | string $content | string | Text used for the reading time. |
anansi/frontend/time_to_read_wpm | int $wpm (200) | int | Words 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.
| Parameter | Type | Description |
|---|---|---|
$data | array | Graph nodes, keyed. |
$jsonld | Anansi_Schema | The 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:
| Priority | Step | Keys it adds |
|---|---|---|
| 8 | Rank Math FAQ and HowTo blocks | FAQPage and HowTo nodes |
| 9 | Publisher | publisher (Organization or Person) |
| 10 | Page context | WebSite, primaryImage, BreadcrumbList, WebPage, ProfilePage, richSnippet (default Article) |
| 10 | Stored schemas | schema-{meta_id} |
| 30 | Video schema | VideoObject nodes |
| 99 | Linking | Adds @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.
| Parameter | Type | Description |
|---|---|---|
$data | array | Graph nodes. |
Returns array.
Other schema filters
All have a rank_math/ twin with the same name after the prefix.
| Hook | Parameters | Returns | Purpose |
|---|---|---|---|
anansi/schema/language | string $lang | string | inLanguage value. |
anansi/schema/add_global_entities | bool $add, Anansi_Schema $jsonld | bool | Whether Organization, WebSite and WebPage nodes are added. |
anansi/snippet/remove_taxonomy_data | bool $remove, string $taxonomy | bool | On term archives: drop the global nodes. |
anansi/json_ld/breadcrumbs_enabled | bool $on | bool | Add the BreadcrumbList node. |
anansi/json_ld/disable_search | bool $disable (true except on the front page) | bool | Leave out the WebSite SearchAction. |
anansi/json_ld/search_url | string $url (/?s={search_term_string}) | string | SearchAction target. |
anansi/snippet/breadcrumb | array $node | array | The BreadcrumbList node. |
anansi/schema/article_entity | array $entity | array | Every Article node (default or stored). Rank Math twin: rank_math/snippet/rich_snippet_article_entity. |
anansi/snippet/rich_snippet_{type} | false, array $parts, array $data | mixed | Return 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_entity | array $node (empty) | array | Your replacement node when the previous filter did not return false. |
anansi/snippet/rich_snippet_{type}_entity | array $schema | array | One stored node of that type (not Article: Article uses anansi/schema/article_entity). |
anansi/snippet/rich_snippet_entity | array $node | array | Every stored node, last step. |
anansi/schema/default_type | string $type, string $post_type, int $post_id | string | Default 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
| Hook | Parameters | Returns | Purpose |
|---|---|---|---|
anansi/video/sources | string[] $urls, string $content | string[] | Video URLs found in a post (YouTube and Vimeo are parsed). Runs when a post is scanned. |
anansi/video/youtube_api_key | string $key | string | YouTube Data API key (from settings). Return '' to use oEmbed only. |
anansi/video/node | array $node, array $video, WP_Post $post | array | One VideoObject node. Return an empty value to drop it. |
anansi/video/creator_type | string $type (Person), array $video | string | Person 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.
| Hook | Parameters | Returns | Purpose |
|---|---|---|---|
anansi/schema/block/before_filter | array $blocks (from parse_blocks()) | array | Blocks before Anansi looks for Rank Math blocks. |
anansi/schema/nested_blocks | string[] $names (core/group, core/columns, core/column) | string[] | Container blocks searched for nested Rank Math blocks. |
anansi/schema/block/{name} | array $data, array $block | array | Graph after one Rank Math block was handled. {name} is the block name without rank-math/, for example faq-block. |
anansi/schema/block/faq/content | string $html, string[] $parts, array $attributes | string | Front-end HTML of the FAQ block (when Rank Math is inactive). |
anansi/schema/block/howto/content | string $html, string[] $parts, array $attributes | string | Same for HowTo. |
anansi/blocks/{block}/title_wrapper | string $tag | string | Heading tag for questions or steps. {block} is faq or howto. Allowed: h2–h6, p, div. |
anansi/block/preserve_line_breaks | bool $keep (true), string $block | bool | Passed to wpautop() for answer and step text. |
anansi/preferred_source/domain | string $domain | string | Domain sent to Google’s preferred-source page. |
anansi/preferred_source/url | string $url, string $domain | string | Link target of the preferred-source block and [anansi_preferred_source] shortcode. |
Breadcrumbs
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.
| Parameter | Type | Description |
|---|---|---|
$crumbs | array | Each crumb: array( 0 => string $label, 1 => string $url, 'hide_in_schema' => bool ). |
$breadcrumbs | Anansi_Breadcrumbs | The 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.
| Parameter | Type | Description |
|---|---|---|
$term | WP_Term | First term (the primary term comes first). |
$terms | WP_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).
| Parameter | Type | Description |
|---|---|---|
$html | string | Breadcrumb HTML in Rank Math’s markup. |
$crumbs | array | The trail. |
$args | array | wrap_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.
| Parameter | Type | Description |
|---|---|---|
$entry | array | loc (URL) and lastmod (date string, may be '@' + timestamp for authors). |
$kind | string | post, term or author. |
$object | string\|WP_User | Post 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).
| Parameter | Type | Description |
|---|---|---|
$url | array | loc (URL), mod (last-modified date), images (array of array( 'src' => URL )). |
$kind | string | post, term or user. |
$object | WP_Post\|WP_Term\|WP_User | The 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.
| Parameter | Type | Description |
|---|---|---|
$xml | string | ''. |
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.
| Parameter | Type | Description |
|---|---|---|
$xml | string | ''. |
Returns string, a full <urlset>…</urlset>. '' gives a 404.
See theme-integration.md for a full example.
Exclusions
| Hook | Parameters | Returns | Purpose |
|---|---|---|---|
anansi/sitemap/exclude_post_type | bool $exclude (false), string $post_type | bool | Leave a post type out. |
anansi/sitemap/exclude_taxonomy | bool $exclude (false), string $taxonomy | bool | Leave a taxonomy out. |
anansi/sitemap/posts_to_exclude | int[] $ids | int[] | Post IDs left out (from the “Exclude posts” setting). |
anansi/sitemap/include_noindex | bool $include (false), string $kind (post or term) | bool | List noindex content anyway. |
anansi/sitemap/exclude_empty_terms | bool $hide (true), array $taxonomies | bool | Hide terms with no posts. |
anansi/sitemap/exlude_posts_with_canonical_urls | bool $exclude (false), string\|string[] $post_type | bool | Leave out posts with a custom canonical URL. The misspelling is Rank Math’s and is kept on purpose. |
anansi/sitemap/author/query | array $args | array | get_users() arguments for the author sitemap. |
anansi/excluded_post_types | array $types (name => name) | array | Post types the sitemaps consider at all. Rank Math twin: rank_math/excluded_post_types. |
anansi/excluded_taxonomies | array $taxonomies (name => WP_Taxonomy) | array | Same 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
| Hook | Parameters | Returns | Purpose |
|---|---|---|---|
anansi/sitemap/xml_post_url | string $url, WP_Post $post | string | URL listed for a post. |
anansi/sitemap/post_type_archive_link | string\|false $url, string $post_type | string\|false | Archive URL listed first in a post type sitemap. |
anansi/sitemap/post_object | WP_Post $post | WP_Post\|false | Post before its entry is built. false skips it. |
anansi/sitemap/urlimages | array $images, int $post_id | array | All images for one post. |
anansi/sitemap/xml_img_src | string $src, WP_Post $post | string | One image URL. '' skips it. |
anansi/sitemap/xml_img | array $image (src), WP_Post $post | array | One image entry. |
anansi/sitemap/content_before_parse_html_images | string $content, int $post_id | string | Content scanned for images. |
anansi/sitemap/include_external_image | bool $include (false) | bool | List images on other hosts. |
anansi/links/is_external | null, array $parts (from wp_parse_url()) | bool\|null | Whether 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
| Hook | Parameters | Returns | Purpose |
|---|---|---|---|
anansi/sitemap/enable_caching | bool $on | bool | Use 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_this | bool $cache (true), string $type ('1' = index), int $page | bool | Return false for sitemaps whose content changes with time. |
anansi/sitemap/http_headers | array $headers, bool $is_xsl | array | Response headers (name => value). |
anansi/sitemap/remove_credit | bool $remove (false) | bool | Drop the “generated by Anansi SEO” comment. |
anansi/sitemap/maybe_redirect | bool $redirect (true) | bool | 302 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
| Hook | Parameters | Returns | Purpose |
|---|---|---|---|
anansi/sitemap/html_sitemap_post_types | string[] $types | string[] | Post types listed. |
anansi/sitemap/html_sitemap_taxonomies | array $taxonomies | array | Taxonomies listed. |
anansi/sitemap/html_sitemap_post_statuses | string[] $statuses (publish), string $post_type | string[] | Statuses listed. |
anansi/sitemap/html_sitemap/sort_items | array $sort (field, order), string $kind (posts or terms), string $type | array | Sort field and ASC/DESC. |
anansi/html_sitemap/get_posts/join | string $sql (''), string $post_type | string | Extra SQL JOIN. Rank Math twin: rank_math/html_sitemap/get_posts/join. |
anansi/html_sitemap/get_posts/where | string $sql (''), string $post_type | string | Extra 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.
| Hook | Parameters | Returns | Purpose |
|---|---|---|---|
anansi/sitemap/providers | object[] $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_type | string $type | string | Sitemap type being built ('1' = index). |
anansi/sitemap/{type}_urlset | string $xml | string | Opening <urlset> tag. |
anansi/sitemap/{type}_sitemap_url | array $url, generator | string | When used, builds each <url> element yourself. |
anansi/sitemap/{type}_content | string $xml ('') | string | XML added at the end of page 1 of a sitemap type. |
anansi/sitemap/url | string $xml, array $url | string | One finished <url> element. |
anansi/sitemap/{type}_stylesheet_url | string $line | string | The <?xml-stylesheet ?> line. |
anansi/sitemap/{context}/join, anansi/sitemap/{context}/where | string $sql (''), string $post_type | string | Raw SQL for post queries. {context} is post_count or get_posts. Returned SQL is used as is. |
anansi/sitemap/base_url | string $base | string | Path prefix for sitemap URLs. |
anansi/sitemap/index/slug | string $slug (sitemap_index) | string | File name of the index. |
anansi/sitemap/{type}/slug | string $slug | string | File 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).
| Parameter | Type | Description |
|---|---|---|
$items | WP_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.
| Hook | Type | Parameters | Returns | Purpose |
|---|---|---|---|---|
anansi/redirection/pre_search | filter | null, string $uri, string $full_uri | array\|null | Decide the redirect yourself before stored redirects are checked. Return array( 'url_to' => URL, 'header_code' => 301 ), or null to continue. |
anansi/redirection/get_clean_pattern | filter | string $cleaned, string $pattern, string $comparison | string | Pattern used for matching. Using it turns off the combined regex pre-check, so matching is slower. |
anansi/redirection/fallback_exclude_locations | filter | string[] $paths (login, admin, dashboard) | string[] | Paths the “404 fallback” setting never redirects. |
anansi/redirection/add_query_string | filter | bool $add (true), array $row | bool | Pass the request’s query string on to the destination. |
anansi/redirection/add_redirect_header | filter | bool $add (true) | bool | X-Redirect-By: Anansi SEO (else WordPress). |
anansi/redirection/cache_control | filter | string $value, int $code, array $row | string | Cache-Control header (max-age=3600 for 301/308, no-cache, no-store, max-age=0 otherwise). '' sends none. |
anansi/redirection/auto_created | action | int $redirect_id, int $object_id, string $type (post or term) | — | A redirect was created or extended after a slug change. |
anansi/redirects/changed | action | int[] $ids | — | Redirects were added, edited, had their status changed, or were deleted. |
anansi/404_monitor/per_minute | filter | int $budget (120) | int | Most 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 );
Internal link suggestions
| Hook | Parameters | Returns | Purpose |
|---|---|---|---|
anansi/links/post_types | string[] $types | string[] | Post types that can be suggested (from settings, default post). |
anansi/links/editor_enabled | bool $on (true), string $post_type | bool | Show the suggestions panel for a post type. |
anansi/links/exclude | bool $exclude (false), int $post_id, string $url | bool | Never suggest this post. The redirects module uses it to skip URLs that redirect. |
anansi/links/score | float $score (0–1), int $post_id, array $signals, array $args | float | Final score of one suggestion. $signals keys: semantic, words, taxonomy, keyword, title. |
anansi/links/min_score | float $min (0.15) | float | Lowest score shown. |
anansi/links/weights | array $weights, bool $semantic | array | Blend weights: semantic, words, taxonomy, keyword, title, pillar, related. |
anansi/links/cache_ttl | int $seconds (300) | int | How long one suggestion result is cached. |
anansi/links/voyage_models | array $models (id => label) | array | Choices for the Voyage AI model setting. |
anansi/links/voyage_daily_cap | int $cap (from settings) | int | Voyage AI requests per day. 0 or less means no cap. |
anansi/links/voyage_user_rate | int $max (30) | int | Draft 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
| Hook | Parameters | Returns | Purpose |
|---|---|---|---|
anansi/crawlers/ai_bots | array $bots | array | Known AI crawlers: user-agent token => array( 'group' => 'training'\|'search'\|'user', 'vendor' => string, 'note' => string ). |
anansi/crawlers/blocked_bots | string[] $tokens | string[] | Tokens robots.txt disallows, after the preset and per-bot choices. |
anansi/crawlers/post_indexable | bool $indexable, WP_Post $post | bool | Whether a post counts as indexable for llms.txt and IndexNow. |
anansi/crawlers/term_indexable | bool $indexable, WP_Term $term | bool | Same for terms (llms.txt). |
anansi/nosnippet/blocks | string[] $blocks | string[] | 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.
| Hook | Type | Parameters | Returns | Purpose |
|---|---|---|---|---|
anansi/llms_txt/sitemap_url | filter | string $url | string | Sitemap URL listed ('' for none). Has no Rank Math twin. |
anansi/llms_txt/posts_query_args | filter | array $args | array | WP_Query arguments per post type. |
anansi/llms_txt/posts | filter | WP_Post[] $posts, array $args | array | Posts found for one query. |
anansi/llms_txt/post_description | filter | string $description, WP_Post $post | string | Text after a post’s link. |
anansi/llms_txt/terms | filter | WP_Term[] $terms, string $taxonomy | array | Terms listed for a taxonomy. |
anansi/llms_txt/extra_content | filter | string $text | string | Text added at the end. |
anansi/llms_txt/remove_credit | filter | bool $remove (false) | bool | Drop the credit line. |
anansi/llms_txt/before_output | action | — | — | Just before the body is printed. |
anansi/llms_txt/after_output | action | — | — | Just after the body is printed. |
The llms.txt body is cached. Saving General or Crawlers settings clears it.
IndexNow
| Hook | Parameters | Returns | Purpose |
|---|---|---|---|
anansi/indexnow/key | string $key | string | IndexNow API key. |
anansi/indexnow/key_location | string $url, string $context (serve, payload or admin) | string | Key file URL. |
anansi/indexnow/host | string $host | string | host value sent to IndexNow. |
anansi/indexnow/publish_url | string\|false $url, WP_Post $post | string\|false | URL queued when a post changes. false cancels. Rank Math twin: rank_math/instant_indexing/publish_url. |
anansi/indexnow/submit_urls | string[] $urls, bool $manual | string[] | URLs about to be sent. [] cancels. Rank Math twin: rank_math/instant_indexing/submit_url. |
Editor
| Hook | Parameters | Returns | Purpose |
|---|---|---|---|
anansi/editor/enabled | bool $on (true) | bool | Show Anansi’s editor: sidebar, meta box, term and user fields, list columns. |
anansi/editor/post_types | string[] $types (public types except attachments) | string[] | Post types that get the editor and registered _anansi_* meta. |
anansi/editor/taxonomies | string[] $taxonomies | string[] | Taxonomies that get SEO fields. |
anansi/admin_bar/noindex_badge | bool $show (true) | bool | Show the noindex badge in the admin bar. |
anansi/editor/data | array $data, WP_Post $post | array | Data 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
| Hook | Parameters | Returns | Purpose |
|---|---|---|---|
anansi/schema_builder/types | array $specs (slug => spec from includes/modules/schema-builder/types/*.json) | array | Add, 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.
| Hook | Parameters | Returns | Purpose |
|---|---|---|---|
anansi/lock_modified_date | bool $allow (true) | bool | false turns the “lock modified date” feature off. |
anansi/tweaks/lock_for_save | bool $locked, int $post_id, array $postarr | bool | Final lock decision for one save. No Rank Math twin. |
anansi/frontend/attachment/redirect_url | string $url, WP_Post $attachment | string | Where an attachment page redirects. |
anansi/frontend/rss/include_footer | bool $include (true), string $context (full or excerpt) | bool | Add the RSS before/after text. |
anansi/frontend/rss/before_content | string $text | string | Text before each feed item. |
anansi/frontend/rss/after_content | string $text | string | Text after each feed item. |
anansi/frontend/rss/nofollow_links | bool $nofollow (true) | bool | rel="nofollow" on links in that text. |
anansi/frontend/add_ugc_attribute | bool $add (true) | bool | rel="ugc" on comment links. |
anansi/frontend/remove_reply_to_com | bool $remove (true) | bool | Remove ?replytocom from reply links. |
anansi/tweaks/category_base_handled_elsewhere | bool $other | bool | Tell 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.
| Hook | Parameters | Returns | Purpose |
|---|---|---|---|
anansi/last_updated/show | bool $show, WP_Post $post | bool | Show the line on this post. $show already reflects the settings (switch, content types, “only changed posts”) and the password check. |
anansi/last_updated/html | string $html, WP_Post $post, string $date (local MySQL datetime) | string | The 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.
| Parameter | Type | Description |
|---|---|---|
$sections | array | Section id => array( 'title' => string, 'desc' => string, 'links' => array( array( label, url ) ), 'fields' => array[] ). |
$page | string | titles, 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.
| Parameter | Type | Description |
|---|---|---|
$stored | array | Sanitised values. |
$option | string | Option 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
| Hook | Parameters | Returns | Purpose |
|---|---|---|---|
anansi/settings_io/importable | string[] $options | string[] | 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/excluded | bool $excluded (false), string $option | bool | Leave an option out of export and import. |
anansi/import/snapshot/fetch | null, string $url | array\|null | Answer 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.
| Parameter | Type | Description |
|---|---|---|
$post_id | int | Post ID. |
$changed | string[] | 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 );
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_ldrun 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 hook | Anansi hook |
|---|---|
rank_math/frontend/title | anansi/title_raw |
rank_math/frontend/description | anansi/description |
rank_math/frontend/robots | anansi/robots |
rank_math/frontend/advanced_robots | anansi/advanced_robots |
rank_math/frontend/canonical | anansi/canonical |
rank_math/frontend/prev_rel_link, rank_math/frontend/next_rel_link | anansi/prev_rel_link, anansi/next_rel_link |
rank_math/frontend/breadcrumb/items | anansi/breadcrumb/items |
rank_math/frontend/breadcrumb/main_term | anansi/breadcrumb/main_term |
rank_math/opengraph/{network}/{property} and every other rank_math/opengraph/… filter in the Open Graph section | anansi/opengraph/… |
rank_math/frontend/time_to_read_content, rank_math/frontend/time_to_read_wpm | anansi/frontend/time_to_read_… |
rank_math/schema/language, rank_math/schema/validated_data, rank_math/schema/add_global_entities | anansi/schema/… |
rank_math/json_ld/breadcrumbs_enabled, rank_math/json_ld/disable_search, rank_math/json_ld/search_url | anansi/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_entity | anansi/snippet/… |
rank_math/snippet/rich_snippet_article_entity | anansi/schema/article_entity |
rank_math/schema/default_type | anansi/schema/default_type |
rank_math/webmaster/{id} | anansi/webmaster/{id} |
rank_math/sitemap/{x} for every anansi/sitemap/{x} filter and the xsl_{type} action | anansi/sitemap/{x} |
rank_math/sitemap/enable_caching (fired before Anansi’s) | anansi/sitemap/enable_caching |
rank_math/excluded_post_types, rank_math/excluded_taxonomies | anansi/excluded_post_types, anansi/excluded_taxonomies |
rank_math/html_sitemap/get_posts/join, rank_math/html_sitemap/get_posts/where | anansi/html_sitemap/get_posts/… |
rank_math/links/is_external | anansi/links/is_external |
rank_math/lock_modified_date | anansi/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_com | anansi/frontend/… |
Fired only when Rank Math is not active
| Rank Math hook | Anansi hook |
|---|---|
rank_math/redirection/pre_search (only if the Anansi filter returned null) | anansi/redirection/pre_search |
rank_math/redirection/get_clean_pattern | anansi/redirection/get_clean_pattern |
rank_math/instant_indexing/publish_url | anansi/indexnow/publish_url |
rank_math/instant_indexing/submit_url | anansi/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 hook | Anansi hook |
|---|---|
rank_math/blocks/{block}/title_wrapper | anansi/blocks/{block}/title_wrapper |
rank_math/block/preserve_line_breaks | anansi/block/preserve_line_breaks |
rank_math/schema/block/faq/content, rank_math/schema/block/howto/content | anansi/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.
Shared filter: wp_helpers_is_affiliate_link
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.