このブログの記事は、WP-CLIというコマンドラインのツールで投稿しています。
作業してるのはClaude Codeで、私は内容を確認して「これでお願い」と頼む役です。
先日、新しく作った記事のカテゴリを確認したら、狙ったカテゴリの横に「未分類」がくっついていました。
しかも外そうとしたコマンドは「Success」と返してきたのに、実際には外れていなかったんです。
起きたこと:未分類がどうしても消えない
流れはこうです。
Claude Codeがまずwp post createで記事を作り、そのあとカテゴリを追加しました。
wp post term add 880 category 5 --by=id
5は「コーディングTips」のIDです。
ここで確認すると、カテゴリが「コーディングTips」と「未分類」の2つになっていました。
そこで未分類(IDは1)を外そうとして、Claude Codeがこう実行しました。
wp post term remove 880 category 1
Success: Removed term.
成功と出ています。
でも、もう一度確認すると未分類は残ったまま。
同じ日に作った記事は、ローカルと本番を合わせて4つ全部これでした。
未分類が付いた理由
1つ目の謎は、そもそもなぜ未分類が付いたのか。
これはWordPressの仕様です。
投稿を作るときにカテゴリを指定しないと、設定の「デフォルトの投稿カテゴリー」が自動で付きます。
初期状態では、これが未分類です。
そしてterm addは、名前のとおり「追加」するコマンドです。
今あるカテゴリはそのまま残して、横に足すだけ。
なので、未分類の隣にコーディングTipsが並ぶのは、コマンドとしては正しい動きでした。
「Success」なのに外れなかった理由
2つ目が本題です。
最初は、表示と中身が食い違うバグかと思いました。
ところが、Claude CodeがWP-CLIとWordPress本体のソースを読んで追いかけたら、ちゃんと理由がありました。
wp post term removeは、何も指定しないと、渡した値を「スラッグ」として探します。
IDとして扱ってほしいときは、--by=idを付ける決まりです。
今回はこれを付け忘れていました。
未分類のスラッグはuncategorizedです。
なので「1」というスラッグで探しても、何も見つかりません。
実際に手元で確かめると、文字列の「1」で探した結果は空っぽ、数値の1で探すと未分類が見つかりました。
wp eval 'var_dump( term_exists( "1", "category" ) );'
NULL
wp eval 'var_dump( term_exists( 1, "category" ) );'
array(2) {
["term_id"]=> string(1) "1"
["term_taxonomy_id"]=> string(1) "1"
}
問題は、見つからなかったときの扱いです。
WordPress本体のwp_remove_object_terms()は、外す対象が見つからなくてもエラーは返しません。
「何も消さなかった」という意味のfalseを返すだけです。
WP-CLIはエラーかどうかしか見ていないので、そのまま「Success: Removed term.」と表示します。
削除の結果はfalseだったのに、エラーではないので成功扱いになった、というわけです。
前にも踏んだ罠と同じだった
ここで思い出しました。
このブログでは以前、--by=idを付け忘れて「11」という名前のカテゴリを作ってしまった話も書いています。term addで同じ付け忘れをすると、「11」という名前のカテゴリが新しく作られてしまう、という罠でした。
今回はその裏返しです。addだと、見つからないものを勝手に作ってしまう。removeだと、見つからないものを黙ってスルーして成功と言う。
どちらも原因は同じ、IDをスラッグとして扱われたことでした。
解決:termはsetで上書きする
最終的に落ち着いたのは、addでもremoveでもなくsetを使う方法です。
wp post term set 880 category 5 --by=id
setは、今付いてるカテゴリを丸ごと入れ替えるコマンドです。
これなら未分類も一緒に外れて、指定したカテゴリだけになります。
1回で済むので、付け忘れる機会も減ります。
いまは、新しい記事のカテゴリ設定はsetを使うことに決めました。
最後にwp post term list 880 categoryで、狙ったカテゴリだけになってるかを確認します。
「Success」は何をしたかまでは教えてくれない
今回いちばん残ったのは、成功メッセージを信じすぎていた、という反省です。
今回のterm removeのSuccessは、実際に外せたことまでは保証してくれていませんでした。addでは付けた--by=idを、removeでだけ忘れる。
一度記事にした罠でも、コマンドが変わると普通にまた踏みます。
だから今は、setのあとにterm listで結果を見るところまでを1セットにしてます。

