Amazon10/19まで!プライム感謝祭開催中! セール会場へ

WordPress│ギャラリーブロックをカルーセル付スライダー表示にする方法│Swiper

WordPressのギャラリーブロックを、Swiperの大きな画像とサムネイルボタンで切り替える表示にします。指定したギャラリーだけが対象で、前後ボタンとTab・Enter・Spaceで操作できます。自動再生は行いません。

著者

WEB制作をしているデジタルノマド
WordPressのカスタマイズが好きで、色々と自作しています。

WordPressのカスタマイズに困ったらご相談ください!

動くサンプル

サムネイルを押すと選んだ画像に切り替わります。端の前後ボタンは無効になります。画像が2枚未満の場合やSwiperを読み込めない場合は、元のギャラリーを残します。

複数設置と1枚だけのギャラリー

上の6枚の見本と、この2枚の見本は、それぞれ別のボタンで切り替わります。操作するギャラリーを区別できるよう、生成する領域にはページ内の順番を付けています。JSはページに一度だけ読み込み、ギャラリーごとに追加CSSクラスを指定します。

次は画像1枚のギャラリーです。2枚未満ではスライダーを作らず、元のギャラリー表示を残します。

公開見本ではSWELL 2.19.0同梱のSwiper 7.0.6を使用しています。1280px幅と390px幅で、片方の画像を変えてももう片方の選択が変わらないこと、前後・サムネイルのEnter・Space操作、画像1枚の通常表示を確認しました。下のPHP例で固定しているCDN版11.2.10の子テーマへの導入は、この公開見本とは別の確認が必要です。

WAZA公開見本の2番目のギャラリー。1枚目Cを選択したサムネイルと、その下の1枚だけの通常ギャラリーE。
2026年10月2日撮影。SWELL 2.19.0同梱のSwiper 7.0.6、390px幅。2つのギャラリーを独立操作した状態。

貼り付け先と適用範囲

子テーマに waza-gallery.js と waza-gallery.css を作成し、下のJS・CSSをそれぞれ保存します。functions.phpにはPHP例を一度だけ追加してください。既存のSwiper読み込みコードと旧carousel用コードは併用せず、導入前にファイルをバックアップします。PHP開始タグの内側へ貼り、開始タグを重複させないでください。

ギャラリーブロックの「高度な設定 → 追加CSSクラス」に waza-gallery-slider u-lb-off を入力します。画像リンクは「なし」にします。u-lb-offはSWELLの画像拡大を止めるクラスです。この例は画像専用で、キャプションや画像リンクをスライダーへ引き継ぎません。通常のページ読み込みを対象とし、Pjaxや後から追加するブロックは対象外です。

Swiperとファイルを読み込むPHP

この例ではSwiper 11.2.10を固定して読み込みます。CDNへのアクセスが必要です。テーマや別のプラグインがSwiperを使うページでは二重読み込みの影響を検証し、必要なら既存の依存関係へ統合してください。

add_action('wp_enqueue_scripts', function () {
    if (!is_singular()) return;
    wp_enqueue_style('waza-swiper', 'https://cdn.jsdelivr.net/npm/swiper@11.2.10/swiper-bundle.min.css', array(), '11.2.10');
    wp_enqueue_script('waza-swiper', 'https://cdn.jsdelivr.net/npm/swiper@11.2.10/swiper-bundle.min.js', array(), '11.2.10', true);
    wp_enqueue_style('waza-gallery', get_stylesheet_directory_uri() . '/waza-gallery.css', array('waza-swiper'), '1.0');
    wp_enqueue_script('waza-gallery', get_stylesheet_directory_uri() . '/waza-gallery.js', array('waza-swiper'), '1.0', true);
});

ギャラリーごとに初期化するJavaScript

(() => {
  function start() {
    if (typeof window.Swiper !== 'function') return;
    document.querySelectorAll('.wp-block-gallery.waza-gallery-slider').forEach((gallery, galleryIndex) => {
      if (gallery.dataset.wazaReady) return;
      const sources = [...gallery.querySelectorAll('figure.wp-block-image img')];
      if (sources.length < 2) return;
      const root = document.createElement('section');
      root.className = 'waza-gallery-view u-lb-off';
      root.setAttribute('aria-label', `${galleryIndex + 1}番目の画像ギャラリー`);
      const stage = document.createElement('div');
      stage.className = 'swiper';
      const wrapper = document.createElement('div');
      wrapper.className = 'swiper-wrapper';
      const thumbs = document.createElement('div');
      thumbs.className = 'waza-gallery-thumbs';
      const buttons = [];
      const makeButton = label => {
        const b = document.createElement('button'); b.type = 'button'; b.textContent = label; return b;
      };
      sources.forEach((source, index) => {
        const img = new Image();
        img.src = source.getAttribute('data-lazy-src') || source.currentSrc || source.src;
        img.alt = source.alt; img.loading = 'eager'; img.setAttribute('data-luminous', 'off');
        const slide = document.createElement('div'); slide.className = 'swiper-slide'; slide.append(img);
        wrapper.append(slide);
        const b = makeButton(String(index + 1));
        b.setAttribute('aria-label', `${index + 1}枚目を表示`);
        const thumb = img.cloneNode(); thumb.alt = ''; b.replaceChildren(thumb);
        thumbs.append(b); buttons.push(b);
      });
      stage.append(wrapper);
      const controls = document.createElement('div'); controls.className = 'waza-gallery-controls';
      const prev = makeButton('前の画像'), next = makeButton('次の画像');
      const status = document.createElement('span'); status.setAttribute('aria-live', 'polite');
      controls.append(prev, status, next); root.append(stage, controls, thumbs); gallery.before(root);
      let slider;
      try {
        slider = new Swiper(stage, { slidesPerView: 1, spaceBetween: 16, loop: false,
          speed: window.matchMedia('(prefers-reduced-motion: reduce)').matches ? 0 : 300,
          a11y: { enabled: true, slideLabelMessage: '{{index}} / {{slidesLength}}' } });
        const sync = () => {
          const i = slider.activeIndex;
          status.textContent = `${i + 1} / ${sources.length}`;
          prev.disabled = i === 0; next.disabled = i === sources.length - 1;
          buttons.forEach((b, j) => b.setAttribute('aria-pressed', String(i === j)));
        };
        prev.addEventListener('click', () => slider.slidePrev());
        next.addEventListener('click', () => slider.slideNext());
        buttons.forEach((b, i) => b.addEventListener('click', () => slider.slideTo(i)));
        slider.on('slideChange', sync); sync();
        gallery.dataset.wazaReady = '1'; gallery.hidden = true;
      } catch (error) {
        if (slider) slider.destroy(true, true);
        root.remove(); console.warn('ギャラリーを通常表示に戻しました。', error);
      }
    });
  }
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start, { once: true });
  else start();
  window.addEventListener('load', start, { once: true });
})();

このスライダーだけに適用するCSS

.wp-block-gallery.waza-gallery-slider[hidden] { display: none !important; }
.waza-gallery-view { max-width: 100%; margin-block: 1.5em; }
.waza-gallery-view .swiper { width: 100%; overflow: hidden; }
.waza-gallery-view .swiper-slide img { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: contain; }
.waza-gallery-controls { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-block: 12px; }
.waza-gallery-view button { min-height: 44px; padding: 8px; border: 1px solid currentColor; background: #fff; color: #222; cursor: pointer; }
.waza-gallery-view button:disabled { opacity: .45; cursor: default; }
.waza-gallery-view button:focus-visible { outline: 3px solid #865d00; outline-offset: 2px; }
.waza-gallery-thumbs { display: flex; gap: 8px; overflow-x: auto; padding: 5px; }
.waza-gallery-thumbs button { flex: 0 0 72px; }
.waza-gallery-thumbs img { display: block; width: 100%; height: 40px; object-fit: cover; }
.waza-gallery-thumbs [aria-pressed="true"] { border: 3px solid #865d00; }

確認と戻し方

PC・スマートフォン幅で画像とボタンを確認し、Tabでサムネイルへ移動してEnterまたはSpaceを押します。複数ギャラリーを置く場合はそれぞれが独立して切り替わることも確認してください。動きを減らす設定では切り替え時間を0にします。

戻す場合はギャラリーのwaza-gallery-sliderクラスと今回追加したPHPを外します。元の画像ブロックは保持しています。キャッシュを更新して通常のギャラリーに戻ったことを確認してください。

記事カードを並べるスライダーは、次の記事を参照してください。

実装の参照先:Swiper API、WordPressのスクリプト読み込み。旧GitHubサンプルは今回の修正と同期していないため、このページのコードを使用してください。

スマートフォン幅での表示例

2026年10月1日に公開サンプルを390px幅で撮影しました。サムネイルの枠が現在の選択を示します。実機のタッチ操作や画面読み上げは別途確認が必要です。

WAZAの実画面。スマートフォン幅のスライダーと選択中のサムネイル。

初期化処理は、DOMとSwiperの代役を使ったローカルテストでも確認しました。ライブラリがない場合は元画像を残し、初期化例外では作りかけの表示だけを取り除きます。動きを減らす条件を代役で指定した場合は切り替え速度が0になりました。この確認は実ブラウザーのCDN障害やOSの設定操作を再現したものではありません。

目次

よくある質問:ギャラリーブロックをカルーセル付きスライダー表示にする方法(Swiper)

このスライダーは、どんな表示になりますか?

記事では、WordPressのギャラリーブロックを、Swiperの大きな画像とサムネイルボタンで切り替える表示にします。指定したギャラリーだけが対象で、前後ボタンとTab・Enter・Spaceで操作できます。自動再生は行いません。端の前後ボタンは無効になります。

画像が1枚のときや、Swiperが読み込めないときは?

記事では、画像が2枚未満の場合やSwiperを読み込めない場合は、元のギャラリーを残します。ライブラリがない場合は元画像を残し、初期化例外では作りかけの表示だけを取り除きます。

同じページに、複数のギャラリーを置けますか?

記事では、複数設置でき、それぞれが別のボタンで独立して切り替わります。操作するギャラリーを区別できるよう、生成する領域にはページ内の順番を付けています。JSはページに一度だけ読み込み、ギャラリーごとに追加CSSクラスを指定します。複数ギャラリーを置く場合は、それぞれが独立して切り替わることも確認してください。

ファイルは、どこに置きますか?

記事では、子テーマにwaza-gallery.jsとwaza-gallery.cssを作成し、記事のJS・CSSをそれぞれ保存します。PHPでSwiperとファイルを読み込みます。Swiperを使うページでは二重読み込みの影響を検証し、必要なら既存の依存関係へ統合してください。

SWELLに同梱のSwiperと、PHP例のSwiperは同じですか?

記事では、公開見本ではSWELL 2.19.0同梱のSwiper 7.0.6を使用しています。PHP例で固定しているCDN版11.2.10の子テーマへの導入は、この公開見本とは別の確認が必要です。

動きを減らす設定の場合は、どうなりますか?

記事では、動きを減らす設定では切り替え時間を0にします。動きを減らす条件を代役で指定した場合は切り替え速度が0になりましたが、この確認は実ブラウザーのCDN障害やOSの設定操作を再現したものではありません。

元に戻すには、どうしますか? 確認の範囲は?

戻す場合はギャラリーのwaza-gallery-sliderクラスと今回追加したPHPを外します。記事では、元の画像ブロックは保持しており、キャッシュを更新して通常のギャラリーに戻ったことを確認してください。確認は1280px幅と390px幅の公開見本で、実機のタッチ操作や画面読み上げは別途確認が必要です。旧GitHubサンプルは今回の修正と同期していないため、このページのコードを使用してください。最新は公式で確認してください。

  • URLをコピーしました!

実装を任せたい方へ

WordPressのカスタマイズ代行

ブロックの追加、テーマの改修、管理画面の調整など、記事で紹介している内容の実装を承ります。1時間 ¥8,000〜(税込)。

WAZAの有料記事のサブスクリプションも開始しました。

サービス

Service

WordPressサイトのカスタマイズのサービスに関心がありましたら、ぜひ詳細をご覧ください。

目次