タグ別アーカイブ: PHP

複数人開発の時にデータベースの同期をうまく取る方法

最近「意外に若かったんだね」と言われるようになりました、その言葉の指すところについては考えないようにしています岡田洋一ですコンニチハ。

さて、僕はしばらくチームで開発を行っています。大人数というわけでも無く、2〜3人での小規模プロジェクトチームです。少人数制のチームではありがちで、僕以外のメンバーもプログラム〜インフラ周りも修正することが多く、データベースのテーブル構造を修正することが各自にありえます。

さてそんなときにデータベースの同期を取る方法について考えてみました。

現状はテーブルのCREATE分を出力させ、プロジェクトのwikiに書き込んでいます。

wikiは変更情報を保存しますので、ある程度のバージョン管理ができました。が、いかんせん「出力、編集、保存、確認、伝達、適用」と、修正内容をチーム内で共有するためのステップが多いのです。少人数チームでステップが多いのは良くないですね。素早さこそがウリですから。

次に「テーブルの差分になるALTERのみを書く」ということについて勘案しました。が、こちらも開発を兼ねているため、テーブルの変更となるALTER分はそこそこの数が出てしまい、すべてのALTERを記録して適用することは面倒となりました。素早さがなくなってしまいます。

 

というわけで、現在のテーブル情報を書き出しつつバージョン管理システムで共有、という手段にしました。

現在プロジェクトはSVNで管理されていたので、テーブル情報のみをファイルに書き出してコミット、それを手元へ適用という手段をとりました。ちなみにデータベースはMySQLです。

テーブル情報のみを書き出す為に必要なコードは

shell> mysqldump -h mysqlhost -u user -ppassword --no-data target_schema | sed 's/ AUTO_INCREMENT=[0-9]*//' > tables.sql

shell> svn commit tables.sql -m 'update table sql.'

となりました。mysqlのホスト名、ユーザ名、パスワード、対象スキーマは読み替えて下さい。パスワードはナシにするとプロンプトで聞いてきます。

パイプでsedに渡してAUTO_INCREMENTを消しています。

最後にこの出力をファイルに書き出して、コミットして共有します。

 

これだと差分をうまく見ることができるので便利ですね!

WordPressのテーマ/テンプレート開発の時に役に立つコード

ダイエットが終わらない岡田洋一です、コンニチハ。

さて、最近ひょんなことからWordPressのテンプレートを修正する機会がありました。WordPressはで見た目をいじるときにはテーマ(テンプレート)ファイルを編集する必要があります。

WordPressでのページ表示には色々な仕組みがあるのですが、今回僕が編集することになったのは「カスタム投稿タイプのカスタムタクソノミーのアーカイブ」だったんです。この辺りについてはテンプレートヒエラルキーなんていう聞き慣れない仕組みが関わってきています。

さて、このテンプレートヒエラルキーというのは、簡単に言ってしまえば「テンプレートを適用する順序」を決めるモノなのです。「カスタムタクソノミーのアーカイブ」であれば「taxonomy-archive.php」とかになるのですが、これがなかなかうまく見つけられなかったりします。

さてこんな時、開発を行うにあたっては、現在どのテンプレートファイルを表示しているか、というのが分かると非常に助かります。

今回はこの「どのテンプレートファイルで表示しているか」を調べるためのコードを紹介します。

下記のコードを header.php の好きな位置に埋めて下さい。

<?php if(is_user_logged_in()) : ?></span>

<!-- <?php global $template; print_r($template); ?> -->
 <?php endif; ?>

Screen Shot 2013-10-01 at 4.48.45 PM

こうすることでHTMLのヘッダにコメントとして、「表示に使用しているテンプレート」が書き込まれます。

ちなみに if文で「ログインしている状態にのみ」に表示されるようになっていますので、知らない人には表示されません!ちょっと安心ですね。

Screen Shot 2013-10-01 at 4.55.28 PM

これでどのテンプレートを使っているか迷わずに開発ができますね!

リバースプロキシを使っているとWordPressで記事の参照がループしてしまう問題について

0. WordPressで記事の参照がループしてしまう問題について

WordPressで記事ページを開いたときに無限ループしてしまう。記事ページはいわゆるsingle.php シングルというページ。ブラウザの表示は

“このウェブページにはリダイレクト ループが含まれています” (chrome)
“ページの自動転送設定が正しくありません” (FireFox)

といった感じでループがおかしいという事を告げられる。
開発ツールで転送設定を見てみると、確かに同じアドレス宛に301の “Moved Permanently” が連続して返却されている。
このままでは利用者が入って来れないので調査をしてみた。

1

1. WordPressでのリダイレクト

WordPressで転送はwp-includes/canonical.phpというファイルが担当する。
このファイルはリクエストURLを見てカスタムパーマリンク設定などに照らし合わせて最適なURLへ誘導してくれる機能を持っている。

例えばパーマリンクを投稿名にしているとき、 http://www.example.com/?p=123 というURLへアクセスがあった場合、
http://www.example.com/test-post/ というパーマリンクへ301(こっちのURLが正しいですよ、というブラウザへの命令)などのコードで転送してやるのだ。

他にも http://www.example.com/test-pos/ なんていうのを http://www.example.com/test-post/ へ転送することも行っている。(推測です)

こういったことを担当しているcanonical.phpなんだけれど、その中身はちょっと複雑。主に301系の転送を担当してはいるものの、いろいろな処理が入り乱れている。

2. 問題点

そこでこの処理を超ナナメ読みして今回の問題点を洗い出すとこうだ。
以下に二つのURLがある。
パーマリンクを元に作成された、記事自体のパーマリンク。リダイレクトしたいURLを redirect_url と呼ぶ。
リダイレクトされる前の、実際に今アクセスされているURLを requested_url とする。
この二つが一致しないので延々とredurect_urlにリダイレクトさせようとしてしまっている。

canonical.phpにあるredirect_canonicalという関数。すでにかなーり縦長で読みにくい上、一度だけ自身を呼び出すプチ再帰になってるのでこれまたわかりにくい。中にデバッグ用のコードがコメントアウトされて配布されてるところをみても苦労が窺える。
canonical.phpにあるredirect_canonicalという関数。すでにかなーり縦長で読みにくい上、一度だけ自身を呼び出すプチ再帰になってるのでこれまたわかりにくい。
中にデバッグ用のコードがコメントアウトされて配布されてるところをみても苦労が窺える。

普通の情況であれば一度リダイレクトされればredirect_urlはrequested_urlとなるんだけれど、今回の問題は違った。
じつはこのrequested_urlは$_SERVERを元に作成される。サーバ環境変数。つまり見せかけ上のURL(ドメイン名)と実際にPHPが動いているドメイン名が違っていると無限ループする、というわけだ。
この見せかけ上のドメインとPHPが動いているサーバのドメイン名が違う、というのはリバースプロキシを使っていると起こってしまう。
リバースプロキシは大規模なウェブサイトになると負荷分散の為に用いられる手法だ。

今回このサイトではapacheのmod_proxyを利用した簡単なリバースプロキシを噛ましていた。
手前で動いていてWordPressに登録されているドメイン名はwww.example.comなのに、背後のウェブサーバではwww1.example.comという具合にドメイン名が違う。
なのでredirect_urlとrequested_urlが延々と違う、ということになってしまったのだ。

3. 解決方法

この問題を解決するにはいくつかの方法がある。
一つはcanonical.phpを書き換えてしまう方法。
requested_urlが$_SERVERから取得しているので該当部分を書き換えてしまえば良い。
ただしWordPressのコアファイルを書き換える、というのは禁断の果実を食べるに等しいのであまりオススメしない。

次にフィルタを書いてやる、という方法。redirect_url側をrequested_url側のドメイン名に揃えてやる、というやり方。これならば問題は起きにくいだろう。

// Note that you can use the "redirect_canonical" filter to cancel a canonical redirect for whatever reason by returning false
    $redirect_url = apply_filters('redirect_canonical', $redirect_url, $requested_url);

というわけでridirect_urlを書き換えるフィルタを書いてみました。これをfunctions.phpに加えておけばURLのドメイン部分がリバースプロキシの奥側のドメインに一致します。

add_action('redirect_canonical', 'change_requested_url');
function change_requested_url($redirect_url, $requested_url) {
 $redirect_url = is_ssl() ? 'https://' : 'http://';
 $redirect_url .= $_SERVER['HTTP_HOST'];
 $redirect_url .= $_SERVER['REQUEST_URI'];
 return $redirect_url;
}

今回のサイトでは複雑なクエリの組み立てなども行っていないのでこれで問題なさそうです。元のコードは先ほどのcanonical.phpから拝借してきました。

今回は見事、上記のフィルタ動作にてうまく動きました。めでたしめでたし。

エックスサーバでwordpressのカスタムフィールドテンプレートが文字化けした

エックスサーバでwordpressのカスタムフィールドテンプレートが文字化けした。

エックスサーバでwordpressのカスタムフィールドテンプレートをいじる機会があった。カスタムフィールドテンプレートはわかりやすいマークダウン記法みたいな書き方でカスタムフィールドを色々と設定できる優れものなプラグイン。このプラグインなのだけれど開発環境から本番環境にアップロードすると使えなくなる現象に遭遇した。

具体的にはカスタムフィールドテンプレートでテンプレートをロードさせようとするとロードした文字が化けてしまっていること。
キャプチャ

これじゃあせっかくのテンプレートが使い物にならないです。
少し調べてみるとサーバからのレスポンスヘッダに文字コードが指定してある。

Content-Type: text/html; charset=Shift_JIS

これがどうにもこうにも原因らしい。

文字コードはすべてUTF-8で統一しているはずで、どこかにShift-JISなんて指定したか、とか思いながら確認してみた。

  • wordpressの管理画面にある文字コード
  • php.iniのmbstring.internal_encoding
  • プラグイン本体のコード

疑わしきは調べていったんだけれど解決できず。

で、テスト環境ではうまくいっているのだろうからこれはやっぱり本番環境のエックスサーバがおかしいのだろうということでさらに疑ってみた。php.iniが編集できる柔軟さは認めるのだけれど、Shift-JISを吐かれては困る。

色々調べたところapacheが.phpに対してheaderをデフォルトで吐き出す設定があることにたどり着いた。同時に湯バード先生からも同じトコロを指摘される。

通常この項目はapacheのhttpd.conf辺りで設定するのだけれど.htacessでも設定できるらしい。というわけで以下の項目をwordpressのドキュメントルートにある.htacess追記してみた。

AddDefaultCharset UTF-8

この設定で無事に治りました。

注意すべきは.htaccessはworpdressのカスタムURLストラクチャとかを書き換えることがあるのでその際には再度同じ文を書き加える必要があること、かな。忘れないようにしよう。

またこのような問題だとなかなか対処しづらいと思う。たまたまapacheのレスポンスヘッダから分かったのだけれど文字化けしたときにはmbstringを見て下さい、ってエックスサーバに書いてあったりして困る。これ恐らくデフォルトの文字コードをShift-JISで、とかに設定されたのかなと推測するけれどそれが困りました。たぶん問い合わせても対応できかねます、で終わっちゃうだろうし。しょんぼりっすね。

emacsのphp-modeでarrayのインデントを改善した

1. はじめに

emacsでphp-modeを利用している。とても便利なelispなんだけどデフォルトだといくつか不便な点がある。

基本的にはPEARに準拠したコーディング規約にしたかったので下記のブログ記事を参考にしてinit.elの設定を行った。

(setq php-mode-force-pear t)

PHP開発で追加しておきたいEmacs Lisp 8選 : アシアルブログ

だけれどもこれだけだとarrayのインデントがおかしい。

2. おかしいインデント

<?php
function hoge(){
    $hoge = array(
                 'hoge' => 1,
    );
}

このように連想配列の添え字(キー名)のインデント位置が前述の括弧の位置まで下がってしまうのだ。 コレは見づらい。できれば $hoge の開始位置から規定のタブ幅(4とか)で字下げして欲しい。

2. 解決方法は見かけるのだけれど

この問題でググってみるといくつか解決方法が出てきた。だけれどもその辺のelispを適用してみてもうまくいかない。バージョンがダメなのか他のelispと競合しているのか、とにかく動かなかった。というかelispに対する理解が少ないというのが一番の根本的な問題かな。

で、しばらくこの問題は放置していたのだけれど、あまりにも気になると言うことで気合いを入れて調べてみた。すると意外にも(?)公式的なみんな大好き emacswiki が出てきた。

3. 解決

Indentation of arrays
The php-mode indentation for array is not good, It will indent like this:

$post=Post::model()->find(array(
                              'select'=>'title',
                              'condition'=>'postID=:postID',
                              'params'=>array(':postID'=>10),
                              ));

The better indentation is like:

$post=Post::model()->find(array(
    'select'=>'title',
    'condition'=>'postID=:postID',
    'params'=>array(':postID'=>10),
));

Add this to php-mode-hook:

(add-hook 'php-mode-hook (lambda ()
    (defun ywb-php-lineup-arglist-intro (langelem)
      (save-excursion
        (goto-char (cdr langelem))
        (vector (+ (current-column) c-basic-offset))))
    (defun ywb-php-lineup-arglist-close (langelem)
      (save-excursion
        (goto-char (cdr langelem))
        (vector (current-column))))
    (c-set-offset 'arglist-intro 'ywb-php-lineup-arglist-intro)
    (c-set-offset 'arglist-close 'ywb-php-lineup-arglist-close)))

EmacsWiki: Php Mode Indentation of arrays

さて早速コレを適用。init.elを開いて、php-completionですでにphp-mode-hookがあったのでそこに追記して再起動。

うまくいきました。

<?php
function hoge(){
    $hoge = array(
        'hoge' => 1,
    );
}

めでたしめでたし。

Smartyを2系列から3系列に移行するにあたって困ったこと

1. 始めに

自分が運用しているいろいろなwebサイトでテンプレートエンジンであるSmartyを利用している。エスケープとかを全部オマカセにできてMVCが分離できるっていうのでなかなかの優れものだ。

で、最近、ひょんなことからwebサーバを構築し直すことになった。従来のサーバではSmartyのバージョンが2系列を利用したのだけれど、どうやら3系列が最新版らしかったのでこっちを入れてみた。

動作が高速になるだとかいろいろと恩恵があるそうで、それならば、ということで。何より最新版があるならばそっちを利用しよう、というのがモットーなので今回も多分に漏れず移行してしまったみました。

Smarty2.0からSmarty3.0への変更点 | suinasia

2. 問題その1

さて、インストールなどは簡単に終わり早速移行したのだけれどいきなり問題が発生した。

smartyでappendしている変数がどうにも表示されない。{debug}を埋め込んでみても変数が渡されている形跡が無い。不審に思ってappend(assign)している箇所にて渡される変数を見てみるとこちらはちゃんと内容が入っている。うーん、これは困ったなぁ、と思いながら眺めているとすべての変数が渡されていないわけじゃないことに気がついた。一部変数はちゃんと渡されているのだ。ということはappend(assign)が絶対的に悪いわけじゃ無いらしい。

で、どんな値なら渡されてどんな値は渡されていないのか、そこが気になった。で、一目瞭然、日本語データが渡されていないのだ。

mb_convert_stringなどでテキトウに変換して渡してやると変な状態になった。出力がUTF-8の時のみ、データが表示されたのだ。

今回対象となっているwebサイトは作られた時期が古く、SJISでやりくりしていた。smartyの出力もSJISだったんだ。というわけでどうやらそこが原因らしい。

で、smarty3とutf-8あたりでググるとさっそく情報が出てきた。というか前述のページにもしっかり書かれてました。

SMARTY_RESOURCE_CHAR_SETという変数がUTF-8で宣言されるのですが、コレをsmartyより先にSJISとかでdefineしないとダメぽです。

UTF-8 以外でテンプレートを作成する – smarty3

define('SMARTY_RESOURCE_CHAR_SET', 'SJIS');
require_once('Smarty.class.php');

PHPで平仮名からローマ字書きに変換したかった

PHPで平仮名からローマ字書きに変換したかった。と、諸事情があってひとまずリストを配列で書き出した。

またいつか何かの機会に使うかもしれないので貼っておく。でももうこういうのやりたくない。

$hoge = array
('あ' => array('a'), 'い' => array('i'), 'う'=>array('u'),
'え'=>array('e'), 'お'=>array('o'),
'か'=>array('ka'), 'き'=>array('ki'), 'く'=>array('ku'),
'け'=>array('ke'), 'こ'=>array('ko'),
'さ'=>array('sa'), 'し'=>array('si', 'shi'), 'す'=>array('su'),
'せ'=>array('se'), 'そ'=>array('so'),
'た'=>array('ta'), 'ち'=>array('ti', 'chi'), 'つ'=>array('tu', 'tsu'),
'て'=>array('te'), 'と'=>array('to'),
'な'=>array('na'), 'に'=>array('ni'), 'ぬ'=>array('nu'),
'ね'=>array('ne'), 'の'=>array('no'),
'は'=>array('ha'), 'ひ'=>array('hi'), 'ふ'=>array('hu', 'fu'),
'へ'=>array('he'), 'ほ'=>array('ho'),
'ま'=>array('ma'), 'み'=>array('mi'), 'む'=>array('mu'),
'め'=>array('me'), 'も'=>array('mo'),
'や'=>array('ya'), 'ゆ'=>array('yu'), 'よ'=>array('yo'),
'ら'=>array('ra'), 'り'=>array('ri'), 'る'=>array('ru'),
'れ'=>array('re'), 'ろ'=>array('ro'),
'わ'=>array('wa'), 'を'=>array('wo'), 'ん'=>array('n', 'nn'),
'が'=>array('ga'), 'ぎ'=>array('gi'), 'ぐ'=>array('gu'),
'げ'=>array('ge'), 'ご'=>array('go'),
'ざ'=>array('za'), 'じ'=>array('ji'), 'ず'=>array('zu'),
'ぜ'=>array('ze'), 'ぞ'=>array('zo'),
'だ'=>array('da'), 'ぢ'=>array('di', 'ji'), 'づ'=>array('du', 'zu'),
'で'=>array('de'), 'ど'=>array('do'),
'ば'=>array('ba'), 'び'=>array('bi'), 'ぶ'=>array('bu'),
'べ'=>array('be'), 'ぼ'=>array('bo'),
'ぱ'=>array('pa'), 'ぴ'=>array('pi'), 'ぷ'=>array('pu'),
'ぺ'=>array('pe'), 'ぽ'=>array('po'),
'きゃ'=>array('kya'), 'きゅ'=>array('kyu'), 'きょ'=>array('kyo'),
'しゃ'=>array('sya', 'sha'), 'しゅ'=>array('syu', 'shu'),
'しょ'=>array('syo', 'sho'),
'ちゃ'=>array('tya', 'cha'), 'ちゅ'=>array('tyu', 'chu'),
'ちょ'=>array('tyo', 'cho'),
'にゃ'=>array('nya'), 'にゅ'=>array('nyu'), 'にょ'=>array('nyo'),
'ひゃ'=>array('hya'), 'ひゅ'=>array('hyu'), 'ひょ'=>array('hyo'),
'みゃ'=>array('mya'), 'みゅ'=>array('myu'), 'みょ'=>array('myo'),
'りゃ'=>array('rya'), 'りゅ'=>array('ryu'), 'りょ'=>array('ryo'),
'ぎゃ'=>array('gya'), 'ぎゅ'=>array('gya'), 'ぎょ'=>array('gyo'),
'じゃ'=>array('zya', 'ja', 'jya'), 'じゅ'=>array('zyu', 'jyu', 'ju'),
'じょ'=>array('zyo', 'jyo', 'jo'),
'びゃ'=>array('bya'), 'びゅ'=>array('byu'), 'びょ'=>array('byo'),
'ぴゃ'=>array('pya'), 'ぴゅ'=>array('pyu'), 'ぴょ'=>array('pyo'),
);

PHPでマルチバイト(日本語)に対して正規表現を使って後方参照したかった

PHPでマルチバイト(日本語)に対して正規表現を使って後方参照したかった。ちょっと正規表現でごにょごにょしてるとつっかえたことがあったのでメモ。

まず、次のような試験がうまく通らなかった。


<?php

$str[] = '1あああ2'; // 1) hit => OK
$str[] = '1ああ)あ2'; // 2) not hit => OK
$str[] = '1ららら2'; // 3) not hit => NG
$str[] = '1らら)ら2'; // 4) not hit => NG
$ptrn = '/1([^\)]*)2/';

foreach($str as $val){
if(preg_match($ptrn, $val, $matches)){
var_dump($matches);
}
}


この例の場合、”あ”が検査対象となっている場合には思った通りの動作をしてくれる。でも”ら”が入った文字列には思い通りの動作にならない。

いろいろ悩んだところ、これはマルチバイトの問題だろう,というところに行き着いた。

まず最初に、preg_matchのマルチバイト版がないか探した。mb_preg_match的な関数で探した。でも無い。残念。

どうやらmb_ereg系はあるらしい。でも最近のPHP (5.3以降)ではeregじゃなくてpreg_matchが推奨されている。

>PHP: PHP 5.3.x で推奨されない機能 – Manual

そしてmb_eregを使うと後方参照(あとで括弧を使って正規表現で合致した文字列の一部を利用できるようになる機能)が使えない。なのでmb_eregは今回の解決方法対象外。

で、ぐぐってると正解にたどり着けた。

どうやら検査パターンの最後のオプションにuを付けるとイイらしい。おそらくutf-8で解釈しなさいよ、ってことかな。

preg系でオプションを付けるには終了デリミタ(って言えば良いのかな)の後ろに文字を列挙して指定する。今回の場合にはこんな感じ。

<?php

$str[] = '1あああ2'; // hit => OK
$str[] = '1ああ)あ2'; // not hit => OK
$str[] = '1ららら2'; // not hit => NG
$str[] = '1らら)ら2'; // not hit => NG
$ptrn = '/1([^\)]*)2/u';

foreach($str as $val){
if(preg_match($ptrn, $val, $matches)){
var_dump($matches);
}
}

?>

原因についても考えてみた。今回は文字(列)”ら”と文字(列)”)”が問題を起こしていた。双方のUTFコードは以下の通りである。

ら E38289

)EFBC89

パっと見た感じ、下二バイトが合致してるとダメみたい。試しに同様に下2バイトが合致する”ド”で試したら案の定”)”と区別できなくなってた。ほむー。

JavaScript Unicode Charts

PHPで動作させたスクリプトが徐々に重くなっていった

PHPで動作させたスクリプトが徐々に重くなっていった。

本番環境から切り出した5000件あまりのデータを処理してたら途中からどんどん重くなっていってた。コレはまずいなーとか思ってメモリ使用量を調べてみると増えていってる。

8GBを積んだFreeBSDなマシンだったんだけど、memory_get_usage()で調べたところ300MBを超えるあたりから急激に重くなっていった。

8GBのメモリに対しての300MBであればまだまだ高速に動きそうなもんなんだけど、その辺の追求はPHP&OSに起因する問題っぽいのであきらめる。

ちなみにテストコードを書いてみてもやっぱり300MBあたりで遅くなった。

以下テストコード

<?php

main();

function main(){
$test = new test();
for($i=0; $i<1000000; $i++){
$hoge = array('test'=>'tete', 'hoge'=>$i);
$test->test($hoge);
var_dump($i.':'.(memory_get_usage()/1024/1024));
}
}

class test{
private $hoge = array();
public function test($str){
$this->hoge[] = $str;
}
}


そのときのtopの様子。気づいたらutimeが19になっとるじゃん。いつ再起動したんだっけ。

last pid: 62467;  load averages:  0.45,  0.38,  0.47   up 19+03:19:24  11:35:32
123 processes: 2 running, 119 sleeping, 1 stopped, 1 zombie
CPU: 23.7% user,  0.0% nice,  6.3% system,  0.0% interrupt, 70.0% idle
Mem: 1292M Active, 1310M Inact, 869M Wired, 806M Buf, 4322M Free
Swap: 4096M Total, 4096M Free

PID USERNAME       THR PRI NICE   SIZE    RES STATE   C   TIME   WCPU COMMAND
62447 yousan           1 113    0   664M   514M CPU3    3   0:16 76.95% php

wordpressのsingle.phpとかでquery_postsを自前で実行した後に元のpostを参照したかった

wordpressのsingle.phpとかでquery_postsを自前で実行した後に元のpostを参照したかった。

どういうことかというと、single.phpの中で以下のような順序で上から順にpost(ID=123)にアクセスしてた。

  1. post ID=123のタイトル
  2. post ID=123の内容
  3. 関連記事の表示のため、query_posts(array(‘post__in’)); を実行
  4. while(have_posts()) the_post(); をして関連記事のタイトルを表示
  5. post ID=123のコメントを表示したい!! <– ココ重要

最後のコメントを表示しようとするとうまくいかない。というのもその前段階の関連記事表示でthe_postをしてしまっているのでグローバル変数の$postが関連記事のものになっている。なのでコメントを表示しようとしたときに利用されるpostは関連記事の一番最後のpost、while(have_posts())が回りきった最後のpostとなってしまうのだ。

試しに echo $post->ID; すると確かにIDは123でなく関連記事の最後のpost_IDになっている。

さて困ったぞ、ということでググってたらコレを解決してくれるような関数を発見。

Function Reference/wp reset postdata » WordPress Codex

以前は$post->IDを変数に保存しておいてquery_postをかまして・・・、ってやってたんだけど、このwp_reset_postdataを使えばその手間が省ける・・・、かどうかは微妙かもしれない。結局同じような手立てに。

でも標準で用意されてるってことは今後に期待もしていいってことで利用してみる。

仕組みは単純でその使用方法で示唆されている。使い方はグローバルの$wp_queryを一時待避させておいて必要になったら戻す,というもの。

$original_query = $wp_query;

 query_posts(‘hogehoge’);

$wp_query = $original_query;

 wp_reset_postdata();

the_title(); comment_template();

コレでうまくいくようになった。