Extending with hooks
SleekRank fires filters and actions that let site code change the data a page is built from and the HTML it produces, and add its own data source types, mapping types and sitemap integrations. This page shows how they fit together; Hooks reference lists every public hook with its parameters, generated from the code.
Changing the data
sleekRank/data/item filters the row a generated page is built from, after
it was found in the cache and before any mapping reads it.
sleekRank/data/item/{slug} then does the same for one page group, named by
its slug. Both run for public pages and the workspace preview. On a public
page they run while WordPress parses the request, before the main query, so
conditional tags such as is_page() do not answer in them yet.
add_filter("sleekRank/data/item", function ($item, $pageGroup) {
$item["name"] = strtoupper($item["name"]);
return $item;
}, 10, 2);
add_filter("sleekRank/data/item/city-pages", function ($item) {
$item["description"] = wp_trim_words($item["description"], 30);
return $item;
});
sleekRank/data/resolved fires once the row is final, on
template_redirect before the base page loads, with the row and the page
group.
Changing mapping values
Every value a tag, selector or meta mapping writes passes through
sleekRank/replacement/value, then through
sleekRank/replacement/value/{type} for its mapping type (tag, selector
or meta). The value is already escaped for where it goes. List mappings do
not pass through these filters.
add_filter("sleekRank/replacement/value/meta", function ($value, $mapping, $data) {
return $mapping["target"] === "description"
? wp_trim_words($value, 25)
: $value;
}, 10, 3);
Changing the page
Four filters receive the page’s complete HTML:
sleekRank/output/beforeandsleekRank/output/afterrun on every generated page and preview, before and after the mappings, with the page group and the rowsleekRank/replacements/beforeandsleekRank/replacements/afterrun directly around the mappings, with the row and the mappings, and only when the group has at least one mapping
add_filter("sleekRank/output/after", function ($html, $pageGroup, $data) {
$banner = '<div class="generated-page-banner">' . esc_html($data["name"] ?? "") . "</div>";
return preg_replace("/<body([^>]*)>/", '<body$1>' . $banner, $html, 1);
}, 10, 3);
On a public page, Rank points the canonical link and og:url at the
generated URL after these filters, whichever of WordPress, Yoast SEO, Rank
Math, The SEO Framework or All in One SEO printed them.
sleekRank/output/canonical filters that URL; return an empty string to keep
the base page’s canonical:
add_filter("sleekRank/output/canonical", function ($url, $pageGroup) {
return "city-pages" === $pageGroup->getSlug() ? "" : $url;
}, 10, 2);
sleek_rank_related_items() lists a page’s siblings with a title taken from
the first of pageTitle, heroHeadline, title and name the row has, or
its slug; sleekRank/data/relatedItem filters each listed item with its row,
so the title can come from any field.
The registration hooks below fire on after_setup_theme, so a plugin or
the theme’s functions.php can add to them.
Adding a data source type
sleekRank/register/dataSources passes the data source registry after the
seven built-in types are registered. Register a class that implements
SleekRank\DataSourceInterface; extending SleekRank\Sources\BaseDataSource
and implementing its fetchRaw() gives the new type Rank’s cache, refresh
and lookups. The class receives the source’s config array, with
cacheDuration added.
add_action("sleekRank/register/dataSources", function ($registry) {
$registry->register("airtable", MyAirtableDataSource::class);
});
sleekRank/dataSource/registered fires for every registered type. The
workspace editor offers the built-in types for new sources and keeps a source
of a custom type as it is, showing its type; its settings are configured
through WP-CLI or REST (see
Data sources).
A mapping of a custom type is kept and shown the same way.
Adding a mapping type
sleekRank/register/replacements passes the replacement engine after the four
built-in mapping types are registered. Register an object that implements
SleekRank\ReplacementInterface: its supports() decides which mappings it
handles, and replace() returns the changed HTML.
add_action("sleekRank/register/replacements", function ($engine) {
$engine->registerReplacement(new MyCountdownReplacement());
});
Adding a sitemap integration
sleekRank/register/sitemapIntegrations passes the sitemap registry after the
built-in SEO plugin integrations and before the WordPress core fallback.
Register an object that implements SleekRank\SitemapIntegrationInterface;
the first registered integration whose isActive() is true is used. Build it
on sleekRank()->getSitemapProvider(), which supplies the entries.
add_action("sleekRank/register/sitemapIntegrations", function ($registry) {
$registry->register(
new MySitemapIntegration(sleekRank()->getSitemapProvider())
);
});
sleekRank/sitemap/urlsPerSitemap changes how many URLs one sitemap file
holds (see Sitemap).
Lifecycle and build hooks
sleekRank/initfires once Rank has booted, onafter_setup_theme, with the instancesleekRank()returnssleekRank/rewrites/registeredfires after the published groups’ rewrite rules are addedsleekRank/activatedandsleekRank/deactivatedfire when Rank is activated or deactivated on a sitesleekRank/runtime/allowRouteInventorydecides whethersleek_rank_generated_route_inventory()may list the generated URLs in a request other than WP-CLI, wherewp sleek rank routesuses it