カテゴリーやタグを一括登録する場合は、名前・スラッグ・親カテゴリーを一覧にしてから登録します。この記事では、WP-CLIを利用できる管理者向けに、追加予定を確認してから登録するPHP例を紹介します。既存の分類を一括上書きする用途には使いません。
実行前の準備
対象サイトのデータベースをバックアップし、復元できることを確認します。まず複製した検証サイトで試してください。WP-CLIがない場合は、このコードをfunctions.phpや投稿本文へ貼らず、管理画面のカテゴリー・タグ画面で登録します。旧版WP Taxonomy ImportのZIP導入手順は、今回の検証対象として維持できないため掲載を終了しました。
登録データとPHPファイル
次の内容をUTF-8・BOMなしの waza-terms.php として、Web公開ディレクトリの外に保存します。末尾のrowsを編集します。各行は「名前、半角英小文字・数字・ハイフンのスラッグ、親のスラッグ」です。親は子より先に記載し、親なしは空文字にします。名前の前後の空白や、保存時に取り除かれるスラッグの前後のハイフンは入力エラーとして登録前に止めます。WordPressに保存した値が入力表と食い違うと再実行の照合ができないためです。タグの場合はすべて親なしにしてください。
<?php
// wp eval-file waza-terms.php category dry-run
// wp eval-file waza-terms.php category apply
function waza_import_terms(array $rows, string $taxonomy, bool $apply = false): array {
if (!in_array($taxonomy, array('category', 'post_tag'), true)) throw new RuntimeException('category / post_tag のみ対応');
$known = array(); $plan = array();
foreach ($rows as $row) {
if (!is_array($row) || array_keys($row) !== array(0, 1, 2)
|| count(array_filter($row, 'is_string')) !== 3) {
throw new RuntimeException('各行は名前・スラッグ・親スラッグの3つの文字列にしてください');
}
list($name, $slug, $parent_slug) = $row;
if ($name !== trim($name) || sanitize_title($slug) !== $slug
|| ($parent_slug !== '' && sanitize_title($parent_slug) !== $parent_slug)) {
throw new RuntimeException('前後の空白・ハイフンなど、保存時に変わる入力を修正: ' . $slug);
}
if (!$name || !preg_match('/^[a-z0-9-]+$/D', $slug) || isset($known[$slug])) throw new RuntimeException('名前・スラッグ・重複を確認: ' . $slug);
if ($taxonomy === 'post_tag' && $parent_slug !== '') throw new RuntimeException('タグに親は指定できません');
$parent_id = 0;
if ($parent_slug !== '') {
if (isset($known[$parent_slug])) $parent_id = $known[$parent_slug];
else {
$parent = get_term_by('slug', $parent_slug, $taxonomy);
if (!$parent) throw new RuntimeException('親を先に記載: ' . $parent_slug);
$parent_id = (int) $parent->term_id;
}
}
$existing = get_term_by('slug', $slug, $taxonomy);
if ($existing && ($existing->name !== $name || (int) $existing->parent !== $parent_id)) throw new RuntimeException('既存データと不一致: ' . $slug);
$id = $existing ? (int) $existing->term_id : -(count($plan) + 1);
$known[$slug] = $id;
$plan[] = array('name' => $name, 'slug' => $slug, 'parent_slug' => $parent_slug, 'id' => $id, 'action' => $existing ? 'keep' : 'create');
}
if (!$apply) return $plan;
$resolved = array(); $result = array();
foreach ($plan as $item) {
$id = $item['id'];
if ($item['action'] === 'create') {
$parent_id = 0;
if ($item['parent_slug'] !== '') {
$parent = get_term_by('slug', $item['parent_slug'], $taxonomy);
if (!$parent) throw new RuntimeException('親が消失しました。処理を中止します');
$parent_id = (int) $parent->term_id;
}
// 同時編集を避け、直前にもスラッグの重複を確認します。
if (get_term_by('slug', $item['slug'], $taxonomy)) throw new RuntimeException('実行中に既存データが変わりました: ' . $item['slug']);
$created = wp_insert_term($item['name'], $taxonomy, array('slug' => $item['slug'], 'parent' => $parent_id));
if (is_wp_error($created)) throw new RuntimeException($created->get_error_message());
$id = (int) $created['term_id'];
}
$item['id'] = $id; $result[] = $item;
echo wp_json_encode($item, JSON_UNESCAPED_UNICODE) . PHP_EOL;
}
return $result;
}
if (defined('WP_CLI') && WP_CLI) {
$taxonomy = $args[0] ?? 'category';
$mode = $args[1] ?? 'dry-run';
if (!in_array($mode, array('dry-run', 'apply'), true)) WP_CLI::error('dry-run / apply を指定');
$rows = array(
array('関東', 'kanto', ''),
array('東京', 'tokyo', 'kanto'),
array('神奈川', 'kanagawa', 'kanto'),
);
try {
$result = waza_import_terms($rows, $taxonomy, $mode === 'apply');
if ($mode === 'dry-run') WP_CLI::line(wp_json_encode($result, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
} catch (Throwable $e) { WP_CLI::error($e->getMessage()); }
}
確認してから登録する
WordPressの設置ディレクトリで実行します。下記のファイルパスは保存先に置き換えてください。dry-runの負のIDは未作成を表す仮の値で、データベースへは保存されません。createは追加予定、keepは既存データの維持です。
wp eval-file /private/path/waza-terms.php category dry-run
wp eval-file /private/path/waza-terms.php category apply > terms-created.logタグはcategoryをpost_tagに置き換えます。同じスラッグの名前や親が異なる場合は停止します。同名・別スラッグなどWordPress側の追加検査で失敗することもあり、dry-runは登録成功の保証ではありません。実行中は他の管理者による分類の編集を止めてください。
実行結果のcreateとkeepを読み分ける
| 結果 | 次の操作 |
|---|---|
| dry-runでcreate | 追加予定。まだ分類は作成されていない |
| applyでcreateと正のID | 新しく作られた分類。IDと入力行をログへ残す |
| keep | 名前・スラッグ・親が既存の分類と一致。上書きはしない |
| 途中でエラー | 先に作られた分類は残る。ログと再度のdry-runで現在の状態を確認 |
同じ入力で再実行すると、前回作成した分類はkeepになります。途中のエラーから再開する場合も、入力表を変更せずにdry-runで残りのcreateを確認してからapplyへ進みます。名前や親を変えて再実行しても更新機能にはならず、不一致として停止します。
既存の分類を更新したい場合は、この追加用コードとは分けて管理画面で対象を確認します。既存分類と同じスラッグを使った別名の行を追加して、名前変更を試みることは避けてください。
WP-CLIで確認した登録と再開の結果
| 操作 | 確認した結果 |
|---|---|
| 3行をdry-run | createと負の仮IDを表示。分類は作成されない |
| 3行をapply | 親1件と子2件を作成。子のparentは作成した親のID |
| 同じ3行を再度apply | すべてkeep。IDと件数は変わらない |
| 2行目の追加でエラーを発生させる | 1行目の親は残る。処理全体の自動取り消しは行われない |
| エラー後、同じ入力でdry-runから再開 | 親はkeep、子2件はcreate。その後のapplyで子だけを追加 |
| 8地域・47都道府県の55行を登録 | 親8件と子47件を作成。登録後のdry-runは55行ともkeep |
| post_tagで親を指定 | 登録前に停止。親なしの1件はタグとして追加できる |
途中エラーから再開するときは、前のログのcreateだけで残件を推測せず、同じ入力表でdry-runをやり直してください。
keepになった行はすでに一致しているため、そのIDを維持したまま残りを追加できます。
この確認は検証用分類の一括追加です。
既存投稿への割り当てや公開サイトの分類URL変更を検証したものではありません。
都道府県データへ展開する
次の例はrows配列の中身です。関東を親にして都県を追加する形で、他の地域も同じ構造にできます。スラッグは公開後の分類URLになるため、既存サイトでは先にURL設計と重複を確認します。
array('関東', 'kanto', ''),
array('茨城', 'ibaraki', 'kanto'),
array('栃木', 'tochigi', 'kanto'),
array('群馬', 'gunma', 'kanto'),
array('埼玉', 'saitama', 'kanto'),
array('千葉', 'chiba', 'kanto'),
array('東京', 'tokyo', 'kanto'),
array('神奈川', 'kanagawa', 'kanto'),WP-CLIを使えない場合は少数件を管理画面で登録する
少数件なら「投稿 → カテゴリー」で追加できます。最初に親カテゴリの名前とスラッグを入力し、親を「なし」にして追加します。続いて子カテゴリの名前とスラッグを入力し、「親カテゴリー」で先ほどの親を選んでから追加してください。タグには親子関係がないため、この手順はカテゴリー用です。
追加後は一覧から子カテゴリの編集画面を開き直し、名前・スラッグ・親の選択を照合します。隔離したWordPress 7.1.2で検証関東を親、検証東京を子として登録し、子の親IDと再表示した選択欄が一致することを確認しました。カテゴリの登録だけでは既存投稿には割り当てられません。必要な投稿を編集し、対象カテゴリを選んで更新する作業は別途行います。
この実画面は管理画面による代替手順です。WP-CLIがない環境で上のコマンドを実行できたという証拠ではありません。大量登録を行う場合は、WP-CLIを使える検証環境でdry-runの結果を確認してから進めてください。

登録後の確認と戻し方
管理画面で名前・スラッグ・親子関係を確認します。再度dry-runを実行して対象行がkeepになることも確認してください。この例は分類だけを作成し、投稿への割り当てや表示順は変更しません。
途中でエラーになっても、先に作成した分類は残ります。ログのcreateとIDを確認し、再実行前にdry-runで現在の状態を調べます。戻す場合は今回作成した分類だけを管理画面で確認し、投稿の割り当てがないことを確認して子から親の順に整理します。運用データを変更した場合は、バックアップ復元の影響も含めて管理者が判断してください。
2026年10月3日、隔離したWordPress 7.1.2 / PHP 8.2.29 / WP-CLI 2.12.0で、実際のwp eval-fileによる確認・登録・再実行を検証しました。
検証用の名前とスラッグへ置き換え、掲載コードの登録処理と親子関係は維持しています。
他プラグインの登録制限や既存サイト固有の分類との競合は、各環境でdry-runとバックアップを確認してください。
参照:WP-CLI eval-file、wp_insert_term()。旧GitHub例とは同期していません。
都道府県47件と地域の入力例
rows配列の中身を次の一覧へ置き換えると、8地域と47都道府県を扱えます。群馬のスラッグは上の関東例と同じgunmaに統一しています。すでにgummaで登録済みの場合は、この表をそのまま追加実行せず既存のスラッグに合わせてください。分類URLを変更する操作は、この一括追加コードの対象外です。名称・スラッグは既存設計に合わせて確認してください。
array('北海道・東北', 'hokkaido-tohoku', ''),
array('北海道', 'hokkaido', 'hokkaido-tohoku'),
array('青森', 'aomori', 'hokkaido-tohoku'),
array('岩手', 'iwate', 'hokkaido-tohoku'),
array('宮城', 'miyagi', 'hokkaido-tohoku'),
array('秋田', 'akita', 'hokkaido-tohoku'),
array('山形', 'yamagata', 'hokkaido-tohoku'),
array('福島', 'fukushima', 'hokkaido-tohoku'),
array('関東', 'kanto', ''),
array('茨城', 'ibaraki', 'kanto'),
array('栃木', 'tochigi', 'kanto'),
array('群馬', 'gunma', 'kanto'),
array('埼玉', 'saitama', 'kanto'),
array('千葉', 'chiba', 'kanto'),
array('東京', 'tokyo', 'kanto'),
array('神奈川', 'kanagawa', 'kanto'),
array('甲信越・北陸', 'koshinetsu-hokuriku', ''),
array('新潟', 'niigata', 'koshinetsu-hokuriku'),
array('富山', 'toyama', 'koshinetsu-hokuriku'),
array('石川', 'ishikawa', 'koshinetsu-hokuriku'),
array('福井', 'fukui', 'koshinetsu-hokuriku'),
array('長野', 'nagano', 'koshinetsu-hokuriku'),
array('山梨', 'yamanashi', 'koshinetsu-hokuriku'),
array('東海', 'tokai', ''),
array('岐阜', 'gifu', 'tokai'),
array('静岡', 'shizuoka', 'tokai'),
array('愛知', 'aichi', 'tokai'),
array('三重', 'mie', 'tokai'),
array('近畿', 'kinki', ''),
array('滋賀', 'shiga', 'kinki'),
array('京都', 'kyoto', 'kinki'),
array('大阪', 'osaka', 'kinki'),
array('兵庫', 'hyogo', 'kinki'),
array('奈良', 'nara', 'kinki'),
array('和歌山', 'wakayama', 'kinki'),
array('中国', 'chugoku', ''),
array('鳥取', 'tottori', 'chugoku'),
array('島根', 'shimane', 'chugoku'),
array('岡山', 'okayama', 'chugoku'),
array('広島', 'hiroshima', 'chugoku'),
array('山口', 'yamaguchi', 'chugoku'),
array('四国', 'shikoku', ''),
array('徳島', 'tokushima', 'shikoku'),
array('香川', 'kagawa', 'shikoku'),
array('愛媛', 'ehime', 'shikoku'),
array('高知', 'kochi', 'shikoku'),
array('九州・沖縄', 'kyushu-okinawa', ''),
array('福岡', 'fukuoka', 'kyushu-okinawa'),
array('佐賀', 'saga', 'kyushu-okinawa'),
array('長崎', 'nagasaki', 'kyushu-okinawa'),
array('熊本', 'kumamoto', 'kyushu-okinawa'),
array('大分', 'oita', 'kyushu-okinawa'),
array('宮崎', 'miyazaki', 'kyushu-okinawa'),
array('鹿児島', 'kagoshima', 'kyushu-okinawa'),
array('沖縄', 'okinawa', 'kyushu-okinawa'),


