【WordPress×ACF】YouTube動画をモーダル表示で軽量埋め込み

Youtube

YouTube動画をWordPressサイトに埋め込むと、表示速度の低下やSEOスコアの悪化を引き起こすことがあります。特にモバイルではLCPやCLSに悪影響を及ぼすため注意が必要です。

この記事では、Advanced Custom Fields(ACF)とJavaScriptを使って、YouTube動画をクリック時にモーダル表示する方法を解説します。

目次

実装イメージ

Youtube動画のサムネイルを表示させ、それをクリックすると動画のモーダルウィンドウが表示されます。
iPhone以外なら自動再生されます。

(ちなみにこの動画は、私のアート作品になります)

この実装のSEOメリット

  • 初期表示にiframeを読み込まない → ページ高速化
  • 画像はloading=”lazy”で遅延読込 → LCP(Largest Contentful Paint)改善
  • サムネイルに固定サイズを指定 → CLS(Cumulative Layout Shift)対策
  • 動画はクリックされたときだけ再生 → JSでiframeを生成

実装の概要

  • ACFで最大6個までYouTube IDを登録
  • PHPでサムネイルを出力(imgは、youtubeのサムネイル画像)
  • JavaScriptでクリック時にポップアップでiframeを差し替え再生

1.ACFフィールドの設定

Youtube動画を6つまで設定できるようにしています。

  • フィールド名:youtube_id_post1 ~ youtube_id_post6
  • タイプ:テキスト
  • 入力値:YouTubeの動画ID(例: dQw4w9WgXcQ)
  • 手順:https://www.youtube.com/watch?v=〇〇〇〇〇〇 の〇部分を入力
ACF設定画面(全般)
ACF設定画面(プレゼンテーション)

2.PHPコード:サムネイル表示+動画再生ボタン出力

<?php
// YoutubeのACFに入力がある時は、Youtubeを表示
for ($i = 1; $i <= 6; $i++) {
	$youtube_id_post = get_field('youtube_id_post' . $i);

	if ($youtube_id_post):
		// Youtubeのサムネイル画像URLを取得
		$thumbnail_url = 'https://img.youtube.com/vi/' . $youtube_id_post . '/hqdefault.jpg';
?>

		<div class="p-single-youtube p-single-youtube--post<?php echo $i; ?>">
			<button class="p-single-youtube__video js-button-youtube" data-video="<?php echo esc_attr($youtube_id_post); ?>" data-start="0">
				<img class="youtube-img" src="<?php echo esc_url($thumbnail_url); ?>" alt="<?php the_title_attribute(); ?>" width="720" height="404" loading="lazy" />
			</button>
		</div>

<?php
	endif;
}
?>

3.JavaScriptでYouTubeiframeを後から挿入

  // モーダルYoutube処理
  const modalYoutube = () => {
    const modal = document.querySelector(".js-modal-youtube");
    const modalClose = document.querySelectorAll(
      ".js-modal-close, .js-modal-bg"
    );
    const btnMovie = document.querySelectorAll(".js-button-youtube");
    const videoIframe = document.querySelector(".p-modal__player iframe");
    let videoUrl, videoId, videoStart;

    function videoPlay(id, start) {
      videoUrl = `https://www.youtube.com/embed/${id}?autoplay=1&rel=0&playsinline=1&start=${start}`;
      videoIframe.setAttribute("src", videoUrl);
    }

    function videoStop() {
      videoIframe.setAttribute("src", "");
    }

    // ボタンをクリックして、モーダルウィンドウを表示
    btnMovie.forEach((btn) => {
      btn.addEventListener("click", () => {
        videoId = btn.getAttribute("data-video");
        videoStart = btn.getAttribute("data-start");
        modal.style.display = "block";
        setTimeout(() => modal.classList.add("is-show"), 10);
        videoPlay(videoId, videoStart);
      });
    });

    // モーダルウィンドウを閉じる
    modalClose.forEach((btn) => {
      btn.addEventListener("click", () => {
        modal.classList.remove("is-show");
        setTimeout(() => {
          modal.style.display = "none";
          videoStop();
        }, 500);
      });
    });
  };

  window.addEventListener("DOMContentLoaded", () => {
    modalYoutube();
  });

4.ボタン部分とモーダル部分のCSS

ボタン部分

.p-single-youtube {
  position: relative;

  &__video {
    position: relative;
    width: 100%;
    height: 0;
    padding-bottom: 56.11%; // 404/720*100%

    display: block;
    position: relative;
    cursor: pointer;
    margin: 40px 0;

    img {
      position: absolute;
      top: 0;
      left: 0;
      object-fit: cover;
      width: 105%; //Youtubeの上下の黒帯を隠すために大きめに設定
      height: 100%;
      &::after {
        content: "";
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: #acacac;
        opacity: 0.5;
        //乗算
        mix-blend-mode: multiply;
      }
    }

    // ボタン部分(擬似クラスで追加)
    &::before,
    &:after {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      z-index: 100;
      margin: auto;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    &::before {
      content: "再生";
      overflow: hidden;
      text-indent: -9999px;
      width: 6.2rem;
      aspect-ratio: 1/1;
      border: 1px solid #fff;
      border-radius: 50%;
      color: transparent;
    }
    &::after {
      content: "";
      border-color: transparent;
      border-style: solid;
      border-left-color: #fff;
      border-width: 1.325rem 0 1.325rem 2.1625rem;
      width: 0.05rem;
      height: 0.05rem;
    }
  }
}

モーダル部分

/*
 * モーダルウィンドウ
 */

.p-modal {
  text-align: center;
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100%;
  z-index: 10000;
  display: none;
  overflow-y: auto;
  -ms-scroll-chaining: none;
  overscroll-behavior: contain;
  /*クリックアニメーション*/
  display: none; //初期値として入れておく
  opacity: 0;
  transition: opacity 0.5s ease;

  /*クリックしたらクラスを追加*/
  &.is-show {
    opacity: 1;
  }

  &__bg {
    position: absolute;
    top: 0;
    left: 0;
    width: 100vw;
    height: calc(100vh + 1px);
    background: rgba(0, 0, 0, 0.4);
    z-index: 1;
  }

  &__inner {
    position: absolute;
    top: 50%;
    left: 50%;
    height: auto;
    width: calc(100% - 160px);
    max-width: 1037px;
    transform: translate(-50%, -50%);
    z-index: 2;

    @media screen and (max-width: 750px) {
      width: 100%;
    }

    &::after {
      content: "";
      display: block;
      width: 100%;
      padding-top: 56.25%;
    }
  }

  &__player {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;

    iframe,
    video {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
    }
    iframe {
      border: none;
    }
  }

  &__close {
    width: 29px;
    font-size: 40px;
    color: #fff;
    position: absolute;
    top: -44px;
    right: -52px;
    background-color: transparent;
    cursor: pointer;

    @media screen and (max-width: 750px) {
      top: -50px;
      right: 15px;
    }
    &-icon {
      position: relative;
      overflow: hidden;
      text-indent: -9999px;
      display: block;

      &::before,
      &::after {
        content: "";
        position: absolute;
        top: 50%;
        left: 50%;
        width: 1px; // 棒の幅(太さ)
        height: 30px; // 棒の高さ
        background: #fff;
      }
      &::before {
        transform: translate(-50%, -50%) rotate(45deg);
      }
      &:after {
        transform: translate(-50%, -50%) rotate(-45deg);
      }
    }
  }
}

補足:SEO対策として意識したポイント

対策内容説明
loading=”lazy”サムネイル画像の遅延読込でLCP改善
iframeを遅延読み込みJSで挿入することで初期描画を妨げない
固定サイズ指定CLSを防止するため、width と height を明示
alt に記事のタイトルを出力画像の代替テキストにもSEO的意味を持たせる

まとめ

YouTube動画をページ内に複数埋め込む場合でも、このような「サムネイル+クリック再生型」の実装にすることで、以下のメリットが得られます。

  • 高速表示(PageSpeedスコア向上)
  • ユーザー体験の向上(遅延読込・安定した表示)
  • 動画IDの再利用や更新が簡単(ACF連携)

YouTube埋め込みの最適化は、メディアを多用するサイトでは必須の技術です。WordPressとACFを使うことで、更新性も高く、クライアントにもやさしい構成にできます。

Youtube

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
目次