Hooks & Customisation
Every resolver and render method in SEO NEO is hookable. addHookAfter / addHookBefore examples for title, description, og:type, robots directives, Twitter creator, and JSON-LD graph extension.
The pattern
Every value resolver and every render method in SEO NEO is hookable. You never need to subclass or fork the module — add hooks in site/ready.php or a custom module and they apply site-wide, per-template, or per-page as you choose.
Resolver hooks follow the PW triple-underscore hookable method convention (___getTitle, ___getOgImage, etc.) and are called with the page as the first argument. Render hooks follow the same pattern (___renderTitle, ___renderOg, etc.) and return HTML strings.
Overriding a resolved value
Use addHookAfter to intercept the resolved value and replace it:
// site/ready.php
// Override the meta title on a specific template
wire()->addHookAfter('SeoNeo::getTitle', function($event) {
$page = $event->arguments(0);
if ($page->template->name === 'product') {
$event->return = $page->product_name . ' — Buy Now | ' . wire('config')->siteName;
}
});
// Override og:type based on a page field
wire()->addHookAfter('SeoNeo::getOgType', function($event) {
$page = $event->arguments(0);
if ($page->template->name === 'blog_post') {
$event->return = 'article';
}
});
Overriding a rendered section
Use addHookAfter on a render method to append to or replace the HTML output:
// Append a custom og: tag after the standard OG block
wire()->addHookAfter('SeoNeo::renderOg', function($event) {
$event->return .= "\n" . '<meta property="og:custom" content="my-value">';
});
// Replace the robots output entirely for a specific page
wire()->addHookAfter('SeoNeo::renderRobots', function($event) {
$page = $event->arguments(0);
if ($page->id === 1234) {
$event->return = '<meta name="robots" content="noindex,nofollow">';
}
});
Overriding before resolution — addHookBefore
Use addHookBefore with $event->replace = true to short-circuit resolution entirely and supply your own value before the resolver runs:
wire()->addHookBefore('SeoNeo::getDescription', function($event) {
$page = $event->arguments(0);
if ($page->template->name === 'event') {
// Build description from event-specific fields, skip the fallback chain
$event->return = "Join us on {$page->event_date}: {$page->event_title} at {$page->venue}.";
$event->replace = true;
}
});
Per-page robots directives
The granular Google directives are site-wide in module config, but you can vary them per page or per template via ___getRobotsDirectives:
wire()->addHookAfter('SeoNeo::getRobotsDirectives', function($event) {
$page = $event->arguments(0);
$directives = $event->return; // associative array, e.g. ['max-snippet' => '50']
if ($page->template->name === 'news_article') {
$directives['max-snippet'] = '160';
$directives['max-image-preview'] = 'large';
}
$event->return = $directives;
});
Per-page Twitter creator
Return a per-author Twitter handle based on the page's author field:
wire()->addHookAfter('SeoNeo::getTwitterCreator', function($event) {
$page = $event->arguments(0);
if ($page->author instanceof Page && $page->author->twitter_handle) {
$event->return = $page->author->twitter_handle;
}
});
Extending the JSON-LD graph
Hook ___getJsonLd to add custom Schema.org nodes to the @graph:
wire()->addHookAfter('SeoNeo::getJsonLd', function($event) {
$page = $event->arguments(0);
$graph = $event->return;
if ($page->template->name === 'event') {
$graph['@graph'][] = [
'@type' => 'Event',
'name' => $page->title,
'startDate' => $page->event_date,
'location' => [
'@type' => 'Place',
'name' => $page->venue,
],
];
}
$event->return = $graph;
});
Full list of hookable resolver methods
SeoNeo::getTitleSeoNeo::getDescriptionSeoNeo::getCanonicalSeoNeo::getRobotsSeoNeo::getRobotsDirectivesSeoNeo::getAiDirectivesSeoNeo::getOgTypeSeoNeo::getOgImageSeoNeo::getOgLocaleSeoNeo::getOgLocaleAlternatesSeoNeo::getArticleAuthorsSeoNeo::getArticlePublishedTimeSeoNeo::getArticleModifiedTimeSeoNeo::getTwitterCreatorSeoNeo::getHreflangCodeSeoNeo::getHreflangAlternatesSeoNeo::getAuthorSeoNeo::getJsonLdSeoNeo::renderJsonLd
Full list of hookable render methods
SeoNeo::renderTitleSeoNeo::renderDescriptionSeoNeo::renderCanonicalSeoNeo::renderRobotsSeoNeo::renderOgSeoNeo::renderTwitterSeoNeo::renderHreflangSeoNeo::renderVerificationSeoNeo::renderAuthorSeoNeo::renderSchema
See also
- Template API — the full list of value getters and render methods available without hooks.
- Structured Data (JSON-LD) — extending the @graph via
getJsonLd. - Robots & Indexing —
getRobotsDirectivesfor per-template robot control.
Last updated