WordPressでSSLアクセス時に警告が出ないようにする

6c06bc979db56cc86c70bf9643706e5b_s

別にCMSはなんでもいい派なのだけど(炎上用語)、
このサイトはWordPressで 作っている。
で、WordPressでいちばん個人的にイヤなのがあらゆるリソースを

http://www.example.com/some/thing/to/load.png
http://www.example.com/some/thing/to/load.css
http://www.example.com/some/thing/to/load.js

と、プロトコル・ドメイン名(FQDN)から絶対参照で書いてくれること。

これ、 おそらくもともとは「絶対参照で書いたほうがSEO上ポイント高い」とかいう 都市伝説から来ているんだと思う。これでPageRank上げるような情報弱者な 検索エンジンがあったら窓から投げ捨てたい…。まあ、WordPressだけじゃな くMovableTypeも同じ動作なんだけどね、あっちはカスタマイズありきだからさ…。

で、絶対参照で書かれると何が困るかというと、

  • HTTPでアクセスしたとき
    • 特に困らない
  • HTTPSでアクセスしたとき
    • 下図のようなアラートが出たり、
      mixed-alert
    • そもそもHTTPで参照しているリソースが読み込まれなかった
      りする(CSSが反映されなかったりJavaScriptが動かなかったり)

ということなので。
これを「HTTP/HTTPSミクストコンテンツ」問題と言います。

解決方法としては、

  • ドキュメントルート(/)からの絶対参照で書く
    これがいちばん正しいと思う。みんななぜそうしないのかわからない…
  • 実は「//www.example.com/some/thing/to/load.png」のように
    プロトコルを省略して書くとブラウザがよしなにはからってくれて、
    問題が起きない

のどちらか。WordPressの場合は、

  • ヘッダ・フッタ領域のCSS・JavaScript読み込みは自動で読み込みコントロール
    されているので、手書きで絶対参照に直すことができない
  • 自ドメイン(FQDN)だけでなく、外部ドメイン(FacebookとかGoogleとか)の
    リソースを読み込むことがあるため、ドメイン部分を省略できない

ということで、後者に沿って直す方法を検討する必要がある。 具体的には、自動的に生成されたヘッダ・フッタを加工してくれるフィルタメソッド をテーマのfunctions.phpに定義することだ。

ということで書いてみた。自分のfunctions.phpのおしりのほうに追加してみるとよ いと思われ。

/**
 * resolve http|https mixed contens
 */

// delete hostpart of attachment urls
function delete_host_from_attachment_url( $url ) {
    $regex = '/^http(s)?:\/\/[^\/\s]+(.*)$/';
    if ( preg_match( $regex, $url, $m ) ) {
        $url = $m[2];
    }
    return $url;
}
add_filter( 'wp_get_attachment_url', 'delete_host_from_attachment_url' );
add_filter( 'attachment_link', 'delete_host_from_attachment_url' );

// replace the output of wp_head()
add_action( 'wp_head', 'wp_head_buffer_start', 0 );
add_action( 'wp_head', 'wp_head_buffer_end', 100 );
function wp_head_filter($buffer) {
    $buffer = preg_replace(
        '/^(<script.*?src=[\'"])https*:/im',
        '$1',
        $buffer
    );
    $buffer = preg_replace(
        '/^(<link rel=[\'"]stylesheet[\'"] .*?href=[\'"])https*:/im',
        '$1',
        $buffer
    );
    // for crayon syntax higlighter
    $buffer = preg_replace(
        '/^(var CrayonSyntaxSettings.*"ajaxurl":")http:/im',
        '$1',
        $buffer
    );
    // Remove some plugins' credits. Sorry.
    $buffer = preg_replace(
        '/^.*<!-- This site is .*-->.*\r?\n/im',
        '',
        $buffer
    );
    $buffer = preg_replace(
        '/^<!-- \/ Yoast WordPress SEO plugin. -->\r?\n/im',
        '',
        $buffer
    );

    return $buffer;
}
function wp_head_buffer_start() {
    ob_start( 'wp_head_filter' );
}
function wp_head_buffer_end() {
    ob_end_flush();
}

// replace the output of wp_footer()
add_action( 'wp_footer', 'wp_footer_buffer_start', 0 );
add_action( 'wp_footer', 'wp_footer_buffer_end', 100 );
function wp_footer_filter($buffer) {
    $buffer = preg_replace(
        '/^(<script.*?src=[\'"])https*:/im',
        '$1',
        $buffer
    );
    // for contact form 7
    $buffer = preg_replace(
        '/^(var _wpcf7 = {"loaderUrl":")http:/im',
        '$1',
        $buffer
    );
    return $buffer;
}
function wp_footer_buffer_start() {
    ob_start( 'wp_footer_filter' );
}
function wp_footer_buffer_end() {
    ob_end_flush();
}
  • 最初のブロックで、投稿にメディア挿入する際のリソースリンクを / からの 絶対参照に修正している
  • 次のブロックで、wp_head() の出力を修正。
    crayon syntax higlighter のJSON設定中にある絶対参照も書き直しつつ、
    マナー上どうかとは思うが各種プラグインのクレジットコメントを消している
    (ごめんね。でもなんか汚くて…)
  • 最後のブロックは wp_footer() の出力を修正。
    こちらはContact Form 7のJSON設定中の絶対参照も書き直している

これで終わり! …と思った? 残念でした!

なんとJetPackに!付属しているFacebook Like Boxプラグインも、ミクストコンテ ンツの原因になるので、使っている場合は外すこと。自分で Facebookのサイト に行って、安全なコードを取得して貼り付けること(Facebook Page URLにはhttpsの URLを入力)。JetPackまでこれだもんなぁ…トホホ。

追記

で、これだけだと img, script などのHTML要素しか対処できないのを忘れてました…。

実際には、サイト内リンクもすべてa要素で href=”http://www.example.com/…” な
どとなっているし、form要素の action 属性も対処が必要です。

ということでネットをさまよって類似の全文フィルタを書いている人のを参考にしつつ、
より安全なほうに振った正規表現に書き換えてみました(自サイトURLをすべて/に置換
するのはさすがにやばいので)。

functions.php の最後のほうに追加しましょう。

// remove protocol and fqdn part from internal links
class relative_URI {
    function relative_URI() {
        add_action('get_header', array(&$this, 'get_header'), 1);
        add_action('wp_footer', array(&$this, 'wp_footer'), 99999);
    }
    function replace_relative_URI($content) {
        $home_url = trailingslashit( get_home_url('/') );
        $r = preg_replace(
            '!<a(.*?href=[\'"])' . $home_url . '!i',
            '<a$1/',
            $content
        );
        $home_url = untrailingslashit( $home_url );
        $r = preg_replace(
            '!<form(.*?action=[\'"])' . $home_url . '!i',
            '<form$1/',
            $r
        );
        return $r;
    }
    function get_header(){
        ob_start(array(&$this, 'replace_relative_URI'));
    }
    function wp_footer(){
        ob_end_flush();
    }
}
new relative_URI();

いやー、絶対参照書き換えは地獄だぜ。フーハハハー。