リッチザルトテスト
動画の構造化データ・mRSS・video sitemap の自動生成 は。Search Console 動画がメインコンテンツでない時の対処法です。
「動画がメインコンテンツでない」とSearch Consoleで動画がインデックスされない場合があります。
次の場合は、動画がメインコンテンツとみなされず、動画がインデックスされない可能性があります。
- 動画がページの主なコンテンツではなくテキストを補完するものであるブログ投稿
- 補完的な動画を含む商品の詳細ページ
- 複数の動画を同等の視認性で一覧表示している動画カテゴリページ
ページはインデックスされてるが動画がメインコンテンツでなければインデックスされない。
記事の抜粋は100文字程度
記事の抜粋
「このページには動画がありますよ」と明確に伝えることが大事で、Search Consoleの「動画ページ」のインデックスのせるための構造化データを追加する必要があります。
「動画サイトマップ」または「 MRSSフィード」を作成して、Googleに動画情報を明確に認識させます。
動画をインデックスさせるには、動画サイトマップまたはMRSSフィードを送信してください。
gooogle
インデックスさせるために、次の3つの方法で動画コンテンツであることをGoogleに伝えます。
| 構造化データ | 各記事の <head> に自動挿入 | Google検出 |
| mRSSフィード | mrss.xml など | 更新情報を届ける |
| video-sitemap | video-sitemap.xml など | Search Console登録 |
| サイトマップ | sitemap.xml など※ | Search Console登録 |
※yoast のサイトマップはhttps://ドメイン/sitemap_index.xml
「video-sitemap」「mRSSフィード」でGoogle・検索エンジンに動画があることを伝え、「構造化データ」で動画の必要項目を伝えます。
「video-sitemap」「mRSSフィード」「構造化データ」の自動生成コードを functions.php などに記述しますが、記述後の動作確認の方法は以下の通りです。
| 確認する場所 | 確認 | |
|---|---|---|
| 構造化データ | 動画投稿ページ<head>内 | VideoObject を確認 |
| mRSSフィード | /video-feed/ | <rss> が表示される |
| 動画サイトマップ | /video-sitemap.xml | <sitemapindex> が表示される |
※mRSSフィードのURLは /video-feed/ や /?feed=mrss 動画サイトマップは /video-sitemap.xml ですがコードの記述によって、URLは変わります。
下記の「video-sitemapとmRSSフィードのコード」では次の通り設定しています。
構造化データ生成コードやmRSSフィード・video-sitemap 生成コードを貼った後に、コードの動作確認します。その手順を先に説明しておきます。
VideoObject (動画の構造化データ)を確認します。
| テスト | テストするURL |
|---|---|
| リッチザルトテスト | サイトのURL |
| 構造化データテスト | 動画がある投稿のURL |
リッチザルトテスト
構造化データテスト
動画投稿ページ<head>内
この結果で、記述するコードが問題なく動いていることがわかります。
mRSSフィード は、世の中に動画や画像などメディアコンテンツがあることを発信するFeedで、動画サイトマップの代替手段にもなります。
ページが表示され、動画コンテンツ が出力されている。(もし404の場合は下記のリトライルールを再生成をしてみて下さい)
video sitemap を作り、Googleに動画のあるページであることを伝えます。
https://○○○/video-sitemap.xml でXMLが生成されるか確認する。(もし404の場合は下記のリトライルールを再生成をしてみて下さい)
<sitemapindex> が表示される
video sitemap や mRSSフィード を自動生成後に、そのURLを以下に登録します。
| video sitemap | Google Search Console へ登録する https://search.google.com/search-console |
| mRSSフィード | Bing Webmaster Tools へ登録する https://www.bing.com/webmasters |
video sitemap や mRSSフィード の確認で404になる場合の対処法です。
https://ドメイン/video-sitemap.xml →404になるhttps://ドメイン/mrss.xml →404になるリトライルールを再生成する
video-feed や mrss.xml にアクセスするvideo-feed や mrss.xml が表示されるGoogle Search Consoleに登録するサイトマップのURLの例
もしサイトマップを分割した場合
この場合はもGoogle Search Consoleに登録するサイトマップのURLは
Webページの構造を検索エンジン(Google)により分かりやすく伝えるためにHTMLにマークアップするコードを「構造化データ」と言います。
動画に、JSON-LD形式でVideoObject構造化データを挿入すること。
<head>に自動挿入動画をマークアップするのに必要な情報(構造化データ)
<script type=”application/ld+json”>
{
“@context”: “http://schema.org”,
“@type”: “VideoObject”,
“name”: “動画のタイトル”,
“description”: “動画の説明”,
“thumbnailUrl”: “http://img.youtube.com/〇〇〇.jpg /*動画のサムネイル*/ ”,
“uploadDate”: “2025-2-23T18:00:00+09:00 /*動画の公開日時*/ ”,
“duration”: “PT00H00M40S /*動画の長さ*/ ”,
“contentUrl”: “https://youtube.com/〇〇〇”,
“embedUrl”: “”,
“interactionStatistic”:: {
"@type": "InteractionCounter",
"interactionType": { "@type": "WatchAction" },
"userInteractionCount": 100 /*動画の視聴回数*/ },
}
</script> | name | 動画のタイトル(記事タイトルでも可) |
| description | 動画の説明 |
| thumbnailUrl | 動画のサムネイルURL |
| uploadDate | 動画の公開日時 |
| duration | 動画の再生時間 PT00H00M40S(ISO 8601形式) |
| contentUrl | https://youtube.com/〇〇〇(Youtube等) |
| embedUrl | contentUrl を使用できない場合 embedUrl を指定 https://youtube.com/embed/○○〇 |
このコードでできること
<head> にJSON-LD形式でVideoObjectを自動挿入(動画がある投稿のみ)img.youtube.com 利用)functions.php に追加する→<head>内に自動挿入される
// YouTube動画とショート動画の構造化データ
add_action('wp_head', function() {
if (!is_single()) return;
global $post;
$content = $post->post_content;
// YouTube埋め込みURLを抽出
if (!preg_match('/https?:\/\/(?:www\.)?(?:youtube\.com|youtu\.be)\/[^\s"\'<>]+/', $content, $match)) return;
$url = $match[0];
// 動画ID抽出
if (preg_match('/(?:v=|youtu\.be\/)([A-Za-z0-9_-]+)/', $url, $id_match)) {
$video_id = $id_match[1];
} else return;
// サムネイルURL
$thumbnail = "https://img.youtube.com/vi/{$video_id}/maxresdefault.jpg";
// サムネが存在しない場合 fallback
$headers = @get_headers($thumbnail);
if (!$headers || strpos($headers[0], '404') !== false) {
$thumbnail = "https://img.youtube.com/vi/{$video_id}/hqdefault.jpg";
}
// それでも404なら代替画像
$headers = @get_headers($thumbnail);
if (!$headers || strpos($headers[0], '404') !== false) {
$thumbnail = get_template_directory_uri() . '/no-thumbnail.jpg';
}
// duration の自動生成
// URL内に「shorts」が含まれていれば 59秒(PT59S)として扱う
$duration = (strpos($url, 'shorts') !== false) ? 'PT59S' : 'PT3M00S'; // デフォ3分
// 公開日と更新日
$uploadDate = get_the_date('c', $post);
$modDate = get_the_modified_date('c', $post);
// VideoObject構造化データの出力
$schema = [
"@context" => "https://schema.org",
"@type" => "VideoObject",
"name" => get_the_title($post),
"description" => wp_strip_all_tags(get_the_excerpt($post)),
"thumbnailUrl" => [$thumbnail],
"uploadDate" => $uploadDate,
"dateModified" => $modDate,
"contentUrl" => $url,
"embedUrl" => $url,
"duration" => $duration,
"publisher" => [
"@type" => "Organization",
"name" => get_bloginfo('name'),
"logo" => [
"@type" => "ImageObject",
"url" => get_site_icon_url()
]
]
];
echo "\n<script type='application/ld+json'>" . wp_json_encode($schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "</script>\n";
});
| 投稿・固定ページの 動画の構造化データ | add_action('wp_head', function() { |
| 動画のURL抽出 | if (!preg_match('/https?:\/\/(?:www\.)?(?: |
| 動画ID抽出 | if (preg_match('/(?:v=|youtu\.be\/)([A-Za-z0-9_-]+)/', $url, $id |
| サムネURL | /maxresdefault.jpg |
| サムネがない場合 | /hqdefault.jpg |
| 404の代替画像 | /no-thumbnail.jpg |
| duration | PT3M00S |
| shortsならば59秒 | (strpos($url, 'shorts') !== false) ? 'PT59S' |
| 公開日更新日 | get_the_date('c', $post) |
構造化データにはサムネイルと動画の再生時間が必要です。ショート動画はサムネがありません。次のコードではYouTube API を使わず、サムネイルを自動で取得できます。
functions.php
// YouTube動画・ショート動画の構造化データ生成
add_action('wp_head', function() {
if (is_single()) {
global $post;
// YouTube埋め込みURLを本文から取得
if (preg_match('/youtube\.com\/embed\/([a-zA-Z0-9_-]+)/', $post->post_content, $matches)) {
$video_id = $matches[1];
$title = esc_attr(get_the_title($post->ID));
$url = get_permalink($post->ID);
$uploadDate = get_the_date('c', $post->ID);
$desc = wp_strip_all_tags(get_the_excerpt($post->ID));
// サムネイルを最大 → hqdefault → デフォルト画像の順でチェック
$thumb_candidates = [
"https://img.youtube.com/vi/{$video_id}/maxresdefault.jpg",
"https://img.youtube.com/vi/{$video_id}/hqdefault.jpg",
"https://img.youtube.com/vi/{$video_id}/default.jpg",
];
$thumb = '';
foreach ($thumb_candidates as $t) {
$headers = @get_headers($t);
if ($headers && strpos($headers[0], '200') !== false) {
$thumb = $t;
break;
}
}
if (!$thumb) {
// サムネが存在しない場合のバックアップ画像(サイトロゴなど)
$thumb = get_site_icon_url() ?: 'https://via.placeholder.com/480x360?text=No+Thumbnail';
}
// duration(時間)を自動生成
// → "shorts"(ショート動画) とタイトル・URLを検出したら 60秒以内とみなす
if (strpos($post->post_content, '/shorts/') !== false || stripos($title, 'short') !== false) {
$duration = 'PT60S'; // ショート動画(最大1分)
} else {
$duration = 'PT180S'; // 通常動画(3分)
} | サムネイル自動取得 | maxresdefault → hqdefault → default の順にチェック |
| duration(再生時間) | /shorts/ や YouTubeショートURLを自動検出しdurationをPT59Sに設定 |
| 30秒 | PT30S |
| 5分 | PT5M00S |
//Youtube動画
if (preg_match('/https?:\/\/(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)([A-Za-z0-9_-]+)/', $content, $m)) {
//Youtubeショート動画
if (preg_match('/https?:\/\/(?:www\.)?(?:youtube\.com\/(?:watch\?v=|shorts\/)|youtu\.be\/)([A-Za-z0-9_-]+)/', $content, $m)) { このコードでできること
<footer> にJSON-LD形式でVideoObjectを自動挿入(動画がある投稿のみ)img.youtube.com 利用)テーマ:cocoon
functions.php に追加する→<footer>内に自動挿入される
※example.comはサイトのドメインに変更
// YouTube動画構造化データ自動出力
function cocoon_add_videoobject_jsonld() {
if (is_single()) {
global $post;
$content = $post->post_content;
// YouTube動画を検出(iframe で埋め込んでる場合)
if (preg_match('/youtube\.com\/embed\/([a-zA-Z0-9_-]+)/', $content, $matches)) {
$video_id = $matches[1];
$title = get_the_title();
$description = wp_strip_all_tags(get_the_excerpt());
$thumbnail = "https://i.ytimg.com/vi/{$video_id}/hqdefault.jpg";
$upload_date = get_the_date('c');
$publisher_name = get_bloginfo('name');
$publisher_logo = 'https://example.com/wp-content/uploads/logo.png'; // ← サイトのロゴURL
$videoobject = [
"@context" => "https://schema.org",
"@type" => "VideoObject",
"name" => $title,
"description" => $description,
"thumbnailUrl" => [$thumbnail],
"uploadDate" => $upload_date,
"embedUrl" => "https://www.youtube.com/embed/{$video_id}",
"contentUrl" => "https://www.youtube.com/watch?v={$video_id}",
"publisher" => [
"@type" => "Organization",
"name" => $publisher_name,
"logo" => [
"@type" => "ImageObject",
"url" => $publisher_logo
]
]
];
echo '<script type="application/ld+json">' .
wp_json_encode($videoobject, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) .
'</script>';
}
}
}
add_action('wp_footer', 'cocoon_add_videoobject_jsonld');
「VideoObject(動画)」が検出される。
/**
* 完全版 YouTube VideoObject 自動生成(ショート動画対応)
* - パラメータ付き embed URL でも100%動画IDを抽出
* - 重複URLなし(Googleインデックス最適化)
* - oEmbed API で動画情報取得
*/
function perfect_videoobject_single() {
if (!is_single()) return;
global $post;
$content = $post->post_content;
// パラメータ付き embed URL に完全対応
if (!preg_match('/youtube\.com\/embed\/([a-zA-Z0-9_-]+)(?=[\?"]|$)/', $content, $matches)) {
return; // 動画がない投稿はスキップ
}
$video_id = $matches[1];
$youtube_url = "https://www.youtube.com/watch?v={$video_id}";
$embed_url = "https://www.youtube.com/embed/{$video_id}";
// oEmbed で動画情報取得
$oembed_api = "https://www.youtube.com/oembed?url=" . urlencode($youtube_url) . "&format=json";
$response = wp_remote_get($oembed_api, ['timeout' => 5]);
if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) == 200) {
$oembed = json_decode(wp_remote_retrieve_body($response), true);
$title = $oembed['title'] ?? get_the_title();
$thumbnail = $oembed['thumbnail_url'] ?? "https://i.ytimg.com/vi/{$video_id}/hqdefault.jpg";
$description = wp_strip_all_tags(get_the_excerpt());
} else {
$title = get_the_title();
$thumbnail = "https://i.ytimg.com/vi/{$video_id}/hqdefault.jpg";
$description = wp_strip_all_tags(get_the_excerpt());
}
// Shorts / 縦動画判定(高さ > 横)
$duration = 'PT2M';
if (preg_match('/height="([0-9]+)".*width="([0-9]+)"/', $content, $dims)) {
if ($dims[1] > $dims[2]) $duration = 'PT1M';
}
$upload_date = get_the_date('c');
$publisher_name = get_bloginfo('name');
$publisher_logo = get_site_icon_url();
// VideoObject(Google最適化版)
$videoobject = [
"@context" => "https://schema.org",
"@type" => "VideoObject",
"name" => $title,
"description" => $description,
"thumbnailUrl" => [$thumbnail],
"uploadDate" => $upload_date,
"duration" => $duration,
// Google推奨:URLを1個に統一(重複なし)
"embedUrl" => $embed_url,
"contentUrl" => $youtube_url,
"url" => get_permalink(),
"inLanguage" => "ja",
"publisher" => [
"@type" => "Organization",
"name" => $publisher_name,
"logo" => [
"@type" => "ImageObject",
"url" => $publisher_logo
]
]
];
echo '<script type="application/ld+json">' .
wp_json_encode($videoobject, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) .
'</script>';
}
add_action('wp_footer', 'perfect_videoobject_single');
/**
* トップページ:最新3動画を VideoObject 化
*/function perfect_videoobject_home() {
if (!is_front_page()) return;
$query = new WP_Query([
'post_type' => 'post',
'posts_per_page' => 3,
'post_status' => 'publish'
]);
$videos = [];
while ($query->have_posts()) {
$query->the_post();
if (preg_match('/youtube\.com\/embed\/([a-zA-Z0-9_-]+)(?=[\?"]|$)/', get_the_content(), $m)) {
$video_id = $m[1];
$youtube_url = "https://www.youtube.com/watch?v={$video_id}";
$embed_url = "https://www.youtube.com/embed/{$video_id}";
// oEmbed取得
$oembed_api = "https://www.youtube.com/oembed?url=" . urlencode($youtube_url) . "&format=json";
$response = wp_remote_get($oembed_api, ['timeout' => 5]);
if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) == 200) {
$oembed = json_decode(wp_remote_retrieve_body($response), true);
$title = $oembed['title'] ?? get_the_title();
$thumbnail = $oembed['thumbnail_url'] ?? "https://i.ytimg.com/vi/{$video_id}/hqdefault.jpg";
$description = wp_strip_all_tags(get_the_excerpt());
} else {
$title = get_the_title();
$thumbnail = "https://i.ytimg.com/vi/{$video_id}/hqdefault.jpg";
$description = wp_strip_all_tags(get_the_excerpt());
}
$videos[] = [
"@context" => "https://schema.org",
"@type" => "VideoObject",
"name" => $title,
"description" => $description,
"thumbnailUrl" => [$thumbnail],
"uploadDate" => get_the_date('c'),
"duration" => "PT1M30S",
"embedUrl" => $embed_url,
"contentUrl" => $youtube_url,
"url" => get_permalink(),
"inLanguage" => "ja",
"publisher" => [
"@type" => "Organization",
"name" => get_bloginfo('name'),
"logo" => [
"@type" => "ImageObject",
"url" => get_site_icon_url()
]
]
];
}
}
wp_reset_postdata();
if ($videos) {
echo '<script type="application/ld+json">' .
wp_json_encode($videos, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) .
'</script>';
}
}
add_action('wp_head', 'perfect_videoobject_home');
/**
* LazyLoad 除外(CLS対策)
*/function perfect_lazyload_exclude() {
if (class_exists('LiteSpeed_Cache_API')) {
LiteSpeed_Cache_API::config([
'lazyload_img_excludes' => '.youtube, .video-container, .video',
'lazyload_iframe_excludes' => '.youtube, .video-container, .video',
]);
}
}
add_action('init', 'perfect_lazyload_exclude');
| 機能 | 効果 |
|---|---|
| VideoObject構造化データ | 検索結果で動画リッチリザルト表示 |
| Video Sitemap | Google動画検索等に掲載されやすくなる |
| mRSS Feed | 検索エンジン最適化 |
このコードでできること
functions.php に追加する
// Video Sitemap と mRSS Feed 自動生成
// YouTube ID 抽出関数
function extract_youtube_id_from_post($content) {
if (preg_match('/youtube\.com\/embed\/([a-zA-Z0-9_-]+)/', $content, $matches)) {
return $matches[1];
}
return false;
}
// 動画サイトマップ出力
function generate_video_sitemap() {
$output = '<?xml version="1.0" encoding="UTF-8"?>';
$output .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">';
$query = new WP_Query([
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => 1000,
]);
while ($query->have_posts()) {
$query->the_post();
$video_id = extract_youtube_id_from_post(get_the_content());
if ($video_id) {
$url = esc_url(get_permalink());
// HTML実体参照をUTF-8文字に変換してからエスケープ
$title = esc_html( html_entity_decode( get_the_title(), ENT_QUOTES, 'UTF-8' ) );
$desc = esc_html( html_entity_decode( wp_strip_all_tags( get_the_excerpt() ), ENT_QUOTES, 'UTF-8' ) );
$thumbnail = esc_url("https://i.ytimg.com/vi/{$video_id}/hqdefault.jpg");
$embed = esc_url("https://www.youtube.com/embed/{$video_id}");
$pub = get_the_date('c');
$output .= "<url>";
$output .= "<loc>{$url}</loc>";
$output .= "<video:video>";
$output .= "<video:thumbnail_loc>{$thumbnail}</video:thumbnail_loc>";
$output .= "<video:title>{$title}</video:title>";
$output .= "<video:description>{$desc}</video:description>";
$output .= "<video:player_loc allow_embed='yes'>{$embed}</video:player_loc>";
$output .= "<video:publication_date>{$pub}</video:publication_date>";
$output .= "<video:family_friendly>yes</video:family_friendly>";
$output .= "</video:video>";
$output .= "</url>";
}
}
wp_reset_postdata();
$output .= '</urlset>';
return $output;
}
// mRSS出力(動画RSSフィード)
function generate_video_mrss() {
$output = '<?xml version="1.0" encoding="UTF-8"?>';
$output .= '<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/">';
$output .= '<channel>';
$output .= '<title>' . esc_html( get_bloginfo('name') . ' - Video Feed' ) . '</title>';
$output .= '<link>' . esc_url( home_url() ) . '</link>';
$output .= '<description>Video feed generated from posts with YouTube embeds.</description>';
$query = new WP_Query([
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => 1000,
]);
while ($query->have_posts()) {
$query->the_post();
$video_id = extract_youtube_id_from_post(get_the_content());
if ($video_id) {
$url = esc_url(get_permalink());
$title = esc_html( html_entity_decode( get_the_title(), ENT_QUOTES, 'UTF-8' ) );
$desc = esc_html( html_entity_decode( wp_strip_all_tags( get_the_excerpt() ), ENT_QUOTES, 'UTF-8' ) );
$thumb = esc_url("https://i.ytimg.com/vi/{$video_id}/hqdefault.jpg");
$video = esc_url("https://www.youtube.com/watch?v={$video_id}");
$pub = get_the_date('r');
$output .= "<item>";
$output .= "<title>{$title}</title>";
$output .= "<link>{$url}</link>";
$output .= "<description>{$desc}</description>";
$output .= "<media:thumbnail url='{$thumb}' />";
$output .= "<media:content url='{$video}' medium='video' />";
$output .= "<pubDate>{$pub}</pubDate>";
$output .= "</item>";
}
}
wp_reset_postdata();
$output .= '</channel></rss>';
return $output;
}
// URLルールを追加
function add_custom_video_feeds() {
add_rewrite_rule('video-map\.xml$', 'index.php?video_sitemap=1', 'top');
add_rewrite_rule('video-mrss\.xml$', 'index.php?video_mrss=1', 'top');
}
add_action('init', 'add_custom_video_feeds');
// クエリ変数登録
function add_custom_video_query_vars($vars) {
$vars[] = 'video_sitemap';
$vars[] = 'video_mrss';
return $vars;
}
add_filter('query_vars', 'add_custom_video_query_vars');
// XML出力(テンプレートルート)
function custom_video_template_redirect() {
if (get_query_var('video_sitemap')) {
header('Content-Type: application/xml; charset=UTF-8');
echo generate_video_sitemap();
exit;
}
if (get_query_var('video_mrss')) {
header('Content-Type: application/rss+xml; charset=UTF-8');
echo generate_video_mrss();
exit;
}
}
add_action('template_redirect', 'custom_video_template_redirect', 1);
Video Sitemap のURL と mRSS Feed のURL を変更する場合は、上記のコードの「// URLルールを追加」の部分を変更します。
【例】/video-sitemap.xml にする場合
add_rewrite_rule('video-sitemap\.xml$', 'index.php?video_sitemap=1', 'top'); “thumbnailUrl”: “http://img.youtube.com/vi/〇〇〇.jpg”, “uploadDate”: “2025-2-23T18:00:00+09:00”, 下の①②の手順で公開日時を知ることができます。
YouTube動画の公開時刻を表示する Google Chrome の拡張機能
ショート動画の公開時間を調べる方法
| ショート動画 | https://www.youtube.com/shorts/ONiK0ywYiI8 |
| 通常の表示 | https://youtube.com/watch?v=ONiK0ywYiI8 |
DenCode (https://dencode.com/ja/date)を利用する
“duration”: “PT00H00M40S”,