WordPressを4.4.0にアップデートしたら画像が表示されなくなった

Wordpress

クラウドフレアがHTTP/2に対応を始めて、その後Wordpressのコアやテーマをアップデートしたら、画像の表示がおかしくなりました。

具体的には、ほとんど全ての画像が表示されなくなるという状態でした。

trouble-in-thumbnails

最初は、使用させて頂いているテーマ「Simplicity 1.7.8」のHTTP/2への対応にバグがあるかと思ったのですが、あれこれ試行錯誤した結果WordPressの新しいコアがSSLに対応していないのが原因だったようです。

ついでに、そもそもWordPressがSSL対応していなくて、<img src=の部分だけ置き換えていたのを思い出したのでした・・・。

画像が表示されない!

ブログの更新履歴に画像が表示されない

トップページのサムネイル画像も表示されませんでした。

これは、テーマのカスタマイズで「レイアウト(全体・リスト)」を選択して、「一覧リストのスタイル」を「サムネイルカード(デフォルト)」から「サムネイル大」や「タイル2列」「タイル3列」に変更したところ表示されるようになりました。

このため、テーマにバグがあるかと思っていました・・・。

関連記事リストの画像も表示されない

trouble-in-thumbnails

関連記事のリストも表示されません。

記事中の画像も表示されない

サムネイル画像だけではなく、記事中の大きい画像も表示されません。

trouble-in-images

ソースを見てみると、<img>タグにsrcset=”http://…….”という目新しい記述が追加されています。

これがそもそもの原因でHTTP/2になって混在コンテンツのポリシーが変わったせいか、画像が表示できなくなっています。

ChromeでもFirefoxでも

Google ChromeとMozilla Firefoxで試しましたが、同じ症状です。

原因と対策

色々試した結果、WordPressの中身をいじる、もしくは置き換えプラグインを使う必要がありましたが、復旧できました。

画像が表示できなくなった原因

今回画像表示ができなくなったのは、

  1. 使っているCDN(元サーバーの変わりにファイルを送信してくれるネットワーク)のクラウドフレアがHTTP/2接続に移行しこと
  2. ブラウザのポリシーで非SSLの混在コンテンツが表示できない、もしくはリダイレクト(HTTPSへリダイレクトしています)して表示することができない(おそらくHTTP/2接続の場合に限る?)
  3. WordPress 4.4.0で画像表示にsrcset(レスポンシブデザインにネイティブ対応するためのタグが使われ始めた

ためだと思います。

(追記)WordPress 4.5.0でsrcset内の表示は改善された模様です。私のWordPressはどこかいじっていた(そしてどこをいじったのか忘れてしまった・・・・)ので完全な検証は出来ませんが、<img src=部分はhttpのままで変わりませんが、srcsetはプロトコル非依存になっているような気がします。

対策1:プラグインで書き換え

元々<img src=”http://….”を書き換える設定をしたまま忘れていましたのが混乱の原因でしたが、srcset=”http://…”も書き換えれば解決できそうです。

プラグイン利用のほうが簡単ですが、若干遅くなるかもしれません。

対策2:WordPressのコード書き換え

書き換えが必要なファイルは、

/wp-include/media.php

です。srcset=”http://…”の部分を書き換えるだけであれば、WordPress 4.4.0では1000行目辺りの関数「wp_calculate_image_srcset」内で置換させたところ、上手くいきました。

function wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id = 0 ) {
  if ( empty( $image_meta['sizes'] ) ) {
    return false;
  }

  $image_sizes = $image_meta['sizes'];

  // Get the width and height of the image.
  $image_width = (int) $size_array[0];
  $image_height = (int) $size_array[1];

  // Bail early if error/no width.
  if ( $image_width < 1 ) {
    return false;
  }

  $image_basename = wp_basename( $image_meta['file'] );
  $image_baseurl = _wp_upload_dir_baseurl();

  /*
   * WordPress flattens animated GIFs into one frame when generating intermediate sizes.
   * To avoid hiding animation in user content, if src is a full size GIF, a srcset attribute is not generated.
   * If src is an intermediate size GIF, the full size is excluded from srcset to keep a flattened GIF from becoming animated.
   */
  if ( ! isset( $image_sizes['thumbnail']['mime-type'] ) || 'image/gif' !== $image_sizes['thumbnail']['mime-type'] ) {
    $image_sizes['full'] = array(
      'width'  => $image_meta['width'],
      'height' => $image_meta['height'],
      'file'   => $image_basename,
    );
  } elseif ( strpos( $image_src, $image_meta['file'] ) ) {
    return false;
  }

  // Uploads are (or have been) in year/month sub-directories.
  if ( $image_basename !== $image_meta['file'] ) {
    $dirname = dirname( $image_meta['file'] );

    if ( $dirname !== '.' ) {
      $image_baseurl = trailingslashit( $image_baseurl ) . $dirname;
    }
  }

  $image_baseurl = trailingslashit( $image_baseurl );

  // Calculate the image aspect ratio.
  $image_ratio = $image_height / $image_width;

  /*
   * Images that have been edited in WordPress after being uploaded will
   * contain a unique hash. Look for that hash and use it later to filter
   * out images that are leftovers from previous versions.
   */
  $image_edited = preg_match( '/-e[0-9]{13}/', wp_basename( $image_src ), $image_edit_hash );

  /**
   * Filter the maximum image width to be included in a 'srcset' attribute.
   *
   * @since 4.4.0
   *
   * @param int   $max_width  The maximum image width to be included in the 'srcset'. Default '1600'.
   * @param array $size_array Array of width and height values in pixels (in that order).
   */
  $max_srcset_image_width = apply_filters( 'max_srcset_image_width', 1600, $size_array );

  // Array to hold URL candidates.
  $sources = array();

  /*
   * Loop through available images. Only use images that are resized
   * versions of the same edit.
   */
  foreach ( $image_sizes as $image ) {

    // Filter out images that are from previous edits.
    if ( $image_edited && ! strpos( $image['file'], $image_edit_hash[0] ) ) {
      continue;
    }

    // Filter out images that are wider than '$max_srcset_image_width'.
    if ( $max_srcset_image_width && $image['width'] > $max_srcset_image_width ) {
      continue;
    }

    // Calculate the new image ratio.
    if ( $image['width'] ) {
      $image_ratio_compare = $image['height'] / $image['width'];
    } else {
      $image_ratio_compare = 0;
    }

    // If the new ratio differs by less than 0.002, use it.
    if ( abs( $image_ratio - $image_ratio_compare ) < 0.002 ) {
      // Add the URL, descriptor, and value to the sources array to be returned.
      $sources[ $image['width'] ] = array(
        'url'        => $image_baseurl . $image['file'],
        'descriptor' => 'w',
        'value'      => $image['width'],
      );
    }
  }

  /**
   * Filter an image's 'srcset' sources.
   *
   * @since 4.4.0
   *
   * @param array  $sources {
   *     One or more arrays of source data to include in the 'srcset'.
   *
   *     @type array $width {
   *         @type string $url        The URL of an image source.
   *         @type string $descriptor The descriptor type used in the image candidate string,
   *                                  either 'w' or 'x'.
   *         @type int    $value      The source width if paired with a 'w' descriptor, or a
   *                                  pixel density value if paired with an 'x' descriptor.
   *     }
   * }
   * @param array  $size_array    Array of width and height values in pixels (in that order).
   * @param string $image_src     The 'src' of the image.
   * @param array  $image_meta    The image meta data as returned by 'wp_get_attachment_metadata()'.
 	 * @param int    $attachment_id Image attachment ID or 0.
   */
  $sources = apply_filters( 'wp_calculate_image_srcset', $sources, $size_array, $image_src, $image_meta, $attachment_id );

  // Only return a 'srcset' value if there is more than one source.
  if ( count( $sources ) < 2 ) {
    return false;
  }

  $srcset = '';

  foreach ( $sources as $source ) {
    $srcset .= $source['url'] . ' ' . $source['value'] . $source['descriptor'] . ', ';
  }

  return rtrim( $srcset, ', ' );
}

最後のreturnにstr_replaceをかませればOKです。

return str_replace('http://', '//', rtrim( $srcset, ', ' ));

この方法の問題点は、srcsetだけしか置換していないところと、WordPressを更新すると消えてしまうことです。

テーマ内で関数のオーバーライドとか、できそうな気がしますが、とりあえずこれだけで・・・。

ページ内容書き換えプラグインを使わないで済ませるなら、<img src=”http://…”のほうも同じように書き換える必要がありそうです。

たぶん、同じmedia.php内の

  • function _wp_upload_dir_baseurl()
  • function wp_image_add_srcset_and_sizes( $image, $image_meta, $attachment_id )

辺りで何とかなりそうな気がします。

(追記)恐らく現行バージョンでは不要になっていますが、一応残しておきます。

コメント

タイトルとURLをコピーしました