Skip to main content
Signocore
// signocore seo docs

Hooks

Every filter in Signocore SEO with parameters, return values and code examples for developers.

Signocore SEO passes its output through WordPress filters, so a theme or a small plugin can adjust titles, meta tags, the schema graph, sitemaps, breadcrumbs, robots.txt and the global scripts without editing the plugin. Add callbacks with add_filter() from your theme's functions.php or a must-use plugin. Every hook name starts with wpsseo_, and the plugin fires no actions of its own.

Much of this output is cached, and a filter only runs when its cache is rebuilt: the head output for a week, breadcrumb trails for an hour, sitemaps for a day and the sitemap stylesheet for 30 days. Each group below says when its filters run and what clears the cache. While you work on a callback, saving any Signocore SEO settings page clears the cached head output and the sitemaps.

Return the type listed for each filter. Most values go straight into typed plugin code, where a wrong type such as null causes a fatal error. Hooks renamed in 6.0.0 still work under their old names and trigger a deprecation notice when WP_DEBUG is on.

No hooks match "".

Meta tags

These filters shape what Signocore SEO prints at the top of wp_head, and they run inside it, so conditional tags such as is_singular() work. The head output is cached for a week per post, term, author or home page, with separate variants for each language, year, page number and breadcrumb trail, so apart from the <title> element these filters only run when that cache is rebuilt. Saving a post, term or user profile clears its own entry, and saving any Signocore SEO settings page or updating the plugin clears them all. Search results, date archives and post type archives are never cached, and neither is anything on a site set to discourage search engines. 404 pages get no head output, only the title.

Filters the document title used for the <title> element, og:title and twitter:title.

The title can already carry the company name and, on paginated archives, a page number, both joined with &bull;, and it can contain other HTML entities. Return plain text: the result is escaped for output, and existing entities are kept. The <title> element is built on every request through core's pre_get_document_title filter, so a change shows there at once, while og:title and twitter:title keep the cached value until the head output is rebuilt. The filter can run twice in one request. Return an empty string to let WordPress build its own <title> and drop the two social title tags. Not applied to feeds.

Parameter Type Description
$title string The document title. Can contain HTML entities such as &bull;.

Returns string The title as plain text.

add_filter('wpsseo_meta_doctitle', function (string $title): string {
    // Use a pipe instead of the bullet before the company name and the page number.
    return str_replace(' &bull; ', ' | ', $title);
});

Filters the meta description used for the description, og:description and twitter:description tags.

The value comes from the SEO box, a description template, the home page settings or an automatic description, with placeholders resolved. Paginated archives get the page number appended. Return an empty string to print none of the three tags. Post type archives and date archives have no description of their own, and since they are never cached, the filter runs on every request there.

Parameter Type Description
$description string The meta description. Can be empty.

Returns string The meta description, or an empty string for none.

add_filter('wpsseo_meta_description', function (string $description): string {
    if ($description === '' && is_post_type_archive('event')) {
        return 'Upcoming workshops, webinars and meetups, with dates, venues and tickets.';
    }

    return $description;
});

Filters the canonical URL used for <link rel="canonical"> and og:url.

The value already includes a custom canonical URL from the SEO box, and a trailing slash when the permalink structure ends with one. Paginated archives point to their own page. Return an empty string to print neither tag.

Parameter Type Description
$url string The canonical URL.

Returns string The canonical URL, or an empty string for none.

add_filter('wpsseo_meta_canonical_url', function (string $url): string {
    // Point canonical URLs on the staging copy at the live site.
    return str_replace('https://staging.example.com', 'https://example.com', $url);
});

Filters the image used for the Open Graph and Twitter image tags.

The plugin takes the custom social image of the post, term or author, then the post's featured image, then the Default Social Image from the settings, in the 1200 x 630 social-image size. Return an empty array to print no image tags, which also drops twitter:card. width and height are only printed when they are above zero.

Parameter Type Description
$image array An array with the keys url (string), width (int), height (int) and alt (string), or an empty array when no image was found. The alt text falls back to the attachment title.

Returns array The image with at least url, or an empty array for no image.

add_filter('wpsseo_meta_social_image', function (array $image): array {
    if (!is_singular('post')) {
        return $image;
    }

    $postId = get_queried_object_id();

    // An image rendered for each post by an external service.
    return [
        'url' => 'https://images.example.com/og/' . $postId . '.png',
        'width' => 1200,
        'height' => 630,
        'alt' => wp_strip_all_tags(get_the_title($postId)),
    ];
});

Filters the site name used for og:site_name.

Receives the Site Title from Settings > General, which WordPress stores HTML-escaped. It does not change the company name used in titles and in the schema graph.

Parameter Type Description
$blogName string The site title.

Returns string The site name as plain text.

add_filter('wpsseo_meta_blog_name', function (string $blogName): string {
    // The site title is "Example Store | Handmade leather goods"; share only the brand.
    return 'Example Store';
});

Filters the block of meta and link tags that the plugin prints in the head.

The string holds the description, canonical, author, prev and next, prefetch, Open Graph, Twitter, Facebook app and site verification tags, one per line, and the result is what gets cached. The plugin appends its schema.org JSON-LD <script> through this same filter at priority 10, so a callback at a lower priority sees the tags without the schema, and one above 10 sees both. The opening and closing comments are added outside this filter.

Parameter Type Description
$metaTags string The tags as HTML.

Returns string The tags to print, as HTML.

add_filter('wpsseo_meta_tags', function (string $metaTags): string {
    // Drop the prefetch hints for the previous and next page on paginated archives.
    return (string) preg_replace('/<link rel="prefetch" href="[^"]*">\n/', '', $metaTags);
});

Filters the HTML comments that open and close the plugin's head output.

Fires twice each time the head output is built: first with <!-- Signocore SEO -->, then with <!-- Signocore SEO End -->, each followed by a newline. Check the value to change only one of them, and return an empty string to remove a comment.

Parameter Type Description
$comment string The HTML comment, including the trailing newline.

Returns string The comment to print, or an empty string for none.

add_filter('wpsseo_meta_comment_block', function (string $comment): string {
    // Remove both the opening and the closing comment.
    return '';
});

Schema

The schema.org graph is printed as one JSON-LD script with the head output, so these filters run when the head cache is rebuilt (see Meta tags). The graph is only printed once the Schema or Social settings page has been saved at least once. Both filters work without a license, but some of the nodes they deal with need Pro.

Filters the schema.org types of the current page, which set the @type of the page node and decide some of the other nodes in the graph.

On single posts the list holds WebPage plus Article, Product or, with Pro, FAQPage where they apply, and the page type chosen in the SEO box, such as ContactPage. Author archives get WebPage and ProfilePage, the blog home WebPage and CollectionPage, and other archives start with CollectionPage. Article and Product are taken out of the page node and produce a separate Article or Product node instead. Article and ProfilePage add the author's Person node, and ProfilePage and CollectionPage add an ItemList of the posts in the main query. The Product, Person and ItemList nodes need Pro. Entries that are not strings are dropped. The filter runs several times while one graph is built, so return the same result for the same page.

Parameter Type Description
$pageTypes string[] schema.org type names.

Returns string[] The type names for the page.

add_filter('wpsseo_schema_page_types', function (array $pageTypes): array {
    if (function_exists('is_checkout') && is_checkout()) {
        $pageTypes[] = 'CheckoutPage';
    }

    return $pageTypes;
});

Filters the complete list of schema.org nodes before they are printed as one JSON-LD @graph.

Receives the nodes as a list of arrays without @context: WebSite, Organization, the site navigation, BreadcrumbList, the primary image, the page node and Article, plus, with Pro, Product, Person, ItemList, FAQ questions, advanced types such as Recipe or Event, the glossary term set and the custom JSON-LD from the SEO box. Nodes refer to each other by @id, such as https://example.com/#organization. Entries that are not arrays are dropped, and the rest is printed in one <script type="application/ld+json"> with @context added. When no nodes are left, no script is printed.

Parameter Type Description
$schema array[] The graph nodes, each an array such as ['@type' => 'WebSite', '@id' => '...', ...].

Returns array[] The nodes to print.

add_filter('wpsseo_schema_graph', function (array $schema): array {
    foreach ($schema as $index => $node) {
        if (str_ends_with((string) ($node['@id'] ?? ''), '#organization')) {
            $schema[$index]['foundingDate'] = '2015-03-01';
        }
    }

    return $schema;
});

Sitemap

Sitemaps are generated early in the request, on send_headers, before WordPress runs the main query, so conditional tags do not apply here. Each sitemap page is cached for a day per locale, and the XSL stylesheet that styles the sitemaps in a browser for 30 days. Saving a post or any Signocore SEO settings page clears every sitemap and the stylesheet, saving a term clears the sitemap index and that taxonomy's sitemaps, and saving a user profile clears the index and the author sitemap. Updating the plugin clears them all.

Filters every URL written to the XML sitemaps: sitemap index entries, page URLs and image URLs.

The URL arrives escaped for XML (& as &amp;) and is written into <loc> or <image:loc> exactly as returned, so keep it XML-safe. The front_page entry is only added to the page sitemap when no static front page is set, so its $objectId is always null.

Parameter Type Description
$url string The URL, escaped for XML.
$type string What the URL points to: sitemap_index for an entry in the sitemap index, a post type name such as post, page or product, term, author, front_page, or attachment for an image.
$objectId int|null The post ID, term ID or user ID. null for sitemap_index, front_page and attachment.

Returns string The URL, escaped for XML.

add_filter('wpsseo_sitemap_url', function (string $url, string $type, ?int $objectId): string {
    // Serve image URLs from the CDN.
    if ($type === 'attachment') {
        return str_replace('https://example.com/wp-content/uploads/', 'https://cdn.example.com/uploads/', $url);
    }

    return $url;
}, 10, 3);

Filters the IDs of posts left out of the post type sitemaps.

Despite its name, this filter works with post IDs, not URLs. The list starts with every post marked noindex in the SEO box plus the WooCommerce pages from wpsseo_woocommerce_page_ids, and the result goes to the post type sitemap queries as post__not_in. It does not change the robots meta of those posts, and it does not affect term or author sitemaps. The filter only runs when a post type sitemap is built, so conditional tags do not apply. Changes show when a sitemap is rebuilt.

Parameter Type Description
$postIds int[] Post IDs, as integers.

Returns int[] The post IDs to leave out.

add_filter('wpsseo_sitemap_excluded_urls', function (array $postIds): array {
    // The newsletter thank-you page and a campaign landing page.
    return array_merge($postIds, [128, 256]);
});

Filters the URL of an author archive in the author sitemap.

Receives the URL from get_author_posts_url() before it is escaped, so return a plain URL. The result then passes through wpsseo_sitemap_url with the type author. The author sitemap lists authors with published posts of the post type, except authors marked noindex, and is left out entirely when author archives are set to noindex.

Parameter Type Description
$url string The author archive URL.
$authorId int The author's user ID.

Returns string The URL to list, not escaped.

add_filter('wpsseo_sitemap_author_url', function (string $url, int $authorId): string {
    // List the team member's profile page instead of the author archive.
    $profilePageId = (int) get_user_meta($authorId, 'profile_page_id', true);
    $profileUrl = $profilePageId > 0 ? get_permalink($profilePageId) : false;

    return $profileUrl ?: $url;
}, 10, 2);

Filters the accent color of the stylesheet that styles the sitemaps in a browser.

Only changes how the sitemaps look to people, since search engines ignore the stylesheet. Return a hex color such as #c4782e, without quotes; any other value falls back to the default. The stylesheet is cached for 30 days, and saving a post, saving any Signocore SEO settings page or updating the plugin clears it.

Parameter Type Description
$color string A hex color. Default #546e7a.

Returns string A hex color.

add_filter('wpsseo_sitemap_accent_color', function (string $color): string {
    return '#c4782e';
});

Breadcrumbs print through the [signocore-breadcrumbs] shortcode or a theme call to \Signocore\Features\Breadcrumbs::render(), never in the admin or on 404 pages. The trail is cached per URL for an hour. It also feeds the BreadcrumbList node in the schema graph and keys the head cache, so the trail is built on every page view that misses its cache, even when the theme prints no breadcrumbs. The two display filters run on every render.

Filters the HTML that wraps and separates the breadcrumbs.

The keys are wrap_start and wrap_end around the whole trail, separator between items, and item_wrap_start and item_wrap_end around each item. Every call receives the defaults, the values are printed without escaping, and the result is merged over the defaults, so you can return only the keys you change. Anything other than an array is ignored.

Parameter Type Description
$args array Display arguments. By default wrap_start is <div class="breadcrumbs">, wrap_end is </div>, separator is <span class="sep" aria-hidden="true">&rsaquo;</span> with a space on each side, and both item wraps are empty.

Returns array The display arguments, as HTML strings.

add_filter('wpsseo_breadcrumb_args', function (array $args): array {
    $args['wrap_start'] = '<nav class="breadcrumbs" aria-label="Breadcrumb">';
    $args['wrap_end'] = '</nav>';
    $args['separator'] = ' <span class="sep" aria-hidden="true">/</span> ';

    return $args;
});

Filters the breadcrumb trail before it is cached, printed and added to the schema graph.

The first crumb is the home page and the last is the current page. On the front page the trail is empty. The plugin runs URLs through esc_url() and labels through esc_html(), and labels are decoded and stripped of tags before output, so plain text works too. The result is cached per URL for an hour, except on search results, so base changes on the requested page, not on the visitor. Saving a post, term or user profile clears its trail.

Parameter Type Description
$breadcrumbs array[] The crumbs in order, each an array with url (string), label (string) and add_link (bool, whether the crumb is printed as a link).

Returns array[] The crumbs, each with url, label and add_link.

add_filter('wpsseo_breadcrumb_structure', function (array $breadcrumbs): array {
    if (!is_singular('event') || count($breadcrumbs) < 2) {
        return $breadcrumbs;
    }

    $archiveUrl = get_post_type_archive_link('event');

    if ($archiveUrl === false) {
        return $breadcrumbs;
    }

    // Home > Events > Event title
    array_splice($breadcrumbs, -1, 0, [[
        'url' => esc_url($archiveUrl),
        'label' => 'Events',
        'add_link' => true,
    ]]);

    return $breadcrumbs;
});

Filters the rendered breadcrumb items before they are joined with the separator.

Each item is HTML: an <a> link for crumbs with add_link, the escaped label for the others, wrapped in item_wrap_start and item_wrap_end. The items are then joined with separator and wrapped in wrap_start and wrap_end. Return an empty array to print nothing. Does not affect the BreadcrumbList node in the schema graph.

Parameter Type Description
$links string[] The breadcrumb items as HTML.

Returns string[] The items to print, as HTML.

add_filter('wpsseo_breadcrumb_links', function (array $links): array {
    $lastIndex = array_key_last($links);

    if ($lastIndex !== null) {
        $links[$lastIndex] = '<span aria-current="page">' . $links[$lastIndex] . '</span>';
    }

    return $links;
});

Robots.txt and scripts

wpsseo_robots_txt changes the robots.txt that WordPress generates. The script filters change the global Header Scripts and Body Scripts from the plugin settings. None of this output is cached.

Filters the robots.txt that Signocore SEO generates.

The plugin builds robots.txt from scratch on core's robots_txt filter at priority 11, so lines that other callbacks added before it are discarded. Add your rules here instead. The filter is skipped when the site is set to discourage search engines, because the file then disallows everything, and WordPress never handles the request when a physical robots.txt file exists in the web root.

Parameter Type Description
$output string The robots.txt content, ending with the Sitemap: lines.
$companyName string The Company Name from the plugin settings, without HTML tags.

Returns string The robots.txt content.

add_filter('wpsseo_robots_txt', function (string $output): string {
    $output .= "\n# AI training crawlers\n";
    $output .= "User-agent: GPTBot\n";
    $output .= "User-agent: CCBot\n";
    $output .= "Disallow: /\n";

    return $output;
});

Filters the global Header Scripts before they are printed in wp_head.

Also runs when the Header Scripts setting is empty, so a callback can add scripts on its own. The result is printed as is, and an empty string prints nothing. Users who can manage_options get no global scripts unless Header Scripts For Admins is on, and the per-page scripts from the SEO box are printed separately, without this filter.

Parameter Type Description
$scripts string The Header Scripts setting, as HTML.

Returns string The HTML to print, or an empty string for none.

add_filter('wpsseo_script_header', function (string $scripts): string {
    // Keep third-party tracking off the checkout page.
    if (function_exists('is_checkout') && is_checkout()) {
        return '';
    }

    return $scripts;
});

Filters the global Body Scripts before they are printed in wp_footer.

The Body Scripts print on wp_footer, near the closing </body> tag, not after the opening one. Also runs when the Body Scripts setting is empty, so a callback can add scripts on its own, and the result is printed as is. Users who can manage_options get no global scripts unless Body Scripts For Admins is on, and the per-page body scripts from the SEO box are printed separately, without this filter.

Parameter Type Description
$scripts string The Body Scripts setting, as HTML.

Returns string The HTML to print, or an empty string for none.

add_filter('wpsseo_script_body', function (string $scripts): string {
    // The stored scripts use a {{PAGE_ID}} placeholder for the tracking pixel.
    return str_replace('{{PAGE_ID}}', (string) get_queried_object_id(), $scripts);
});

WooCommerce

Signocore SEO keeps the functional WooCommerce pages, such as the cart, checkout and account pages, out of the sitemaps.

Filters the WooCommerce page IDs that are left out of the sitemaps.

The list holds the cart, checkout, pay, order received, my account, edit address, view order, terms and conditions, and refund and returns pages, read from the WooCommerce page settings. Pages that are not set are skipped. The list is only used for the sitemaps, as part of wpsseo_sitemap_excluded_urls, and like that filter it only runs when a post type sitemap is built. With WPML or Polylang, the plugin translates the IDs to the current language in a callback at priority 10; use a later priority, such as 20, to work with the translated IDs.

Parameter Type Description
$pageIds int[] The page IDs.

Returns int[] The page IDs to leave out of the sitemaps.

add_filter('wpsseo_woocommerce_page_ids', function (array $pageIds): array {
    // Keep the terms and conditions page in the sitemap.
    $termsPageId = (int) get_option('woocommerce_terms_page_id');

    return array_values(array_diff($pageIds, [$termsPageId]));
});

Deprecated hooks

These names were renamed. They still run, but log a deprecation notice when WP_DEBUG is on. Switch to the new name.

Old name Use instead Deprecated in
signocore_seo_schema_page_types wpsseo_schema_page_types 6.0.0
signocore_seo_schema_graph wpsseo_schema_graph 6.0.0
signocore_seo/sitemap_author_url wpsseo_sitemap_author_url 6.0.0
signocoreseo_robots_txt wpsseo_robots_txt 6.0.0

Stuck on something the docs don't cover?

Questions go straight to the developer who builds the plugins. Replies usually within a day.

September Sale

€20 off Signocore SEO Pro

Pay €49 instead of €69, one time for unlimited sites. code SEP20