WordPressで投稿のスラッグを取得する方法、まとめ。

最終更新:2019-03-29 by Joe

WordPressで、特定の投稿の「スラッグ」を取得する方法です。

スラッグとは?

スラッグ(slug)とは、投稿やカテゴリーなどに対する、簡単な名前です。主にユーザフレンドリーなURLの一部として使われる事が意図されています。1つのワードプレスサイト上で、ユニーク(唯一)である必要があります。

# 投稿のスラッグの例
what-is-wordpress-2017

# 該当の投稿のURL
http://my-website.com/what-is-wordpress-2017

投稿のスラッグを取得する関数

スラッグを含む、投稿に関連する任意のフィールドを取得するには、関数「get_post_field()」を使います。第一引数にフィールド名(必須)、第二引数に投稿ID(必須)を引き渡します。

ループの中でスラッグを取得

メインループの例

ループの中では、容易に該当の投稿のIDを、「get_the_ID() 」で取得できます。

while ( have_posts() ) {
  the_post();

  // スラッグを出力
  echo get_post_field( 'post_name', get_the_ID() ); 

}

ループの中で、「global $post;」を宣言すれば、フィールドに直接アクセスできますが・・・、これは後述もしますが、投稿オブジェクトを上手に取り扱うための関数群がすでにたくさん用意されているので、そちらを利用すべきでしょう。

サブループの例(WPクエリオブジェクト)

念のため、WPクエリオブジェクトを利用したサブループの例です。

$my_posts = new WP_Query( /* 所望の引数 */ );

while ( $my_posts->have_posts() ) {
  $my_posts->the_post();

  // スラッグを出力
  echo get_post_field( 'post_name', get_the_ID() ); 

}

サブループの例(投稿オブジェクト配列)

サブループの場合で、投稿オブジェクト配列をforeachでループさせている場合は、「setup_postdata()」が実行されていないと、get_the_IDなどのループ系の関数は使えませんのでご注意ください。

そのような場合は下記を利用できるはずです。

// もし投稿オブジェクトが参照かのうなら、スラッグ(post_name)へ直接のアクセスする
$my_posts = get_posts( /* 所望の引数 */ );

foreach ( $my_posts as $p ) {

  // スラッグを出力
  echo $p->post_name;
}

ループの外でスラッグを取得

もちろん、ループの外でも、投稿IDさえわかっていれば、get_post_fieldが利用できます。

define ( 'WWWC_POST_ID_SOME_PAGE', 209 )

$slug = get_post_field( 'post_name', WWWC_POST_ID_SOME_PAGE );

開発編:スラッグの取扱いについて

ここからは少し踏み込んで見ていきます。

投稿のスラッグが格納されている場所

スラッグは、データベースの「post」というテーブルの、post_nameというカラムに保存されています。

下記がデータベースから、wp_post.post_nameをふくめた、wp_postテーブルのカラムです。こららのフィールド名と同じ文字列で、すべて上記のget_post_field() 関数を通して、その値にアクセスできるはずです。

$ show columns from wp_posts;

+-----------------------+---------------------+------+-----+---------------------+----------------+
| 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(20) | 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 | |
+-----------------------+---------------------+------+-----+---------------------+----------------+

テーブルはこちらでも参照できます。

さて、スラッグの話からすこし脱線しますが、関連情報です。

投稿オブジェクトのフィールドには、どうやってアクセスするべきなのか?

get_post_field()が投稿オブジェクトのフィールドにアクセするための関数です。もちろん、ループの中であれば

global $post;
$slug = $post->post_name;

で同じことが可能です。まあ、できればglobalをしないほうが気持ちがいいでしょう。

感じ方は人によると思いますが・・・、もしそのループ内で、get_the_ID()や、 get_the_tilte()を使って、投稿オブジェクトのフィールドにアクセスしているのであれば、スラッグの時だけ、get_the_slug() なんて名前の関数がないからといって、すぐに「global $post」 というより、やはり用意されているアクセサ関数を利用したほうが、一貫性があって、気持ちがいいのではないでしょうか。

上記のように、get_posts()関数から投稿オブジェクトの配列を取得して、サブループを生成した場合は、すこし勝手が違うかもしれませんね。

get_posts()からの配列でループを作成したとき・・・

$arg = array( 
  // 任意の引数 
);

$my_posts = get_posts( $arg );

foreach ( $my_posts as $post ) {

  echo $post->post_title; //素のタイトル
  echo $post->post_content; //素のコンテンツ
  echo $post->post_name; //スラッグ
}

そもそも、投稿オブジェクトのフィールドに、直接アクセスするしかありません。get_the_xxx 関数群を使うには、global $post; を含む手続き(参考)を行う必要があります。

get_posts()関数自体が、サブループの作成に適している関数のように思えません。ちょっと特定の投稿のなんらかの値を参照したいときに、小規模にサクッと使う、といった温度感です。

とくに、タイトルや本文などの主要なコンテンツは、本来通っているフィルター関数(the_contentフィルターなど)をとおらないので、the_content関数から出力した本文と大きく異なることに注意が必要です。

英語のDEVリファレンスですが、実コードが見られます:

WPクエリオブジェクトを使ったサブループの例

サブループを作るときあは、わたしは極力既存関数群の恩恵に預かれるよう、こう書きます。

$arg = array (
  'post_type' => 'post',
  'posts_per_page' => 10,
  'ignore_sticky_posts' => 1,
  'no_found_rows' => 1,
);
$my_posts = new WP_Query( $arg );

if ( $my_posts->have_posts() ) {
  while ( $my_posts->have_posts() ) {
    $my_posts->the_posts();

     // the_title(), the_content(), the_post_field()がすぐに使える。
     // メインループと同じ記法ができる

  }
}

実際コードを見ると、get_posts()関数は、WP_Queryクラスを利用して、いくつかのデフォルト引数を加えたり、フィルターをかけているだけです。最終的に、投稿オブジェクト配列だけを返します。

wp-includes/post.php

function get_posts( $args = null ) {
  $defaults = array(
    'numberposts' => 5,
    'category' => 0, 'orderby' => 'date',
    'order' => 'DESC', 'include' => array(),
    'exclude' => array(), 'meta_key' => '',
    'meta_value' =>'', 'post_type' => 'post',
    'suppress_filters' => true
    );

  $r = wp_parse_args( $args, $defaults );
  if ( empty( $r['post_status'] ) )
    $r['post_status'] = ( 'attachment' == $r['post_type'] ) ? 'inherit' : 'publish';
  if ( ! empty($r['numberposts']) && empty($r['posts_per_page']) )
    $r['posts_per_page'] = $r['numberposts'];
  if ( ! empty($r['category']) )
    $r['cat'] = $r['category'];
  if ( ! empty($r['include']) ) {
    $incposts = wp_parse_id_list( $r['include'] );
    $r['posts_per_page'] = count($incposts);  // only the number of posts included
    $r['post__in'] = $incposts;
  } elseif ( ! empty($r['exclude']) )
    $r['post__not_in'] = wp_parse_id_list( $r['exclude'] );

  $r['ignore_sticky_posts'] = true;
  $r['no_found_rows'] = true;

  $get_posts = new WP_Query;
  return $get_posts->query($r);

}

 

以上です。

参考