Docs SEO NEO Version 1.x Hooks & Customisation

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::getTitle
  • SeoNeo::getDescription
  • SeoNeo::getCanonical
  • SeoNeo::getRobots
  • SeoNeo::getRobotsDirectives
  • SeoNeo::getAiDirectives
  • SeoNeo::getOgType
  • SeoNeo::getOgImage
  • SeoNeo::getOgLocale
  • SeoNeo::getOgLocaleAlternates
  • SeoNeo::getArticleAuthors
  • SeoNeo::getArticlePublishedTime
  • SeoNeo::getArticleModifiedTime
  • SeoNeo::getTwitterCreator
  • SeoNeo::getHreflangCode
  • SeoNeo::getHreflangAlternates
  • SeoNeo::getAuthor
  • SeoNeo::getJsonLd
  • SeoNeo::renderJsonLd

Full list of hookable render methods

  • SeoNeo::renderTitle
  • SeoNeo::renderDescription
  • SeoNeo::renderCanonical
  • SeoNeo::renderRobots
  • SeoNeo::renderOg
  • SeoNeo::renderTwitter
  • SeoNeo::renderHreflang
  • SeoNeo::renderVerification
  • SeoNeo::renderAuthor
  • SeoNeo::renderSchema

See also

Last updated