without language codes to permalink may causes 404

After activating SimpleTagging plugin I faced some problem. To avoid that I disabled the Gengo’s feature `Gengo should append language codes to permalinks automatically.’.

Days later I noticed a WordPress’ strange behavior.

I have pages having translations and when I clicked a link to the another language’s page then I saw a `404 Error’ page.

That’s strange.

Went further investigation I found a bad smelling code in the `locale’ filter.

Index: gengo.php
===================================================================
--- gengo.php   (revision 80)
+++ gengo.php   (working copy)
@@ -1222,7 +1222,7 @@
  } else {
    $value = $parser->query_vars['pagename'];
    if (($position = strpos($parser->query_vars['pagename'], '/')) !== false) {
-     $value = substr($value, $position + 1);
+     $value = substr($value, 0, $position);
    }
    $where = "p.post_name = '$value'";
    $join = "INNER JOIN $wpdb->posts AS p ON p.ID = p2l.post_id";

One of the pair pages I faced 404 error have 3 depth hierarchy.

software/wordpress-plugins/l10n-helper.html    <English>
software_ja/wordpress-plugins/l10n-helper.html <Japanese>

Before modification the value of $value was set as:

wordpress-plugins/l10n-helper.html <English>
wordpress-plugins/l10n-helper.html <Japanese>

$wpdb->posts.post_name only have a post name for 1 depth of hierarchy but the code got of 2 depth. And the code does not seem to care of WordPress feature that it allows to have same post name among pages while the top of ancestors of those page’s are not same.

I fixed the code to obtain the first part of uri.

Gengo and cache

It seems that Gengo cares WordPress’ cache feature a bit but not entirely.
I don’t know it comes from the fact that the cache feature is disabled by default.

Anyway there must be some bugs on it.

Past days I saw a kind of it on category listing then I gave away the category listing and replaced by SimpleTagging.

After that I noticed that there was similar thing on page listing. I couldn’t throw away this feature. I needed it.

The problem was that the page list block in the sidebar could be empty for all locales but the one visited firstly after cache feature had been enabled or cache for the page listing had expired.

I tried to fix the bug and have done.

I made a function gengo_list_pages(), which is to be replaced by wp_list_pages() in sidebar.php, in general.

<?php
if (!function_exists('gengo_list_pages')) {
function gengo_list_pages($args = '') {
    if (is_array($args)) {
        $r = &$args;
    } else {
        parse_str($args, $r);
    }
    $r = array_merge(array('language' => the_language(true)), $r);
    return wp_list_pages($r);
}
}
?>

There is also a related bug in the core code of WordPress 2.2.1.

Index: post.php
===================================================================
--- post.php    (revision 3)
+++ post.php    (working copy)
@@ -1070,9 +1070,14 @@
        extract($r, EXTR_SKIP);

        $key = md5( serialize( $r ) );
-       if ( $cache = wp_cache_get( 'get_pages', 'page' ) )
-               if ( isset( $cache[ $key ] ) )
-                       return apply_filters('get_pages', $cache[ $key ], $r );
+       if ( $cache = wp_cache_get( 'get_pages', 'page' ) ) {
+               if ( isset( $cache[ $key ] ) ) {
+                       $pages = apply_filters('get_pages', $cache[ $key ], $r );
+            if ( $pages && ( $child_of || $hierarchical ) )
+                $pages = & get_page_children($child_of, $pages);
+            return $pages;
+        }
+    }

        $inclusions = '';
        if ( !empty($include) ) {

Gengoとキャッシュで不具合いろいろ(2)

SimpleTaggingプラグインとの相性の悪さから、Gengo設定の「Gengo should append language codes to permalinks automatically.」をOFFにしているが、この設定におけるGengoの不具合発覚。

l10 helperプラグインは英日2言語を用意しているが、一方のページから他方の翻訳版リンクをクリックすると404エラーが発生。おかしい。

調べてみると、localeフィルタ関数内でページ名からロケールを判定する部分に甘さがあった。

Index: gengo.php
===================================================================
--- gengo.php   (revision 80)
+++ gengo.php   (working copy)
@@ -1222,7 +1222,7 @@
  } else {
    $value = $parser->query_vars['pagename'];
    if (($position = strpos($parser->query_vars['pagename'], '/')) !== false) {
-     $value = substr($value, $position + 1);
+     $value = substr($value, 0, $position);
    }
    $where = "p.post_name = '$value'";
    $join = "INNER JOIN $wpdb->posts AS p ON p.ID = p2l.post_id";

当該ページは英日ともに多階層構造になっていて、各相対リンクはこう:

software/wordpress-plugins/l10n-helper.html    <英>
software_ja/wordpress-plugins/l10n-helper.html <日>

上記変更前のコードで $value に代入される値はこう:

wordpress-plugins/l10n-helper.html <英>
wordpress-plugins/l10n-helper.html <日>

$wpdb->posts.post_nameには1階層分しか登録されてないのに修正前は2階層取得してしまっている。さらに最初の階層(software/software_ja)さえ異なっていれば以降の階層では同一名が使えるようになっているWordPressの仕様も考慮されていない。

ということで、最初の階層部分のみを取り出すようにコードを修正した。

…あ、これはキャッシュと関係なかったか。

はてな記法プラグイン公開

WordPress用のはてな記法プラグインを公開した。

そもそもは、誰か作っててくれないかなと探してみても誰も作ってないのか見つからない、探す間に現行のText:Hatena Perl モジュール機能縮小版であって、ソースコードのハイライト表示機能もパッチを当てないと本家はてな日記のようには表示されないというのが分かって、「それじゃぁ、ちょっとやってみよか」と始めたもの。

ほどなく動くようにはなったものの、それでは公開してみよか、という段になって、「設定画面が必要だ」「設定方法をちょっとは易しく」「Windows対応にもチャレンジ」「設定テストも入れてまえ」「Text::Hatena 0.16でも試してみよか」だのと、どんどん工数がかさんで公開まで日数がかかってしもた。

ようやく完了。

しかし、Text::Hatenaのインストールが必要だのなんだので、サーバに慣れてない人にはだいぶ敷居の高いものになってしもた。

Gengoとキャッシュで不具合いろいろ

どうもGengoはキャッシュと相性が悪い、というかキャッシュを考慮してない様子。

WordPress自体、キャッシュ機能がデフォルトで無効になっている影響なのか、不具合や考慮もれがあちらこちらにありそう。

wp-hackers MLにもポストしたが、ちょこちょことパッチを作っている次第。

そのひとつに、サイドバーのページリストが、あるロケールでは表示されるけどそれ以外のロケールでは表示されない、という不具合がある。

wp_list_pages() にかわるgengo_list_pages()を作って解決を目指す。

<?php
if (!function_exists('gengo_list_pages')) {
function gengo_list_pages($args = '') {
    if (is_array($args)) {
        $r = &$args;
    } else {
        parse_str($args, $r);
    }
    $r = array_merge(array('language' => the_language(true)), $r);
    return wp_list_pages($r);
}
}
?>

/wp-includes/post.php にも不具合があるので、パッチ。

Index: post.php
===================================================================
--- post.php    (revision 3)
+++ post.php    (working copy)
@@ -1070,9 +1070,14 @@
        extract($r, EXTR_SKIP);

        $key = md5( serialize( $r ) );
-       if ( $cache = wp_cache_get( 'get_pages', 'page' ) )
-               if ( isset( $cache[ $key ] ) )
-                       return apply_filters('get_pages', $cache[ $key ], $r );
+       if ( $cache = wp_cache_get( 'get_pages', 'page' ) ) {
+               if ( isset( $cache[ $key ] ) ) {
+                       $pages = apply_filters('get_pages', $cache[ $key ], $r );
+            if ( $pages && ( $child_of || $hierarchical ) )
+                $pages = & get_page_children($child_of, $pages);
+            return $pages;
+        }
+    }

        $inclusions = '';
        if ( !empty($include) ) {

ActivePerlにText::Hatenaをインストール

「はてな記法」の実装であるText::HatenaActivePerlに組み込む手順。

  • ActivePerlをインストール。
    オプション等はデフォルト設定を推奨。
  • nmake.exeを持っていなければインストール。
    何のことか分からなければ、配布場所からダウンロードし、そのファイルを実行して展開されたNMAKE.EXENMAKE.ERRC:\Windows\SYSTEM32あたりに放り込む。
  • コマンドプロンプト(cmd.exe)を開く
  • cpanを開く。
C:\WINDOWS\SYSTEM32> cpan
  • Text::Hatenaのインストール1回目。何か聞かれたらすべて YES で。
cpan> install Text::Hatena
  • 順調であれば、「mk_classdataが見つからない」という意味のエラーでインストールが中断する。
    Class::Data::Inheritableをインストール。
cpan> install Class::Data::Inheritable
  • Text::Hatenaのインストール2回目。うまくいけばそれで完了。
cpan> install Text::Hatena

xampp環境のPerlにText::Hatenaをインストール

「はてな記法」の実装であるText::Hatenaxamppに組み込む手順。

  • xamppのインストール
  • xamppと共に公開されているXAMPP Windows版 アドオン、perl-5.xをインストール
  • 環境変数 PATH に、インストールしたPerlのディレクトリを追加
    1. 「コントロールパネル」を開く
    2. 「システム」を選択
    3. 「詳細設定」タブを開く
    4. 「環境変数(N)」を選択
    5. ユーザ環境変数またはシステム環境変数にすでにPATHがあれば選択して「編集(E)」を、なければ「新規作成(N)」
    6. 「変数名(N)」にPATH変数値(V)にPerlへのパスを追加。「編集(E)」の場合、既存の値の後ろにセミコロン (;) を挟んで追加。
      (例) C:\WINDOWS;c:\xampp\perl\bin
  • コマンドプロンプト(cmd.exe)を開く
  • cpanを開く。
C:\WINDOWS\SYSTEM32> cpan
  • Text::Hatenaのインストール1回目。何か聞かれたらすべて YES で。
cpan> install Text::Hatena
  • 順調であれば、「mk_classdataが見つからない」という意味のエラーでインストールが中断する。
    Class::Data::Inheritableをインストール。
cpan> install Class::Data::Inheritable
  • Text::Hatenaのインストール2回目。うまくいけばそれで完了。
cpan> install Text::Hatena

Installed `Gengo’

I installed Gengo, a WordPress plugin, which enables WordPress to write blog/Pages in multi languages.

But its installation was painful. Very poor document – there’s only FAQ but not manual. What’s `Summary’? What’s `Group’ in Gengo context? Force users to build installation knowledge from a tiny pieces in FAQ. Just nonsense.

Gengo導入

Gengoという多言語プラグインを導入。導入マニュアルみたいなんが見つからないので結構時間がかかった。整備したらんとあかんなぁ。

本家サイトのプラグインリストに登録

そういえば、OS再インストールの前に、2007/6/14のエントリで書いたプラグインを本家のプラグインディレクトリ公開した

ブログに書いてから本家公開まで間が空いたのは、本家にプラグイン登録のリクエストをしてから承認されるまで時間が掛かったから。

6/14 19:47:44 JST に申請して、承認が 6/16 6:04 JST。

何にそんなに時間かかったんかなぁ。