WordPress の DB を別サイトに移行する時に WP-CLI の「wp search-replace」コマンドでデータ変換するのがとっても便利ですが、WordPress をマルチサイト(ネットワーク機能)で使っていたり、独自にカスタマイズしたテーブルを持っていたりといった、ちょっと変わったケースでの対応方法を紹介します。
wp search-replace でマルチサイトのテーブルも置換する
wp search-replace で URL 文字列を置換するときの基本コマンドはこちらです。
ところが、WordPress のネットワーク機能で作ったあるマルチサイトについて、サイト移行時に URL 文字列の置換をしようとしたのですが、どうにも置き換わらないデータが残ってしまいます。。
で、そのデータを調べると、マルチサイトのテーブル(マルチサイトのテーブル名は「wp_2_posts」のように間に wp_blogs.blog_id が含まれます)ばかりだったので、wp search-replace は未対応なのかな・・・と一時は思い込んでしまいました。
wp search-replace はマルチサイトに対応してないのか。
— Ko Takagi (@ko31) 2015, 10月 22
でも安心してください、さすが WP-CLI!ちゃんとネットワーク機能に対応するためのオプション「–network」が用意されていました。
オプションを付けたコマンドはこのようになります。
コマンド実行結果を見ると、ちゃんとマルチサイトのテーブルも対象にして置換が行われていることが分かります。
$ wp search-replace --network 'http://example.com' 'http://example.jp'
+---------------------+-----------------------+--------------+------+
| Table | Column | Replacements | Type |
+---------------------+-----------------------+--------------+------+
| wp_2_commentmeta | meta_key | 0 | SQL |
| wp_2_commentmeta | meta_value | 0 | SQL |
| wp_2_comments | comment_author | 0 | SQL |
| wp_2_comments | comment_author_email | 0 | SQL |
| wp_2_comments | comment_author_url | 0 | SQL |
| wp_2_comments | comment_author_IP | 0 | SQL |
| wp_2_comments | comment_content | 0 | SQL |
| wp_2_comments | comment_approved | 0 | SQL |
| wp_2_comments | comment_agent | 0 | SQL |
| wp_2_comments | comment_type | 0 | SQL |
| wp_2_links | link_url | 0 | SQL |
| wp_2_links | link_name | 0 | SQL |
| wp_2_links | link_image | 0 | SQL |
| wp_2_links | link_target | 0 | SQL |
| wp_2_links | link_description | 0 | SQL |
| wp_2_links | link_visible | 0 | SQL |
| wp_2_links | link_rel | 0 | SQL |
| wp_2_links | link_notes | 0 | SQL |
| wp_2_links | link_rss | 0 | SQL |
| wp_2_options | option_name | 0 | SQL |
| wp_2_options | option_value | 2 | PHP |
| wp_2_options | autoload | 0 | SQL |
| wp_2_postmeta | meta_key | 0 | SQL |
| wp_2_postmeta | meta_value | 0 | PHP |
| wp_2_posts | post_content | 0 | SQL |
| wp_2_posts | post_title | 0 | SQL |
| wp_2_posts | post_excerpt | 0 | SQL |
| wp_2_posts | post_status | 0 | SQL |
| wp_2_posts | comment_status | 0 | SQL |
| wp_2_posts | ping_status | 0 | SQL |
| wp_2_posts | post_password | 0 | SQL |
| wp_2_posts | post_name | 0 | SQL |
| wp_2_posts | to_ping | 0 | SQL |
| wp_2_posts | pinged | 0 | SQL |
| wp_2_posts | post_content_filtered | 0 | SQL |
| wp_2_posts | guid | 23 | SQL |
| wp_2_posts | post_type | 0 | SQL |
| wp_2_posts | post_mime_type | 0 | SQL |
| wp_2_term_taxonomy | taxonomy | 0 | SQL |
| wp_2_term_taxonomy | description | 0 | SQL |
| wp_2_terms | name | 0 | SQL |
| wp_2_terms | slug | 0 | SQL |
| wp_3_commentmeta | meta_key | 0 | SQL |
| wp_3_commentmeta | meta_value | 0 | SQL |
| wp_3_comments | comment_author | 0 | SQL |
| wp_3_comments | comment_author_email | 0 | SQL |
| wp_3_comments | comment_author_url | 1 | SQL |
| wp_3_comments | comment_author_IP | 0 | SQL |
| wp_3_comments | comment_content | 0 | SQL |
| wp_3_comments | comment_approved | 0 | SQL |
| wp_3_comments | comment_agent | 0 | SQL |
| wp_3_comments | comment_type | 0 | SQL |
| wp_3_links | link_url | 0 | SQL |
| wp_3_links | link_name | 0 | SQL |
| wp_3_links | link_image | 0 | SQL |
| wp_3_links | link_target | 0 | SQL |
| wp_3_links | link_description | 0 | SQL |
| wp_3_links | link_visible | 0 | SQL |
| wp_3_links | link_rel | 0 | SQL |
| wp_3_links | link_notes | 0 | SQL |
| wp_3_links | link_rss | 0 | SQL |
| wp_3_options | option_name | 0 | SQL |
| wp_3_options | option_value | 2 | PHP |
| wp_3_options | autoload | 0 | SQL |
| wp_3_postmeta | meta_key | 0 | SQL |
| wp_3_postmeta | meta_value | 0 | SQL |
| wp_3_posts | post_content | 2 | SQL |
| wp_3_posts | post_title | 0 | SQL |
| wp_3_posts | post_excerpt | 0 | SQL |
| wp_3_posts | post_status | 0 | SQL |
| wp_3_posts | comment_status | 0 | SQL |
| wp_3_posts | ping_status | 0 | SQL |
| wp_3_posts | post_password | 0 | SQL |
| wp_3_posts | post_name | 0 | SQL |
| wp_3_posts | to_ping | 0 | SQL |
| wp_3_posts | pinged | 0 | SQL |
| wp_3_posts | post_content_filtered | 0 | SQL |
| wp_3_posts | guid | 10 | SQL |
| wp_3_posts | post_type | 0 | SQL |
| wp_3_posts | post_mime_type | 0 | SQL |
| wp_3_term_taxonomy | taxonomy | 0 | SQL |
| wp_3_term_taxonomy | description | 0 | SQL |
| wp_3_terms | name | 0 | SQL |
| wp_3_terms | slug | 0 | SQL |
| wp_blog_versions | db_version | 0 | SQL |
| wp_blogs | domain | 0 | SQL |
| wp_blogs | path | 0 | SQL |
|
〜省略〜
|
| wp_users | user_url | 0 | SQL |
| wp_users | user_activation_key | 0 | SQL |
| wp_users | display_name | 0 | SQL |
+---------------------+-----------------------+--------------+------+
Success: Made 41 replacements.
wp search-replace で独自のテーブルも置換する
さて、WordPress をカスタマイズしていると、新規に独自テーブルを使って機能を開発することもあるかと思います。
wp search-replace の「–all-table」オプションを付けると全てのテーブルが対象になるので、そんな独自テーブルも含めたいときにも便利です。
例えば、URL 文字列を含んだ company テーブルをこのように作ったとします。
そして「–all-table」オプションを付けた形でコマンドを実行。
campany テーブルの URL もちゃんと置換が行われました。
$ wp search-replace --all-tables 'http://example.com' 'http://example.jp'
+---------------------+-----------------------+--------------+------+
| Table | Column | Replacements | Type |
+---------------------+-----------------------+--------------+------+
| company | name | 0 | SQL |
| company | url | 1 | SQL |
|
〜省略〜
|
+---------------------+-----------------------+--------------+------+
Success: Made 1 replacements.
※ちなみに、search-replace のソースを見たところ、「–all-table」の対象テーブルは Primary Key を持ったカラムが存在することが条件のようです。Primary Key を持たないテーブルの方が珍しいかとは思いますが、この点はご注意ください。
まとめ
ドキュメントはちゃんと読むこと!今回のオプション説明も WP-CLI の公式サイトにちゃんと書いてあります(笑)
他にも至れり尽くせり便利なオプションが揃っているので、何か困ったらオプション調べてみるときっと幸せになれるかと思います。