既存記事の更新では、対象のpost_idがそのサイトに実在することを先に確認します。
存在しないIDは新規作成につながるため、別サイトのIDを流用しません。
画面写真には旧版の操作記録と、2026年10月3日に撮影した保存結果が含まれます。
旧画面の入力例をそのまま使わず、現在の更新用CSVと補正コードの対象列を優先してください。
Smart Custom Fields(SCF)の単一テキスト欄を、CSVからまとめて更新する手順を紹介します。
対象は繰り返しのないtext・textareaで、既存値が未保存か文字列1行の項目です。
Excelやスプレッドシートで更新用CSVを作り、検証環境の1件から保存結果を照合します。
更新用CSVを1行から確認する
この手順は単一の文字列を保存する項目に限定します。
CSV作成前に、対象フィールドの定義で繰り返しを使っていないことと、同名のメタ値が複数ないことを確認してください。
繰り返し・複数値の項目はCSVから対象列を外し、対応した保存方法を検証してから更新します。
SCF連携用の列はscf_とフィールド名を組み合わせます。
通常の投稿メタと混同しないでください。
SCF連携用の列の空セルは、既存値を空文字へ更新します。
値を保持したい項目は列ごと省き、空欄のまま含めないでください。
詳細はReally Simple CSV Importerの公式説明を確認してください。
post_id,post_type,post_status,scf_card-title,scf_card-review
123,post,publish,"確認用タイトル","確認用の説明"123は検証環境に存在する対象記事へ置き換えます。
更新したくないpost_title・post_contentなどの列は入れず、公開状態と投稿種別を元の記事に合わせます。
文字コードはUTF-8で保存し、カンマ・改行・引用符のあるセルが分割されていないか確認してください。
最初にデータベースをバックアップし、検証環境の1件で更新前後の値・タイトル・本文・公開状態を比較します。
CSVのアップロードだけで正しい更新を保証できません。
誤更新時はバックアップか変更前の値から復元します。
2026年10月2日、Really Simple CSV Importer 1.3.1とSmart Custom Fields 5.0.8の実処理で単一テキスト項目を更新し、空セルによる空文字への更新、文字列0の保持、引用符・カンマ、投稿タイプ不一致の拒否を確認しました。
同じSCF列名を2本並べたCSVも実処理で確認しました。
たとえば4.5・3.2を同名の2列に入れると、最後の3.2だけが保存され、既存の繰り返し値を置き換えました。
繰り返し欄を増やして複数値を更新しないでください。
繰り返しグループ全体の移行・復元は未検証です。
単一テキストの1行更新は、管理画面からのアップロードと保存後のSCF欄まで確認しています。
カスタムフィールド出力CSVから更新用CSVを作る
| 出力CSVの情報 | 更新用CSVでの扱い |
|---|---|
| post_id | 同じサイトなら実在するIDと照合。別サイトでは対象IDを別途対応付ける |
| meta_keyがcard-titleの行 | 単一テキストのSCF項目ならscf_card-title列へ対応付ける |
| values_jsonが1要素の文字列配列 | JSONを復号し、その1要素の文字列をCSVセルへ保存する |
| 複数要素・配列やオブジェクトを含む値 | この手順の対象外。更新用の列を作らない |
| 出力側のpost_title | タイトルを更新しないなら列を含めない |
カスタムフィールドのCSV出力は、1記事・1キーにつき1行の確認用データです。
この形式をインポーターへ直接アップロードしません。
meta_keyを列名へ変換し、values_jsonのJSON配列から文字列を取り出す工程が必要です。
JSONの角括弧や引用符を文字列置換で削らないでください。
値の中にも引用符や改行があるため、JSONとして復号した後、CSV形式で書き出します。
公開状態と投稿種別は更新先の記事に合わせ、変更するフィールドだけを列に含めます。
検証用の出力を別の検証用投稿へ対応付け、JSON復号後の単一文字列をReally Simple CSV Importerで保存しました。
日本語・カンマ・引用符・改行が一致し、更新先のタイトル・本文・公開状態と省略したフィールドも保持されました。
別サイトのIDを照合する移行は未検証です。
管理画面での1行アップロードと保存後の確認手順は、次の節に示します。
バックスラッシュを含む単一テキストの補正
Really Simple CSV Importer 1.3.1とSmart Custom Fields 5.0.8では、CSVに入れたC:\work\fileがC:workfileとして保存されることを実処理で確認しました。
CSV出力の段階では元の文字列が保持されており、取り込み時のメタ値保存でバックスラッシュが除かれていました。
WordPressのメタ値保存の説明にあるwp_slashを、対象のSCF列だけに適用して補正します。
以下をPHP用のCode Snippetsに1件として登録するか、子テーマのfunctions.phpへ追記します。
両方へ重複登録せず、すでに同じ補正を行っている場合は追加しないでください。
この例はPHP 8以降とmbstring拡張を前提に、scf_card-titleとscf_card-reviewの単一テキスト欄を既存の投稿・固定ページへ更新します。
列名を変える場合は検査側と保存側の両方を合わせます。
投稿種別と公開状態は元の記事と一致させ、ファイルはUTF-8、1MB以下、1000データ行以下にします。
繰り返し・配列値や同名メタが複数ある項目は列に含めません。
フィールド名が違う場合は配列の列名を合わせ、繰り返し・配列値や他のフィールド型には適用しないでください。
バックスラッシュ直後に引用符がある値と、末尾がバックスラッシュの値は対象外です。
以下はCSVインポーターのアップロード時に全行を検査し、対象外の文字列、列の重複・不足、不正なIDや状態があれば、ファイル全体を保存前に拒否します。
CSV解析後の1行だけを止める旧補正では、停止より前の行が保存される可能性がありました。
対象外のバックスラッシュを含む値は、補正で取り込めるようにするのではなく、全行検査で拒否します。
全行検査を通過した後の保存処理は、一括で巻き戻せる仕組みではありません。
保存中にエラーが起きた場合は、再実行する前に各対象IDの値を更新前の記録と照合します。
// Really Simple CSV Importer 1.3.1 / SCF 5.0.8の単一テキスト更新用。
function waza_csv_single_scf_target($post, $name) {
if (!class_exists('SCF')) return false;
$matches = 0;
foreach (SCF::get_settings($post) as $setting) {
foreach ($setting->get_groups() as $group) {
$field = $group->get_field($name);
if (!$field) continue;
if ($group->is_repeatable() || !in_array($field->get_attribute('type'), ['text','textarea'], true)) return false;
++$matches;
}
}
$stored = get_post_meta($post->ID, $name, false);
if ($matches !== 1 || count($stored) > 1) return false;
return !$stored || is_string($stored[0]);
}
function waza_csv_upload_preflight($file) {
if (!is_admin() || ($_GET['import'] ?? '') !== 'csv' || ($_GET['step'] ?? '') !== '1') return $file;
if (!empty($file['error'])) return $file;
$fail = function ($message) use ($file) { $file['error'] = $message; return $file; };
if (!current_user_can('import')) return $fail('インポート権限がありません。');
if (!is_readable($file['tmp_name']) || filesize($file['tmp_name']) > 1048576) return $fail('読める1MB以下のCSVに分割してください。');
$raw = file_get_contents($file['tmp_name']);
if ($raw === false || !mb_check_encoding($raw, 'UTF-8') || str_contains($raw, "\0")) return $fail('UTF-8のCSVを指定してください。');
$a = fopen($file['tmp_name'], 'r');
$b = fopen($file['tmp_name'], 'r');
if (!$a || !$b) {
if ($a) fclose($a);
if ($b) fclose($b);
return $fail('CSVを開けませんでした。');
}
$header = null; $seen = []; $rows = 0; $error = '';
try {
while (($row = fgetcsv($a, 0, ',', '"', '')) !== false) {
$legacy = fgetcsv($b, 0, ',', '"', '\\');
if ($row !== $legacy || ftell($a) !== ftell($b)) { $error = 'CSV解析結果が一致しません。引用符直前・末尾のバックスラッシュを含む行を外してください。'; break; }
if ($header === null) {
$row[0] = preg_replace('/^\xEF\xBB\xBF/', '', (string) $row[0]);
$allowed = ['post_id', 'post_type', 'post_status', 'scf_card-title', 'scf_card-review'];
if (count($row) !== count(array_unique($row)) || array_diff($row, $allowed) || array_diff(['post_id','post_type','post_status'], $row) || !array_intersect(['scf_card-title','scf_card-review'], $row)) { $error = '列名が対象外・重複・不足です。'; break; }
$header = $row; continue;
}
if (++$rows > 1000 || count($row) !== count($header)) { $error = '1000行以下で、各行の列数をそろえてください。'; break; }
$values = array_combine($header, $row);
$id = filter_var($values['post_id'], FILTER_VALIDATE_INT, ['options'=>['min_range'=>1]]);
$post = $id ? get_post($id) : null;
if (!$post || isset($seen[$id]) || !current_user_can('edit_post', $id) || !in_array($values['post_type'], ['post','page'], true) || $post->post_type !== $values['post_type'] || $post->post_status !== $values['post_status']) { $error = 'IDの不存在・重複、権限、投稿種別、公開状態を確認してください。'; break; }
foreach (['scf_card-title','scf_card-review'] as $key) {
if (isset($values[$key]) && !waza_csv_single_scf_target($post, substr($key, 4))) { $error = '単一の非繰り返しテキスト欄として確認できません。定義と既存メタ行を確認してください。'; break 2; }
if (isset($values[$key]) && (str_contains($values[$key], '\\"') || str_ends_with($values[$key], '\\'))) { $error = '引用符直前・末尾のバックスラッシュを含む行は対象外です。'; break 2; }
}
$seen[$id] = true;
}
if (!$error && ($rows === 0 || fgetcsv($b, 0, ',', '"', '\\') !== false)) $error = 'データ行またはCSVの終端を確認してください。';
} finally { fclose($a); fclose($b); }
return $error ? $fail($error) : $file;
}
add_filter('wp_handle_upload_prefilter', 'waza_csv_upload_preflight');
function waza_csv_preserve_scf_text($meta) {
foreach (['scf_card-title', 'scf_card-review'] as $key) {
if (isset($meta[$key]) && is_string($meta[$key])) {
if (str_contains($meta[$key], '\\"') || str_ends_with($meta[$key], '\\')) wp_die('対象外の値です。更新前のバックアップを確認してください。');
$meta[$key] = wp_slash($meta[$key]);
}
}
return $meta;
}
add_filter('really_simple_csv_importer_save_meta', 'waza_csv_preserve_scf_text');
補正後に確認した保存値
| 更新用CSVの単一値 | 実インポーターでの結果 |
|---|---|
| C:\work\file | バックスラッシュを保持 |
| 日本語・カンマ・引用符・改行 | 元の文字列を保持 |
| 0/空文字 | 0と空文字を別々に保持 |
| O'Reilly | 引用符を保持 |
| 省略したcard-review列 | 既存値を保持 |
隔離したWordPress 7.1.2で、全行検査を通った2行をReally Simple CSV Importer 1.3.1へ渡し、SCF 5.0.8の日本語・引用符・改行・パスと文字列0を照合しました。
2行目が対象外の文字列や不正なIDであるCSVはアップロードの事前フィルターで拒否され、1行目の値・本文・下書き状態も変更されませんでした。
これはWordPressのアップロード用フィルターと実インポーターのPHP実行検証です。
ブラウザーから新しい検査付きコードを使ったアップロードは未確認です。
CSVの括弧や引用符を文字列置換で削らず、JSONの復号とCSVの書き出しを順に行います。
補正後の管理画面アップロード、スマホ表示、複雑なフィールド型は今回の追加検証には含めていません。
旧waza_csv_preserve_scf_textを含むスニペットは、このコード全体へ置き換えます。
二重定義しないでください。
戻すときは追加したスニペットを無効にするか、waza_csv_single_scf_target・waza_csv_upload_preflight・waza_csv_preserve_scf_textの三つの関数と二つのフィルター登録をバックアップへ戻します。
過去の保存値は戻らないため、誤更新した値は変更前のバックアップから復元します。
スニペットを無効にした状態で同じCSVを再投入すると、事前検査とバックスラッシュ補正は働きません。
更新先の定義と既存メタ行も全行検査する
CSVの列名が単一テキスト用に見えても、更新先には繰り返しやチェックボックスの値が保存されている場合があります。
改訂コードはCSVにあるSCF列ごとに、その投稿に適用される定義を調べ、重複なく1つの非繰り返しtextまたはtextareaとして確認できる場合だけ受け付けます。
既存値は0行または文字列1行に限定します。
2行以上の既存メタ、配列の既存値、繰り返しグループ、チェックボックス、定義が見つからない項目は、ファイル全体を保存前に拒否します。
SCFが停止中で定義を確認できない場合も拒否します。
省略したSCF列は更新対象にせず、検査と保存の対象から外れます。
隔離環境で、以前の検査が既存メタ2行の更新用CSVを通すことを確認しました。
改訂後は2行目が対象外のファイルを拒否し、1行目の単一値と2行目の複数値を保持しました。
繰り返し・配列・未定義・チェックボックスも拒否し、定義済み単一テキストは通りました。
改訂コードを使う管理画面アップロード、PC・スマホ表示、キーボード操作は未検証です。
保存を始める前の検査範囲
| 検査 | 処理 |
|---|---|
| CSV全体の解析 | 標準の引用符処理とインポーターの処理を比較し、不一致なら拒否 |
| 更新先 | 実在ID・重複なし・編集権限・投稿種別・公開状態の一致を確認 |
| 元データの復元 | 事前検査では代替しない。変更前バックアップを残す |
この検査はCSVの解析器を修理する機能ではありません。
PHP公式のfgetcsv()説明にあるescape指定の違いを比較し、問題のある入力を拒否します。
WordPressのアップロード事前フィルターで動くため、別のCLI処理から直接process_posts()を呼ぶ経路には適用されません。
検査通過後の保存中エラーや別操作との同時更新を巻き戻す機能もありません。
実行中は対象記事を別画面から更新せず、保存後は値と本文・公開状態を照合してください。
アップロード後は対象の編集欄を開き直す
まず、更新する投稿1件だけをCSVに残します。
post_id・post_type・post_statusと、変更するSCF列を指定し、変更しないSCF列はCSVから外してください。
カンマ・引用符・改行を含む値は、CSVの書き出し機能でセル全体を引用符で囲みます。
引用符を手作業で消すと、別の列や行として読み込まれることがあります。
管理画面の「ツール → インポート」からCSVのインポーターを実行し、ファイルを選んでアップロードします。
完了表示が出たら、対象投稿の編集画面を開き直してください。
SCF欄の値に加え、投稿タイトル・本文・公開状態・変更しない欄を照合します。
完了表示だけでは更新内容を判断できません。
隔離環境でReally Simple CSV Importer 1.3.1の実フォームから1行をアップロードし、日本語・カンマ・引用符・改行がSCF 5.0.8の編集欄に保存されたことを確認しました。
省略したcard-review欄と投稿タイトル・本文・下書き状態も保持されました。
複雑なSCF型の一括更新や、別サイトのIDを使う移行はこの確認に含めていません。

複数行の0・空欄・省略列を照合する
| 更新する行 | scf_card-title列 | 列を省略したcard-review |
|---|---|---|
| 対象ID A | 文字列0を保存 | 更新前の値を保持 |
| 対象ID B | 空文字で上書き | 更新前の値を保持 |
実CSVインポーターの管理画面から2行の更新用CSVをアップロードし、別々の既存投稿を更新しました。
再表示したSCF欄ではAの0とBの空文字が区別され、CSVに含めなかったcard-review、投稿タイトル、本文は保持されました。
ID列には導入先の実在IDを指定します。
空欄にした列は変更指示になるため、残したい値の列を空欄にする代わりに列ごと省略してください。
更新前のバックアップとCSVを照合し、完了表示の後に両方の記事を開き直します。
カスタムフィールドの値をcsvファイルからまとめて編集する方法
以下は旧版の画面を使った操作場所の説明です。
2026年10月3日の保存結果の画像と、現行の全行検査コードを使った管理画面操作の検証は分けて扱ってください。
インポートとエクスポート、それぞれ違うプラグインを用います。
Smart Custom Fields
この記事ではSmart Custom Fieldsで作成した項目を扱います。
掲載した補正コードを別のカスタムフィールドプラグインへそのまま適用しないでください。

現在の手順では、繰り返しを使わないtextまたはtextareaを選び、CSVのscf_以降と一致するフィールド名を指定します。

記事IDをCSVで出力する
カスタムフィールドの値は各記事編集で入力できます。
更新先の記事IDとタイトルを照合するため、対象記事の一覧をCSVで出力します。
Export All URLsというプラグインを用います。

エクスポートする内容をチェックします。
下記の項目にチェックしました。
- Pages(固定ページ。投稿はPostsを選択)
- Post IDs(記事ID)
- Titles(記事タイトル)
- 公開状態の絞り込み(公開記事を対象にする場合)
- CSV File(CSVファイル出力)

Click hereからCSVをダウンロードします。

CSVファイルが出力できました。

Really Simple CSV Importerのインポート用にCSVを編集する
Really Simple CSV Importerというプラグインを使って、CSVをインポートして記事内容を更新できます。

以下の一覧と画面は、タイトルやタクソノミーも扱った旧入力例です。
現行の補正コードではpost_titleとtax_priceを含むCSVを拒否します。
今回使う列はpost_id・post_type・post_statusと、変更するscf_card-title・scf_card-reviewだけにしてください。
- post_id(既存記事を更新する場合の照合ID)
- post_title(記事タイトル)
- post_type(postまたはpage)/post_status(保持したい公開状態)
- scf_card-title(SCFのcard-titleフィールド)
- scf_card-review(SCFのcard-reviewフィールド)
- tax_price(カスタムタクソノミーの名前 tax_名前を入れる、名前部分はスラッグ名を入力)

旧例のtax_priceはカスタムタクソノミー用の列です。
この記事の全行検査付き手順では対象外なので、更新用CSVに含めません。

今回はスプレッドシートで編集しました。
入力が終わったら、ファイル>ダウンロード>カンマ区切り形式(.csv)でcsvファイルをダウンロードします。

ダウンロードしたcsvをwordpressにインポートします。
ツール>CSV インポーターの実行を押します。

ファイルを選択からcsvファイルをアップロード、その後にファイルをアップロードしてインポートボタンを押しましょう。

実行後は対象IDの編集画面を開き、変更したフィールドと、変更しないタイトル・本文・公開状態を更新前の記録に照合します。
インポート画面の完了表示だけで成功を判断しません。
カスタムフィールドの値をcsvファイルからまとめて編集する方法まとめ
まず検証環境の1件で、変更したSCF欄と、変更しないタイトル・本文・公開状態を照合してください。
この記事の補正コードは、既存の投稿・固定ページにある対象のSCF単一テキスト欄へ用途を限定しています。
タイトルやタクソノミーの更新、複雑なフィールド型の移行は、このCSVへ列を追加するだけでは行えません。



