WordPress のリビジョンについての間違った認識と正しい対処

WordPress のリビジョン機能は冷遇されているようで検索すれば無効化する方法がたくさん見つかります。 一方でこの機能が「使える」ものだったらやっぱり使いたいよなあ、という人も多いのではないでしょうか。 ブログ記事は書き捨てというやり方だけでなく、注目を集め反応が多かった記事に情報を追記していく場合もあるでしょう。 また、WordPress のビジネス利用も増えていますが、そうであればなおさらリビジョン管理は重要です。 そこで今回は現行のリビジョン機能の何が問題でどうすれば解決するかをまとめたいと思います。

まあ、リビジョン機能止めて別に困らないという人はそれでいいのですけれど。

まずは正しい認識を

まず、WordPress のリビジョン機能について正しい認識を持ちましょう。 あまり理解されていないように思われるのは以下の点です。

  • 自動保存は 1世代のみ
  • リビジョンが作成されるのはポストテーブル (wp_posts) 内容のみ。 wp_postmeta や wp_term_relationships などの関連テーブルは (プラグイン等を用いない限り) リビジョンが作成されない。

つまり、デフォルトの 60秒間隔自動保存でバンバンリビジョンが増えていくというわけではないです。 また、ポストテーブルのリビジョンのみ、すなわちカテゴリーやタグの付け替え履歴は残らないので、WordPress のリビジョン機能は、基本的に記事にしたテキストデータの変更履歴を取るための機能と捉えるのが良いと思います。

データベース関連についても一言言っておきます。

  • 通常の一記事表示ではインデックスを使用した検索になるので、ポスト数が増えても検索時間は比例しない。 なので、個人ブログレベルであれば、リビジョンを作成したからといって (よほど作りの悪いテーマやプラグインを使っていない限り) パフォーマンスに影響が出ることはまずない。

まあ、データベースの容量に関しては確かにリビジョンを作成することでその分使用領域は増えます。 しかし、所詮テキストデータなので、画像に比べればたかが知れています。

あっ、まさかリビジョンを作成するとそのページで使った画像まで何世代も保管されちゃう、なんて思っていたりします? 念のために言っておきますが、それはないです。 イメージデータそのものはデータベースに入らないですし。

もう一度書きますが、リビジョンが作成されるのはポストテーブルの内容のみです。 ポストテーブルの内容を知らなければこちらで確認しておきましょう。 タグやカテゴリーの情報はポストテーブルに入っておらず、別テーブルから post_id を使ってポストテーブルを参照するようになっています。

でもリビジョン多くね?

と、ここまで読んでも「実際には多数リビジョンが出来てるし、嘘書いてんじゃねーの?」と疑っている人もいるでしょう。 確かにリビジョンが多く作成されてしまうのは事実です。 これは WordPress の以下の動作によるものです。

  1. 下書きの状態 (公開前も含む) でプレビューをするたびにリビジョンが作成される。
  2. クイック編集や一括編集でもリビジョンが作成される。

1. については思い当たる方が多いのではないでしょうか? 公開前はプレビュー操作を行って最終的な見栄えをチェックしながら文章を調整することがあると思いますが、そこでプレビューする度にリビジョンができてしまうのです。公開された記事のプレビュー操作では自動保存リビジョンとなるのでどんなにプレビューしても 1世代なのですが、公開前だと何世代ものリビジョンができてしまいます。 たいていの場合は公開初版のリビジョンだけあればよいですよね。

2 については更に不要です。 このような編集方法を採るときはタグやカテゴリーを直す場合が多いと思うのですが、そうなるとポストテーブルの項目に変更は発生しないことが多いにも関わらずリビジョンが作成されてしまうということになってしまいます。 ですので、リビジョン比較をしても「同じ内容です」というちょっと悲しいリビジョンばかりできてしまいます。

どうすりゃいいのさ?

さて、これらの不要なリビジョンを保存せずに、意味のあるリビジョンだけ残すにはどうすれば良いのでしょう? ちょっと考えてもどうしようもなさそうですね。 でも簡単な解決策があるんです。 それは…。

(縦に長い空白地帯)

じゃーん。 リビジョン管理用のプラグイン「Thin Out Revisions」を使えばよいのです。 以下の手順で不要なリビジョンとおさらば!

  1. あなたのサイトのプラグイン検索画面から Thin Out Revisions を検索してインストール、有効化する
  2. 「設定」-「Thin Out Revisions」とメニューを選び 3項目全て ON にして保存する

えっ? 作者が日本人っぽい? どっかで見たアイコン?

…実は私がつくったのです。

ステマではありません。作者による告知です! それとこんな機能もあります。 気に入ったら是非つぶやいたり、「いいね!」したりしてください。お願いします! お願いします!

(後半雰囲気を変わってしまいましたが、同じ著者によるものです。セッティング項目の見出しは一応読んでね。)

WordPress は最初からマルチサイト化しておこう

WordPress のマルチサイト化について経験に基づきもろもろをまとめておきます。

はじめに

「マルチサイト」は 1つの WordPress インストレーションで複数のブログを運用するための機能のことです。 各ブログごとにドメインを分ける「サブドメイン方式」と、同じホスト名でディレクトリを分ける「サブディレクトリ方式」があります。

インストール完了直後に設定するのがお勧め

既に運用を始めている WordPress を後からマルチサイト化することもできますが、それなりの設定変更となるので運用を始める前にマルチサイト化しておくのが良いと思います。 一人でブログを書き始めるとしても、将来複数のブログ (例えば、日本語版と英語版とか、仕事用と趣味用とか) を運用したくなるときが来るかも知れないので、とりあえず失敗してもさほど痛くない運用開始前にやっておこうということです。 そもそも最初にやっておいた方が制限も少なくすんなり設定できるはずです。 最初からマルチサイト化しておけば「マルチサイト未対応プラグインを使ってしまい切り替えるときに困る」ということもありません。 マルチサイト機能を有効化しておいて 1つのブログで記事を書き始めれば良いのです。

運用開始後はサブドメイン方式一択

運用開始後にマルチサイト化する際の制限として、サブディレクトリ方式はできず、サブドメイン方式でやるしかないというものがあります。 公式情報には以下のようにあります。

You cannot choose Sub-directory Install (for a path-based network) if your existing WordPress installation has been set up for more than a month, due to issues with existing permalinks.

一か月経つとパーマネントリンクの何がかわるのかが今一つわからないのですが、基本的にはサブディレクトリ方式でマルチサイト化したいならばインストール直後に設定しなければならないと捉えておくべきでしょう。 その他にもサブドメイン方式を選ぶときは WordPress ディレクトリがドキュメントルートでなければならないと書かれています。 以下のような URL はダメということです。

http://example.com/wordpress/

あるいは下の様に標準ポートでない場合はそもそもマルチサイト化できません。

http://example.com:8000/

ハマらないために公式情報はきちんと読んでおきましょう。

サブドメイン方式の構成

実際のところ、私もマルチサイト機能を知ったのは運用開始後なので、選択の余地はありませんでした。 というわけでここからはサブドメイン方式の話です。 共用レンタルサーバでは仮想ホスト機能を使いホスト名とディレクトリを対応付けすると思いますが、使用するホスト名は全て同一の WordPress ディレクトリに対応するように設定を行います。 以下のようなイメージです。

example.com → wordpress ディレクトリ (最初のサイト)
sub1.example.com → wordpress ディレクトリ
sub2.example.com → wordpress ディレクトリ

もちろん DNS のレコードもドメインの数だけ登録して同じ Web サーバーを指すようにしておかねばなりません。

実際にやってみる

実際の手順は公式情報の通りです。 wp-config.php や .htaccess の修正、blogs.dir の作成といったあたりをこなさなければなりませんが、どのように変更するかは指示されるのであまり迷うこともありません。 あちらこちらのブログにやり方が書かれていますが、中途半端な記事を読むよりは公式情報を読んで作業する方がすんなり行くように思います。 英語も難しくないんで慣れましょう。

1点注意があるのですが、それは .htaccess の修正です。 これを失敗すると 2番目以降のサイトでアップロードした画像が表示されなかったりします。 私の場合、元の .htaccess は以下の様なものでした。

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

その .htaccess に以下を追加するよう指示されました。 (少なくとも私にはそう読めました)

RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]

# uploaded files
RewriteRule ^files/(.+) wp-includes/ms-files.php?file=$1 [L]

RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule . index.php [L]

しかし、実際は後ろに追記しても動かず、正常動作のためには指示された内容に置き替えなければなりません。 このあたり WordPress バージョンや状況によって表示される指示が異なる可能性があるので Apache の Rewrite ルールをある程度把握しておかねばなりません。 元 .htaccess の最初の RewriteCond からの 3行で以下の置き換えが行われます。

「実体としてのファイルやディレクトリが無い URL は /index.php に書き替え処理を停止する ([L]フラグ)」

サブドメインサイトにアップロードされたファイルを表示するための書き替えは以下の行なのですが、実体がない URL の置き換えなのでここに来る前に先のルールが適用されると /index.php に変換され処理が終わってしまいます。

RewriteRule ^files/(.+) wp-includes/ms-files.php?file=$1 [L]

ちなみに追記指示分の最初の RewriteCond からの 3行は以下の置き換えルールです。

「実体としてファイルかディレクトリが存在する URL は変換せず ("^ -" の部分) 処理を停止する」

ド・モルガンの法則でしたっけ? 最終行は残り全て index.php に書き替えるので結局元の .htaccess の RewriteCond の部分と同じ結果になるんですよね。 なので、元のルールは必要なく、表示されたもので置き換えれば動きます。 Rewrite ルールは奥が深いです。 私も「^ -」と「. -」の差異とか / があったりなかったり等の細部は気にしないことにしましたが、ある程度は把握していないと動かずに苦労することになるのです。

ということもあったりなので、インストール直後のマルチサイト化がお勧めなのです。 まあ、この記事を目にする人の多くは既に WordPress を運用しているんだろうとは思いますが…。

コマンドラインから WordPress 関連処理を実行する

FC2 ブログで行ってたつぶやきアーカイブを hetarena.com に移すために、コマンドラインで実行するための記事投稿用プログラムを書く方法を調べてみました。 wp-cron ではなく OS の crontab を使用したいので、単独の PHP プログラムファイルとして動かしたいのです。

結論からすると簡単で wp-load.php をプログラムの最初に読み込めば良いです。 参考にしたのはこちらの記事ですが、投稿を作成する程度であれば特に $_SERVER を設定しなくても動きました (→ マルチサイト化されていると $_SERVER を設定しなければ動きませんでした。追記参照)。 以下サンプルコードです。 コマンドラインから実行すると 7/7 付けの投稿が作成されます。 使用する場合はご自分の環境に合わせて修正してからお試しください。

#!/usr/bin/php
<?php

//require the WP bootstrap
require_once('/usr/share/wordpress-ja/wp-load.php');

class WP_Command_Line {

  public function __construct() {
    //nothing here
  }

  public function main() {

    $post = array (
      'post_content'   => 
        "<p>これはインポートされた記事です。</p>\n<p>よろしく!</p>",
      'post_type'      => 'post',
      'comment_status' => 'closed',
      'ping_status'    => 'closed',
      'post_status'    => 'publish',
      'post_author'    => 2,
      'post_title'     => 'テスト用記事',
      'post_date'      => '2012-07-07 00:00:00',
      'post_category'  => array(6)
    );
    $e = wp_insert_post($post, true);
    if (is_wp_error($e)) {
      print $e->get_error_message();
    }
    else {
      print "Post ID = " . $e . "\n";
    }
  }
}

$importer = new WP_Command_Line();
$importer->main();

wp_insert_post の Tips も簡単に紹介しておきます。

  • $post->post_date を設定しなければ実行時の時刻で記事が作成されます。
  • $post->post_author や $post->post_category は既に存在するユーザ/カテゴリーの ID を渡します。 カテゴリーは配列を渡します。
  • 記事 ID 指定で追加したい時は $post->import_id に ID をセットします。$post->ID は更新の時に使います。

詳しくは wp_insert_post のリファレンスをご確認ください。


2012.7.28 追記
マルチサイト化されていると $_SERVER の設定が必要です。以下の様な感じで動きました。

$_SERVER = array(
  "HTTP_HOST" => "hetarena.com",
  "SERVER_NAME" => "hetarena.com",
  "REQUEST_URI" => "/",
  "REQUEST_METHOD" => "GET"
                 );

内部リンクを壊さずに FC2 ブログの記事を WordPress にインポートする

内部リンク切れを起こさずに FC2 ブログを WordPress サイトに移行する際の手順です。 ブログ記事番号を合わせることで、FC2 ブログからの個別記事へのリダイレクトも可能なようにします。 ある程度プログラムや HTTP、HTML の知識がある人向けで、説明を端折っている部分もあります。 スクリプトプログラム等もダウンロードできるようにしていますが、環境に合わせて修正が必要となるので最終的には自己責任でご利用ください。 WordPress のバージョンは 3.3、3.4 で試していますが、Movable Type and TypePad Importer のバージョン (0.4) の方が重要です。 これ以降の説明はホスト名として実際に私が行った blogger323.blog83.fc2.com (FC2) と hetarena.com (WordPress) を使用します。

以下の条件で移行を行います。

  • http://blogger323.blog83.fc2.com/blog-entry-NNN.html を https://hetarena.com/archives/NNN に対応させます。(追記: 他のパーマリンク形式が良い人はコメント欄参照。)
  • FC2 にこれまでアップロードしたファイルは https://hetarena.com/oldimages/ の下に置きます。

手順の概要は以下の通りです。

  1. FC2 ブログでエクスポートした記事と sitemaps.xml を使用して、各記事に ID (先述の URL 内の NNN の部分) を付与したエクスポートデータを作成します。
  2. 記事中の内部リンクの変換を行います。
  3. Movable Type and TypePad Importer を一部変更し、ID を読むようにしてから記事をインポートします。
  4. 画像の引越し、FC2 のリダイレクトの設定を行います。

インポートするデータの作成

実際の手順では先の 1. 2 を合わせてプログラムで処理しました。 FC2 ブログの記事をエクスポートし、UTF-8 に変換して blogger323.txt として保存します。 続いて http://blogger323.blog83.fc2.com/sitemaps.xml をファイルとして保存します。 こちらの perl スクリプトをダウンロードし、先の 2つのファイルと同じディレクトリに置いて以下を実行します。

perl fc22wp.pl blogger323.txt > blogger323_wp.txt

これで「ID: 」の行が足され、更に内部リンクの変換が行われます。 perl のスクリプトについて簡単に説明すると以下の処理をしています。

  • blogger323.txt の「DATE:」行を sitemaps.xml の「<lastmod>」の日時とマッチさせ、記事番号の含まれる「ID:」行を挿入する。
  • blog-entry-NNN.html を archives/NNN に変換
  • blogger323.blog83.fc2.com を hetarena.com に変換
  • http://blog-imgs*.fc2.com/b/l/o/blogger323/ を /oldimages/ に変換

使い捨てで書いているので使用する際は「blogger323」、「hetarena.com」の含まれている行を適切に修正し、処理内容を確認してから使用してください。 まあ、短いプログラムなので見ていただければ perl を知らなくても何をしているか想像がつくと思います。

インポートの実行

WordPress に標準でついてくる「Movable Type and TypePad Importer」(Version 0.4) を使用しますが、そのままだと「ID:」行を読んでくれません。 そこで movabletype-importer.php に以下の修正を行います。 (wp-content/plugins/movabletype-importer/ の下にあるファイルにこのパッチファイルを当てても良いですが、WordPress 管理画面の「プラグイン編集」から修正するのがお手軽です)

--- movabletype-importer.php.orig       2011-01-15 09:53:03.000000000 +0900
+++ movabletype-importer.php    2011-08-02 20:22:59.000000000 +0900
@@ -388,6 +388,10 @@
                                $slug = trim( substr($line, strlen('BASENAME:')) );
                                if ( !empty( $slug ) )
                                        $post->post_name = $slug;
+                       } else if ( 0 === strpos($line, 'ID:') ) {
+                               $post_id = trim( substr($line, strlen('ID:')) );
+                               if ( !empty( $post_id ) )
+                                       $post->import_id = $post_id;
                        } else if ( 0 === strpos($line, 'STATUS:') ) {
                                $status = trim( strtolower( substr($line, strlen('STATUS:')) ) );
                                if ( empty($status) )

import_id はまともに公式解説されていないパラメータなのですが、更新のときは $post->ID に、新規のときは $post->import_id に記事 ID をセットして wp_insert_post を呼ぶと希望通りの ID で記事が更新/作成されます。

安全を期すならば blogger323_wp.txt をインポートする前に記事ID の大きなダミーデータを 1つ作成してインポートしておきます。 import_id で指定した番号の記事が存在すると既存最大 ID + 1 の番号が振られて記事が作成されてしまうのですが、こうしてダミーデータを入れておけば万が一既に記事が存在していたとしてもダミーデータの後ろの番号で作成され、続く記事のインポートに影響を与えません。

そのほかもろもろ

他にもいくつか実行しておくべきことがあります。

  • WordPress でパーマネントリンク設定を行って archives/NNN 形式を選んでおきます。
  • FC2 にアップロードされているファイルをダウンロードして WordPress ディレクトリの下の oldimages の中に置きます。 ダウンロードするファイルが多い場合は何かツールを使うなりしてダウンロードしましょう。 (私は HTML からリンクを取り出して wget を回すスクリプトを書いたような気がします)
  • RSSフィード読者向けに FC2 側に移転告知エントリを一つ書いておく必要があると思います。 FeedBurner を使っていれば、Original Feed URL を変更することで読者の手を煩わせることなく引き続きフィードを提供することができます。 しかし、この場合もリーダー上で既読情報等がリセットされるようなので告知をしておいた方が良いでしょう。
  • どこまでやるかという問題になるのですが、ここまでの手順で救えるのは個別記事 URL です。 カテゴリーやタグつき記事に対してのリンクが記事中に大量に埋め込まれている場合、それらへの手当ても必要かも知れません。 一つの手として Redirection プラグインを使う方法を紹介しておきます。 Redirection プラグインでは正規表現も使えるので、例えば「/\?tag=(.*)」→「/?s=$1」みたいなルールを作るとかつてタグで指定していた単語での検索結果を表示するようになります。
  • WordPress サイトの準備が整ったら FC2 テンプレートに meta refresh でリダイレクトする設定を入れます。 あと rel="canonical" の <link> タグも入れておいた方が良いでしょう。

最後の FC2 テンプレートの件については説明が必要ですね。 まずはリダイレクトは以下の記述を <head> セクションに追記します。 (実際は改行なしで書いています)

<meta <!--index_area--><!--/index_area--> http-equiv="refresh" 
content="0;URL=https://hetarena.com/<!--permanent_area-->
<!--topentry-->archives/<%topentry_no><!--/topentry--><!--/permanent_area-->" />

リダイレクトの設定についてはこちらの記事を参考とさせていただきました。 続いて <link> タグですが、以下の記述を同じく <head> セクションに追記します。

<!--permanent_area--><!--topentry-->
<link rel="canonical" href="https://hetarena.com/archives/<%topentry_no>" />
<!--/topentry--><!--/permanent_area-->

ところで

hetarena.com を立ち上げてからこれまでは FC2 ブログを Twitter のつぶやきアーカイブ用に使っていたのですが、最近、WordPress のカスタム投稿タイプを使えば hetarena.com 側でアーカイブしてもブログ記事と混ざらないことに気づき、FC2 ブログの方は閉鎖することにしました。 そんなこともあってこんな記事を書いてみたのでした。 ちなみにつぶやきアーカイブはこちらです。


コメントいただいたので、ちょっと追記

実行例を挙げておきます。 まずコマンドプロンプトを開きます。 アクセサリの下にありますが、スタートメニューで cmd.exe と入力してもコマンドプロンプトを実行できます。 まずディレクトリを作成します。まあ、ここはエクスプローラーで実行しても良いですが。

C:\Users>blogger323>mkdir c:\temp
C:\Users>blogger323>cd \temp
C:\temp>

強調部分が入力するところです。 ここまでで C:\temp フォルダができているので必要なファイルをそこに入れます。 そして perl コマンドを実行します。

C:\temp>perl fc22wp.pl blogger323.txt > blogger323_wp.txt

これで C:\temp フォルダの中に blogger323_wp.txt というファイルができます。