WordPressにfancybox4(プラグインなし)

WordPressにfancybox4(プラグインなし)

前記事でもプラグインなしで fancybox4 を導入する方法を記事にしていますが、それは「はてなブログ」の記事を移行した場合という特殊なケースでした。移行が完了しましたので、WordPress でも同じように画像をモーダルダイアログで表示する必要があります。その方法です。

この方法で fancybox を導入しているのは次のサイトです。「国際芸術祭あいち2022 STILL ALIVE」以降が WordPress で書いている記事です。

https://tokotokotekuteku.com/aichitriennale2022/

なお、fancybox は V4 から jQuery に依存しなくなっていますのでそのあたりの導入方法などは以下の前記事「WordPress にプラグインなしで fancybox4 導入」をご覧ください。

01WordPress の画像保存

fancybox 導入の前に画像サイズの整理です。WordPress では画像を保存しますと複数の画像が保存されます。

私の場合はコンテンツ表示幅を最大で 650px にしていますし、サムネイルとして 100px, 300px を使いますので次のように設定しています。

この設定で画像を保存しますと、

と、なぜか 2048px, 1536px, 768px, scaled の画像まで保存してくれます。

なお、元画像は 4032×2268(px) のサイズでどの画像も数MBあります。ページ内の 650px の画像をクリックするとその元画像がモーダルダイアログで表示されるようにしようということです。

02不要な画像サイズの保存停止

まず不要な画像サイズの保存を停止する方法です。

add_filter( 'big_image_size_threshold', '__return_false');
add_filter('intermediate_image_sizes_advanced', 'remove_default_img_sizes');
function remove_default_img_sizes($sizes){
 	unset( $new_sizes['thumbnail'] ); // サムネイル
	unset( $new_sizes['medium'] ); // 中サイズ
	unset( $new_sizes['large'] ); // 大サイズ
	unset($sizes['medium_large']); // 768px
	unset($sizes['2048x2048']); 
	unset($sizes['1536x1536']); 
	return $sizes;
}

scaled は big_image_size_threshold に false を返しておきます。scaled のサイズを変更する場合は、次のように画像の長辺を返します。

add_filter( 'big_image_size_threshold', function( $threshold ) {
	return 3072;
});

その他の画像サイズは intermediate_image_sizes_advanced で各画像サイズの設定解除をしてフィルターフックをかけます。私の場合は、thumbnail, medium, large は残してありますので次のようになります。

03ブロックエディタでは get_image_tag_class が使えない

当初は前記事の方法を踏襲して img 要素に fancybox 用のクラスを追加し、前記事と同じスクリプトで実現しようとしたのですが、img 要素のクラスを変更できるフィルターフック get_image_tag_class がどうやっても働きません。

あれこれ調べましたところ、WordPress5.0から標準搭載となったブロックエディタではこのフィルターフックは機能しないようです。

さらに調べたところ、個々のブロックを HTML 文字列にレンダリングする際のフィルターフックがありました。render_block です。

この render_block のパラメータの $block は次のように各ブロックの名前や属性を配列で持っています。画像の場合のものです。

array(5) {
  ["blockName"]=>
  string(10) "core/image"
  ["attrs"]=>
  array(3) {
    ["id"]=>
    int(659)
    ["sizeSlug"]=>
    string(5) "large"
    ["linkDestination"]=>
    string(4) "none"
  }
  ["innerBlocks"]=>
  array(0) {
  }
  ["innerHTML"]=>
  string(170) "
<figure class="wp-block-image size-large"><img src="http://localhost:8000/wp-content/uploads/2022/08/sample-650x366.jpg" alt="" class="wp-image-659" title=""/></figure>
"
  ["innerContent"]=>
  array(1) {
    [0]=>
    string(170) "
<figure class="wp-block-image size-large"><img src="http://localhost:8000/wp-content/uploads/2022/08/sample-650x366.jpg" alt="" class="wp-image-659" title=""/></figure>
"
  }
}

04render_block で画像に data-fancybox 付リンクを貼る

この render_block のフィルターフックを利用して画像に data-fancybox 属性付きのリンクを貼ります。

add_filter( 'render_block', 'add_fancybox_handler', 10, 2 );
function add_fancybox_handler( $block_content, $block ) {
	if ( $block['blockName'] !== 'core/image' ) return $block_content;
	$url = wp_get_original_image_url( $block['attrs']['id'] );
	$pattern        = '/(<figure.*?>)(<img.*?>)(.*<\/figure>)/i';
	$replacement    = '$1<a data-fancybox href="' . $url . '">$2</a>$3';
	$content  = preg_replace($pattern,$replacement,$block_content);
	return $content;
}

ブロックが画像以外はそのままコンテンツを返します。画像の場合は元画像の URL を取得して、正規表現で img 要素を data-fancybox 付きのリンクで包みます。

これですべての画像に fancybox のモーダルダイアログが設定されます。

05画像から fancybox を解除する

しかし、このままでは fancybox を利用したくない画像にまでモーダルダイアログが設定されてしまいます。その場合は、ブロックに CSS クラス not-fancybox(クラス名は自由)を設定してモーダルダイアログへのリンク設定をスルーさせます。

この場合の $block の [“attrs”] 属性には [“className”] が追加されます。

array(5) {
  ["blockName"]=>
  string(10) "core/image"
  ["attrs"]=>
  array(4) {
    ["id"]=>
    int(659)
    ["sizeSlug"]=>
    string(5) "large"
    ["linkDestination"]=>
    string(4) "none"
    ["className"]=>
    string(12) "not-fancybox"
  }
略

したがって render_block のフィルターフックは次のようになります。

add_filter( 'render_block', 'add_fancybox_handler', 10, 2 );
function add_fancybox_handler( $block_content, $block ) {
    if ( $block['blockName'] !== 'core/image' or $block['attrs']['className'] === 'not-fancybox' ) return $block_content;
	$url = wp_get_original_image_url( $block['attrs']['id'] );
	$pattern        = '/(<figure.*?>)(<img.*?>)(.*<\/figure>)/i';
	$replacement    = '$1<a data-fancybox href="' . $url . '">$2</a>$3';
	$content  = preg_replace($pattern,$replacement,$block_content);
	return $content;
}

ということで、WordPress でも元画像そのままを挿入しながら記事を書けるようになりました。