【WordPress 】文字エンコーディングをページごとに切り替える

【WordPress 】文字エンコーディングをページごとに切り替える

スマートフォンと Bluetooth 接続できる歯ブラシをつい買ってしまった kagata です。歯の健康維持という点で値段なりの価値があるのかはいまいちわかりませんが、たかが歯ブラシのくせにファームウェアアップデートがインターネットから降ってくるという大げさな雰囲気にはたいへん満足しています。

さて、今回は業務上の必要にかられて書いた WordPress カスタマイズのスニペットを紹介します。

やりたいこと

実案件で出てきた課題を、今回の記事のために少し簡略化します。次のような具合です。

  • スラッグ foo という固定ページを文字エンコーディング Shift-JIS で出力したい
  • 固定ページ foo 以外は WordPress デフォルトの UTF-8で出力する

コード

課題解決のため、次のようなコードを書きました。そんなに長いコードではないので、一挙にどーん。

add_action('wp', function () {

    // 固定ページ foo は文字エンコーディング Shift-JIS で出力する
    if (is_page('foo')) {

        // (1) HTTP ヘッダで文字エンコーディング Shift-JIS を指定する
        header('Content-Type: text/html; charset=Shift_JIS');

        // (2) ページのレンダリング結果をバッファする
        add_action('get_header', function () {
            ob_start();
        });

        // (3) ページのレンダリングが終わったところで、バッファしていた内容を UTF-8から Shift-JIS に変換して出力する
        add_action('shutdown', function () {
            $content = ob_get_clean();
            echo mb_convert_encoding($content, 'SJIS-win', get_bloginfo('charset'));
        }, 0); // wp_ob_end_flush_all() の実行順 1 より小さな値を指定する!
    }
});

これをテーマの functions.php なりにつっこんでやれば OK です。

では、内容を順に追っていきましょう。

やっていること

アクションフック wp で、表示しようとするページが固定ページ foo であるか判定します。 foo であれば、出力を Shift-JIS にするのに必要な次の3つの処理を実行します。

(1) HTTP ヘッダで文字エンコーディングを指定する

PHP の組み込み関数 header() で文字エンコーディングを指定します。これをしないと、HTTP レスポンスのヘッダで WordPress デフォルトの文字エンコーディング UTF-8が指定されてしまいます。その結果、続く (2) や (3) の処理を実行しても多くのブラウザでは文字化けしてしまうでしょう。

なお、WordPress に関数 header() を呼び出す処理を追加するときは、ふつうアクションフック wp でなく send_headers を使います。ただ、 send_headers の時点では条件分岐タグ関数が使えません。今回の処理では関数 is_page() を使いたいので、あえて wp を使いました。

一般的な WordPress のカスタマイズでは、アクションフック wpheader() を呼び出しても処理順として遅くはないはずです。同居するほかのカスタマイズとの兼ね合いでアクションフック send_headers を使わざるをえないときは、どのページがリクエストされているか WordPress クエリから直接判定する処理を書くことになるでしょう。

プラグイン API/アクションフック一覧 - WordPress Codex 日本語版

(2) ページのレンダリング結果をバッファする

PHP には、 echo をすぐさま実行するのでなく、 echo する内容をいったんバッファに貯めておいて、適当なタイミングで取り出す機能があります。これを出力バッファと呼んだりします。

PHP: 出力制御 - Manual

ふつうテンプレートで get_header() を呼び出すと、header.php の内容がすぐさま出力されてしまいます。アクションフック get_header を使って、 get_header() の処理の最初に関数 ob_start() を実行することで、テンプレートのレンダリング結果がいったんバッファに貯まるようにします。

(3) ページのレンダリングが終わったところで、バッファしていた内容の文字エンコーディングを変換して出力する

WordPress の処理の最後に呼び出されるアクションフック shutdown で、先ほど ob_start() でバッファしていた内容を関数 ob_get_clean() で取り出します。それを関数 mb_convert_encoding() で UTF-8から Shift-JIS に変換し、最後にその結果をまるまる echo してやります。

なお、アクションフック shutdown にこの処理を add_action() するとき、1より小さな実行順を明示的に指定してやる必要があります。なぜなら、WordPress コアでアクションフック shutdown の実行順1に関数 wp_ob_end_flush_all() がセットされており、この関数 wp_ob_end_flush_all() がすべてのバッファを出力・消去してしまうからです。

別解:テンプレートに処理を追加する

「WordPress Shift-JIS」のようなキーワードで Web 検索すると、「テンプレートの最初と最後に処理を記述する」という方法を紹介する記事がいくつか出てきます。例えば以下のような記事です。

UTF-8を強制的にSJISへ変換して表示する|Katalog

やっていることは今回紹介したコードとほぼ同じで、上に書いた処理 (1) をテンプレートの最初に、処理 (2) (3) をテンプレートの最後にそれぞれ書いているというわけです。

もちろん、この方法でも問題なく動作します。ただ、文字エンコーディングを変えたいテンプレートが複数ある場合、この方法ではそれらのテンプレートすべてに同じ処理を追加しないといけません。コードを DRY に保つという意味では、今回紹介したようなフックを使う形がベターかなと思います。

  • このエントリーをはてなブックマークに追加

この記事を読んだ人にオススメ