ダークモードに切り替えるWordPressブロックを開発する

Interactivity APIの練習として、WordPressをライトモードとダークモードに切り替えるボタンブロックを作成します。

ダークモードの切り替えはcolor-schemeを使用する

ブラウザには画面表示をダークモードに切り替える機能があり、通常はブラウザの設定に従ってWebサイトを表示する。

ダークモードの切り替え方法

  1. ブラウザの開発者ツールを開く
  2. 右上の︙(DevToolsのカスタマイズと管理)>その他のツール>レンダリング
  3. 追加表示された「レンダリング」タブの中から、「CSSメディア特性 prefers-color-scheme をエミュレートする」を探す
  4. いずれかを選択する。デフォルトでは「エミュレートなし」が選択されている
    • エミュレートなし
    • prefers-color-scheme: dark(→オペレーティングシステムのダーク配色を使用して要素をレンダリング)
    • prefers-color-scheme: light(→オペレーティングシステムのライト配色を使用して要素をレンダリング)

配色設定を定義する場合

OSデフォルトの配色を使用せずにカスタマイズしたい場合、color-scheme を :root 要素で設定する。下記は明るいパターンと暗いパターンを定義し、prefers-color-scheme メディアクエリーを用いて各パターンの要素に配色を設定している。

:root { color-scheme: light dark; }

@media (prefers-color-scheme: light) {
  .element {
    color: black;
    background-color: white;
  }
}

@media (prefers-color-scheme: dark) {
  .element {
    color: white;
    background-color: black;
  }
}

ブロックの雛形を生成する

npx @wordpress/create-block@latest dark-light-mode --template @block-developer-cookbook/dark-light-mode

ブロック構成

  • dark-light-mode
    • build/
      • block.json
      • index.asset.php
      • index.js
      • render.php
      • style-index.css
      • view.asset.php
      • view.js
    • src/
      • block.json
      • edit.js
      • index.js
      • render.php
      • style.scss
      • view.js
    • package.json
    • simple-dark-mode.php
    • node_modules/
    • and more …

 TT4 Dark Themeをダウンロードする。

ブロックを登録する

dark-light-mode.php

namespace BlockDevelopersCookbook;

/**
 * Registers the block using the metadata loaded from the `block.json` file.
 * Behind the scenes, it registers also all assets so they can be enqueued
 * through the block editor in the corresponding context.
 *
 * @see https://developer.wordpress.org/reference/functions/register_block_type/
 */
function create_block_dark_light_mode_block_init() {
    register_block_type( __DIR__ . '/build' );
}
add_action('wp_head', __NAMESPACE__  . '\add_color_scheme_styles');

color-schemeプロパティを:rootに設定する

dark-light-mode.php

function add_color_scheme_styles() {
?>
    <style>
        :root {
            color-scheme: light dark;
        }
    </style>
<?php
}
add_action('wp_head', __NAMESPACE__  . '\add_color_scheme_styles');

その結果、<head>内の<style>に:root { color-scheme: light dark; }が出力される。ブラウザを再読込すると、ユーザー設定に基づいてダークモードへ切り替えられるようになる。

ブロックの初期設定

このブロックはInteractivity APIを用いて、stateの管理とcolor-schemeの更新を行うため、block.jsonに書きを記述してInteractivity APIを有効化する

block.json

{
	"supports": {
		"interactive": true
	},
	"viewScriptModule": "file:./view.js"
}

Interactivity APIを有効化しているのは、supports.interactiveの部分。

viewScriptModuleプロパティはInteractivity APIを用いるJavaScriptがどこにあるかを示している。この場合、Interactivity APIは、view.jsで使用されていることを意味している。また、view.jsはESモジュールとして構築する必要がある。

viewScriptModuleで設定したファイルがモジュールとして構築されることを@wordpress/scripts packageに指示しなければならないため、package.jsonのbuildとstartを書き換える。

package.json

"build": "wp-scripts build --experimental-modules",
"start": "wp-scripts start --experimental-modules"

Interactivity APIの設定をする

Interactivity APIではstoreを作成します。storeには「dark-light-mode」という識別名をつけます。

view.js

/**
 * WordPress dependencies
 */
import { store } from '@wordpress/interactivity';

store( 'dark-light-mode', {
	state: {},
	actions: {},
	callbacks: {},
} );

storeは3つのプロパティを持ちます。

  • state:storeからデータを取得する
  • actions:イベントのコールバック関数を格納する(ボタンクリックなど)
  • callbacks:ユーザーの行動をトリガーとしないコールバック関数を格納する(コンポーネントのロードなど)

定義したstoreをブロックと紐づけるには、render.phpにdata-wp-interactiveディレクティブを記述します。data-wp-interactiveディレクティブには、view.jsで定義したstoreの名前を渡します。

2点目のdata-wp-bind–aria-pressedは、data-wp-bindディレクティブを使用して、aria-pressed属をdarkMode変数に接続するためにものです。

3点目のdata-wp-on–clickは、data-wp-onディレクティブを使用して、ボタンのクリックイベントをコールバック関数のtoggleModeに紐づけるためのものです。

render.php

/**
 * Render template for the Dark Light Mode Block.
 *
 * @package block-developers-cookbook
 */

namespace BlockDevelopersCookbook;

?>
<div <?php echo wp_kses_data(get_block_wrapper_attributes()); ?>>
	<button
		data-wp-interactive="dark-light-mode"
		data-wp-bind--aria-pressed="state.darkMode"
		data-wp-on--click="actions.toggleMode"
		class="toggle"
		type="button">
		<span class="toggle__display" hidden></span>
	</button>
</div>

view.jsにtoggleMode関数を定義します。

/**
 * WordPress dependencies
 */
import { store } from '@wordpress/interactivity';

const { state } = store( 'dark-light-mode', {
	state: {},
	actions: {
		/**
		 * Toggles between dark and light mode.
		 *
		 * @return {void}
		 */
		toggleMode() {
			state.darkMode = ! state.darkMode;
		},
	},
	callbacks: {},
} );

render.phpにstateのdarkMode変数を監視するdata-wp-watch=”callbacks.updateColorScheme”を定義します。

		data-wp-watch="callbacks.updateColorScheme"

コールバック関数のupdateColorSchemeを定義します。

view.js

	callbacks: {
		/**
		 * Updates the root element's color scheme CSS property
		 * when the dark mode state changes.
		 * Skips if darkMode state is not yet initialized.
		 *
		 * @return {void}
		 */
		updateColorScheme() {
			// Dark mode will be undefined if there is not cookie or user meta.
			if ( 'undefined' === typeof state.darkMode ) {
				return;
			}
			const root = document.querySelector( ':root' );
			root.style.setProperty(
				'color-scheme',
				state.darkMode ? 'dark' : 'light'
			);
		},
	},

ブロックが最初にレンダリングするときにのみdarkMode変数を初期化するdata-wp-init=”callbacks.initToggle”を定義します。

render.php

data-wp-init="callbacks.initToggle"

view.js

		initToggle() {
			state.darkMode =
				window.matchMedia &&
				window.matchMedia( '(prefers-color-scheme: dark)' ).matches;
		},

参考:https://blockdevelopercookbook.com/recipes/creating-a-dark-light-mode-block/