blogというサブディレクトリ名は禁止

以前はルート直下の”blog”というディレクトリにWordPressをインストールして運営していた当ブログである。WordPressのバージョンアップに伴い、マルチサイトのサブディレクトリとしてブログを構築することにした。

ルートディレクトリにWordPressをインストールし、ネットワーク管理者の[新規サイトを追加]を行ったところ、エラーで作成できなかった。

以下の語句は WordPress の機能によって予約されており、ブログ名として使うことはできません: page, comments, blog, files, feed

とのことで、”blog”というブログ名はダメらしい。
そういわれても、これまで”blog”だったのだからURLは変えたくない。CMSとして複数サイトを運営できるシステムであるなら、そのなかに”blog”という名前のブログを作成するのは自然な要求ではないのか。そうこうしているうちに、ネットワーク管理者の設定に[登録の設定]-[禁止名]の項目を見つけた。そこに、

www web root admin main invite administrator files blog

と設定されているので、おぉここか!?と思って”blog”を削除した。が、新規サイトを作成しようとしても同じエラーである。”blog”はどうしてもダメらしい。設定項目の値と、エラー内容が異なるではないか、この設定はなんなのか?

仕方なく本ブログは別のサブディレクトリ名で作成し、.htaccessにリダイレクトの設定をした。

WordPressを3.1.2にアップデート

ちょうど連休直前にWordPress3.1.2の日本語版がリリースされたので、よいタイミングだった。もともとはルート直下の複数ディレクトリにそれぞれWordPressをインストールしてサイトを運営していた。今回はルートディレクトリに最新版WordPressをインストールし、サブディレクトリ型マルチサイトを構築すればよいと検討をつけた。インストールしたい階層が以前と異なるため、備え付けのアップデート機能は使わず自力で行う。

  1. 旧サイトのデータベースをバックアップ

    • phpMyAdminでmySQLのテーブルをエクスポートする。
      対象テーブルは、WP_USERS、WP_USERMETA、WP_OPTION以外のすべて
      オプションは、

      • エクスポートでSQL形式
      • オプションの構造で、
        • DROP TABLE / DROP VIEWを追加
        • AUTO_INCREMENT 値を追加する
        • テーブル名やフィールド名を逆クォートで囲む
      • オプションのデータで、
        • 完全な INSERT 文を作成する
        • 長い INSERT 文を作成する
        • 作成するクエリの最大長 50000
        • BLOBに16進数表記を利用する
        • エクスポート形式 INSERT
      • ファイルに保存する
      • エンコーディングnon

      もし投稿履歴があれば事前に削除しておくと、バックアップデータが小さくなる。
      DELETE FROM wp_posts WHERE post_type=’revision’

    • 添付ファイルをダウンロード
      /wp-content/uploads/以下すべてのファイルをFTPでダウンロードする。
  2. 旧サイトを削除
    サブディレクトリ型マルチサイトを作成する場合、同じディレクトリ名が物理的に存在してはならない。削除は怖いのでリネームしておく。

  3. WordPress3.1.2のインストール
    同じデータベース内に旧テーブル(例:WP_)を残しつつ、別の接頭辞(例:WW_)を指定してインストール。マルチサイト化しておく。

  4. データベースの移行
    旧ブログの記事を、新サイトの2つめのブログの記事として流し込む。

    • さきほどエクスポートしたSQLファイル内を書き換える
      • テーブル接頭辞のWP_をWW_2_に置換する。
      • 画像のパスを書き換える。
        /wp-content/uploads/ を、/files/ に置換すればよい。
    • phpMyAdminでSQLファイルをインポート
  5. 添付ファイルをアップロード
    アップロード先は、/wp-content/blogs.dir/2/files/
    例えば、
    http://example.com/example/files/2011/05/01/example.jpg
    というURLの画像ファイルがあった場合、
    ディレクトリ上では以下に配置すればよい。
    ↓↓↓
    /wp-content/blogs.dir/2/files/2011/05/01/example.jpg

  6. テーマやプラグインを設定
    WordPressの関数で変更、非推奨になった箇所があるため、自作のテーマやプラグインでエラーや警告が発生した。修正に半日を費やす。
    以前はできていたことができなくなった仕様もある。例えば、

    • URLにパラメータを持たせて処理していたページ、例えばパーマリンク?param=valueの場合valueに全角文字が使えなくなった。
    • 複数のカテゴリを持つ記事のパーマリンクが一意になった

    このように、以前なんとなくできていたことが明示的にできなくなっている。システム的な矛盾をなくすためと理解するものの、パーマリンクを変更せざるを得ないページも発生した。

MySQLを5.1にアップデート

面倒でほったらかしになっていたサーバまわりのアップデートを、連休中に行った。WordPress3.0がリリースされてからほぼ1年になるので、かなりサボっていたことになる。業務ではもちろん3.0以上を使用していながらも、当ブログは2.8のままだった。というのも、WordPressをバージョンアップするには、さくらインターネットでMySQLのバージョンを4から5に上げねばならなかったからだ。MySQLはMovableTypeと併用していることもあり、手を付けるのに勇気を要した。連休の目標はMySQLとWordPressを最新版にすることと決めた。

さくらインターネットでのMySQLのバージョンアップは以下のとおりだ。データが少ないためかなんのトラブルもなく、30分もかからずに終わった。

  1. phpMyAdminですべてのテーブルをエクスポートする。複数サイトを運営しているので、サイトごとに分けてエクスポートした。文字コード(UTF-8)に気をつけながら、念のためSQL形式のほかWordPress形式やMT形式でもバックアップを取っておく。
  2. phpMyAdminからいったんログアウトし、さくらのコントロールパネルでデータベースを削除する。やり直しがきかない作業なので、バックアップ内容の確認に念を入れてから行う。
  3. 新しいphpMyAdminにログインし、データベースをMySQL5.1で新規作成する。ここでデータベースのサーバ名とパスワードが変更された。
  4. データベースの照合順序をutf8_generalciに設定し、SQLファイルをインポートする。
  5. wp-config.phpやmt-config.cgiでデータベースのサーバ名とパスワードを修正
  6. ブログの表示を確認して完了

この投稿を先頭に固定表示

公開状態のオプションとして「この投稿を先頭に固定表示」がある。
テーマのループでは先頭に出現し、投稿ブロックにstickyというクラスが付加される。テーマを作成する際には、このstickyに対応することが要件となっている。つまり通常の投稿と区別するために、背景や文字色を変更しておくとよい。実際には「お知らせ」や「イベント告知」のようなかんじで利用するとよいのか?

stickyかどうかは、is_sticky()で調べることができる。ついでに、どこに保存されているのかと調べてみるとwp_optionsテーブルのoption_nameが’sticky_posts’の箇所にあった。複数指定した場合でも、ここに配列として格納される。

コメントの表示数を制限する

singleページでのコメントの表示数について、
ディスカッション設定によりコメントを複数ページに分割表示できるものの、singleページを表示するタイミングで取得するコメントは常にその記事に関するコメントすべてとなる。つまりコメントを5件づつ表示する場合でも、その投稿についてコメントが100件あれば100件を取得している。

あるサイトのサーバー負荷が異様に重くて調べたところ、特定の記事についてコメントが10000件以上ついているためと分かった。この10000件とは決してスパムではなく、singleページがFLASHゲームで遊ぶ構成になっているため人気ゲームにコメントがたくさんついてしまったのだ。コメントは最新の50件を5件づつ分割表示している。必要なコメントは50件なので、できれば古くなったコメントを削除してしまいたかった。しかしサイト運営者からは過去のコメントを削除しないようにと要求されている。
そうこうしているうちに、問題となるslow queryが浮かび上がった。
SELECT wp_comments.* FROM wp_comments WHERE comment_post_ID = '99' AND comment_approved = '1' ORDER BY comment_date_gm

このSQL文はwp-includes/comment-template.phpのcomments_template()という関数にあった。singleページを表示するさいにグローバル変数の$commentsにコメント配列をセットしている部分である。

ここにLIMITを追加すればよいのだろうがコアコードは修正できない。フォーラムで質問したところ、query フックでlimit句を追加するアドバイスをいただいた。しかし、コメント取得のSQL文は3とおりがあり並び順が固定の場合もあるため、どうも思ったとおりにいかない。そうこうしているうちに、コメントの取得に件数が制限できないのはコメント階層を考慮してのことだと気付いた。単純にLIMITを付けるだけではダメなのだ。

今回はコメント階層を使っていないということもあり、comments_template()をfunction.phpにリネームコピーしてカスタマイズすることで対処した。 ここのSQL文のORDERをDESCにして、LIMITを追加。さらにsingle.phpからcomments_template()を呼んでいる部分を、新しい関数名に変更した。

問題のsingleページはなんとか軽くなったように思う。
こんな対応でよいのかな?10000件もコメントがつくとは想定外だ。

ログイン画面のロゴ

ログイン画面に表示される「WORDPRESS」というロゴを変更することができる。
[PHP]
function my_login_logo() {

$url = “画像のフルパス”;
echo ‘

‘;
}
add_action(‘login_head’, ‘my_login_logo’);
[/PHP]

さらに、ダッシュボードの左上の「W」というアイコンを変更することもできる。
[PHP]
function my_admin_logo() {

$url = “画像のフルパス”;
echo ‘

‘;
}
add_action(‘admin_head’, ‘my_admin_logo’);
[/PHP]

どちらもフックを利用してCSSを上書きしている。属性が強いのか、!importantが必要だった。
これだけでも、けっこうカスタマイス感が上がる!

表示条件にキーワードを含める

一覧の表示条件にキーワードを含めるとは、指定のキーワードでの検索結果つまり、
ブログのURL?s=キーワード
をやりたいのである。これを検索フォームを使わずに、query_posts()でやってみた。

[PHP]
query_posts(array(‘s’=>’キーワード’));
if (have_posts()){
while (have_posts()) : the_post();
// 処理
endwhile;
}
wp_reset_query();
[/PHP]

Codexには、query_posts()のパタメータとしてキーワードは記載されていないものの、検索フォームのパラメータであるsを使ってみたらうまくいった。あたりまえといえばあたりまえなのか、こんなことやる必要のある人がいないだけか。

コメントをスレッド対応

バージョン2.7あたりからコメントがスレッド対応になっていたものの、使ったことがなかった。コメントのコールバック関数に以下を追加すると、コメントに対して「返信」のリンクが表示される。

[PHP]
comment_reply_link( array_merge( $args, array( ‘depth’ => $depth, ‘max_depth’ => $args[‘max_depth’] ) ) );
[/PHP]

$depthはコメント階層を示す値で、コールバック関数の第3パラメータに入ってくる。

「返信」をクリックすると返信用のフォームが表示され、特定のコメントに対して返信することができる。表示する際にはCSSで<li>のネストに対応すればよい。以前から謎のひとつだった、コールバック関数の<li>を閉じてはいけない理由はここにあったのだ!

検索範囲をコントロールする

日本語ページと英語ページに対応した企業サイトを作成した際に、検索フォームをそのまま使うと検索結果に日本語と英語が混在してしまい悩んだことがある。もちろん日本語ページで検索した場合には日本語のみ、英語ページでは英語のみの結果がヒットしなければならない。

検索フォームにhiddenパラメータを追加することで、検索範囲を絞ることができる。前述の企業サイトではデフォルトは日本語の記事で、英語の記事には”英語”というカテゴリをチェックする決まりにしていたので、検索範囲としてカテゴリを指定すればよいことが分かった。
具体的には、英語ページのみ対象としたい場合は検索フォームの中に以下を追加する。
[PHP]
term_id; ?>” name=”cat” />
[/PHP]

カテゴリ以外にも投稿タイプなどを指定することができる。例えばデフォルトでは記事とページが検索対象となっているので、記事のみ検索したい場合は、以下の指定になる。
[PHP]
[/PHP]

これらを組み合わせて指定することもできる。ただしこのように検索フォームに記述した場合は、GETパラメータとしてURLに見えてしまう。これが格好悪いとするなら、search.phpのループ前にquery_posts()で条件を加える方法もあるだろう。