カスタム投稿をカスタムタクソノミーのslugを条件として投稿を絞り込む
Wordpressで、$wpdbを使用してカスタムタクソノミーを条件としたSQL文を作成します。
目的
WordPressで同じカスタム投稿の中からカスタムタクソノミーの値をキーに投稿記事を抽出したい、 例えば、Wordpressでサイトを運用していて、サイト内で日本語記事ページと英語記事ページがあった場合、 カスタムタクソノミーで英語記事である目印’en’をつけておく。 日本語記事にはタクソノミーを何もつけない
最初1ページに記事を数件表示し、もっと記事を表示したい時はAJAXを使用してさらに記事を読み込む。その場合に $wpdbを使用して自分でSQL文を作成する。
同じカスタム投稿の中から以下のように分けて記事を抽出するのが期待値
- 日本語投稿記事の場合は記事の中からカスタムタクソノミーに’en’がついていない記事を読み込む
- 英語投稿記事の場合は記事の中からカスタムタクソノミーに‘en’がついてる記事を読み込む
結果
カスタムタクソノミーに’en’がついていない記事の場合
$now_post_num, $get_post_numはオフセット、何個目から何個目までというのを決定するために使っている カスタムタクソノミーが‘en’じゃないことと、slugがNULLの場合を取得している
$sql = "SELECT
p.ID,p.post_title,p.post_content,p.post_type,p.post_status,tte.slug
FROM
$wpdb->posts AS p
LEFT OUTER JOIN $wpdb->term_relationships AS tr ON tr.object_id = p.ID
LEFT OUTER JOIN $wpdb->term_taxonomy AS tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
LEFT OUTER JOIN $wpdb->terms AS tte ON tte.term_id = tt.term_id
GROUP BY
p.ID
HAVING
p.post_type = 'articles' AND p.post_status = 'publish' AND (tte.slug != 'en' OR tte.slug IS NULL)
ORDER BY
p.post_date DESC
LIMIT
$now_post_num, $get_post_num;";
$pre = $wpdb->prepare($sql,$now_post_num,$get_post_num);
$results = $wpdb->get_results($pre);
カスタムタクソノミーに’en’がついている記事の場合
基本的には上記と同じだが カスタムタクソノミーが‘en’のみの場合を取得している。違いはHAVING句の箇所のみ。
$sql = "SELECT
p.ID,p.post_title,p.post_content,p.post_type,p.post_status,tte.slug
FROM
$wpdb->posts AS p
LEFT OUTER JOIN $wpdb->term_relationships AS tr ON tr.object_id = p.ID
LEFT OUTER JOIN $wpdb->term_taxonomy AS tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
LEFT OUTER JOIN $wpdb->terms AS tte ON tte.term_id = tt.term_id
GROUP BY
p.ID
HAVING
p.post_type = 'articles' AND p.post_status = 'publish' AND tte.slug = 'en'
ORDER BY
p.post_date DESC
LIMIT
$now_post_num, $get_post_num;";
$pre = $wpdb->prepare($sql,$now_post_num,$get_post_num);
$results = $wpdb->get_results($pre);
方法
フロー
1SQLを検討する |
↓ |
2$wpdbに置き換える |
SQLを検討する
投稿記事(wp_XXXXposts)とカスタムタクソノミーのSLUG(wp_XXXXterms)を結び付けたい、 結びつけるために以下のテーブルを使用する。意外と関連付けるのにたくさんテーブルがある XXXXはWordpressをインストールした時の接頭語
参考は データベース構造 – WordPress Codex 日本語版
テーブル名 | 説明 |
---|---|
wp_XXXXposts | WordPress データの核である投稿記事のほか、ページ、ナビゲーションメニューのデータを格納 |
wp_XXXXterm_relationships | オブジェクト(wp_posts テーブルの各投稿記事、wp_links テーブル内の各リンク)と wp_term_taxonomy のカテゴリ・タグとの関連付け情報を格納 |
wp_XXXXterm_taxonomy | 投稿およびリンクの分類上の語句(カテゴリ・タグ)データを格納 |
wp_XXXXterms | 投稿およびリンクの分類(カテゴリ・タグ)に使われる語句の基本情報を格納 |
結論からいうとこうなった。カスタムタクソノミーのslugで記事をわける。 例ではslugがenだったら英語記事、slugにenがついていなかったら日本語記事を想定している。
英語記事と日本語記事で異なる点はhaving句の箇所のみ
//英語記事の場合
select p.ID, p.post_type,p.post_status,p.post_title,tte.slug from wp_XXXXposts as p
LEFT OUTER JOIN wp_XXXXterm_relationships AS tr ON tr.object_id = p.ID
LEFT OUTER JOIN wp_XXXXterm_taxonomy AS tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
LEFT OUTER JOIN wp_XXXXterms AS tte ON tte.term_id = tt.term_id
group by p.ID
having p.post_type = 'articles' AND p.post_status = 'publish' AND tte.slug = 'en';
//日本語記事の場合
select p.ID, p.post_type,p.post_status,p.post_title,tte.slug from wp_XXXXposts as p
LEFT OUTER JOIN wp_XXXXterm_relationships AS tr ON tr.object_id = p.ID
LEFT OUTER JOIN wp_XXXXterm_taxonomy AS tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
LEFT OUTER JOIN wp_XXXXterms AS tte ON tte.term_id = tt.term_id
group by p.ID
having p.post_type = 'articles' AND p.post_status = 'publish' AND (tte.slug != 'en' OR tte.slug IS NULL);
テーブル結合箇所、値が入っていないことで結果の行が落ちるのを防ぐためにOUTER JOINで結合する。 結合するキーはそれぞれ下の感じ。
LEFT OUTER JOIN wp_XXXXterm_relationships AS tr ON tr.object_id = p.ID
LEFT OUTER JOIN wp_XXXXterm_taxonomy AS tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
LEFT OUTER JOIN wp_XXXXterms AS tte ON tte.term_id = tt.term_id
このままだとen以外の場合に他のタームが入ってきた場合に、同じ投稿IDが複数個出力されてしまう。 そのためにwp_XXXXpostsテーブルのIDでグループ化する。
group by p.ID
enがカスタムタクソノミーに入っている場合は、enを指定するだけだが、enがはいっていない場合、 値がNULLだと取得できない、対策としてIS NULLを指定する。 また、post_statusがpublishのものをとらないと、ごみ箱などの値を拾ってきてしまう。
having p.post_type = 'articles' AND p.post_status = 'publish' AND (tte.slug != 'en' OR tte.slug IS NULL);
$wpdbに置き換える
作成したクエリをWordpress用に置き換える、$wpdbだと各テーブルが以下のように取得することがきる。
オブジェクトの値 | 対応するテーブル |
---|---|
$wpdb->posts | wp_XXXXposts |
$wpdb->term_relationship | wp_XXXXterm_relationships |
$wpdb->term_taxonomy | wp_XXXXterm_taxonomy |
$wpdb->terms | wp_XXXXterms |
置き換えるとこのような感じ、テーブル名がオブジェクト内の値に置き換わっているだけ
$sql = "SELECT
p.ID,p.post_title,p.post_content,p.post_type,p.post_status,tte.slug
FROM
$wpdb->posts AS p
LEFT OUTER JOIN $wpdb->term_relationships AS tr ON tr.object_id = p.ID
LEFT OUTER JOIN $wpdb->term_taxonomy AS tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
LEFT OUTER JOIN $wpdb->terms AS tte ON tte.term_id = tt.term_id
GROUP BY
p.ID
HAVING
p.post_type = 'articles' AND p.post_status = 'publish' AND tte.slug = 'en'
ORDER BY
p.post_date DESC
LIMIT
$now_post_num, $get_post_num;";
$pre = $wpdb->prepare($sql,$now_post_num,$get_post_num);
$results = $wpdb->get_results($pre);
prepareはSQLエスケープをする目的で使用される。
$pre = $wpdb->prepare($sql,$now_post_num,$get_post_num);
引数 | 説明 |
---|---|
query | (文字列) 実行したい SQL クエリ。%s および %d がプレースホルダーになる。 |
value_parameter | (整数|文字列|配列) プレースホルダーへ代入する値。sprintf() 風の書き方でたくさんの値を渡すことができます。別の方法として、PHP の関数 vsprintf() 風に値を並べた配列を第2引数にすることもできます。 |
get_resultsは結果取得部分
$results = $wpdb->get_results($pre);
引数 | 説明 |
---|---|
query | (文字列) 実行したい SQL クエリ。 |
output_type | (定数)4つの定数のいずれか。初期値は OBJECT。詳細は省略。 |
参考
その他詳細
wp_XXXXpostsの中身
WordPressのPostsテーブル 表示する記事の本体
mysql> DESCRIBE wp_XXXXposts;
+-----------------------+---------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+---------------------+------+-----+---------------------+----------------+
| ID | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| post_author | bigint(20) unsigned | NO | MUL | 0 | |
| post_date | datetime | NO | | 0000-00-00 00:00:00 | |
| post_date_gmt | datetime | NO | | 0000-00-00 00:00:00 | |
| post_content | longtext | NO | | NULL | |
| post_title | text | NO | | NULL | |
| post_excerpt | text | NO | | NULL | |
| post_status | varchar(20) | NO | | publish | |
| comment_status | varchar(20) | NO | | open | |
| ping_status | varchar(20) | NO | | open | |
| post_password | varchar(255) | NO | | | |
| post_name | varchar(200) | NO | MUL | | |
| to_ping | text | NO | | NULL | |
| pinged | text | NO | | NULL | |
| post_modified | datetime | NO | | 0000-00-00 00:00:00 | |
| post_modified_gmt | datetime | NO | | 0000-00-00 00:00:00 | |
| post_content_filtered | longtext | NO | | NULL | |
| post_parent | bigint(20) unsigned | NO | MUL | 0 | |
| guid | varchar(255) | NO | | | |
| menu_order | int(11) | NO | | 0 | |
| post_type | varchar(20) | NO | MUL | post | |
| post_mime_type | varchar(100) | NO | | | |
| comment_count | bigint(20) | NO | | 0 | |
+-----------------------+---------------------+------+-----+---------------------+----------------+
23 rows in set (0.00 sec)
wp_XXXXterm_relationshipsの中身
WordPressのterm_relationshipsテーブル ここのobject_idとPostidが紐づく
mysql> DESCRIBE wp_XXXXterm_relationships;
+------------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------+---------------------+------+-----+---------+-------+
| object_id | bigint(20) unsigned | NO | PRI | 0 | |
| term_taxonomy_id | bigint(20) unsigned | NO | PRI | 0 | |
| term_order | int(11) | NO | | 0 | |
+------------------+---------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
wp_XXXXterm_taxonomyの中身
WordPressのterm_taxonomyテーブル term_taxonomy_idでwp_XXXXterm_relationshipsテーブルとつなぎ、term_idでwp_XXXXtermsとつなげる
mysql> DESCRIBE wp_XXXXterm_taxonomy;
+------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+---------------------+------+-----+---------+----------------+
| term_taxonomy_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| term_id | bigint(20) unsigned | NO | MUL | 0 | |
| taxonomy | varchar(32) | NO | MUL | | |
| description | longtext | NO | | NULL | |
| parent | bigint(20) unsigned | NO | | 0 | |
| count | bigint(20) | NO | | 0 | |
+------------------+---------------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
wp_XXXXtermsの中身
WordPressのtermsテーブル ここのslugの値をキーにして判断する
mysql> DESCRIBE wp_XXXXterms;
+------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------------+------+-----+---------+----------------+
| term_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(200) | NO | MUL | | |
| slug | varchar(200) | NO | MUL | | |
| term_group | bigint(10) | NO | | 0 | |
+------------+---------------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
get_postsで取得する場合
get_postsで取得する場合は以下のような形になる。なぜ$wpdbを使わなければならなかったのか、 今となっては忘れてしまう。ちゃんと設計時の思想を残すべきだなと。
$lang = getLang();
if ( $lang == "jp" ) {
$args = array(
'post_type' => 'articles',
'tax_query' => array (
array(
'taxonomy' => 'articles-category',
'field' => 'slug',
'terms'=> 'en',
'operator' => 'NOT IN',
),
),
'posts_per_page' => 3,
'paged' => $paged ,
);
} else if ( $lang == "en" ) {
$args = array(
'post_type' => 'articles',
'tax_query' => array (
array(
'taxonomy' => 'articles-category',
'field' => 'slug',
'terms'=> 'en',
),
),
'posts_per_page' => 3,
'paged' => $paged ,
);
}