Filters allow you to change interpreted data conditionally.
We recommend against using filters if you aren’t an avid PHP developer. This is because you must revalidate (and possibly update) your implementation on every major release, although that shouldn’t happen often.
As of v4.2.0, The SEO Framework registers over 225 filters.
Below you’ll find frequently requested filter implementations. It’s not a long list, because many filters now have options and only exist for backward compatibility reasons.
Advanced filters, such as those used for script loading, aren’t listed here either. For these, we urge you to review the code.
If you don’t know how filters work or where to place them, read our filter guide first.
Query related
The query-related filters affect how The SEO Framework interacts with the interface.
Disable SEO support
N.B. This example filter does not affect the admin interface.
add_filter( 'the_seo_framework_query_supports_seo', function( $supported ) {
$tsf = tsf();
// This TSF method also works in the admin area, and prevents ID collision with terms.
if ( $tsf->is_singular() ) {
// Define your excluded page IDs here.
$excluded_ids = [ 42, 9001 ];
// This TSF method supports page-as-archive pages, like blog and shop pages.
$current_id = $tsf->get_the_real_ID();
if ( in_array( $current_id, $excluded_ids, true ) ) {
$supported = false;
}
}
return $supported;
} );
Title related
The title-related filters affect all functions that make use of the titles. This includes (and is not limited to) the meta title, generated descriptions, social metadata, and structured data (Schema.org).
Run shortcodes in the custom title.
N.B. This example filter is for custom titles, not generated titles. You can use them interchangeably.
add_filter( 'the_seo_framework_title_from_custom_field', function( $title, $args ) {
return apply_shortcodes( $title );
}, 10, 2 );
Set custom post type archive titles
N.B. This example filter is for generated titles, not custom titles. You can use them interchangeably.
add_filter( 'the_seo_framework_title_from_generation', function( $title, $args ) {
/**
* @link https://developer.wordpress.org/reference/functions/is_post_type_archive/
* When $args is filled in, the call is not for the current query. Post-type-archives can't be queried via TSF.
*/
if ( null === $args && is_post_type_archive( 'my_post_type_name' ) ) {
$title = 'My custom title';
}
return $title;
}, 10, 2 );
Remove title branding on all WooCommerce product categories.
N.B. The use of this filter is not recommended because search engines tend to ignore unbranded titles.
add_filter( 'the_seo_framework_use_title_branding', function( $use, $args ) {
// Get taxonomy with admin support.
$taxonomy = null === $args
? tsf()->get_current_taxonomy()
: $args['taxonomy'];
// If taxonomy is a WooCommerce product category, disable the branding.
if ( 'product_cat' === $taxonomy ) {
$use = false;
}
return $use;
}, 10, 2 );
Description related
The description-related filters affect all functions that make use of the description. This includes (and is not limited to) the meta description, social metadata, and structured data (Schema.org).
Run shortcodes in the custom description.
add_filter( 'the_seo_framework_custom_field_description', function( $description, $args ) {
return apply_shortcodes( $description );
}, 10, 2 );
Set custom post type archive descriptions
add_filter( 'the_seo_framework_generated_description', function( $description, $args ) {
/**
* @link https://developer.wordpress.org/reference/functions/is_post_type_archive/
* When $args is filled in, the call is not for the current query. Post-type-archives can't be queried via TSF.
*/
if ( null === $args && is_post_type_archive( 'my_post_type_name' ) ) {
$description = 'My custom description';
}
return $description;
}, 10, 2 );
Use long descriptions instead of short descriptions for WooCommerce products
add_filter(
'the_seo_framework_fetched_description_excerpt',
function( $excerpt, $d, $args ) {
$tsf = tsf();
if ( null === $args ) {
// In the loop.
$is_product = $tsf->is_product();
} else {
// Out the loop, admin etc.
$is_product = ! $args['taxonomy'] && ! $args['pta'] && $tsf->is_product( $args['id'] );
}
if ( $is_product ?? false ) {
$product = get_post( $args['id'] ?? $tsf->get_the_real_ID() );
$product_id = $product->ID;
// Don't leak protected content.
if ( $tsf->is_protected( $product_id ) ) return $excerpt;
$old_excerpt = $excerpt;
$excerpt = $tsf->uses_non_html_page_builder( $product_id ) ? '' : $product->post_content;
if ( $excerpt ) {
// Apply half of TSF's description AI here: selectively strip content and HTML.
$excerpt = $tsf->s_excerpt_raw(
$tsf->strip_paragraph_urls( $tsf->strip_newline_urls( $excerpt ) )
);
}
$excerpt = $excerpt ?: $old_excerpt;
}
return $excerpt;
},
10,
3
);
Robots related
The robots-related filters can be used to direct crawlers, like Googlebot.
Set noindex and nofollow for all tags
N.B. The args and ignore parameters are only available since TSF v4.0.0.
add_filter( 'the_seo_framework_robots_meta_array', function( $meta, $args, $ignore ) {
$taxonomy = null === $args
? tsf()->get_current_taxonomy()
: $args['taxonomy'];
if ( 'post_tag' === $taxonomy ) {
$meta['noindex'] = 'noindex';
$meta['nofollow'] = 'nofollow';
}
return $meta;
}, 10, 3 );
Add robots.txt rules
N.B. The SEO Framework overwrites the dynamic file to prevent plugin conflicts. So, you should always set your callback priority to a greater value than 10.
// This is a WordPress Core filter.
add_filter( 'robots_txt', function( $robots ) {
$robots .= "\r\nDisallow: /my-custom-folder/\r\n";
return $robots;
}, 11 );
Image related
The image-related filters affect social metadata as well as structured data.
Append image generators for social images
This filter is advanced and powerful. For real-world usage, see this issue comment and this issue comment.
N.B. This only works on TSF v4.0.0 or later.
add_filter( 'the_seo_framework_image_generation_params', function( $params = [], $args = null, $context = 'social' ) {
// Let's not mess with non-social sharing images.
if ( 'social' !== $context ) return $params;
if ( null === $args ) {
// In the loop.
if ( is_singular() ) {
// Append. Use array_unshift() on 'cbs' to prepend.
$params['cbs']['custom'] = 'my_tsf_custom_singular_image_generator';
}
} else {
// Out the loop. Use $args to evaluate the query...
if ( ! $args['taxonomy'] && ! $args['pta'] ) {
// Singular.
// Append. Use array_unshift() on 'cbs' to prepend.
$params['cbs']['custom'] = 'my_tsf_custom_singular_image_generator';
}
}
return $params;
}, 10, 3 );
function my_tsf_custom_singular_image_generator( $args = null, $size = 'full' ) {
// Arbitrary URL and ID.
$url = 'https://example.com/path/to/image/';
$id = 42;
if ( $url ) {
yield [
'url' => $url,
'id' => $id, // Optional. Used for alt-tag fetching and dimension testing.
];
}
}
Sitemap related
The sitemap is sufficient for all websites as-is. The sitemap doesn’t need to have all URLs of your website listed.
“Improving” the sitemap is utterly redundant; but, go ahead.
Add categories and tags to base sitemap
add_filter( 'the_seo_framework_sitemap_additional_urls', function( $custom_urls = [] ) {
// Set the taxonomy types you'd like to include.
$taxonomies = [
'category',
'tag',
];
$tsf = tsf();
foreach ( $taxonomies as $tax ) {
// When the taxonomy is disabled or isn't public, don't include it.
if ( ! $tsf->is_taxonomy_supported( $tax ) ) continue;
$terms = get_terms( $tax );
foreach ( $terms as $term ) {
if ( isset( $term->taxonomy, $term->term_id ) ) {
if ( tsf()->is_robots_meta_noindex_set_by_args(
[
'id' => $term->term_id,
'taxonomy' => $term->taxonomy,
],
\The_SEO_Framework\ROBOTS_IGNORE_PROTECTION
) ) continue;
// create_canonical_url() escapes.
$url = $tsf->create_canonical_url(
[
'id' => $term->term_id,
'taxonomy' => $term->taxonomy,
]
);
$custom_urls[ $url ] = [
'lastmod' => null, // difficult to determine.
];
}
}
}
return $custom_urls;
} );
Add custom sitemaps
If you wish to implement custom sitemaps, see our example sitemap plugin. Use that plugin as a reference.
SEO settings page related
The SEO settings page is accessible via the left-side WordPress admin menu.
List edit settings related
These filters are applicable to the post and term overview pages.
Hide quick-and bulk-edit
add_action( 'the_seo_framework_after_admin_init', function() {
remove_action( 'admin_init', [ tsf(), '_init_list_edit' ] );
} );
Post SEO settings related
The post SEO settings are placed in a meta box on each public post type edit screen.
Change meta box priority
N.B. Only new users are affected by this filter. Users can drag and position the meta box to their liking, the location is stored and locked as a user-setting.
add_filter( 'the_seo_framework_metabox_priority', function() {
return 'default'; // Accepts 'high', 'default', 'low'. Default is 'high'.
} );
Move meta box to the sidebar
N.B. Only new users are affected by this filter. Users can drag and position the meta box to their liking, the location is stored and locked as a user-setting.
add_filter( 'the_seo_framework_metabox_context', function() {
return 'side'; // Accepts 'normal', 'side', and 'advanced'. Default is 'normal'.
} );
SEO Bar related
The SEO Bar helps you see what needs attention for each page. Since TSF v4.0, we provide an API. These are actions, not filters, but you’re probably reading this page because you want to adjust things — to which filters make more sense.
Register custom SEO Bar item
add_action( 'the_seo_framework_seo_bar', function( $interpreter ) {
/**
* This is a collector method. However, it's best to use
* `register_seo_bar_item()` and `edit_seo_bar_item()` instead.
*/
$items = $interpreter::collect_seo_bar_items();
// Don't do anything if there's a blocking redirect.
if ( ! empty( $items['redirect']['meta']['blocking'] ) ) return;
// Add a custom item:
$interpreter::register_seo_bar_item(
'something',
[
'symbol' => 'S',
'title' => \__( 'Some assessment', 'my-text-domain' ),
'status' => $interpreter::STATE_BAD,
'reason' => \__( 'Something bad happened.', 'my-text-domain' ),
'assess' => [
'something' => \__( 'Something is not right.', 'my-text-domain' ),
'else' => \__( 'Something else is not right either.', 'my-text-domain' ),
],
]
);
} );
Adjust SEO Bar item
add_action( 'the_seo_framework_seo_bar', function( $interpreter ) {
/**
* This is a collector method. However, it's best to use
* `register_seo_bar_item()` and `edit_seo_bar_item()` instead.
*/
$items = $interpreter::collect_seo_bar_items();
// Don't do anything if there's a blocking redirect.
if ( ! empty( $items['redirect']['meta']['blocking'] ) ) return;
// Edit known items. Warning: Advanced magic! Know your PHP.
// NB: If the item isn't registered, this won't produce errors, but all changes will be voided.
$index_item = &$interpreter::edit_seo_bar_item( 'indexing' );
$index_item['status'] = $interpreter::STATE_UNKNOWN;
$index_item['reason'] = \__( 'Robots.txt blocks all crawlers.', 'my-text-domain' );
$index_item['assess'] = []; // clear all assessments... be considerate!
$index_item['assess']['plugin'] = \__( 'This is a developer site. Plugin "MyNoRobots - Robots.txt Robot Blocker" is activated.', 'my-text-domain' );
} );