スライダーのダイナミックブロックを作ってみた話

サイト制作でよく依頼のある「スライダーの設置」を、カスタムブロック(ダイナミックブロック)でサクッと実装できるようにしたくて、あれこれ試行錯誤した話です。

この記事は、ブロック入れたらそれだけでスライダーが実装できるようになる!という話とは、違いますので、そういうものをお求めの方は、即離脱をお勧めします。

なお、当方、黒い画面とかReactとか、そもそもJavascriptが大の苦手だということも初めに宣言しておきますね・・・。

トップページにスライダー欲しいって話

ウェブサイトの制作で、トップページのファーストビュー内にビジュアルスライダーが欲しい、という話がよくあります。

ウェブサイトをWordPressで作るなら、サイトを形作る要素のおおよそは管理画面で操作できたほうがいい、と考えています。その範囲は多ければ多いほど良い。それゆえ、スライダーを作る場合も、管理画面で、できればクライアントで自由に管理できるほうがいいかなと。

スライダーの要件

今回の話の前提は「サイトにひとつだけ、トップページにスライダーを設置する」というものです。私にくる依頼の大半はこれなので。
その上で、下記のような要件を想定しています。

  • スライドはクライアントで自由に管理したい
  • スライドの枚数に制限を設けない(0〜多数)
  • スライドの並べ替えを可能にしたい
  • スライドの内容を保ったまま表示/非表示を切り替えたい
  • 日時を指定してスライドの公開をしたい

スライドの中身は、画像だけやHTMLコンテンツを入力するものなど雑多なものがあると考えています。この要件を満たす方法を考えます。

閑話休題:そもそも・・・要る??

スライダーについてはかなりカジュアルに依頼はくるものの、いつも思うのは「それ必要?ユーザのためになる??」です。あくまで個人の意見ですが。
オートプレイになっているスライダーをゆっくり眺めるようなユーザいるのかしら?、バナーやCTAコンテンツのカルーセルとしても、せいぜい1枚目で離脱では?…などなど、思うところは多々あります。動きのあるものはアクセシビリティを担保しようとするとだいぶ手間もかかります。
それをおしてまで、設置する意義とは?ということをつい考えてしまいます。

なので、私の中でスライダーはあまり工数をかけたくないUIという位置付けです。

これまでのスライダー実装

これまでは以下の方法で作ることが多かったです。

  1. 'wp_enqueue_scripts' フックをテーマの functions.php に記載してスライダー用ライブラリを読み込み
  2. 上記は、必要なページでのみ読み込まれるように、条件分岐を書く
  3. スライダーのコンテンツはカスタム投稿を作って、1スライド1記事で管理
  4. フロントへの出力はテンプレートパーツで記載
  5. 上記のテンプレートパーツを呼び出すショートコードを作り、ブロックエディタもしくはテーマエディタに配置

Swiper というライブラリが気に入っていてよく使っています。このライブラリで必須のJavascriptとCSSのファイルをテーマフォルダに入れています。トップページのみでスライダを使う前提なので、スライダを不要とするページでファイルが読み込まれないように条件分岐を書いています。

スライダーのコンテンツをカスタム投稿を作って管理するのは、要件にある「並べ替え」「表示/非表示の切り替え」「日時指定で公開」あたりを実現するのに都合が良いからです。

もちろん、他にもやり方はあると思いますし、案件によって異なると思います。

並べ替えもWordPressのデフォルトである「日付の降順」と説明して、日付の操作で管理してもらうことがあります。もしくはサクッとGUIで記事を並べ替えできるプラグインを使います。
並び順の情報なのだから、日付ではなく、専用のメタ情報を使うべきだろうと思います。実際、日時投稿と組み合わせる場合は「日付の降順」だけでは対応できないこともあるでしょう。
WordPress はもともと記事に「順序」というデータを付与できます。固定ページにありますね。カスタム投稿を追加する時に、サポートする機能のところで「ページ属性('page-attributes')」を追加すれば使うことができます。管理画面でも「順序の昇順」に従って記事が並ぶようにするには、ひと手間かける必要があります。また、順序は列にも表示されないので、わかりやすくするなら、こちらもひと手間かけて表示するのが良いかと。こう書くと、結構面倒ですね。

スライドの中身、記事の管理画面については、必要な入力内容をカスタムフィールドであらかじめ決めておくことが多いです。

カスタムフィールドを使うのは、そのほうが入力しやすいと感じるクライアントがいるためです。ブロックにも慣れて欲しいな、と思いますが、人を変えるのは難しいので・・・。
とはいえ、例に挙げたのは画像とかリンクだけのシンプルなものでそれほど手間でもないですが、自由な内容にしたいと言われるとカスタムフィールドを用意するのが面倒な場合も。

余談:カスタムフィールドについて

カスタムフィールド、つまり投稿メタをつかう場合の基本的なポリシーは、情報設計に則しているか、寄与するものに限定する、です。メタデータって必要なものは必要だと思っています。なんでもかんでもWYSIWYGエディタに塊のHTMLで突っ込んでしまって良しとは思えないので。たとえば、イベント情報のようなものなら、イベントの内容自体はWYSIWYGエディタに自由に書けばいいけど、開催日や開催場所の情報など、独自に取り出せるように適切なデータ型でメタ情報に取り分けておく。そうしないとそのデータを使って絞り込みや串刺し検索がしずらいな、と考えます。

一方で、入力しやすくするためとか、見た目を整えるためだけにメタデータを作るのは、違うよなと思っています。コンテンツの中で2カラムを作りたいから1カラム目2カラム目をそれぞれカスタムフィールドに入れて、という感じのものです。こういうのが、ブロックで対応できるようになって、マジ神。

カスタムフィールドを使う場合は、もうほとんど、Advanced Custom Fields (ACF) プラグイン頼りになっています。とはいえ、プラグイン依存も脱却したいなとは思っています。カスタムフィールドに値を保存する用のブロックを作ることが、今後の課題です。

余談が長くなりましたが、本来、スライダーの中身の部分は、カスタムフィールドで作るべきものとはちょっと違うだろうなと思っています。

カスタムブロックにするメリットとは?

まあ、正直なところ、そんなに多くないかなとは思っています。そもそもの動機はカスタムブロックの勉強がてらだったわけで。違いといえば、以下のようなことでしょうか。

  • ブロックが挿入されたページだけでスライダに必要なライブラリを読み込むことができるので、テーマの functions.php にいちいち記述をしなくていい
  • プラグインに独立できるので使い回しがもう少し容易になる(微々たるものかも)

プラグインにしたとしても、フロント側は、毎回案件ごとちょっとした変更を加える必要があるかもなので、単純な使い回しにはできないですけどね。今までのやり方よりは、多少、現代的?な、やり方になるような気が・・・します!(強引)

ブロックのプラグインを作成

先ほどのスライダーの要件に加えて、スライダーのブロックの要件を補足しますが、ブロックを挿入しても、管理画面では「ここにスライダが表示されます」というテキストが表示されるだけのものを想定しています。ダイナミックブロックで、レンダリングはフロントだけです。className が追加できるだけの、ごくごくシンプルなもの。いままでもショートコードだったので、そこは、諦めの境地ということで。

プラグインの雛形は、「create-block」パッケージを使って作りました。これがないと、カスタムブロックが作れない。開発してくれた人ありがとう・・・!

ビルド後ですが、ファイル群はこんな感じ。

scrフォルダどこ行ったよ?ですが、ええ、やっちゃダメなんでしょうけど、buildフォルダの中身を直接書き換えています。言い訳をすると、いちいちビルドするやり方がどうにも慣れなくて・・・。

良い子は真似しちゃダメだよ!

ライブラリの読み込みはPHPで

生成されたプラグインのPHPファイルに、wp_register_script関数とwp_register_style関数で、ライブラリのファイルを登録。

これにたどり着くまで一悶着あって(というかたどり着いた後も大変だったが)、Twitterで、できないできないと騒いでいたら、アドバイスをいただきました。

まじ神。

「普通にview.jsでimportできたらそれが一番簡単」というのは、納得で、Swiper もnpmインストール対応のライブラリではあるんです。
が、残念ながら、私があんまりよくわからんので、慣れた方法でスクリプトを読み込みたかった。

こう言ってしまうと元も子もないのだけど、node 使って、ビルドして、というやり方に本当慣れなくてですね・・・。プラグインのPHPファイルに書いて、実際のファイルを読み込んで、ライブラリの必須ファイルもプラグインに留めておけば、もしも差し替えたかったら、FTPなりで差し替えればいいなーと思って。ビルド必要ないじゃん。

良い子は真似しちゃダメだよ!!!

不勉強で、そもそもビルドなしの方法でダイナミックブロック作れないことを解決すべきなんだけど、これも今後の課題ですねー。

ちなみに、wp_register_script関数とwp_register_style関数で、読み込むファイルのURL(パス?)を記述するところ。下記の記述では、ローカルの環境ではパスの解決がうまくいかなくて、ファイルを読み込めなかった。

plugins_url( 'swiper/swiper-bundle.min.js', __FILE__ )

wp-now で作ってた環境だったから??
解決方法もわからずこちらも棚上げになっています。誰か教えて欲しい・・・。

block.json は、だいたいこんなもので。

スライダーの発火用とか細かい設定用のJSは view.js に書いて、スライダーの見た目に必要なCSSはstyle-index.cssに書けば良い。

フロントにレンダリングする内容は、render.php に書くのだけど、おおよそこんなもので。

ひとまず、カスタムブロック側はこんな感じで用意しました。

スライドの登録方法について

スライド用のカスタム投稿を準備して、1スライド1記事でスライドの中身を登録します。以前は記事管理画面にカスタムフィールドを用意して入力してもらうようにしていました。

スライドの中身は、ほとんどの場合画像だけですが、画像がPC用とスマホ用と別だったり、画像だけではなくコンテンツスライダーにする場合なども、たまにある。
また、カスタムフィールドにするべき情報とも捉えていないし、なるべく脱却したい。

一番自由にするなら、記事のブロックエディタにスライドの内容を任意に入力してもらうことだが、入力枠があらかじめ用意されていないと入力しづらい人はいる。これをどう解決するか?

例えば、あらかじめ雛形になるブロックが入っていて、任意の画像やテキストに差し替えるだけなら、かなりハードルは下がるのかな?と考えました。

そしてそれを実現する方法・・・・・ありました!

ブロックテンプレートを利用する

正確な日本語訳がわからないですが、ブロックテンプレートといって、新規記事を作ったときに所定のブロックを配置しておく方法があるようです。詳しくは下記に。

実際には、こんなふうに書いてみました。書いた場所はプラグインのPHPファイルです。

そうすると、管理画面では、こう。

わざわざ画像を指定して読み込んでいますが、こう、ダミー画像を用意して、そこにある程度説明を書いておけば、便利かな、というだけなので、ただの画像で良い場合は下記のような記載で十分と思います。

$post_type_object->template = array(
	array( 'core/image', 
		array(
			'sizeSlug' => 'full',
		)
	),
);

各ブロックに設定する内容のキー名は、実際に一度、ブロックエディタ内で組んでみた上で、コードエディタモードで、各ブロックの波括弧内をみるといいかなと思います。

あとは、Attributes の内容はコードに表れないものもあるので、下記のコアブロックリファレンスを参考にしました。

まとめてあるの助かるけど、本当の一次情報としたら、下記を見て、ブロックごとの block.json に何が書かれているか?を調べることになるのかな。

https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src

まあたいへん。

別案:ブロックパターンを選択

スライドの記事を新規追加する時に、「パターンを選択」のモーダルを表示して、任意の雛形を選択する方法もあるかなと思うので、一応紹介です。コンテンツスライドの入力パターンが複数あるなら、こちらの方法が良いかも。

「パターンを選択」のモーダルは、表示したいパターンの登録時に、メタデータを次のように書いておくと、出てきます。

Block Types: core/post-content
Post Types: slider

Block Types に 「core/post-content」が書かれていることが必須のようです。さらに、今回はスライダーでしか使わないため、Post Types にスライダの投稿タイプを指定しています。設定しないと、全ての投稿タイプで表示されてしまうのではないかな・・・?

というか、これだけでモーダル実装できちゃうのかと思うとすごいなあ、と。
よくよく調べたら、下記の記事が見つかった。6.0から実装されてたんですね、知らなかった・・・。

2024テーマで実際に使われているのを見たとき、最初は、記事の新規追加するたびにモーダルが表示されてウザいなあ、と思ったけど。雛形を入れておくことで入力を助けるというのがユーザのサポートになる場面は、意外とあるのかな、と考え直しました。浅慮を反省。

余談 ブロックパターンについて

パターンの登録方法

テーマへのパターンの登録方法は2種類ある。

  1. テーマに /patterns フォルダを作って、そこへphpファイルでパターンの内容を記述する
  2. register_block_pattern() 関数で記述する

最初の方法は、ブロックに対応したクラシックテーマでも使えたので、こちらの方法のがいいと思う。下記に詳しく。

ファイルヘッダー Template Types について

パターンのPHPファイルの最初に記述するファイルヘッダーのキーの中で、「Template Types」についての補足を。

ブロックテーマの場合、管理画面からもテンプレートが増やせるのだけど、テンプレートを新規追加する時にも、「パターンを選択」モーダルが出ます。そのモーダルに出したいパターンに、「Template Types」を設定すると良いみたい。下記は2024テーマの例。

公式の記事は、おそらくこちら。

コアパターンの拒否方法

パターンがあまりに多くなっても、しんどいので、テーマで実装したもの以外は隠したい場合、fonctions.php'after_setup_theme' のアクションフックで、以下を記述。

remove_theme_support( 'core-block-patterns' );

おわりに

というわけで、なんかとりあえずスライダーのダイナミックブロックができました。テーマに書くのと手間の面ではそれほど変わらないかもしれないなと思いつつ。ベストな方法ってきっと人それぞれでしょうから。

今後開発とか試してみたいと思っていること(随時更新

ごくシンプルなSEO用のプログラム

ガチのやつは、正直プラグインを使った方が早いと思うので、簡易版。とりあえず仕様を考えるところから・・・・
ACFを使うことが多いけど、とりあえず「カスタムフィールド」を利用して、そっちに任意の入力があればそれを使い、無ければ記事の抜粋、とかかなあ、、、
meta description だけでいいわ、っていうぐらいの軽いもので。
OGPとか含むようだったら、プラグインのが楽だって気がするし。

Youtube API を使ってみるテスト

再生数:13155、いいね数:84、コメント数:12

Youtube API を利用して、特定の動画の再生回数やいいね数を表示してみるテストです。
すみません、本当にテストで作ってみただけなので、詳しい解説は追って追記します(…しないかもしれません)

https://developers.google.com/youtube/v3/getting-started?hl=ja

APIキーの制限を「なし」にしないと403エラーになるのは、いまいち納得いかない。PHPに書いているからだとしても、IPアドレスか、HTTPリファラーでいいんじゃないの、、、と思ったり。不明。

URLを知る人しか見られない、という動画であっても、再生回数とかが取得できるのかどうかは謎。

許可したタグをエスケープしない wp_kses()

たまに使おうと思うたびに忘れるので、ここにメモ

wp_kses()

だいたいこんな書き方

wp_kses(
	$string,
	array(
		'span' => array(
			'class' => array(),
		),
	)
)

KSES is a recursive acronym which stands for “KSES Strips Evil Scripts”.

https://developer.wordpress.org/reference/functions/wp_kses/#more-information

KSES が、びみょーに覚えづらい・・・・

WPサイト URL の変更

wp-config.php ファイルを使った手動設定

//WordPress のコアファイルが存在する URL 
define( 'WP_SITEURL', 'https://example.com/wordpress' );

//フロントのURL
define( 'WP_HOME', 'https://example.com/wordpress' );

いつも忘れるのでメモ……

  • https:// の部分は含める必要があります
  • 最後のスラッシュ “/” は含めないでください
  • データベースの値を上書きしません
  • 管理画面の設定>一般 で値を変更することはできなくなります
https://ja.wordpress.org/support/article/editing-wp-config-php/#wp_siteurl

WordPress の「サイトで技術的な問題が発生しています」のメールを停止

WPサイトを編集している最中にうっかりエラーを出してしまうと、「サイトで技術的な問題が発生しています」という表題のメールが、WordPress管理者のメアドに飛ぶ場合があります。「場合があります」というのは、はっきりしないんですが、エラーを踏んだら、その度に必ずメールが送られているわけではなさそうだからです。(今のところ、管理画面でエラーを踏んだ場合かな、、、と思っていますが、はっきりしません)

WordPress 管理者のメアドがクライアントのものになっている場合に、「なんかメールきましたけど!!?」と要らぬ心配をかけてしまったことがあります(反省)。
もちろん、公開中のサイトではなかったんですが、開発中でも、驚かせてしまうことには変わりがないので、時々止めておきたいこの機能・・・、探したら方法が見つかりました。

wp-config.php に一文追加

//エラーのメッセージを送信しない
//define( 'WP_DISABLE_FATAL_ERROR_HANDLER', true );

この一文をwp-config.php の
/* 編集が必要なのはここまでです ! WordPress でのパブリッシングをお楽しみください。 */
の前に書き込んでおけばOKです。

参考:https://ja.wordpress.org/support/article/editing-wp-config-php/#wp_disable_fatal_error_handler

私は、下記のように、デバッグモードの近くに書いておくようにしました。
テーマなどを触る時だけ使って、通常時はコメントにしておくといいかもしれません。

/**
 * 開発者へ: WordPress デバッグモード
 *
 * この値を true にすると、開発中に注意 (notice) を表示します。
 * テーマおよびプラグインの開発者には、その開発環境においてこの WP_DEBUG を使用することを強く推奨します。
 *
 * その他のデバッグに利用できる定数についてはドキュメンテーションをご覧ください。
 *
 * @link https://ja.wordpress.org/support/article/debugging-in-wordpress/
 */
// WP_DEBUG モードを有効化
define( 'WP_DEBUG', true );

// /wp-content/debug.log ファイルへのデバッグログの出力を有効化
define( 'WP_DEBUG_LOG', true );

// エラーと警告の画面への表示を無効化
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );

//エラーのメッセージを送信しない
define( 'WP_DISABLE_FATAL_ERROR_HANDLER', true );

そもそもこのメール何??

ほぼ常にデバッグモードと共に開発をしているせいか、「なんでわざわざメール送ったりするわけ???」と不思議でならなかったのですが、調べたところ、致命的なエラーがある時にサイトにログインできなくなる場合もあり、それを回避するために導入されたようです。

https://make.wordpress.org/core/2019/04/16/fatal-error-recovery-mode-in-5-2/

「サイトで技術的な問題が発生しています」のメールはつまり、「リカバリーモード」の一環として、エラーが起きたことを知らせて、リカバリー(復旧)用の特別なログインURLを送るメールなのかなと。「リカバリーのメール」って表題にしてくれたらいいのに…。サイトの所有者がサイトの開発者に知らせて直してもらうための基本的な情報が書いてあります。

具体的な内容

リカバリーのメールの具体的な内容は以下の通りです。

こんにちは。
WordPress 5.2から、サイトでプラグインやテーマが致命的なエラーを発生させた場合にそれを検知してこの自動メールでお知らせする機能が追加されました。
今回の場合、WordPress がテーマ テーマ名 でエラーを捉えました。
まずはじめに、ご自分のサイト(URL)を開き、目に見える問題がないか確認してください。次に、エラーが発生したページ(URL)を開き、同様に問題がないか確認してください。
この問題をさらに調査するにはサーバーホストに連絡してみてください。

もしサイトが壊れていてダッシュボードに正常に接続できない場合、WordPress には特別な「リカバリーモード」があります。これによりダッシュボードに安全にログインし、さらに調査をすることができます。
〈リカバリー用URL〉
サイトを安全に保つため、このリンクは 1日 で有効期限が切れます。ですが、心配なく。有効期限後にこのエラーが再度発生すれば新しいリンクをお送りします。

この問題を解決しようとする際、以下の情報を聞かれるかもしれません。
WordPress バーション5.8.2
現在のテーマ: テーマ名 (バージョン 1.0)
現在のプラグイン: (バージョン )
PHP バージョン8.0.12
===========
エラー詳細
エラータイプ E_PARSE が template-tags.php ファイルの 213 行目で発生しました。 エラーメッセージ: syntax error, unexpected token “;”, expecting “)”

メールの文章をざっくり3つに分けました。
1番目の塊は、どのサイトのどのページでエラーを検知したかの内容。
2番目の塊は、リカバリー用URLの案内、
3番目の塊は、基本的な環境の情報と、エラーの原因についての記載(デバッグモードでみる内容と同じ)
という感じでしょうか。

サイト公開後の運用中の段階で何か起こった時には、とても便利な機能かな、と思っています。

XML サイトマップからユーザ別一覧を除外する

テーマの functions.php に以下を追加

/**
 * サイトマップからユーザを外す
 * https://make.wordpress.org/core/2020/07/22/new-xml-sitemaps-functionality-in-wordpress-5-5/
 */
function remove_user_archive_from_sitemap ( $provider, $name ) {
	if ( 'users' === $name ) {
		return false;
	}
		return $provider;
	}
add_filter( 'wp_sitemaps_add_provider', 'remove_user_archive_from_sitemap', 10, 2 );

これでOKです!

プラグイン不要でXMLサイトマップを自動生成

WordPress はそのサイトの(ほぼ)全てのページを網羅する XML サイトマップを自動で生成します。この機能はWordPress パージョン 5.5 で追加されました。
すでにWPサイトをお持ちの方は(そして5.5以上なら)、公開のアドレス(トップページ)の最後に「/wp-sitemap.xml」を付けると確認できるはずです。

詳しい解説は下記にあります。

https://make.wordpress.org/core/2020/07/22/new-xml-sitemaps-functionality-in-wordpress-5-5/

XMLサイトマップにリストされる内容は?

ちなみにこのサイトのXMLサイトマップはこちらです。(ユーザ別アーカイブは外してあります)

https://learning.ccc-labo.net/wp-sitemap.xml

上記のXMLサイトマップは、階層構造になっていて、「/wp-sitemap.xml」にさらにXMLサイトマップのURLがリストされている、という構造になっています。XMLサイトマップにリストされるのは以下のようなページです。

  • 投稿の全てのページ
  • 固定ページの全てのページ
  • カスタム投稿があればその全てのページ(※)
  • カテゴリやタグなどのアーカイブページ
  • カスタムタクソノミーのアーカイブページ(※)
  • Author のアーカイブページ

※公開クエリがfalseになっている場合はそのカスタム投稿のページは掲載されません

カスタム投稿のアーカイブは、XMLサイトマップに入らないので、追加したい場合は、XMLサイトマップをカスタマイズする必要があると思います。

さて、XMLサイトマップに列挙される中に、「Author のアーカイブページ」があります。これは、そのサイトで「記事を書くユーザ別のアーカイブ」のことです。この「ユーザ」を知られたくない場合があります。「ユーザ別のアーカイブ」では、うっかり、アカウント名がURLに利用されますので、セキュリティ上、ユーザのアカウントを見られたくない、知られたくないと言う場合は、多いと思います。

「ユーザ別のアーカイブはサイトマップから外したい!!」

そんな時は、冒頭に紹介したコードをテーマの functions.php に書けばOKです。

ちなみに、自動のXMLサイトマップは、設定>表示設定の「検索エンジンがサイトをインデックスしないようにする」にチェックが入っていると表示されません(404エラー扱いになる)ので、お気をつけください(こないだうっかりひっかかった…)。