WordPressで投稿フォームなどを作る時のカテゴリーやタグの扱い

Wordpressの管理画面以外から記事を投稿する手段としてメールでの投稿などありますが、wp_insert_postというオブジェクトを利用すると簡単にDBにアクセスしてくれます。MySQLのinsert文のWP版といったところでしょうか。
しかし、カテゴリーやタグを選択(または記述)して記事として入れ込むにはちょっと一工夫必要です。

記事の情報はwp_postsテーブルに入っています。しかしこのテーブルのレコードにはカテゴリー情報もタグ情報も入っていないんですね。逆にカテゴリーやタグの情報は、wp_termに入っています。term_idとname(カテゴリー・タグ名)が紐付いています。(驚きなのは、カテゴリーとタグは同じものとして扱われているんです。勿論カテゴリーとタグはこれまた別のテーブルで分類されているんですが。)これらの「記事」と「カテゴリー・タグ」というバラバラになった情報をwp_term_relationshipで紐付けています。例えば記事のIDが2050だったとすると、

  1. wp_posts ID: 2050
  2. wp_term_relationship: object_id: 2050, term_taxonomy_id: 29
  3. wp_term_taxonomy term_taxonomy_id: 29, term_id: 30
  4. wp_terms term_id: 30

となっているわけです。これどういうことかというと、

  1. まず、記事のIDがあります。[wp_posts]
  2. 記事のIDと紐付けられたterm_taxonomy_idなるものがあります。(これは、カテゴリーであるかタグであるかをここで分類できます。)[wp_term_relationship]
  3. term_taxonomy_idとterm_idを紐付けます。[wp_term_taxonomy]
  4. term_idからカテゴリー名やタグ名(日本語)を抽出することができます。[wp_terms]

どうしてこんなややこしいことになっているのかというと、いわゆる正規化というやつです。記事を削除した場合にはカテゴリーやタグは残さなければならないわけですが、その場合、記事それ自体とwp_term_relationship切って(削除して)あげればいいわけです。記事のIDはユニークなので、wp_term_relationshipにある記事のIDに関連するカテゴリーやタグをすべて削除してしまえばいいというわけです。これは1つの記事に複数のタグを設定することが可能であるためにこんなことになっているんです。しかし、よくできてますね。
4つのテーブルを紐付けているわけですが、実際問題としてそれ程複雑なことではないです。

  1. wp_posts: 記事の情報で、今回必要なのはIDのみ。
  2. wp_term_relationship: 記事のIDとterm_taxonomy_idの紐付けをします。3カラムしかない単純なテーブルです。IDに対して複数のterm_taxonomy_idを紐付けることができます。
  3. wp_term_taxonomy: ここではwp_term_taxonomy_idとterm_idの紐付け、そのtermがカテゴリーであるかタグであるかの分類、最後にそのカテゴリーやタグに関連する記事がいくつかるのかカウントしています。このカウントはたぶんwp_term_relationshipのデータから解析して書き込んでいると思われる。
  4. wp_terms: wp_terms_idとそのカテゴリー・タグに関する日本語名、slugを定義しています。スラッグは日本語の場合はエンコードされちゃってるので長いです。

これらを理解するとなかなかやりやすくなります。

WP3.2.1-ERD

タグをインサートする(追加する)

実際にWordpressのオブジェクトを使ってタグをインサートするには、wp_insert_term()という関数が用意されています。この関数は、先のwp_term_taxonomyテーブルと、wp_termsテーブルの2つを同時に扱ってくれるので非常に助かります。新しいタグを挿入すると2つのテーブルに自動的にその関連付けまで行なってくれるわけです。このオブジェクトはwordpressのテーマ内(wordpress内)であればどこでも使うことができます。
$insert_term = 'TESTTAG';
$exist_term_flg = term_exists($insert_term);
if (!$exist_term_flg) {
wp_insert_term(
'TESTTAG',// タグ名
'post_tag',// タグの場合は'post_tag',カテゴリーの場合は'category'
array(
'description'=> $insert_term,// タグの説明
'slug'=> $insert_term,//タグのslug(日本語の場合はエンコードされる)
'parent'=> $post_id //タグが与えられた記事のID
)
);
}

term_exists()という関数があるのでこれを使わない手はないです。これで既存のタグがあるかないか確認しておきます。この関数は、もし同じタグがすでに存在する場合はそのタグのterm_idを返します。もしなければ空を返します。wp_insert_term()は、term_exists()が空だった場合に実行した方が効率的です。
wp_insert_term()では、
wp_insert_term([タグ名],[post_tag | category],[array([タグの説明],[slug],[記事のポストID])])
となっています。インサートが成功した時は1が返ってきます。失敗した場合は空が返ってきます。
wp_insert_term()はカテゴリーやタグを挿入するWP関数ですが、記事にタグを結びつけるのはwp_insert_post()関数になります。wp_insert_postからはコンマ切りの複数のタグを挿入することができます。
$post = array(

'tags_input' => '[タグ1], [タグ2], [タグ3]',

);

記事と同時にタグを挿入する場合は、先のwp_term,wp_term_taxonomyテーブルの両方に自動的に関わってくれます。記事の登録でもあるのでwp_term_relationshipsにもデータを適切に格納してくれます。記事からタグを挿入する場合はこちらだけの作業でOKです。

タグを削除する

タグを削除したい場合は、wp_delete_term()を使います。この関数はwp_insert_term()の全く反対の作業をしてくれます。wp_insert_term()で挿入したデータをそのまま削除しれくれます。但しwp_term_relationshipsからも記事のIDと削除したタグのIDを削除します。

$delete_term = 'SLAPSTICKR';
$exist_term_id = term_exists($delete_term);//返り値 term_id
if ($exist_term_id) {
$re = wp_delete_term( $exist_term_id,'post_tag' );//返り値1
}

削除時は削除項目(タグ)の指定にはterm_idを利用します。なので、IDが不明確の場合はterm_exists()でタグ名を指定しつつ、そのタグ名のIDを取り出す必要があります。第二引数には'category'または'post_tag'を指定します。
これでwpのテーマ内でタグを扱うことがそこそこ可能になります。

codexには英語しかなくて日本語版には詳しい情報なかったです。
http://codex.wordpress.org/Function_Reference/wp_insert_term
http://codex.wordpress.org/Function_Reference/wp_delete_term