2015年8月19日、 WordPress バージョン 4.3 “Billie” が公開されました。
なんでもジャズミュージシャンの Billie Holiday から命名されているそうですが、その”Billie”もとい 4.3 にアップデートをすると画面が真っ白になる不具合が発生しています。特に WP-Ban プラグイン が入っている場合は要注意!!です。WP-Ban のバージョンにより確実に真っ白画面になります。
バージョンによる動作状況
WordPress 4.2.4, 4.3 と WP-Ban 1.65, 1.66 バージョンによる動作状況を以下のマトリクスで示します。
WordPress 4.3 + WP-Ban 1.65 の組み合わせでは確実に真っ白画面になります。
また WordPress 4.2.4 以下 + WP-Ban 1.66 の組み合わせでは WP-Ban プラグインを有効化できません。
|
|
WP-Ban |
|
バージョン |
1.65 |
1.66 |
WordPress |
4.2.4 以下 |
正常 |
有効化不可 |
4.3 |
真っ白画面 |
正常 |
原因
真っ白画面 (WordPress 4.3 + WP-Ban 1.65)
WordPress 4.3 で general-template.php に get_language_attributes() 関数が追加されました。この get_language_attributes() という名前の関数は、すでに以前から同名の関数が WP-Ban に実装されており 1.65 まで存在していました。
したがって WordPress 4.3 + WP-Ban 1.65 の組み合わせの場合、以下のような関数の二重定義エラーとなり、画面が真っ白になります。
関数の二重定義エラー
[cc]
Fatal error: Cannot redeclare get_language_attributes() (previously declared in /wp-includes/general-template.php:2624)
in /wp-content/plugins/wp-ban/wp-ban.php on line 249
[/cc]
WordPress 4.3 – general-template.php
/**
* Gets the language attributes for the html tag.
*
* Builds up a set of html attributes containing the text direction and language
* information for the page.
*
* @since 4.3.0
*
* @param string $doctype Optional. The type of html document. Accepts 'xhtml' or 'html'. Default 'html'.
*/
function get_language_attributes( $doctype = 'html' ) {
$attributes = array();
if ( function_exists( 'is_rtl' ) && is_rtl() )
$attributes[] = 'dir="rtl"';
if ( $lang = get_bloginfo('language') ) {
if ( get_option('html_type') == 'text/html' || $doctype == 'html' )
$attributes[] = "lang=\"$lang\"";
if ( get_option('html_type') != 'text/html' || $doctype == 'xhtml' )
$attributes[] = "xml:lang=\"$lang\"";
}
$output = implode(' ', $attributes);
/**
* Filter the language attributes for display in the html tag.
*
* @since 2.5.0
* @since 4.3.0 Added the `$doctype` parameter.
*
* @param string $output A space-separated list of language attributes.
* @param string $doctype The type of html document (xhtml|html).
*/
return apply_filters( 'language_attributes', $output, $doctype );
}
この get_language_attributes() 関数は、 WordPress 4.2.4 までは、ほぼ language_attributes() という関数名でした。ですので正確にはリネーム(リファクタリング)ですかね。なお language_attributes() 関数のコメントには以下の記載があります。
/**
* Displays the language attributes for the html tag.
*
* Builds up a set of html attributes containing the text direction and language
* information for the page.
*
* @since 2.1.0
* @since 4.3.0 Converted into a wrapper for get_language_attributes().
*
* @param string $doctype Optional. The type of html document. Accepts 'xhtml' or 'html'. Default 'html'.
*/
function language_attributes( $doctype = 'html' ) {
echo get_language_attributes( $doctype );
}
WP-Ban 1.65 – wp-ban.php
### Function: Returns page's language attributes depends on WordPress language
function get_language_attributes($doctype = 'html') {
ob_start();
language_attributes();
$language_attributes = ob_get_contents();
ob_end_clean();
return $language_attributes;
}
WP-Ban 有効化不可 (WordPress 4.2.4 以下 + WP-Ban 1.66)
一方 WordPress 4.2.4 以下の場合、WP-Ban 1.66 では get_language_attributes() 関数が削除されたため、関数がない旨の未定義エラーで WP-Ban プラグインを有効化できません。
関数未定義エラー
[cc]
重大なエラーを引き起こしたため、プラグインを有効化できませんでした。
Fatal error: Call to undefined function get_language_attributes() in /wp-content/plugins/wp-ban/wp-ban.php on line 287
[/cc]
対応策
上記マトリクスから対応策を考えますと、以下の2点になるかと思います。
- WordPress 4.3 にアップデートする場合は、アッデート前にまず先に WP-Ban プラグインを 1.66 にアップデートしておいてから WordPress 4.3 にアップデートする。
- WordPress 4.2.4 以下の場合は WP-Ban プラグインは 1.65 のままにしておき、1.66 へはアップデートしない。
真っ白画面になってしまった場合 (WordPress 4.3 + WP-Ban 1.65)
WP-Ban 1.66 の wp-ban.php ファイルをアップロードする方法
- wp-ban.php ファイルのリネーム
WP-Ban 1.65 の /wp-content/plugins/wp-ban/wp-ban.php が真っ白画面になる原因のファイルですので、 FTP, SFTP, SSH やファイルマネージャーなど WordPress 非依存のツールを使い wp-ban.php を適宜 wp-ban.php.bak などの名前にリネームします。これで真っ白画面は解消されます。
- WP-Ban 1.66 の wp-ban.php ファイルのアップロード
解凍した WP-Ban 1.66 の wp-ban.php を /wp-content/plugins/wp-ban/ ディレクトリにアップロードします。
WP-Ban プラグインの削除&インストールする方法
- WP-Ban 1.65 プラグインの削除
FTP, SFTP, SSH やファイルマネージャーなど WordPress 非依存のツールを使い、プラグインのディレクトリ(/wp-content/plugins/)に入り、wp-ban ディレクトリごと削除します。これで真っ白画面は解消されます。
- WP-Ban 1.66 プラグインのインストール
解凍した WP-Ban 1.66 の wp-ban フォルダをすべてアップロードし手動でインストールするか、ダッシュボードのプラグインから新規追加で「プラグインのアップロード」にて wp-ban.1.66.zip ファイルを選択しインストールします。
もしくはダッシュボードのプラグインから新規追加で WP-Ban プラグインを検索し再インストールでもよいです。なお設定はデータベースにありますので消えることはありません。
WP-Ban有効化不可の場合 (WordPress 4.2.4 以下 + WP-Ban 1.66)
WP-Ban 1.65 の wp-ban.php ファイルをアップロードする方法
- wp-ban.php ファイルのリネーム
WP-Ban 1.66 の /wp-content/plugins/wp-ban/wp-ban.php が有効化不可になる原因のファイルですので、FTP, SFTP, SSH やファイルマネージャー(WordPress依存可)などのツールを使い wp-ban.php を適宜 wp-ban.php.bak などの名前にリネームします。
- WP-Ban 1.65 の wp-ban.php ファイルのアップロード
解凍した WP-Ban 1.65 の wp-ban.php を /wp-content/plugins/wp-ban/ ディレクトリにアップロードします。
WP-Ban プラグインの削除&インストールする方法
- WP-Ban 1.66 プラグインの削除
ダッシュボードのプラグインからバージョンが 1.66 の WP-Ban プラグインを一旦削除します。この場合、WP-Ban プラグインをアンインストールしますので設定は消えてしまいます。設定を消したくない場合は、別途 FTP, SFTP, SSH やファイルマネージャー(WordPress依存可)などのツールを使い プラグインのディレクトリ(/wp-content/plugins/)に入り、wp-ban ディレクトリごと削除します。
- WP-Ban 1.65 プラグインのインストール
解凍した WP-Ban 1.65 の wp-ban フォルダをすべてアップロードし手動でインストールするか、ダッシュボードのプラグインから新規追加で「プラグインのアップロード」にて wp-ban.1.65.zip ファイルを選択しインストールします。
おわりに
今回は、以前からプラグイン側にある関数と同名の関数を WordPress 本体側が 4.3 で実装(追加)してしまったのが原因でした。まあ WordPress 本体開発者からすればプラグイン側の関数名など眼中にないのかもしれませんが、そこは grep などで調査し、本体側に追加する関数に同名の関数がプラグイン側に存在した場合は、すみやかにプラグイン開発者側に周知するなり知らせるのがマナーかと思います。プラグイン開発者軽視、本体開発者側の傲慢もそこにはあるのかもしれません。
本体開発者からすれば「WordPress 4.3 リリース前に『プラグイン開発者はプレビュー期間で動作確認しておいてくれよ!』という時間は十分取った」とかいう後付け理由はすぐに思い浮かぶのですが、技術屋視点からしますと、結局被害を被るのは WordPress ユーザで、現に重大な不具合が起きているわけですから、本体への関数追加は充分に調査し慎重に行うべきであると思います。
一方、今回は、WP-Ban プラグイン開発者側にも大いに問題があると思います。WordPress 4.3 で真っ白画面になる不具合が、本体側起因と言えども、1.65 ⇒ 1.66 への対応で wp-ban.php の get_language_attributes() 関数をごっそり削除してしまうというヘタレ対応をしてしまいました。これでは下位互換が保てません。
WordPress 4.3 への WP-Ban 開発者の対応として、バッティングする get_language_attributes() 同名関数を「If you can’t beat them, join them.(長いものに巻かれよ)」ではないですがプラグイン側が折れて名前変更するとか、バージョンチェック処理を入れるとか、方法はいくつかあると思います。
例えば WP-Ban 1.66 で以下のような対応が必要であったと思います。1.67 でなにかしら対応してくれること祈ります。
function_exists() 関数で定義済かを事前確認する
function_exists() 関数で get_language_attributes() 関数がすでに定義済かどうか事前に確認し下位互換を保持する。
if ( !function_exists('get_language_attributes') ) {
function get_language_attributes($doctype = 'html') {
ob_start();
language_attributes();
$language_attributes = ob_get_contents();
ob_end_clean();
return $language_attributes;
}
}
呼び出し元の関数を get_language_attributes() から language_attributes() に変更する
1.66 と同様に WP-Ban 側の get_language_attributes() は削除し、代わりに呼び出し元の get_language_attributes() を WordPress 4.3 にも 4.2.4 以下にも存在する language_attributes() 関数に変更し下位互換を保持する。(これが一番無難かも)
'<html xmlns="http://www.w3.org/1999/xhtml" '.language_attributes().'>'."\n".
default_template = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" <?php echo str_replace('"', '\"', language_attributes()); ?>>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=<?php echo get_option('blog_charset'); ?>\" />\n<title>%SITE_NAME% - %SITE_URL%</title>\n</head>\n<body>\n<div id=\"wp-ban-container\">\n<p style=\"text-align: center; font-weight: bold;\"><?php _e('You Are Banned.', 'wp-ban'); ?></p>\n</div>\n</body>\n</html>";
WordPress 4.3 本当に “Billie” 敬意を表してるんでしょうか。こんなんでは “Billie” が泣いてますよね! Billie is Crying!
2015/08/25 追記
普段は PHP 使いではないので WordPress ってこんなに簡単にFatal(真っ白)で落ちるのかって思う反面、Plugin Framework というアーキテクチャの観点からすると、 WordPress 本体がプラグインをロードするロジックで、関数の二重定義ぐらい 本体側でチェックしてよねって思ってしまうのは私だけではないはず。この機能さえあれば、例え今回のような関数の二重定義があったとしても、プラグインは動作不可にはなっても WordPress 本体が落ちてしまい、ダッシュボードなどの管理画面にすらたどり着けないという致命的なエラーは起こらないはずです。
いまさら感いっぱいの「整形ルール」などの実装より、このような信頼性を高める機能改善のほうがよっぽどプライオリティが高い気がします。