single.phpが2回呼ばれる

投稿が表示された回数を、single.phpのタイミングでカウントしようとした。MySQLにテーブルを作成して、postIDと参照回数を記録していく。ところがpostID=1の記事を表示した際に、postID=1とpostID=4の2行更新される。1の次は4が登録されていることに関係があるのか。なぜかsingle.phpが2回呼ばれているようにみえる。
defaltテーマでも再現するため、プラグインを疑ってみた。「Top Level Categories Fix」を無効にすると、single.phpは1回しか呼ばれなくなった。これは、パーマリンクの設定がカスタム構造(/%category%/%postname%/)になっているときに、URLから”category”を削除するプラグインだ。そもそもカテゴリ名を含んだパーマリンクは非推奨ではあるが。CMSとして利用する場合にURLにIDや日付が入っていてはかっこ悪いため、「Top Level Categories Fix」を有効にすることが多い。
うまく回数を数える方法はないものか。

投稿一覧の表示件数

管理画面で投稿一覧の表示件数を変更できることを、いまさらながら知った。
右上あたりの[表示オプション]をクリックすると設定項目がある。ここで一覧の表示件数や表示項目を指定することができる。ダッシュボードに表示する項目や、編集画面で表示しない項目を指定することもできる。
業務によってはタグやコメントを使わない場合もあるので、非表示にしておいたほうがユーザにはわかりやすい。

投稿編集の一覧をカスタマイズ

管理画面の投稿編集の一覧に表示されるのは、通常[タイトル][作成者][カテゴリー][タグ][コメント数][日付]となっている。ここに項目を追加することができる。
以下は、右端の列に添付画像の1枚目のサムネイルを表示している。

[sourcecode language=’php’]

function my_post_column($columns) {
$columns[‘thumbnail’] = ‘添付画像’;
return $columns;
}

function my_custom_column($column, $id){

if($column == ‘thumbnail’){

$attachments = get_children(array(‘post_parent’ => $id, ‘post_type’ => ‘attachment’, ‘post_mime_type’ => ‘image’, ‘orderby’ => ‘menu_order’, ‘showposts’ => ‘1’));
if (is_array($attachments) ){
foreach($attachments as $attachment){
$thumbnail = wp_get_attachment_thumb_url(intval($attachment->ID), “thumbnail”);
echo ‘' .$id .'‘;
}
}
}
}

add_filter(‘manage_posts_columns’, ‘my_post_column’);
add_action(‘manage_posts_custom_column’, ‘my_custom_column’, 10, 2);

[/sourcecode]

フォトログなどでは、こうしておくと便利だ。

記事の整形を行うには

記事を表示するには、ループ内でthe_content()を使うのが通常のやり方だ。ループ外でもget_post()やget_page()で、特定の記事の内容を取得することはできる。その場合の表示のしかたを調べてみた。

[sourcecode language=’php’]
$page = get_page_by_title(“ページのタイトル”);
echo apply_filters(‘the_content’, $page->post_content);

[/sourcecode]

記事の内容を表示しようと思って、
echo $page->post_content;
とやっただけでは、改行もなしでプレーンなテキストしか表示されない。the_content()のようにHTMLで整形された表示を行いたいのであれば、apply_filters()を通すとよい。こうすることで記事中のショートコードも実行される。

WordPressでweb API

WordPress に web API インターフェースを追加するプラグインを使ってみた。

WordPressのカテゴリ一覧ページでは、デフォルトで10件づつ表示してページネーションを使う方法が一般的だ。このほどクライアントより、一覧の下に「もっと見る」のようなリンクを用意して、クリックされると同一ページの下にバックナンバーのタイトル一覧を表示して欲しいとの要望があった。
1ページに表示する件数をquery_posts()で増やして、JavaScriptでバックナンバーの部分を表示・非表示すればよいかとも思ったものの、初期表示に時間がかかってしまうし、「もっと見る」がクリックされない場合は無駄だ。Ajaxでタイトルを10件づつ取得して、順に表示できればよいな、と思い投稿データをWeb API的に取得できないものかと調べた。そこで見つけたのが「Wordpress に web API インターフェースを追加するプラグイン」である。

プラグインを追加するとAPI キーを設定することができる。このAPIキーと、アクション(関数)に割り当てたキーとの組み合わせによって、認証を行うようになっている。認証がOKだとアクション名のショートコードが生成、実行されるようだ。アクションはサンプルがいくつか用意されているので、参考にしながら自分で追加することができる。jsonやXMLでのレスポンスが可能だ。
このインタフェースを利用して作成したWeb APIをJavaScriptから呼ぶには、ブログのURL、アクション、APIキー+アクションのキーをAjaxでPOSTする。アクションに関するパラメータを追加することもできる。
思ってたとおりのものができた!

参考:WordPress に web API インターフェースを追加するプラグイン

ショートコードに勝手に入ってくるpタグ

ショートコードが勝手にpタグに囲まれてしまう場合がある。
例えば投稿記事で、
<h3>タイトル</h3>[my_shortcode /]
というふうにhタグの直後にショートコードを使った場合に発生する。hタグの次はpタグがこなくてはならないマークアップの法則にでも準拠してくれた結果なのだろう。出力されるHTMLは、
<h3>タイトル</h3><p>(ショートコードの出力)
となる。<p>だけを勝手に入れて</p>で閉じてくれないのが非常に困る。
このような場合は、
<h3>タイトル</h3><p>[my_shortcode /]</p>
と、最初から投稿記事にpタグを書いてしまうと解決する。出力されるHTMLは、
<h3>タイトル</h3>(ショートコードの出力)
となる。自分で書いたpタグまでもが消えているから不思議なのだが、解決したからいいか。

DBに連想配列を保存するには

DBテーブルのwp_optionsやwp_postmetaに配列っぽいデータが保存されているのを見ることがある。たとえば wp_postmetaでは_”wp_attachment_metadata”というキーに”a:5:{s:5:”width”;s:3:”145″;s:6:”height”;s:2:”74″;s:14:”hwstring_small”;s:23:”height=’65’ width=’128′”;s:4:”file”;s:35:”2010/…”というようなデータが保存されている。画象を添付した際のパスやサイズなどのメタデータである。

この形式を自分でも利用することができる。
例えばwp_optionsに保存するには、
INSERT INTO wp_options(option_id, blog_id, option_name, option_value, autoload) VALUES(null, 0, ‘my_messages’, maybe_serialize( $messages ), ‘yes’)
というようなSQLを実行すればよい。連想配列$messagesをシリアライズしたものをoption_valueにセットする。maybe_serialize()は、WordPressの関数である。

このデータを取得するには、SQLでSELECTして得た値を、
$messages = maybe_unserialize($result->option_value);
とすることで連想配列にセットされる。

ちょっとした情報を保存したいならプラグイン用にテーブルを作成するのではなく、 wp_optionsに保存する手段もあるのだ。Contact Form 7 のコードを見てて、この仕組みがやっと分かった。

Contact Form 7 でユーザーエージェント

WordPressを使う人なら誰もが知ってる「Contact Form 7」はお問い合わせフォームを設置するのにかかせないプラグインだ。カスタマイズ性の良さとAjaxの動作がいい。

この「Contact Form 7」を使ったお問い合わせの際に、ユーザが使っている環境が知りたいとの要望があった。Webサービスに関する問い合わせでは、ユーザがどのOSでどんなブラウザが使っているかが手がかりになる。問い合わせをしてくるユーザに限ってそれを把握していないことが多いため、自動で送って欲しいということだ。
「Contact Form 7」では、IPアドレスを取得する [_remote_ip]というタグは用意されているものの、ユーザーエージェントは用意されていない。「Contact Form 7」に用意されている”wpcf7_special_mail_tags”というフィルタを使ってタグを追加することができる。追加するには、テーマのfunctions.phpにショートコードとして記述するとよい。
[sourcecode language=’php’]
add_filter(‘wpcf7_special_mail_tags’, ‘my_special_mail_tags’,10,2);

function my_special_mail_tags($output, $name)
{
if(!isset($re_agent)){ $re_agent = $_SERVER[‘HTTP_USER_AGENT’]; }
if(‘my_user_agent’ == $name){ $output = $re_agent; }
return $output;
}
[/sourcecode]

これで、「Contact Form 7」のメッセージ本文で[my_user_agent]といタグを使えるようになる。$nameにタグ名が入ってくるので、タグ名で分岐するようにすればこの中で複数を設定することができる。

WordPressフォーラムのContact Form 7 ホスト取得を参考にした。

タイムゾーンがずれる

自作テーマで、時間に関連する部分に不具合がでた。WordPressを商用のCMSとして使っていて、イベントを表示するカレンダーで予約投稿の場合は「予定」と表示しておき、当日になったら「予定」が消えるというふうにしたかったのが、「予定」が消えるのが9時間遅くなるのだ。タイムゾーンの設定が変わってしまったのかと思ったけど、「UTC +9:00」になっているし投稿時間も正常だ。

テーマで現在時刻を取得するのに
date( ‘Y-m-d H:i:s’);
とやっていたのを、WorsPressの関数を使って、
current_time(mysql)
としたら直った。

WordPressの過去のバージョンで使ったことのあるコードを、バージョン2.9.2で流用したのが原因らしい。PHPの基本的な関数が使えなくなっていたとは、不便だ。もとからcurrent_time()を使うことが常識だったのかな?
もっともこの場合は、「当日」の判断をpost_dateではなくて、post_statusで判断すれば良かったのだ。

カテゴリー用のテンプレートファイル

WordPress 2.9よりカテゴリー用のテンプレートファイル category-slug.phpが用意されているようだ。いままでカテゴリごとに異なるデザインを表示するには、archive.phpで現在のカテゴリを取得して、if文で振り分けていた。category-termid.phpというテンプレートファイルもあったものの、サーバが異なるとtermidが同じとは限らないため利用しずらかった。slugであれば使ってみてもいいかな。

カテゴリー用のテンプレートファイルは以下の優先順で表示される。
1. category-slug.php
2. category-termid.php
3. category.php
4. archive.php
5. index.php

カテゴリーごとにHTML構造が変わらずCSSのみ変更したい場合は、テンプレートを分けずに、archive.phpの中で<div class=”スラッグ”>とし、スラッグごとにスタイルを当てる方法もある。