Auto-inject resilience + docs polish
Hardens SeoNeo's head-rendering pipeline against unexpected failures and improves discoverability of two existing features that testers were missing.
Resilience
- Error boundary inside
___renderHead()— the full section-builder pipeline is now wrapped in a try-catch. If any resolver or section builder throws (a hookedgetTitlethat crashes, a field-type edge case, a null reference insidegetOgLines, etc.), the page renders normally without the SeoNeo block, and the error is written to a new ProcessWire log calledseoneo(site/assets/logs/seoneo.txt). The log is created on demand on first failure — clean installs stay clean. - Defence in depth — matching try-catches added to
SeoNeoAccessor::render()(the$page->seoneo->render()template path) andhookPageRenderInject()(the auto-inject hook path), so all three call paths are protected. - Null-template safety —
shouldAutoInject()andhookPageRenderInject()now guard against the (rare) case of a page with no template object, preventing a TypeError on PHP 8.x.
UX
- Config hint when no templates have
seoneo_tab— the auto-inject checkbox in module config shows a one-line note when no fieldgroup includesseoneo_tab, explaining that the field must be on at least one template for injection to take effect.
Documentation
- Installation: clearer auto-complete callout — emphasises that you only need to add
seoneo_tabto a template; the rest of the SEO fields are inserted automatically in the correct order on save (a 1.1.0 feature that was previously buried). - JSON-LD: custom Schema.org types — the hooks section now includes worked examples for adding a
Recipenode on a custom template and suppressingBreadcrumbListon the homepage, plus a link to the full structured-data reference.
Compatibility
Fully backwards-compatible. No database changes, no field changes, no template changes required. Drop in over 1.1.3 and refresh modules.