2026年8月16日

2026年8月16日

WP-CLIでカスタムフィールドを一括更新する方法とスクリプト(CSV読み込み・ドライラン付き)

カスタムフィールド(投稿メタ)の一括更新は、件数が少なければ wp post meta update をループで回すだけで済みます。数百件を超える場合や、CSV の値を投稿ごとに反映したい場合は、wp eval-file で PHP スクリプトを1回だけ実行する方が速く、確認もしやすくなります。この記事では、バックアップと事前確認、コマンドだけでできる一括更新、ドライラン付きの CSV 更新スクリプト、ACF を使っている場合の注意、更新後の確認までを順に説明します。

作業の前に:バックアップと対象の確認

一括更新は取り消しが難しい操作です。最初にデータベースを書き出し、できればステージング環境で同じ手順を試してから本番に進んでください。

wp db export before-meta-update.sql

次に、変更したいメタキーの名前と、今どんな値が入っているかを確認します。画面上の項目名と、データベース上のキー名は一致しないことが多いためです。

wp post meta list 123
wp post meta get 123 price

wp post meta list は指定した投稿のメタをすべて表示します。先頭が _ のキー(例: _price、_thumbnail_id)はプラグインや WordPress 本体が内部で使うもので、管理画面のカスタムフィールド欄には表示されません。WooCommerce の価格のように、プラグインが独自の保存処理や集計テーブルを持っている値は、メタだけ書き換えると表示や検索結果と食い違うことがあるため、そのプラグインが用意している手段(管理画面の一括編集やインポート機能、API)を優先してください。

件数が少ないときはコマンドだけで更新する

1件ずつ更新する

wp post meta update 123 featured 1

update は、キーがあれば値を書き換え、無ければ新しく追加します。同じキーを複数持つ投稿(add_post_meta で重複を許して追加したもの)では、すべてが同じ値で置き換わる点に注意してください。

条件に合う投稿をまとめて更新する

wp post list は WP_Query の引数を --キー=値 の形で受け取れるので、対象の投稿IDを1行に1件ずつ取り出し、xargs で更新コマンドに渡せます。

# 公開中の「book」投稿タイプ(独自の投稿タイプの例)すべての featured を 0 にする
wp post list --post_type=book --post_status=publish --field=ID \
  | xargs -I % wp post meta update % featured 0

# 特定のメタ値を持つ投稿だけを対象にする
wp post list --post_type=post --meta_key=status_label --meta_value=old --field=ID \
  | xargs -I % wp post meta update % status_label new

まず xargs 以降を外して実行し、対象のIDと件数が想定どおりかを見てから更新してください。件数だけなら wp post list ... --format=count で確認できます。

この方法は、コマンド1回ごとに WordPress 全体を読み込み直すため、数百件を超えると時間がかかります。そこからは次のスクリプト方式が向いています。

配列やJSONの値を書き込む

配列を保存したい場合は --format=json を使います。WordPress がシリアライズして保存します。

wp post meta update 123 settings '{"color":"blue","size":2}' --format=json

CSVの値で一括更新するスクリプト

「投稿ID,値」の CSV を読み込み、指定したメタキーを更新するスクリプトです。既定ではドライラン(変更内容の表示だけ)で動き、最後に run を付けたときだけ書き込みます。

post_id,value
101,1980
102,2480
105,980
<?php
/**
 * CSV(post_id,value)でカスタムフィールドを一括更新する。
 * 確認だけ: wp eval-file update-meta.php prices.csv price
 * 書き込み: wp eval-file update-meta.php prices.csv price run
 */

if ( count( $args ) < 2 ) {
	WP_CLI::error( '使い方: wp eval-file update-meta.php <CSVファイル> <メタキー> [run]' );
}

list( $csv_path, $meta_key ) = $args;
$apply = isset( $args[2] ) && 'run' === $args[2];

if ( ! preg_match( '/^[A-Za-z0-9_\-]+$/', $meta_key ) ) {
	WP_CLI::error( 'メタキーに使えない文字が含まれています。' );
}

$fh = fopen( $csv_path, 'r' );
if ( ! $fh ) {
	WP_CLI::error( "CSVを開けません: {$csv_path}" );
}

$rows = array();
while ( false !== ( $row = fgetcsv( $fh, 0, ',', '"', '' ) ) ) {
	if ( count( $row ) < 2 ) {
		continue;
	}
	$id = preg_replace( '/^\xEF\xBB\xBF/', '', trim( $row[0] ) ); // ExcelのBOM対策
	if ( ! ctype_digit( $id ) ) {
		continue; // 見出し行などを飛ばす
	}
	$rows[] = array( (int) $id, trim( $row[1] ) );
}
fclose( $fh );

WP_CLI::log( sprintf( '%d行を読み込みました(%s)', count( $rows ), $apply ? '書き込みモード' : 'ドライラン' ) );

$changed = 0;
$same    = 0;
$errors  = 0;
$bar     = \WP_CLI\Utils\make_progress_bar( '処理中', count( $rows ) );

foreach ( $rows as $row ) {
	list( $post_id, $value ) = $row;
	$bar->tick();

	if ( ! get_post( $post_id ) ) {
		WP_CLI::warning( "投稿 {$post_id} が見つかりません" );
		$errors++;
		continue;
	}

	$current = get_post_meta( $post_id, $meta_key, true );
	if ( is_array( $current ) ) {
		WP_CLI::warning( "投稿 {$post_id} の値が配列のため飛ばしました" );
		$errors++;
		continue;
	}
	if ( (string) $current === $value ) {
		$same++;
		continue;
	}

	if ( $apply ) {
		update_post_meta( $post_id, $meta_key, wp_slash( $value ) );
	} else {
		WP_CLI::log( "#{$post_id}: \"{$current}\" -> \"{$value}\"" );
	}
	$changed++;
}
$bar->finish();

WP_CLI::success( sprintf( '変更%s %d件 / 同じ値 %d件 / エラー %d件', $apply ? '' : '予定', $changed, $same, $errors ) );

スクリプトの要点

  • wp eval-file では、ファイル名の後ろに書いた値が $args 配列として渡されます。WordPress が読み込まれた状態で実行されるため、get_post_meta() などのコア関数がそのまま使えます。
  • update_post_meta() は保存の前に値のスラッシュを取り除くため、\ を含む値(Windows のパスなど)が欠けないよう wp_slash() を通しています。
  • 現在の値と同じ場合は書き込みません。何度実行しても結果が変わらない作りにしておくと、途中で止まったときもやり直しが簡単です。
  • CSV を Excel で保存すると、先頭に BOM が付いたり、文字コードが Shift_JIS になったりすることがあります。日本語の値を扱うときは UTF-8 で保存し、ドライランの表示で文字化けしていないかを確認してください。

数万件規模になるとメモリや実行時間が問題になることがあります。その場合は CSV を数千行ずつに分けて順に実行すると、失敗したときの影響範囲も小さくできます。

ACFのフィールドを更新する場合

Advanced Custom Fields(ACF)で作ったフィールドは、値そのもののメタ(例: price)に加えて、どのフィールド定義に属するかを示す参照用のメタ(例: _price に field_ で始まるフィールドキー)も保存されています。管理画面で一度も保存していない投稿に update_post_meta() で値だけ入れると、この参照が無いため get_field() での整形(画像フィールドの配列化など)が期待どおりに動かないことがあります。

ACF が有効なサイトでは、スクリプト内の更新を update_field() に置き換えると参照も含めて保存されます。

// 値がまだ無い投稿もあるなら、フィールド名よりフィールドキーで指定する方が安全
update_field( 'field_abc123', $value, $post_id );

フィールドキーは ACF のフィールドグループ編集画面で確認できます(表示方法は ACF の版によって異なります)。なお、wp eval-file に --skip-plugins を付けると読み込みは速くなりますが、ACF の関数も使えなくなります。

更新後の確認と後片付け

wp post meta get 101 price
wp post list --post_type=book --meta_key=price --meta_value=1980 --format=count

数件を抜き出して値を確かめ、件数がドライランの「変更予定」と合っているかを見ます。永続オブジェクトキャッシュやページキャッシュを使っている場合は、表示が古いままに見えることがあるため、wp cache flush やキャッシュプラグインの削除機能で反映させてください。

SQL の UPDATE 文を wp db query で直接流す方法もありますが、オブジェクトキャッシュの更新やプラグインのフック(updated_post_meta など)が動かず、テーブル接頭辞の違いでも事故が起きやすいため、ここで紹介した関数経由の方法を基本にしてください。WP-CLI のコマンドやオプションは版によって追加・変更されることがあるため(2026年10月現在)、使う前に wp help post meta で手元の版の説明を確認すると安心です。

まとめ

  • 作業前に wp db export でバックアップを取り、wp post meta list で実際のキー名と現在の値を確認する。
  • 少数なら wp post meta update、条件で絞るなら wp post list --field=ID と xargs の組み合わせで更新できる。
  • 数百件以上や CSV からの反映は wp eval-file のスクリプトにまとめ、ドライランで差分を見てから書き込む。
  • update_post_meta() には wp_slash() を通した値を渡し、同じ値なら書き込まない作りにする。
  • ACF のフィールドは update_field() とフィールドキーで更新し、最後にキャッシュをクリアして結果を確認する。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲