Quick-barの文字化け対策をしたメモ

ずいぶんと、使い続けている『Fastfood[ref]TwoBeers Project – artigiani del byte[/ref]』というWordPressのテーマ。

このテーマはおもしろいギミックが付いているので、気に入って使っています。
画面下の方の左右にアイコンが表示されているのですが、このアイコンにマウスカーソルを乗せると『最近の投稿』や『最近のコメント』などを下からにゅっと飛び出して表示してくれます。
ちょっと、おもしろいですよね。
たぶん、似たような仕掛けをしてあるテーマは他にもあると思いますが、『home』ボタンや、『PageTop』などのボタンもあって機能的に一番バランスがとれているし、デザインも悪くないので、これがお気に入りという次第です。

ただ、このテーマの唯一残念なところが、前述の『最近の投稿』や『最近のコメント』を表示させたときに一部、文字化けを引き起こしてしまっています。
例えば、長いタイトルなどは端折って表示をしているのですが、この端折られたタイトルの末尾などが文字化けを引き起こしています。
fastfood_1_thumb Quick-barの文字化け対策をしたメモ

まあ、こんな感じなのです。
投稿エントリーと比べてみると判りますが、文字化けをしている部分は長いタイトルの端折られた部分になります。

どこで文字化けを引き起こしているのかな…。
まずは、初歩の初歩、HTMLソースを見てみましょう。
Javascriptで非同期通信なんかされて表示されていたらおいらにはお手上げなんですが、幸いなことにソースにそのまま記述がありました。
どうやら、スタイル設定で隠しているだけのようですね。
では、どこで文字列を出力しているのでしょうね?
まずは、場所のヒントを探さなければならないですね。
おいらはいつも、class設定や、id設定をヒントに探します。
今回は

<ul class="solid_ul">

の『solid_ul』というのをヒントに探してみました。
すると、footer.phpというテーマのファイルの中に見つけることが出来ました。
見つけた行の前後とHTMLソースを比べてみて同じHTMLコードが列記してありました。
[php]

[/php]
そして、

    タグの内側に
    [php][/php]
    コードを見つけるわけです。
    どうも、ここで『最近の投稿』の中身を作り出しているようですね。
    では、get_fastfood_recententries() という関数を探しましょう。
    通常、テーマで独自に定義する関数はテーマファイル内のfunction.phpで定義されています。
    そして、見つけた部分です。
    [php]
    // Get Recent Entries
    function get_fastfood_recententries( $mode = ”, $limit = 10 ) {
    $lastposts = get_posts( ‘numberposts=10’ );
    foreach( $lastposts as $post ) {
    setup_postdata( $post );
    $post_title = esc_html( $post->post_title );
    if ( strlen( $post_title ) > 35 ) {
    $post_title_short = substr( $post_title,0,35 ) . ‘…’;
    } else {
    $post_title_short = $post_title;
    }
    if ( $post_title_short == “” ) {
    $post_title_short = __( ‘(no title)’ );
    }
    [/php]
    今回の文字化けもそうなんですがある文字列の一部分を取り出す処理をしている場合に多いのが『マルチバイト文字列を考慮していない』コードを組んでいるケースが多いものです。
    なので、今回も一番最初に疑ってみました。
    8行目にありますね。
    [php]$post_title_short = substr( $post_title,0,35 ) . ‘…’;[/php]
    のsubstr という関数です。
    日本語を処理する場合は文字コードの問題上、マルチバイト文字列処理関数系を使わないと正しくない位置で処理されてしまうことがあります。
    乱暴に言ってしまえば日本語の文字はアルファベット2文字分で表現されている[ref]詳しくはweb検索して解説ページをご覧ください<(_ _)>[/ref]ので、日本語を前提とした処理をしてあげないと文字の途中で斬られてゴミが残ってしまいますよ…と言うことです[ref]乱暴すぎです(^_^;[/ref]
    と言うことで、8行目は
    [php]$post_title_short = mb_substr( $post_title,0,35 ) . ‘…’;[/php]
    としてあげればひとまず文字化けはしないはずです。
    ただね。
    これは、一部の文字列から指定した文字数分の文字列を取り出す…という関数な訳なんですが、取り出す文字列の数は『アルファベット(半角英数文字)』を前提とした文字数なんです。
    関数をsubstrからmb_substrに変えたことで日本語も正しく1文字としてカウントしますから、表示する際には最大、倍の領域が必要と言うことになります。
    実際、mb_substrに変えただけだと改行をしてしまいます。
    お気に召さない場合は、さらにもう一工夫が必要です。
    と言うわけで、さらに一工夫。
    mb_substr( $post_title,0,35 )
    の部分は『取り出す文字数[ref]あれ?解説ページにはバイト数となっているorzそれにしては挙動がバイト数じゃないんだよな…文字数のような気がする[/ref]』を表しています。
    なので、ここを変更すれば取り出す文字数を少なくすることが出来ます。
    そして、もう一カ所。
    その上の行の
    [php]if ( strlen( $post_title ) > 35 ) {[/php]
    でこの処理を行うか否かの判定をしているのですが、実は文字列が一定数(この場合35バイト分の文字数)かどうかという判定をしています。
    ここの判定は、判定自体はバイト数で判断すれば事足りるのでマルチバイト対応である必要性はないのですが、前述のmb_substrで、日本語を前提とした処理に変えてしまっているので、この判定部分の処理もマルチバイト前提の処理に変えてあわせてあげないとおかしな自体が起こりえます。
    なので、この部分も
    [php]if ( mb_strlen( $post_title ) > 35 ) {[/php]
    と、マルチバイト関数に置き換えてあげます。
    もちろん、mb_strlen( $post_title ) > 35も前述の数字に合わせる必要があります。
    これで、文字化けは解消されるはずです。
    解消されたし。

    実際には、他にも何カ所か同様の処理がされている部分があります。
    対処方法は基本的に同じです。
    substrをmb_substrに変更する。
    strlenをmb_strlenに変更する。
    そして、35を少なくする。
    おいらはとりあえず21にしてみた。

    そんな感じです。
    まあ、覚え書きと言うことで。