テーマカスタマイズのライブプレビューでpostMessageをページ遷移に対応させる
配布する用のWordPressテーマを作成するときに、外観設定のテーマカスタマイズは必要不可欠だ。
テーマカスタマイズAPIのコードもCodexにきちんと載っていたりするわけだけど、なんか肝心なところが書かれてないな~というのが印象。
文言変更とかで$wp_customize->add_settingのtransportをrefleshする場合は別になんてこともないんだけど、色変更とかでpostMessageで動的に変更する場合にこのまま書き写すとライブプレビューで色々不都合が生じてくる。文言変更とかもpostMessageにしておくとこれまた同じ。
主にページ遷移のときにね。
新しいバージョンでテーマカスタマイズそのもののリビジョンの概念もできて、この問題はテーマ制作者を置き去りにして、ゼクトのライダーさんばりのクロックアップをしている。クロックアップしたライダーは人間を遥かに超えるスピードで活動できるのだ!
これは俺も当然遭遇したことで、何が問題かというと、テーマカスタマイズで設定した色・・・というか入力したカラーコードがページを遷移した際にライブプレビュー上に反映されないということだ。
調べてみてもテーマカスタマイズの情報は(主にその際に利用するJavaScriptに関して)あまり開示されておらず、もれなくハマった。コピペ制作の結果がこれだよ。
そこを解決するべく、正常にテーマカスタマイズできることを目指してコードを作成した。
今回は色変更を主でやっていくけど、これが文言変更でも仕組みは同じなので、そのあたりは適宜対応するといいと思う。
まずはCodexの内容を踏襲して、セオリー通りにテーマカスタマイズを設定していく。
テーマカスタマイズの項目の追加コード(PHP)
/** テーマカスタマイズの項目設定 **/
function theme_customize_register($wp_customize){
/** 設定のセクション追加 **/
$wp_customize->add_section('theme_color_settings', array(
'title' => __('Color settings', 'theme-language'),
'priority' => 30,
'description' => __('This is site color settings.', 'theme-language'),
));
/** ボディの背景色 **/
$wp_customize->add_setting('body_bgcolor', array(
'default' => '#ffffff',
'transport' => 'postMessage',
));
$wp_customize->add_control(
new WP_Customize_Color_Control($wp_customize, 'control_body_bgcolor', array(
'label' => __('Background color', 'theme-language'),
'description' => __('Enter background color.', 'theme-language'),
'section' => 'theme_color_settings',
'settings' => 'body_bgcolor',
'priority' => '1',
))
);
/** ボディの文字色 **/
$wp_customize->add_setting('body_color', array(
'default' => '#000000',
'transport' => 'postMessage',
));
$wp_customize->add_control(
new WP_Customize_Color_Control($wp_customize, 'control_body_color', array(
'label' => __('Color', 'theme-language'),
'description' => __('Enter color.', 'theme-language'),
'section' => 'theme_color_settings',
'settings' => 'body_color',
'priority' => '2',
))
);
}
add_action('customize_register', 'theme_customize_register');
/** プレビュー用のスクリプトのエンキュー **/
function theme_customize_preview_enqueue(){
// プレビュー側のユーザー定義スクリプトを記載するファイルを指定する
wp_enqueue_script(
'theme-customize-preview',
get_template_directory_uri().'/theme-customize-preview.js', // 指定ファイル(JavaScript) ディレクトリは適宜変更
array('jquery', 'customize-preview'), // wp-adminにパッケージされている依存ファイル
'',
true
);
}
add_action('customize_preview_init', 'theme_customize_preview_enqueue');
/** コントロール用のスクリプトのエンキュー **/
function theme_customize_controls_enqueue(){
// コントローラー側のユーザー定義スクリプトを記載するファイルを指定する
wp_enqueue_script(
'theme-customize-controls',
get_template_directory_uri().'/theme-customize-control.js', // 指定ファイル(JavaScript) ディレクトリは適宜変更
array('customize-controls', 'iris', 'underscore', 'wp-util'), // wp-adminにパッケージされている依存ファイル
'',
true
);
}
add_action('customize_controls_enqueue_scripts', 'theme_customize_controls_enqueue');
/** スタイルシートの出力 **/
function theme_customize_styles(){
$styles = '';
// 実表示ページとテーマカスタマイズで共通出力
$styles .= '
<style type="text/css" id="theme-customize-styles">
body{
background-color:'.get_theme_mod('body_bgcolor', '#ffffff').';
color:'.get_theme_mod('body_color', '#000000').';
}
</style>';
// テーマカスタマイズのみで出力 JavaScriptでカラー設定を変更する際にこのstyleタグへ追加していく
if(is_customize_preview())
$styles .= '<style type="text/css" id="theme-customize-preview-styles"></style>';
echo $styles;
}
add_action('wp_head', 'theme_customize_styles');
エンキューしたユーザー定義スクリプト(JavaScript)
※後記で少し書き換えます。
/** theme-customize-preview.js **/
(function($){
// プレビュー側のDOM操作するスクリプト
// value.bindはwp.customizeに登録されているメソッドなので注意
var prosession = '#theme-customize-preview-styles'; // プレビュー用のスタイルシート書き出し先
wp.customize('body_bgcolor', function(value){
value.bind(function(nvalue){
var target = 'body';
$(prosession).append(target + '{background-color:' + nvalue + ';}');
});
});
wp.customize('body_color', function(value){
value.bind(function(nvalue){
var target = 'body';
$(prosession).append(target + '{color:' + nvalue + ';}');
});
});
})(jQuery);
/** theme-customize-controls.js **/
(function(api){
// コントロール側のDOM操作するスクリプト
// 今回は操作しないので空ファイルで作成しているが、ファイル自体は必須
})(wp.customize);
とりあえず、このコードでテーマカスタマイズとライブプレビューの設定だけならできる。設定だけなら。
だが、このコードを記載して適当にカラー設定を入れた後で、プレビュー側のサイト内のリンクを押して他のページに遷移したときに気づくはず。
そう。色設定が遷移後のページには反映されていないということに。
上記のコードはstlyeタグに追記していく形式を取っているが、Codexのように要素にstyle属性で出力してないからじゃないの~?と思うかもしれない。だが、ちょっと待ってほしい。
要素にstyle属性で設定しようが、上のコードのようにstlyeタグに追記していこうが、結局スタイルシートが出力されている箇所はプレビュー側なので、ページが遷移されたらその設定は言わずもがななくなってしまう。
つまり、Codexの内容をコピペしても改変しても結果としては何も変わらない。
JavaScriptで付与されたstyleタグやstyle属性がページ遷移したに消えるのは仕方のないことであり、これは書き方云々の問題ではない。
そして、これを無理やり保持しようとするのはナンセンスだ。
ならば、プレビュー側がどうページ遷移しようが関係ない、コントロール側を元にして、プレビュー側の遷移後のページにスタイルシートを生成すればいいのでないだろうか。
ここで一度振り返って、テーマカスタマイズの画面の構成がどうなっているかを見ることにする。
そもそもテーマカスタマイズのプレビュー側とコントロール側はフレームで構成された画面となっており、プレビュー側が子、コントロール側が親という関係のフレーム構成である。
そして、そのフレームでの子と親でのスクリプト(「エンキューしたユーザー定義スクリプト(JavaScript)」で読み込んだもの)は以下のように読み込まれる。
- 【子】依存スクリプト「customize-preview」と「theme-customize-preview.js」
- 【親】依存スクリプト「customize-controls」と「theme-customize-controls.js」
そして、色変更の際これらのスクリプトの中で記載される「wp.customize」オブジェクト(「theme-customize-controls.js」では「wp.customize」を「api」にキック)を利用して操作を行うわけであるが、子と親とで扱われている「wp.customize」はそれぞれ異なる。
これは、コントロール側とプレビュー側で別々にそれぞれ有効な「wp.customize」を展開されていることを示しており、図にすると以下のようになっている。

で、この「wp.customize」は同じオブジェクトを別個に展開しているというわけではなく、依存スクリプトの関係で同じ名前でも内容は全くの別物である。
(当初、調べている中でオブジェクトの名前が同じなので、共通のオブジェクトなのかと思っていた^q^)
まぁ、エンキューは別々にしてるし、依存スクリプトが違うから当然といえば当然だったりする。
これが何を意味するかというと「wp.customize」でのプレビュー側とコントロール側のデータの相互の参照はできないということだ。
精々、プレビュー側からコントロール側の実値を受け取れるのは、value.bind()でchangeイベントがを受け取った際の変更後の値のみ。
value.bind()をvalue.load()とかやってもそんなメソッドないよ^^って言われる。
けど、コントロール側の設定を元にプレビュー側でスタイルシートを生成する際において、最低でもプレビュー側からコントロール側で入力したカラーコードを実値でページの読み込み時に引っ張ってくる必要がある。
これをどうやって実現するかというとテーマカスタマイズの構成がiframeというところに注目する。
JavaScirptにはparent.windowという便利なターゲット指定があり、これを利用して子フレーム(プレビュー側)から親(コントロール側)の「wp.customize」オブジェクトを直接参照してやればいい。
それを利用して、エンキューしたユーザー定義スクリプト(JavaScript)の「theme-customize-preview.js」を以下のように書き換える。
エンキューしたユーザー定義スクリプト(JavaScript)書き換え後
/** theme-customize-preview.js **/
(function($){
// プレビュー側のDOM操作するスクリプト
// value.bindはwp.customizeに登録されているメソッドなので注意
var prosession = '#theme-customize-preview-styles'; // プレビュー用のスタイルシート書き出し先
var api = parent.window.wp.customize; // コントロール側のwp.customize
wp.customize('body_bgcolor', function(value){
var ivalue = api.control('control_body_bgcolor').container.find('.color-picker-hex').val();
//↑コントロール側の入力値の参照
body_bgcolor(ivalue);
value.bind(function(nvalue){
body_bgcolor(nvalue);
});
});
function body_bgcolor(nvalue){
var target = 'body';
$(prosession).append(target + '{background-color:' + nvalue + ';}');
}
wp.customize('body_color', function(value){
var ivalue = api.control('control_body_color').container.find('.color-picker-hex').val();
//↑コントロール側の入力値の参照
body_color(ivalue);
value.bind(function(nvalue){
body_color(nvalue);
});
});
function body_color(nvalue){
var target = 'body';
$(prosession).append(target + '{color:' + nvalue + ';}');
}
})(jQuery);
書き換え後、色変更をやってページを遷移させてみると、遷移後にも問題なく有効になっていることが確認できる。
そして、コントロール側の色を直接参照しているため、最近追加されたテーマカスタマイズのリビジョン機能にも対応できるはず。
まぁ、こんなことしなくてもWordPressのJavaScriptが上手いことやってくれればそれが一番いいんだけど・・・。
悲しきかな、度重なるアップデートでもそれは一向にやってくれそうにもない。
テーマカスタマイズを弄るということは、テーマ制作のスタンダードな知識が求められるから「細かいところは自分でやってね!」というのがWPの方針なんだろうか。
海外のサイトとか見ていても、あまりテーマカスタマイズ関係のそこらへんの情報は開示されておらず、内容は似たり寄ったりだった。(それでも日本語Codexよりは幾分か細かい記載はあるけど。)
プリーズ!日本語の情報!ワタシ英語ダメダメよ!
自分の周りでもWordPressのテーマ制作はワンオフがほぼ全部だし、世間一般的にもワンオフみたいな風潮だし、そこで使うことの少ない画面のコードはあまり充実してないんだよね。結局自分で試行錯誤するしかない。
何より「テーマカスタマイズ」と検索したときに「WordPressのテーマをカスタマイズしてオリジナルサイトを作ります!」的なサイトが引っかかってくるのがどうにも。
本来、求めてるはずの情報が入ってこないこのもどかしさよ。
検索エンジンさんお願いですから仕事して下さい(´・ω・`)
