クラシックエディタでフロート画像をラップする処理

Filed under: css,functions.php — kdcs @ 2025年9月23日 火曜日

クラシックエディター(TinyMCE)では画像を「右寄せ」や「左寄せ」にするとfloatが適用されるが、このfloatの解除方法がない。テキストエディタでタグ打ちができればclear: bothを挿入して解除できるが知識が必要。
ビジュアルエディタしか使えない場合、バック部ラウンドで処理する必要がある。

そこで、alignleftやalignrightが付与されたfloat画像をdivタグでラップしてクラスを付ける処理をする。

functions.php(クラスは、class=”imgWrapp”)
※デフォルトの投稿タイプ「post」にだけ適用する

正規表現ベースの軽量版

function wrap_aligned_images_lightweight($content) {
  if (!is_singular('post')) {
    return $content;
  }

  // <p>タグ内に複数のimgタグがあり、すべてがalignクラス付きならラップ
  $pattern = '/<p>\s*((?:<img[^>]+class="[^"]*\balign(?:left|right|center)\b[^"]*"[^>]*>\s*){1,})<\/p>/i';
  $replacement = '<div class="imgWrapp">$1</div>';

  return preg_replace($pattern, $replacement, $content);
}
add_filter('the_content', 'wrap_aligned_images_lightweight');

DOM 操作版(全ての要素をチェックするため処理不可が少しだけ増える 通常の投稿なら問題ないレベル)

function wrap_aligned_images_preserve_position($content) {
  if (!is_singular('post')) {
    return $content;
  }

  libxml_use_internal_errors(true);

  $html = '<?xml encoding="UTF-8"><body>' . $content . '</body>';
  $dom = new DOMDocument('1.0', 'UTF-8');
  $dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

  $bodyList = $dom->getElementsByTagName('body');
  if ($bodyList->length === 0) return $content;

  $body = $bodyList->item(0);
  $newBody = $dom->createDocumentFragment();

  foreach ($body->childNodes as $node) {
    if ($node->nodeType === XML_ELEMENT_NODE && $node->tagName === 'p') {
      $imgNodes = [];
      foreach ($node->childNodes as $child) {
        if ($child->nodeType === XML_ELEMENT_NODE && $child->tagName === 'img') {
          $class = $child->getAttribute('class');
          if (preg_match('/align(left|right|center)/', $class)) {
            $imgNodes[] = $child;
          }
        }
      }

      if (count($imgNodes) > 0 && count($node->childNodes) === count($imgNodes)) {
        $wrapper = $dom->createElement('div');
        $wrapper->setAttribute('class', 'imgWrapp');
        foreach ($imgNodes as $img) {
          $wrapper->appendChild($img->cloneNode(true));
        }
        $newBody->appendChild($wrapper);
      } else {
        $newBody->appendChild($node->cloneNode(true));
      }
    } else {
      $newBody->appendChild($node->cloneNode(true));
    }
  }

  $body->nodeValue = '';
  $body->appendChild($newBody);

  $new_content = '';
  foreach ($body->childNodes as $child) {
    $new_content .= $dom->saveHTML($child);
  }

  return $new_content;
}
add_filter('the_content', 'wrap_aligned_images_preserve_position');

cssでimgWrappにflexboxを適用する
画像は最大横幅270pxを設定してwidth:100%でレスポンシブにも対応させる

/* 回り込み画像の処理ここから */
#main #singlePosts .imgWrapp {
  display: flex;
  gap: 10px;
  width: 100%;
}
#main #singlePosts img.alignleft,
#main #singlePosts img.alignright,
#main #singlePosts img.aligncenter {
    max-width: 270px;
    width: 100%;
    margin: 0;
    float: none;
}
/* 回り込み画像の処理ここまで */

GLightboxの導入方法

Filed under: functions.php,JavaScript — kdcs @ 2025年9月21日 日曜日

jQueryに依存しないlightbox「GLightbox」をWordPressに導入する方法

GLightboxのダウンロード先はこちら

ダウンロード後に解凍。必要なファイルはdistフォルダ内「glightbox.min.cssとglightbox.min.js」
オプション設定はcommon.js内で行う。

cdnでGLightboxのCSSとJSをテーマに読み込ませる
functions.php

function mytheme_enqueue_scripts() {
  // GLightboxのCSS
  wp_enqueue_style('glightbox-css', 'https://cdn.jsdelivr.net/npm/glightbox/dist/css/glightbox.min.css');

  // GLightboxのJS
  wp_enqueue_script('glightbox-js', 'https://cdn.jsdelivr.net/npm/glightbox/dist/js/glightbox.min.js', array(), null, true);

  // 初期化スクリプト
  wp_add_inline_script('glightbox-js', 'const lightbox = GLightbox({ selector: ".glightbox" });');
}
add_action('wp_enqueue_scripts', 'mytheme_enqueue_scripts');

オプション設定
common.js

const lightbox = GLightbox({
  selector: '.glightbox',
  touchNavigation: true,
  loop: true,
  zoomable: false,
});

画像のaタグに class=”glightbox” を自動で追加する
functions.php

function add_glightbox_class_to_image_links($content) {
  // aタグのhrefが画像ファイルの場合にclass="glightbox"を追加
  $content = preg_replace_callback(
    '/<a\s+([^>]*href=["\']([^"\']+\.(jpg|jpeg|png|gif|webp))["\'][^>]*)>/i',
    function($matches) {
      $tag = $matches[0];
      // すでにclass属性があるか確認
      if (strpos($tag, 'class=') !== false) {
        // class属性にglightboxを追加
        $tag = preg_replace('/class=["\']([^"\']*)["\']/', 'class="$1 glightbox"', $tag);
      } else {
        // class属性がない場合は追加
        $tag = str_replace($matches[0], '<a ' . $matches[1] . ' class="glightbox">', $tag);
      }
      return $tag;
    },
    $content
  );
  return $content;
}
add_filter('the_content', 'add_glightbox_class_to_image_links');

※画像ファイルの形式を「jpg|jpeg|png|gif|webp」にしているのでpdfファイルは除外される

デフォルトの投稿タイプpostの記事だけに適用する記述

function add_glightbox_class_to_image_links($content) {
  // デフォルト投稿タイプの個別ページのみ適用
  if (is_singular('post') && is_main_query() && in_the_loop()) {
    $content = preg_replace_callback(
      '/<a\s+([^>]*href=["\']([^"\']+\.(jpg|jpeg|png|gif|webp))["\'][^>]*)>/i',
      function($matches) {
        $tag = $matches[0];
        if (strpos($tag, 'class=') !== false) {
          $tag = preg_replace('/class=["\']([^"\']*)["\']/', 'class="$1 glightbox"', $tag);
        } else {
          $tag = str_replace($matches[0], '<a ' . $matches[1] . ' class="glightbox">', $tag);
        }
        return $tag;
      },
      $content
    );
  }
  return $content;
}
add_filter('the_content', 'add_glightbox_class_to_image_links');

・is_singular(‘post’):通常の投稿だけに限定
・is_main_query():メインクエリ(本文表示)だけに限定
・in_the_loop():WordPressループ内だけに限定
これで、固定ページやカスタム投稿、ウィジェットなどには影響せず、通常の投稿記事だけに glightbox クラスが追加されるようになる。

lightbox機能の速度はcssのanimationで行っている。
以下、アニメーションスピードのカスタマイズ

/*------------------------------------------------
  GLightbox css custom animation
--------------------------------------------------*/
.gfadeIn {
  -webkit-animation: gfadeIn 0.5s ease;
  animation: gfadeIn 0.5s ease !important;
}
.gfadeOut {
  -webkit-animation: gfadeOut 0.5s ease;
  animation: gfadeOut 0.8s ease !important;
}
.gzoomIn {
  -webkit-animation: gzoomIn 0.5s ease;
  animation: gzoomIn 0.5s ease !important;
}
.gzoomOut {
  -webkit-animation: gzoomOut 0.8s ease;
  animation: gzoomOut 0.8s ease !important;
}

【追記 2026.2.19】
カスタム投稿タイプに対応させる記述

/* ---------------------------------------------------------------------------------------
   ◆◆◆ クラシックエディタでフロート画像をラップする処理 ###############################
------------------------------------------------------------------------------------------*/
// カスタム投稿タイプ対応 (正規表現ベースの軽量版)--------------------------------------

function wrap_aligned_images_lightweight($content) {
  // post, custompost1, custompost2 の個別ページでのみ適用
  if (!is_singular(array('post', 'custompost1', 'custompost2'))) {
    return $content;
  }

  $pattern = '/<p>\s*((?:(?:<a[^>]*>\s*)?<img[^>]+class="[^"]*\balign(?:left|right|center)\b[^"]*"[^>]*>(?:\s*<\/a>)?\s*){1,})<\/p>/i';
  $replacement = '<div class="imgWrapp">$1</div>';

  return preg_replace($pattern, $replacement, $content);
}
add_filter('the_content', 'wrap_aligned_images_lightweight');

/* ---------------------------------------------------------------------------------------
   ◆◆◆ 投稿タイプの画像にaタグが付いていれば class="glightbox"を付与する ##############
------------------------------------------------------------------------------------------*/
// 【重要】この記述は上記の画像ラップ処理後に配置する必要がある **************************

function add_glightbox_class_to_image_links($content) {
  // post, custompost1, custompost2 の個別ページでのみ適用
  if (is_singular(array('post', 'custompost1', 'custompost2')) && is_main_query() && in_the_loop()) {
    $content = preg_replace_callback(
      '/<a\s+([^>]*href=["\']([^"\']+\.(jpg|jpeg|png|gif|webp))["\'][^>]*)>/i',
      function($matches) {
        $tag = $matches[0];
        if (strpos($tag, 'class=') !== false) {
          $tag = preg_replace('/class=["\']([^"\']*)["\']/', 'class="$1 glightbox"', $tag);
        } else {
          $tag = str_replace($matches[0], '<a ' . $matches[1] . ' class="glightbox">', $tag);
        }
        return $tag;
      },
      $content
    );
  }
  return $content;
}
add_filter('the_content', 'add_glightbox_class_to_image_links');

Swiperでスライドに動画を使う

Filed under: JavaScript,swiper — kdcs @ 2025年9月17日 水曜日

copilot

基本的な実装方法
html

<div class="swiper-container">
  <div class="swiper-wrapper">
    <div class="swiper-slide">
      <video src="video01.mp4" controls></video>
    </div>
    <div class="swiper-slide">
      <video src="video02.mp4" controls></video>
    </div>
    <div class="swiper-slide">
      <video src="video03.mp4" controls></video>
    </div>
  </div>
  <div class="swiper-button-prev"></div>
  <div class="swiper-button-next"></div>
</div>

・controls を付けると再生・停止ボタンが表示されます。
・autoplay や loop などの属性も使えるが、ユーザー体験を考慮して慎重に設定する必要あり

スライド切り替え時に動画を自動再生・一時停止する
JavaScriptでSwiperのイベントを使って、スライドが切り替わるタイミングで動画を制御できる
javascript

const swiper = new Swiper('.swiper-container', {
  on: {
    transitionStart: function () {
      document.querySelectorAll('video').forEach(video => video.pause());
    },
    transitionEnd: function () {
      const activeSlide = document.querySelector('.swiper-slide-active');
      const video = activeSlide.querySelector('video');
      if (video) video.play();
    }
  }
});

現在表示されているスライドの動画だけが再生される
・動画ファイルのサイズが大きい場合は preload=”none” を使うと読み込みが軽くなる
・モバイル環境では autoplay が制限されることがある

Swiperで静止画と動画が混在するスライダー

実現するためのポイント
・Swiperの自動スライド(autoplay)を使う
・動画スライドが表示されたら autoplay を停止
・動画の再生が終わったら autoplay を再開

javascript

const swiper = new Swiper('.swiper-container', {
  autoplay: {
    delay: 3000,
    disableOnInteraction: false,
  },
  on: {
    slideChangeTransitionStart: function () {
      const videos = document.querySelectorAll('video');
      videos.forEach(video => video.pause());

      const activeSlide = document.querySelector('.swiper-slide-active');
      const video = activeSlide.querySelector('video');

      if (video) {
        swiper.autoplay.stop(); // スライド停止
        video.play();

        // 動画再生終了時にスライド再開
        video.onended = () => {
          swiper.autoplay.start();
        };
      }
    }
  }
});

・autoplay.stop() と autoplay.start() を使えば、Swiperの自動スライドを制御できる
・video.onended は動画の再生が終わったタイミングを検知する
・静止画スライドでは通常通り autoplay が動作

スクロールでナビ固定(jQuery不要)

Filed under: JavaScript — kdcs @ 2025年9月17日 水曜日

jQueryを使わない「スクロールでナビ固定」
ページトップから一定量スクロールした時点で複製したナビ(クローン)をページ上部に固定表示する方法

2025.9.17 改訂
※firefoxでページ途中の#hogeにアンカーリンクで移動する際、固定ナビが出ないのを修正(遅延チェックの部分)

var cloneNav = document.getElementById('nav');
var cloned = cloneNav.cloneNode(true);
var showClass = 'is-show';
cloned.classList.add('clone-nav');
document.body.appendChild(cloned);

// スクロール時の表示制御
function toggleNavVisibility() {
  if (window.scrollY > 500) {
    cloned.classList.add(showClass);
  } else {
    cloned.classList.remove(showClass);
  }
}

// ページ読み込み後にもチェック(Firefox対策)
window.addEventListener('DOMContentLoaded', function() {
  setTimeout(toggleNavVisibility, 100); // 遅延チェック
});

// スクロールイベントでもチェック
window.addEventListener('scroll', toggleNavVisibility);

css

/* スクロールnav固定 css -------------------------*/
.clone-nav {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 500;
    width: 100%;
    transition: .2s;
    transform: translateY(-100%);
    opacity: 0.9;
}
.is-show {
    transform: translateY(0) !important;
    opacity: 0.9 !important;
}

改訂前のコード

//PCナビ スクロール固定 jQuery不要----------------------------------------------

var cloneNav = document.getElementById('nav');
var cloned = cloneNav.cloneNode(true);
var showClass = 'is-show';
cloned.classList.add('clone-nav');
document.body.appendChild(cloned);

window.addEventListener('scroll', function() {
  if(window.scrollY > 500 ) {
    cloned.classList.add('is-show');
  } else {
    cloned.classList.remove('is-show');
  }
});

トップページのメインビジュアルをスクロールで通過したら背景色を付ける

Filed under: JavaScript — kdcs @ 2025年9月15日 月曜日

レスポンシブでスマホ状態になった時、トップページのメインビジュアルをスクロールで通過したらヘッダーにクラスを付与して背景色を付ける方法をjQuery版と非jQuery(バニラjs)で記述したもの。

まず初めに横幅が780pxより広い場合、id=”header”に”pc”というクラスを付け、横幅780px以下でid=”header”に”mobile”というクラスを付ける記述で、こちらはjQueryを使っていないバニラjs。

function updateHeaderClass() {
  const header = document.getElementById("header");
  if (!header) return;

  if (window.innerWidth <= 780) {
    header.classList.add("mobileHeader");
    header.classList.remove("pc");
  } else {
    header.classList.add("pc");
    header.classList.remove("mobileHeader");
  }
}

// 初回の実行
updateHeaderClass();

// ウィンドウサイズ変更時にクラス更新
window.addEventListener("resize", updateHeaderClass);

これをもう少しスッキリとモダンにすると以下のようになる
※classList.toggle を使うと、条件に応じてクラスを追加・削除できる

const updateHeaderClass = () => {
  const header = document.getElementById("header");
  if (!header) return;

  const isMobile = window.innerWidth <= 780;
  header.classList.toggle("mobileHeader", isMobile);
  header.classList.toggle("pc", !isMobile);
};

updateHeaderClass();
window.addEventListener("resize", updateHeaderClass);

ここからが本題

jQuery版

$(function () {
  $(window).on('scroll', function () {
      if ($('#mvSlider').height() < $(this).scrollTop()) {
          $('.mobileHeader').addClass('bgColor');
    } else {
          $('.mobileHeader').removeClass('bgColor');
    }
  });
});

次に非jQuery版
スライダーでSwiperを使う場合jQueryが必要ないのでこちらを使う

document.addEventListener("DOMContentLoaded", function () {
  window.addEventListener("scroll", function () {
    const mvSlider = document.getElementById("mvSlider");
    const mobileHeaders = document.querySelectorAll(".mobileHeader");

    if (!mvSlider) return;

    const scrollTop = window.scrollY || document.documentElement.scrollTop;
    const mvHeight = mvSlider.offsetHeight;

    mobileHeaders.forEach(header => {
      if (scrollTop > mvHeight) {
        header.classList.add("bgColor");
      } else {
        header.classList.remove("bgColor");
      }
    });
  });
});

サイト内検索

カテゴリー

最近の投稿

↑上に戻る