PHPでWordPressの投稿データをSQLiteへエクスポートする

WordPressの基本機能で[ツール]の[エクスポート]から記事データをXMLファイルへ出力する機能はあるのですが、なぜか記事の最終更新日が出力されません

投稿日は出力されるので運用によっては問題ないのかもですが、うちのブログのようにちょいちょい過去記事を見直して修正する場合、記事の最終更新日がないとちょっと管理しづらい。

また、以前に「バリューサーバーのMySQLが落ちやすい」で書いたとおり、WordPressの世界シェアは33%と圧倒的なものの、サーバーへの負荷が高く、ページが重くなりがちなのでWordPressから静的ページや独自のCMSへ移行する企業も増えているようです。

このブログもそのうち自前のCMSへ移行しようかなぁ、と検討中なので、今のうちにWordPressで書いた記事データをsqlite等にコンバートできる仕組みを考えておこうと思いました。

WordPressのwp_postsから取得するデータ

というわけで、WordPressが使っているMySQLデータベースのwp_postsテーブルから直接記事データを吸い出しちゃおう、という話ですが、テーブルのどの項目がどういう意味なのか知らないと抜き出せませんよね。

ざっくり見たところ、wp_postsの中身はこんな感じ。

post_title記事タイトル
post_content本文
post_date投稿日
post_modified最終更新日
post_nameパーマリンク

また、wp_postsテーブルには下書きデータなども含まれるため、post_statusとpost_typeに条件を付けてあげる必要がありそうです。

具体例

SELECT * FROM wp_posts WHERE post_status='publish' AND post_type='post'

このSQL文で公開済の投稿データが全て取得できるハズ。

PHPでWordPressのwp_postsを読み取る例

PHPのPDOで書くならこんな感じでしょうか。

//接続情報
$cfg['WP_PDO_DSN'] = 'mysql:host=localhost;charset=utf8mb4;port=3306;dbname=[データベース名];';
$cfg['WP_PDO_USER'] = '[ユーザー名]';
$cfg['WP_PDO_PASS'] = '[パスワード]';

//WordPressのデータを取得
$conn_wp = new PDO($cfg['WP_PDO_DSN'], $cfg['WP_PDO_USER'], $cfg['WP_PDO_PASS'], 
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
	PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
	PDO::ATTR_EMULATE_PREPARES => true,
	PDO::ATTR_STRINGIFY_FETCHES => false
));
$query = "SELECT * FROM wp_posts WHERE post_status='publish' AND post_type='post'";

$i = 0;
foreach ($conn_wp->query($query) as $row) {
	$i++;
	echo implode(" ", array($i, $row['post_date'], $row['post_modified'], $row['post_title'])).'<br>';
}

うちの環境で試した限りではこれでちゃんと必要な記事データが取得できました。

PHPでWordPressの投稿データをsqliteに変換する

将来的にWordPressを静的コンテンツ(ただのHTML)へ一括変換するのなら、先述のPHPで取得したwp_postsをHTMLへ変換するだけの話ですが、実際は何らかの更新システム(自分で作った独自のCMS等)を用意すると思います。

そのとき、またMySQLを使うと同居している他サイトの影響を受ける可能性が高いかもなので、ひとまずsqliteへ変換してみることにしました。

まぁ変換といっても、単にMySQLからSELECT文でデータ取得して、sqliteにINSERTするだけのことですけども。

<?php
//接続情報
$cfg['WP_PDO_DSN'] = 'mysql:host=localhost;charset=utf8mb4;port=3306;dbname=[データベース名];';
$cfg['WP_PDO_USER'] = '[ユーザー名]';
$cfg['WP_PDO_PASS'] = '[パスワード]';

//sqliteへ接続
$conn_sqlite = new PDO('sqlite:blog.db');

//postsテーブルの作成
$query = '
CREATE TABLE IF NOT EXISTS posts (
ID integer PRIMARY KEY AUTOINCREMENT,
post_title text,
post_content text,
post_date datetime,
post_modified datetime,
post_name varchar(200))';
$conn_sqlite->query($query);

//WordPressのデータを取得
$conn_wp = new PDO($cfg['WP_PDO_DSN'], $cfg['WP_PDO_USER'], $cfg['WP_PDO_PASS'], 
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
	PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
	PDO::ATTR_EMULATE_PREPARES => true,
	PDO::ATTR_STRINGIFY_FETCHES => false
));
$query = "SELECT * FROM wp_posts WHERE post_status='publish' AND post_type='post'";

//sqliteへのINSERT文を準備
$stmt_sqlite = $conn_sqlite->prepare("INSERT INTO posts (post_title, post_content, post_date, post_modified, post_name) VALUES (?,?,?,?,?)");

$i = 0;
foreach ($conn_wp->query($query) as $row) {
	$i++;
	echo implode(" ", array($i, $row['post_date'], $row['post_modified'], $row['post_title'])).'<br>';

	$param = array();
	$param[] = $row['post_title'];
	$param[] = $row['post_content'];
	$param[] = $row['post_date'];
	$param[] = $row['post_modified'];
	$param[] = $row['post_name'];
	$stmt_sqlite->execute($param);
}
?>

解説

sqliteは非常にシンプルでユーザー名とパスワードの指定すら必要なく(というかユーザー管理がない)、データベースをあらかじめ作っておく必要すらないため、

$conn_sqlite = new PDO('sqlite:blog.db');

という実にシンプルな書き方でDBへ接続できます。

ここでは blog.db というファイル名を指定していますが、このファイルがなければ作成し、すでにあればそこへ接続する動作となります。

そして、以下のSQL文を発行することで、postsテーブルを作成しています。

CREATE TABLE IF NOT EXISTS posts

これも IF NOT EXISTS と書かれているとおり、postsテーブルが存在しないときだけ作成する処理をしています。

WordPressのMySQLからの読み込み処理は先述と変わらず、読み込みループの前に $conn_sqlite->prepare でプリペアドステートメントを用意しています。

INSERT INTO posts (post_title, post_content, post_date, post_modified, post_name) VALUES (?,?,?,?,?)

ループの内部で毎回INSERT文を組み立てるのは非効率なので、あらかじめテンプレートとなるINSERT文を用意(プリペアド)し、ループ内部ではプレースホルダ(クエスチョンマークで書かれた部分)に記事タイトルや本文をセットしているわけです。

	$param = array();
	$param[] = $row['post_title'];
	$param[] = $row['post_content'];
	$param[] = $row['post_date'];
	$param[] = $row['post_modified'];
	$param[] = $row['post_name'];
	$stmt->execute($param);

これだけでサクっとWordPressの投稿データ(wp_posts)をsqliteデータベースへエクスポートすることが出来ました。

まとめ

  • WordPressの記事データは以下のSQL文で取得可能
    SELECT * FROM wp_posts WHERE post_status='publish' AND post_type='post'


  • wp_postsテーブルにあるそれぞれの項目は下記のとおり。
    post_title記事タイトル
    post_content本文
    post_date投稿日
    post_modified最終更新日
    post_nameパーマリンク

これだけわかっていればsqliteに限らず、CSVへ変換したり、別のデータベースへ変換することも簡単に出来そう。

Web運営を長く続けるコツは更新処理の簡略化だと思うんですよね。