記事一覧

【カスタムヘッダー】 arrayエラー

 posted by suzu
WordPressのバグ

今回の WordPress バグですが、
またまた、カスタムヘッダーを利用する際のバグ紹介です。
( 解説に使用している WordPress ソースコードは WordPress 3.9 です )

【バグ確認バージョン】
  WordPress 3.9

【前提条件】
  add_theme_support 関数の第一パラメータに ‘custom-header’ を指定して
  カスタムヘッダーを利用する指定をする際、
  明示的にデフォルトヘッダーを指定していない

【現象】
  管理画面[外観 - カスタマイズ] にて下記 Warning が発生
  チラッと出て、他のレイヤーの下に隠れるので、気づかない方もいるかも・・・

Warning: Invalid argument supplied for foreach() in
  /[WordPressディレクトリ]/wp-admin/custom-header.php on line 1248
Warning: array_merge(): Argument #2 is not an array in
  /[WordPressディレクトリ]/wp-admin/custom-header.php on line 1268

【解消方法】
  register_default_headers 関数にて、
  明示的にデフォルトヘッダーを配列として登録する
 

管理画面からヘッダー画像を変更したり、ブログタイトルや
紹介文の文字色を変更できるようにさせるためには、
add_theme_support 関数の
第一パラメータに ‘custom-header’ を、
第二パラメータにデフォルトの挙動を指定する連想配列を与え、
カスタムヘッダーのサポートを有効にします。

/* カスタムヘッダー パラメータを指定して追加 */
add_theme_support('custom-header', array(
	'default-image'      => get_template_directory_uri() . '/images/header_photo-green.jpg',		// デフォルトヘッダー画像
	'random-default'     => false,	// ヘッダー画像をランダム表示するか
	'width'              => 986,		// ヘッダー画像幅
	'height'             => 150,		// ヘッダー画像高
	'flex-width'         => false,	// 画像幅をフレキシブルにするか ・・・true:指定サイズに関係なくトリミング可能 / false:指定サイズに準拠した割合でのみトリミング可能
	'flex-height'        => false,	// 画像高をフレキシブルにするか ・・・true:指定サイズに関係なくトリミング可能 / false:指定サイズに準拠した割合でのみトリミング可能
	'default-text-color' => '464646',	// ヘッダーテキスト文字色
	'header-text'        => true,	// ヘッダーテキストの表示制御可否
	'uploads'            => true,	// ヘッダー画像アップロード可否
	'wp-head-callback'       => 'header_style',			// ユーザ画面ヘッダーで、管理画面でのカスタマイズスタイルを適用するためのコールバック
	'admin-head-callback'    => 'admin_header_style',	// 管理画面で、[外観 - カスタマイズ]をプレビューするためのコールバック
	'admin-preview-callback' => 'admin_header_preview'	// 管理画面で、[外観 - ヘッダー]をプレビューするためのコールバック
));

上記のように、‘default-image’ を指定しているにも関わらず、
「 管理画面[外観 - ヘッダー] 」 を表示すると、
/wp-admin/custom-header.php の get_default_header_images 関数にて、
Warning が発生します。
PHP のエラー表示で Warning を表示しない設定にしていたり、
表示していても、画面表示上はチラッと出て他のレイヤーの下に
隠れてしまうので、気づいていない方もいるかもしれません。

なぜこんなことになるのでしょう?

public function get_default_header_images() {
	$this->process_default_headers();

	// Get the default image if there is one.
	$default = get_theme_support( 'custom-header', 'default-image' );

	if ( ! $default ) { // If not,
		return $this->default_headers; // easy peasy.
	}

	$default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
	$already_has_default = false;

	foreach ( $this->default_headers as $k => $h ) {
		if ( $h['url'] === $default ) {
			$already_has_default = true;
			break;
		}
	}

	if ( $already_has_default ) {
		return $this->default_headers;
	}

	// If the one true image isn't included in the default set, prepend it.
	$header_images = array();
	$header_images['default'] = array(
		'url'           => $default,
		'thumbnail_url' => $default,
		'description'   => 'Default'
	);

	// The rest of the set comes after.
	$header_images = array_merge( $header_images, $this->default_headers );
	return $header_images;
}

実際に Warning を吐いているのは、1248行目と1268行目です。
Invalid argument supplied for foreach() in ・・・ on line 1248
array_merge(): Argument #2 is not an array in ・・・ on line 1268
メッセージから、いずれも配列操作に関する argument の
Warning であることが分かります。
ここで操作している配列は、$this->default_headers です。
では、$this->default_headers はどこで初期化されているのでしょう?
$this は自身のクラスインスタンスを示す疑似変数ですので、
default_headers で custom-header.php を検索してみます。

ぬ?
ないではありませんか! 初期化するコードが!

/**
 * Holds default headers.
 *
 * @var array
 * @since 3.0.0
 * @access private
 */
var $default_headers;

43行目に変数の宣言はありますが、配列としての宣言ではありません。
では、どこで代入があるのでしょう?

/**
 * Process the default headers
 *
 * @since 3.0.0
 */
function process_default_headers() {
	global $_wp_default_headers;

	if ( !empty($this->headers) )
		return;

	if ( !isset($_wp_default_headers) )
		return;

	if ( is_array( $this->default_headers ) ) {
		return;
	}

	$this->default_headers = $_wp_default_headers;
	$template_directory_uri = get_template_directory_uri();
	$stylesheet_directory_uri = get_stylesheet_directory_uri();
	foreach ( array_keys($this->default_headers) as $header ) {
		$this->default_headers[$header]['url'] =  sprintf( $this->default_headers[$header]['url'], $template_directory_uri, $stylesheet_directory_uri );
		$this->default_headers[$header]['thumbnail_url'] =  sprintf( $this->default_headers[$header]['thumbnail_url'], $template_directory_uri, $stylesheet_directory_uri );
	}
}

261行目で $_wp_default_headers を代入しています。
しかし、$_wp_default_headers は249行目で global 宣言されています。
なんてこった・・・
このソース (custom-header.php) だけで完結しねぇ・・・ orz

で、結局、$_wp_default_headers も他のソースでも初期化されているふうはなく、
配列として明示的に指定してやることをやってそうな関数は、
theme.phpregister_default_headers 関数

/**
 * Register a selection of default headers to be displayed by the custom header admin UI.
 *
 * @since 3.0.0
 *
 * @param array $headers Array of headers keyed by a string id. The ids point to arrays containing 'url', 'thumbnail_url', and 'description' keys.
 */
function register_default_headers( $headers ) {
	global $_wp_default_headers;

	$_wp_default_headers = array_merge( (array) $_wp_default_headers, (array) $headers );
}

よって、解消方法としては、この (register_default_headers) 関数を使って、
明示的に、デフォルトヘッダ画像を(配列として)エントリしてやればよさそうです。

register_default_headers(array(
	'photo-green' => array(
		'url' => '%s/images/header_photo-green.jpg',				// ヘッダー画像のアドレス
		'thumbnail_url' => '%s/images/thum_photo-green.jpg',		// ヘッダー画像のサムネイルのアドレス
		'description' => '木漏れ日'									// ヘッダー画像の説明や日本語名など(省略可)
	),
	'photo-sky' => array(
		'url' => '%s/images/header_photo-sky.jpg',
		'thumbnail_url' => '%s/images/thum_photo-sky.jpg',
		'description' => '青空'
	),
	'photo-tunnel' => array(
		'url' =>  '%s/images/header_photo-tunnel.jpg',
		'thumbnail_url' => '%s/images/thum_photo-tunnel.jpg',
		'description' => 'トンネル'
	),
	'texture-green' => array(
		'url' => '%s/images/header_texture-green.jpg',
		'thumbnail_url' => '%s/images/thum_texture-green.jpg',
		'description' => '緑のプリント基盤'
	),
	'texture-blue' => array(
		'url' => '%s/images/header_texture-blue.jpg',
		'thumbnail_url' => '%s/images/thum_texture-blue.jpg',
		'description' => '青い蜂の巣'
	),
	'texture-yellow' => array(
		'url' => '%s/images/header_texture-yellow.jpg',
		'thumbnail_url' => '%s/images/thum_texture-yellow.jpg',
		'description' => '黄色いビームライン'
	)
));

register_default_headers 関数へ食わせるパラメータは、
必ずしも複数のデフォルト画像を用意する必要はありませんが、
連想配列の多次元配列として与えてやる必要があります。
(上記、7行目から31行目はなくても大丈夫ということ)

なんだかなぁ・・・
どうなんだろう、このバグ・・・雑だなぁ

私が発見したときには未だ解決してませんでしたけど、
日本語版でも英語版でもフォーラムで話題に挙がったみたいですね。
このバグ・・・
> WordPress フォーラム 日本語:エラー ヘッダー画像関連?
> php problems with responsive on WordPress 3.9

関連記事

【カスタムヘッダー】 JavaScript

テンプレート作成の手順を徐々に公開しつつ、その中で WordPressのバグにつ...

記事を読む

カレンダー

2019年5月
« 7月    
 1234
567891011
12131415161718
19202122232425
262728293031  
PAGE TOP ↑