WordPressカスタマイズ事例

投稿(post)を階層構造にしてもURLは階層構造にならない!を解決する( parent-slug/child-slug にする)

以下の記事で、投稿(post)を固定ページのように階層構造にする方法をご案内しました。
投稿(post)を固定ページのように階層構造にする
 
ところが、これをしてもURLは階層構造にならないのです!
親投稿:https://domain.com/category/parent-slug/
子投稿:https://domain.com/category/child-slug/
 
え?なんで?だって階層構造だよね?って思いませんか?
別に親子フラットなURLでも実害はないのかもしれないけど、閲覧者に対してこの記事はあの記事の子記事だとURL上でも知らしめておきたいとか、なんとなくSEO的にも評価してほしいので子記事は親記事の下層URLに置きたいとか、サイトマップ的に階層を美しくしておきたいとか、とにかくURLも階層構造になっていることを期待するのが当たり前ですが、WordPressはそれをしてくれません。
 
そこで、今回は子投稿のURLを
https://domain.com/category/parent-slug/child-slug/
こうなるようにします。こうなるべきなのです。
 
テーマの functions.php に以下のように追記します。
投稿(post)を固定ページのように階層構造にするの内容をすでに実施されている方は、1行目~7行目まではすでに記述されていると思いますので、飛ばしてください。

add_action('registered_post_type', 'kaiza_posts_hierarchical', 10, 2);
function kaiza_posts_hierarchical($post_type, $pto){
    global $wp_post_types;
    if ($post_type != 'post') return;
    $wp_post_types['post']->hierarchical = 1;
    add_post_type_support('post', 'page-attributes');
}

/**
 * 親投稿のスラッグを取得する関数
 */
function get_parent_post_slug($post){
    if (!is_object($post) || !$post->post_parent) {
        return false;
    }
    return get_post($post->post_parent)->post_name;
}

/**
 * get_sample_permalinkのfilterフック
 **/
add_filter('get_sample_permalink', function ($permalink, $post_id, $title, $name, $post) {
    if ($post->post_type != 'post' || !$post->post_parent) {
        return $permalink;
    }

    $template_permalink = current($permalink);
    $replacement_permalink = next($permalink);

    $postname_string = '/%postname%/';

    $parent_slug = get_parent_post_slug($post);

    $altered_template_with_parent_slug = '/' . $parent_slug . $postname_string;
    $new_template = str_replace($postname_string, $altered_template_with_parent_slug, $template_permalink);

    $new_permalink = [$new_template, $replacement_permalink];

    return $new_permalink;
}, 99, 5);

/**
 * post_linkのfilterフック
 **/
add_filter('post_link', function ($post_link, $post, $leavename) {

    if ($post->post_type != 'post' || !$post->post_parent) {
        return $post_link;
    }

    $parent_slug = get_parent_post_slug($post);
    $new_post_link = str_replace($post->post_name, $parent_slug . '/' . $post->post_name, $post_link);

    return $new_post_link;
}, 99, 3);

/**
 * pre_get_postsのactionフック
 */
add_action('pre_get_posts', function ($query) {
    global $wpdb, $wp_query;

    $original_query = $query;
    $uri = $_SERVER['REQUEST_URI'];

    if ($query->is_main_query() && !is_admin()) {

        $basename = basename($uri);
        $test_query = sprintf("select * from $wpdb->posts where post_type = '%s' and post_name = '%s';", 'post', $basename);
        $result = $wpdb->get_results($test_query);

        if (!($post = current($result)) || !$post->post_parent) {
            return $original_query;
        }

        $parent_slug = get_parent_post_slug($post);
        $hierarchal_slug = $parent_slug . '/' . $post->post_name;

        if (!stristr($uri, $hierarchal_slug)) {
            return $original_query;
        }

        $query->query_vars['post_type'] = ['post'];
        $query->is_home = false;
        $query->is_page = true;
        $query->is_single = true;
        $query->queried_object_id = $post->ID;
        $query->set('page_id', $post->ID);

        return $query;
    }

}, 1);

 
結構長いコードになりましたが、
https://domain.com/category/parent-slug/child-slug/
の完成。
 
最後に[設定]-[パーマリンク設定]でパーマリンク設定を更新するのをお忘れなく。


関連するWordPressカスタマイズ事例