カレンダーウィジェットのカスタマイズ

WordPress Default Widget Extensionプラグインのカレンダーウィジェットに拡張機能を追加しようと思い、色々考えた結果「土曜日・日曜日の背景色や文字色を変更できるようにする」という機能を実装することにしました。
カラーコードをテキストで入力してもいいのですが、WordPressの管理メニュー内の外観→カスタマイズなどで見かけるカラーピッカーがあるので、これを上手く使えないかと思い調査することに。

カラーピッカー
外観→カスタマイズメニューのカラーピッカー

JavaScriptライブラリ:wp-color-picker

とりあえずサンプルとしてプラグインの形式で作成していこうと思います。

カラーピッカーのライブラリ読み込み

WordPressのデフォルトでインストールされているJavaScript(/wp-includes/js/下)は事前に登録されているので、自分が実装するメインのJavaScriptへの依存関係として読み込みます。

class Wp_Color_Picker {
	public function __construct () {
		add_action( 'admin_menu', array( $this, 'admin_menu' ) );
	}

	public function admin_menu () {
		$page = add_menu_page(
			'Color Picker Sample',
			'Color Picker Sample',
			'manage_options',
			plugin_basename( __FILE__ ),
			array( $this, 'page_render' )
		);
		add_action( 'admin_print_styles-'  . $page, array( $this, 'admin_style' ) );
		add_action( 'admin_print_scripts-' . $page, array( $this, 'admin_scripts') );
	}

	public function admin_style () {
		wp_enqueue_style( 'wp-color-picker' );
	}

	public function admin_scripts () {
		wp_enqueue_script( 'color-picker-main-js', plugins_url( 'js/color-picker-main.js', __FILE__ ), array( 'jquery', 'wp-color-picker' ) );
	}

	public function page_render () {
		echo '<div class="wrap">';
		echo '<h1>Color Picker</h1>';
		echo '<p><input id="color-picker" type="text"></p>';
		echo '</div>';
	}
}

23行目でJavaScirptを読み込んでいます。js/color-picker-main.jsが自分で実装する用のJavaScriptファイル。jQueryも使いたいので、wp-color-pickerと同時にjqueryも依存関係ファイルとして読み込んでおきます。

19行目でカラーピッカー用のスタイルシートをキューに入れます。こちらもJavaScript同様、wp_register_style関数で事前に登録されているのでキューに入れるだけでOKです。

テキストボックスの準備

先程のソースコード内に既に書きましたが、カラーピッカーの対象となるテキストボックスを準備します。

echo '<p><input id="color-picker" type="text"></p>';

id属性にcolor-pickerという値をセットしました。値は任意で大丈夫です。class属性でも可能ですが、JavaScriptなのでid属性のほうがスコープしやすいかもです。好みですけど。(実際はパフォーマンスやStyleとの住み分けなど言いたいことは沢山ありますが割愛)
これでフロント側の準備はOKです。

JavaScriptからカラーピッカーをコールする

コールは非常にシンプル。対象のテキストボックス要素でwpColorPicker()メソッドをコールしてあげるだけです。(10行目)

(function($) {
	$(function() {
		var options = {
			defaultColor: false,
			change: function(event, ui){},
			clear: function() {},
			hide: true,
			palettes: true
		};
		$('#color-picker').wpColorPicker(options);
	});
})(jQuery);

オプションの設定ができるようになっています。

オプション内容
defaultColorデフォルトカラーの設定でデフォルト色を設定したい場合はカラーコード文字列を設定する。
changeカラー変更時のコールバック関数を指定できる。
clearカラークリア時のコールバック関数を指定できる。
hide画面ロード時のカラーピッカー表示/非表示設定。
palettersカラーパレットの表示/非表示設定。

これで完成です。サンプルを動作させると以下の用に画面が表示されます。

カラーピッカーサンプル画面

サンプル完成!\(^o^)/これをプラグインに実装していきます。

プラグインへの実装

カラーピッカーをウィジェットに組込み

まずは管理メニューのウィジェットからカレンダーウィジェットにカラーピッカーを実装します。サンプルと異なりjQueryは既にウィジェットメニュー内で読み込まれているので読み込み不要。カラーピッカーのCSSとJavaScriptをキューにセットします。

/* Color Picker Library Read */
wp_enqueue_style( 'wp-color-picker' );
wp_enqueue_script( 'wp-color-picker' );

if ( !isset( $instance[ 'sat-background-color' ] ) ) { $instance[ 'sat-background-color' ] = "#ffffff"; }
if ( !isset( $instance[ 'sat-font-color' ] ) ) { $instance[ 'sat-font-color' ] = "#000000"; }
if ( !isset( $instance[ 'sun-background-color' ] ) ) { $instance[ 'sun-background-color' ] = "#ffffff"; }
if ( !isset( $instance[ 'sun-font-color' ] ) ) { $instance[ 'sun-font-color' ] = "#000000"; }

$html  = '<script>';
$html .= '(function($) {';
$html .= '$(function() {';
$html .= '$("#' . $this->get_field_id( 'sat-background-color' ) . '").wpColorPicker({"defaultColor": "' . $instance[ 'sat-background-color' ] . '"});';
$html .= '$("#' . $this->get_field_id( 'sat-font-color' ) . '").wpColorPicker({"defaultColor": "' . $instance[ 'sat-font-color' ] . '"});';
$html .= '$("#' . $this->get_field_id( 'sun-background-color' ) . '").wpColorPicker({"defaultColor": "' . $instance[ 'sun-background-color' ] . '"});';
$html .= '$("#' . $this->get_field_id( 'sun-font-color' ) . '").wpColorPicker({"defaultColor": "' . $instance[ 'sun-font-color' ] . '"});';
$html .= '});';
$html .= '})(jQuery);';
$html .= '</script>';

echo $html;

カラーコードを保存するので、もし保存されていたらその値を。保存されていなければデフォルト値をセットしてカラーピッカーに渡すロジックを5〜8行目に記述しています。

あとはJavaScriptを書くだけなのですが、PHP側からJavaScriptに値を渡す必要があるため、外部ファイルにするのは逆に可読性が悪くなるかなと思ったり。

$this->get_field_id()でid値をセットしているのは、カレンダーウィジェットを複数配置する場合、同じclassやid属性を使用してしまうとカラーピッカーが重複して表示されてしまうため、それを防止しています。そのカレンダーウィジェット一意の値が必要です。

カラーピッカー実装(管理メニュー)
カラーピッカーの実装

テキストボックスは通常ウィジェットに追加するのと同じ方法で問題なし。あとは更新処理なども普通のウィジェットフィールドの更新処理と同じです。

カラーコードの正規表現チェック

あとはフロント側に登録したカラーコードを使用してスタイルを設定するのですが、出力時にカラーコードの形式で登録されているかチェックします。正規表現で「#+6桁(数字・アルファベット大文字/小文字)」「#+3桁(数字・アルファベット大文字/小文字)」は真、それ以外は偽という判定用の関数を作ります。

private function is_color_code( $color ) {
	if ( preg_match( "/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/", $color ) ) {
		return __return_true();
	} else {
		return __return_false();
	}
}

この関数に登録したカラーコードを渡して真が返ってきた場合のみスタイルを設定するように処理を書きます。

土曜日・日曜日の判定

悩んだ……。日付→曜日は簡単。曜日→日付?しかもその年月の土曜日・日曜日の日付を配列でほしい。ちょっと力技だけど、その年月の日をループさせて曜日がマッチしたら配列にセットするとかしかないか。

private function get_week_date( $weekday_number ) {
	global $year, $monthnum;

	$time_stamp = current_time( 'timestamp' );
	$this_month = empty( $monthnum ) ? gmdate( 'm', $time_stamp ) : $monthnum;
	$this_year  = empty( $year )     ? gmdate( 'Y', $time_stamp ) : $year;

	/* Month Last Day */
	$days_in_month = (int) date( 't', mktime( 0, 0 , 0, $this_month, 1, $this_year ) );

	$weekday = array();
	for ( $day = 1; $day <= $days_in_month; $day++ ) {
		$w = (int) date( 'w', mktime( 0, 0 , 0, $this_month, $day, $this_year ) );
		if ( $weekday_number == $w ) {
			$weekday[] = $day;
		}
	}
	return json_encode( $weekday, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT );
}

カレンダーの年月を取得するのにWordPressのglobal変数「$year」「$monthnum」を使用します。その年月からその月の月末日を取得します(9行目)。その値を元に1日〜月末日までをループさせて曜日チェックをします。

引数は曜日配列番号を渡します(日曜日なら0、土曜日なら6)。引数と同じ曜日配列番号の日付を配列にプッシュして、その配列をJavaScriptに渡す形としてjson_encode()を通して返す関数です。

JavaScriptでclass設定

最後に土曜日・日曜日の配列をJavaScriptに渡して、カレンダーの日付とマッチングします。マッチした要素にaddClass()でclass値をセットします。しかし、PHPと混在させると美しくない……。

public function widget ( $args, $instance ) {
	parent::widget( $args, $instance );

	wp_enqueue_script( 'jquery' );

	$this->set_color_style( $args['widget_id'], $instance );
	$saturday_week = $this->get_week_date(6);
	$sunday_week   = $this->get_week_date(0);

	$html  = '<script>';
	$html .= '(function($) {$(function() {';
	$html .= 'var satArray = ' . $saturday_week . ',';
	$html .= 'sunArray = ' . $sunday_week . ',';
	$html .= 'tdObj = $("#' . $args['widget_id'] . ' tbody td");';
	$html .= 'tdObj.each(function(){';
	$html .= 'if (satArray.indexOf(Number($(this).text())) >= 0) {';
	$html .= '$(this).addClass("wp-extension-calendar-sat");';
	$html .= '}';
	$html .= 'if (sunArray.indexOf(Number($(this).text())) >= 0) {';
	$html .= '$(this).addClass("wp-extension-calendar-sun");';
	$html .= '}';
	$html .= '})});})(jQuery);';
	$html .= '</script>';

	echo $html;
}

できた!\(^o^)/

カラーピッカー実装後(フロント)

テストデータなのでビビットカラーをセットしているけど、日本のカレンダーだと土曜日=青文字、日曜日=赤文字が通常かな。あとは、祝日設定や今日の色設定をできるようにしようかな。ということでversion1.6.0リリース!

WordPress Default Widget Extension

サンプルソース(GitHub)

以下のURLにサンプルソースのリポジトリがあります。
プラグイン形式で作成しているので、WordPressの環境の wp-content/plugins にディレクトリを作ってクローンすれば動きます。(プラグインを有効にしてください)

GitHub