Skip to content
← Oleksii Turovskyi
Work in progressSEOv3.0.3GPL-2.0-or-later

Yoast Video SEO Booster

Get embedded YouTube and Vimeo videos out of Search Console's "video is not the main content" bucket — with a Yoast-integrated video sitemap and a dedicated watch page per video.

  • Get embedded videos out of Search Console's "not the main content" bucket
  • /video-sitemap.xml registered as a Yoast Sitemap Provider
  • Dedicated watch page per video — the video is the only content on the URL Google indexes
  • Schema.org VideoObject JSON-LD on every page that contains a video
WordPress
6.0+
PHP
8.0+
Required plugins
Yoast SEO (wordpress-seo)

The problem

You embed a YouTube video in a blog post. Months later, you open Search Console's Video indexing report — and the video is sitting under "Not indexed" with the reason "Video is not the main content of the page".

This is the single most common Video SEO failure on WordPress, and it has two roots:

  1. Yoast SEO does not generate a video-sitemap.xml. Without it, Google has to discover the video through on-page heuristics — fine for a video-first site, useless for a blog where every post is mostly text with a video embedded somewhere in the middle.
  2. Even when Google finds the video, it weighs it against the page. On a 1,500-word post, Google decides the text is the main content and the embedded video is decorative. The page won't appear in the video carousel, and Search Console flags it accordingly.

The plugin attacks both halves at once:

  1. It generates video-sitemap.xml and registers it as a Yoast Sitemap Provider, so it appears under /sitemap_index.xml next to post-sitemap.xml and page-sitemap.xml. Each <video:video> entry carries the fields Google's video crawler actually reads — thumbnail_loc, duration, content_loc, player_loc, publication_date, channel info from the YouTube Data API.
  2. For every discovered video it creates a virtual watch page at /video-watch-page/?video_id=… where the embedded video is the only meaningful content on the page. That URL is what ends up in the video sitemap as <loc>, and that URL is what Google indexes as the canonical "video page". The original blog post stays indexed for text search — separately, on its own URL.

Net effect: instead of one URL that Google can't decide what to do with, you ship two — a text page that ranks for text queries, and a watch page that ranks for video queries.

What it does today

It finds the videos. Post content is scanned for YouTube and Vimeo oEmbed URLs and plain links, the [yv_video] shortcode, raw <video> and <source> tags, and ACF fields of type oembed, url, text and file. Local media discovery is opt-in. Whatever the source, a detected video becomes one immutable value object carrying the fields the sitemap needs, so a third hosted provider is a new adapter rather than another branch in the detector.

It fills in what the embed does not tell you. With a YouTube Data API key you get title, description, thumbnail, duration, uploader and publication date — the fields Google's video crawler actually reads. Vimeo goes through the public API. A per-post metabox covers the rest: duration fallback, rating, view count, and a live-broadcast flag.

It publishes a real video sitemap. /video-sitemap.xml is registered as a Yoast Sitemap Provider, so it appears inside /sitemap_index.xml alongside post-sitemap.xml rather than floating somewhere Google has to be told about separately.

It gives each video a page of its own. The virtual watch page at /video-watch-page/?video_id=… carries one video and nothing to compete with it, and that is the URL the sitemap points at. Keeping it there takes four Yoast filters working together: the watch page is excluded from the regular sitemaps via wpseo_exclude_from_sitemap_by_post_ids, while wpseo_canonical, wpseo_opengraph_url and wpseo_robots are rewritten so the canonical, the OpenGraph URL and the robots directive all describe the watch page instead of whatever Yoast inferred. Get one of those wrong and you have built a duplicate of the host post.

VideoObject and WatchAction nodes are injected into Yoast's own schema graph through wpseo_schema_graph, so there is one graph on the page rather than two scripts contradicting each other. A one-click re-index tool in settings rebuilds detection across the library.

Build details

  • WordPress 6.0+, PHP 8.0+, hard dependency on Yoast SEO (wordpress-seo)
  • PSR-4 under AlexTur\YoastVideoSeoBooster\
  • Hosted-video metadata sits behind a VideoMetadataProvider interface with YouTube and Vimeo adapters
  • Five _yvsb_* post meta keys, all reached through one VideoPostMeta accessor
  • A yvsb_video_sitemap_item_properties filter for third parties adding their own <video:*> properties
  • Self-hosted updates via Plugin Update Checker v5

Known gap

The Vimeo adapter caches metadata per video for a day. The YouTube adapter does not cache at all — every sitemap rebuild re-fetches each video from the Data API. On a library of a dozen videos nobody notices; on a few hundred it is the difference between a rebuild being free and a rebuild eating quota. Closing that gap is the next thing worth doing here.

Where it stands

Shipped and stable at v3.0.3. The full case study — in particular how the watch page stays out of Yoast's regular sitemaps while keeping its own canonical — is not written yet. If you want the plugin before then, get in touch.

FAQ

Why doesn't Google index videos embedded in WordPress blog posts by default?

Two reasons. First, Yoast SEO doesn't generate a video sitemap — Google has to discover videos via on-page heuristics. Second, on a long blog post, Google decides the surrounding text is the main content and the embedded video is decorative, so the video lands in Search Console under "Video is not the main content of the page". This plugin fixes both: a proper video sitemap and a dedicated watch page where the video is the only content.

Does this plugin replace Yoast SEO?

No — it requires Yoast SEO to be active. It hooks into Yoast's Sitemap Provider API and the Yoast indexable system to register the video sitemap and inject canonical/OpenGraph signals for the virtual watch page.

How are videos discovered?

The plugin scans post content for YouTube/Vimeo oEmbed URLs and direct links, the [yv_video] shortcode, raw <video> and <source> tags, and ACF fields of type oembed/url/text/file. Local-video discovery is opt-in.

Do I need a YouTube Data API key?

It's optional but recommended. With a key, video-sitemap.xml includes title, description, thumbnail, duration, channel name, and publish date — all fields Google uses to rank video results.

How many API calls does a sitemap rebuild cost?

Vimeo metadata is cached as a transient per video for a day, so a rebuild costs nothing after the first pass. YouTube is not cached yet — every rebuild re-fetches each video from the Data API, which matters once you are past a few dozen videos and are watching your quota. Caching the YouTube provider the way the Vimeo one already is remains open work.

View as Markdown · for AI agents and offline reading

Other plugins

Other tools

Not a WordPress site? I also ship Chrome extensions — small browser utilities for SEO, AI workflows, and research.