Skip to content

Fix: Video SEO for block theme templates, template parts and sync patterns. #2032

Description

@KMchaudhary

Video SEO (VideoObject JSON-LD) missing for videos in block-theme templates, template parts, and synced patterns

Summary

GoDAM outputs VideoObject JSON-LD schema correctly for godam/video blocks stored in a
post/page/CPT's own content, but emits nothing when the same block is placed in a
block-theme template, a template part (e.g. header/footer), or a synced pattern
(wp_block). Videos in those locations are valid, user-facing placements and should
produce structured data for search engines.

Type

Bug / Enhancement (SEO structured data coverage gap)

Component

godam core plugin — inc/classes/class-seo.php

Current behavior

The SEO class works in two decoupled phases:

  • Save-time: save_post parses the post's post_content for godam/video blocks and
    caches the schema in that post's meta.
  • Output-time: wp_head reads the cached meta of the queried singular object and emits
    the JSON-LD.

Because the schema is keyed to the queried post's own content, anything composed into the
page at render time is invisible to it.

Content source Schema emitted?
Post / Page / CPT — video in content ✅ Yes
Unsynced pattern (blocks copied into content) ✅ Yes
Block-theme template (single, page, query loop, etc.) ❌ No
Template part (header / footer) ❌ No
Synced pattern / reusable block (wp_block) ❌ No

Steps to reproduce

  1. Activate a block theme (e.g. Twenty Twenty-Five).
  2. Add a godam/video block to a synced pattern, and insert that pattern into a page.
    (Or: add a godam/video to the footer template part in the Site Editor.)
  3. Visit the front end of a page that uses it and view source.

Expected: a <script type="application/ld+json"> VideoObject for the video.
Actual: no schema is output. (The referencing page's godam_video_seo_schema meta is
empty, because the block lives in the wp_block / wp_template_part post, not in the page.)

Root cause

  • A synced pattern reference stores only <!-- wp:block {"ref":N} /--> in content, so
    parse_blocks() never sees the inner godam/video.
  • Templates and template parts are separate post types (wp_template, wp_template_part)
    that are never the queried singular object whose cached meta is read.

Proposed fix

Add a render-time capture path alongside the existing cached path:

  • Hook render_block to collect godam/video schema from any block actually rendered
    on the page (covers templates, template parts, and synced patterns).
  • Emit the collected schema once in wp_footer.
  • Share a single schema-builder so both paths produce identical output and fire the same
    godam_video_seo_schema filter.

Important ordering detail: in block themes the template renders (firing render_block)
before wp_head. De-duplication (so a video in post content isn't emitted in both
<head> and footer) must therefore happen at flush time (wp_footer), after both the
cached output and the render-time collector have finished — not at collect time.

The existing cached wp_head path is kept unchanged, since it also serves Elementor and
WPBakery content that render_block does not cover.

Scope

  • In scope: singular views (post/page/CPT) — templates, template parts, synced patterns.

Compatibility

The godam-for-woo add-on's godam_video_seo_schemas handlers are safe on the footer
path: the VPG ItemList grouping no-ops on empty cached data, per-entry product enrichment
no-ops without product cache, and product-page suppression continues to prevent duplicates.

Acceptance criteria

  • Video in a synced pattern outputs one VideoObject.
  • Video in a template / template part outputs one VideoObject.
  • Video in a CPT's own content still outputs schema (no regression).
  • A page with a video in both content and a template part emits each distinct
    video exactly once (no duplicates).
  • No measurable performance regression.

Verification (tested)

Environment: WP block theme (Twenty Twenty-Five), PHP 8.2, godam + godam-for-woo active.

  • Synced-pattern page → 1 VideoObject (footer). ✅
  • Footer template-part video on a plain page → 1 VideoObject (footer). ✅
  • CPT (case-studies) with content video + footer-part video → 2 distinct, each once. ✅
  • Post-content video → still 1 VideoObject in <head>, no footer duplicate. ✅

Performance

Added cost is one method call per rendered block; non-video blocks do a single blockName
check and return (is_singular() runs only for actual video blocks).

  • ~54 ns per block; ~40–80 render_block calls on typical pages, so a heavy 500-block page
    adds ~0.027 ms (< 0.01% of a 50–500 ms render).
  • Zero new DB queries on pages without template/pattern videos; the wp_footer callback
    early-returns when nothing was collected.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions