国際化タグの投稿

WordPress 2.7 のカテゴリー/タグごと CSS 割り当て機能を修正する
新機能の問題点を指摘していた WordPress 2.7 ですが、さきほどリリースされてしまいました。trac のチケットを切ったり、WordPress 日本語フォーラムでトピックを作ったんですが、結局直されませんでした……。やっぱり「WordPress 開発者の I18N 対応は優先度が低い」と言えます。これらの改善のためには、英語以外のユーザーが増えてもっと口出ししなければなりません。
さて、嘆いていても進まないので、とりあえず改善用プラグインを作ってみました。詳細は日本語フォーラムを見てもらうとして、ここでは改善コードを出しておきましょう (スラッグを URL デコードする、という仕組みです)。以下のコードを新規テキストファイルにコピー & ペーストして適当な名前 (fix-post_class.php など) で保存し、WordPress のプラグインディレクトリーにアップロードすれば OK です。WordPress 2.7 では、zip ファイルにしておけばインストールが簡単なんですが、「あえて敷居を高くする」ということで、このままにしておきます
<?php
/*
Plugin Name: Fix Post Class
Plugin URI: http://www.yuriko.net/arc/2008/12/11/fix-post_class/
Description: Use url-decoded CSS class names for assigned categories/tags of each post with WordPress 2.7
Version: 1.0.0
Author: IKEDA yuriko
Author URI: http://www.yuriko.net/cat/wordpress/
*/
/* Copyright (c) 2008 yuriko
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
function fix_post_class($classes, $class, $post_id) {
$num_classes = count($classes);
if ($num_classes < 1) {
return $classes;
}
for ($i = 0 ; $i < $num_classes ; $i++) {
if (strpos($classes[$i], '%') !== 0) {
$classes[$i] = preg_replace('/[^-_0-9a-zA-Z\x80-\xff]/', '', urldecode($classes[$i]));
}
}
return $classes;
}
add_filter('post_class', 'fix_post_class', 99, 3);
?>
[追記] 日本語フォーラムでの議論では、XHTML 1.0 の場合は「WordPress 2.7 の実装は問題ないが、style.css の方では % 記号をバックスラッシュでエスケープする必要がある」「上記プラグインによる Unicode 化も正しい方法である」(可読性ではこちらが上) となります。しかし、XHTML 1.1 では、% 記号に加え、Unicode 文字列が不可となるため、WordPress の実装自体 NG となります (上記プラグインの解決方法もだめ)。XHTML 1.1 は class 属性の部分が NMTOKENS になったのですが、NMTOKES は英数字だけじゃなくて Unicode の文字列も含まれるため、日本語でも OK です。つまり、上記プラグインは XHTML 1.1 でも使えます。post_class() 関数は、XHTML 1.1 の出力かどうかで動作を変える必要があるわけです。上記プラグインは、XHTML 1.0 でのみ使ってください。

WordPress 本家開発者の I18N 軽視はどうにかならんか
現在開発中の WordPress 2.7 ですが、新機能として「投稿表示部分を囲む div 要素に、属するカテゴリーごとの class 指定ができる」というものがあります。例えば、mobile カテゴリーの投稿ならば、div class="category-mobile" という div 要素で囲まれます。これ自体はデザインの多様化が図れて歓迎されることなんですが、その実装があまりに国際化や HTML/CSS 仕様を無視したもので、泣けてきます。
この機能は、Changeset 8641 にて post_class() 関数を増強する形で追加されました。コード (下に引用) を見ると分かりますが、”category-XXXX” の XXXX の部分は、カテゴリースラッグそのままです。ところが、カテゴリースラッグに使える文字と、class 指定に使える文字の範囲が異なるため、このままでは XHTML および CSS 違反になってしまいます。カテゴリー名が英数字だけならば、スラッグは a-z, 0-9, – (ハイフン), _ (アンダースコア) だけになるため問題ありません。しかし、カテゴリー名に Unicode 文字 (日本語等) を使うと、スラッグは %nn という URL エンコードした形式になります。しかし、class 名には % 記号は使えないのです!! 現在のコードでは、class 名に % 記号を含んだものになってしまいます (「携帯」カテゴリーならば “category-%e6%90%ba%e5%b8%af” となってしまう)。
186 // Categories
187 foreach ( (array) get_the_category($post->ID) as $cat ) {
188 if ( empty($cat->slug ) )
189 continue;
190 $classes[] = 'category-' . $cat->slug;
191 }
192
193 // Tags
194 foreach ( (array) get_the_tags($post->ID) as $tag ) {
195 if ( empty($tag->slug ) )
196 continue;
197 $classes[] = 'tag-' . $tag->slug;
198 }
今までも、WordPress 開発者は、I18N (国際化対応) がいい加減だと思っていましたが、今回もまた配慮が足りません……。早々にチケットを切らないといけませんが、対応策としては「カテゴリー ID を使う」ぐらいしか思い浮びません。スラッグから % 記号を抜いたもの、とか、% を _ に変化させたもの、を使うのはいまいちだと思いますし。実は class 名には「ASCII 以外の Unicode 文字」が使えるため「category-携帯」という出力でよかったりするんですが、既存のウェブブラウザーがそういう記述を認識するのかは疑問なので、「スラッグではなくカテゴリー名そのものを使う」という変更が有効なのかは疑問です……。
[追記] いい加減な英語でチケット#8446を切りました。結局、解決策としては、バックスラッシュで % 記号をエスケープするか、カテゴリー ID を使うかどちらか、ということにしました。カテゴリー名そのものを使うのは、ASCII 記号が含まれている場合によくないので没としました。
さきほど発表された WordPress 2.7 RC1 でも直っていませんでした……。チケットは切ってあるので、RC2 あたりで直してもらえることを期待しましょう。

上に戻る