フリーランス|WEB 制作経験丸7年、制作会社様からのご依頼に丁寧・高クオリティでお手伝いいたします。 IRODORI DESIGN

B L O G

【WordPress】プラグイン不要!カスタム投稿で「先頭に固定表示」する方法

WordPress
カスタマイズ
カスタム投稿タイプ
先頭に固定表示

WordPressの標準の投稿にはある「先頭に固定表示」機能。
しかし、カスタム投稿を作成するためのプラグイン「Custom Post Type UI」やregister_post_type()関数ではそれらを設定する方法は見当たりませんでした。
そこでfunctions.phpを使い、自作する方法でこの「先頭に固定表示」する機能を実装してみようと思います。
この「先頭に固定表示」するためのプラグインは「Seamless Sticky Custom Post Types」や「Sticky Posts – Switch」がありましたが、不具合があったり、更新されていなかったりするので自作してみることにしました。

完成コード

まずは完成コードを見てみましょう。
とりあえずサクッと使いたいという人はコピペしてご使用ください。

カスタム投稿で「先頭に固定表示」機能を実装するには以下のコードをfunctions.phpに記述します。

/* メタボックス追加 */
function add_sticky_meta_box() {
    add_meta_box(
        'sticky_meta_box',
        '先頭に固定表示',
        'sticky_meta_box_callback',
        'XXX',
        'side',
        'high'
    );
}
add_action('add_meta_boxes', 'add_sticky_meta_box');

function sticky_meta_box_callback($post) {
    $is_sticky = is_sticky($post->ID) ? 'checked' : '';
    echo '<input type="checkbox" id="sticky" name="sticky" value="sticky" ' . $is_sticky . ' />';
    echo '<label for="sticky">先頭に固定表示にする</label>';
}


/* クイック編集を非表示(クイック編集すると「先頭に固定表示にする」が外れてしまうため) */
function remove_quick_edit_for_XXX($actions, $post) {
    if ($post->post_type === 'XXX') {
        unset($actions['inline hide-if-no-js']);
    }
    return $actions;
}
add_filter('post_row_actions', 'remove_quick_edit_for_XXX', 10, 2);


/* クエリ表示 */
function add_sticky_posts_to_custom_post_type($query) {
    if (!is_admin() && $query->is_main_query() && is_post_type_archive('XXX')) {
        $sticky_posts = get_option('sticky_posts');

        if ($sticky_posts) {
            // 固定投稿を最初に表示するためにクエリを修正
            $query->set('post__not_in', $sticky_posts);
            $query->set('ignore_sticky_posts', 1);

            // 固定投稿を最初に追加してマージ
            $query->set('posts_per_page', $sticky_posts);
            $query->set('orderby', 'post_date');
            add_filter('the_posts', function($posts) use ($sticky_posts) {
                $sticky_posts_array = get_posts(array(
                    'post__in' => $sticky_posts,
                    'post_type' => 'XXX',
                    'orderby' => 'post_date',
                    'order' => 'DESC'
                ));
                return array_merge($sticky_posts_array, $posts);
            });
        }
    }
}
add_action('pre_get_posts', 'add_sticky_posts_to_custom_post_type');

上記サンプルコードではカスタム投稿タイプのスラッグ名は「XXX」としています。
「XXX」の部分はそれぞれの環境のカスタム投稿タイプのスラッグ名に書き換えてご使用ください。

あとはテンプレートファイルでメインクエリを使用すれば「先頭に固定表示」の記事を含み、出力されるようになります。

<?php
    if( have_posts() ):
        while( have_posts() ):
            the_post();
?>
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
<?php
        endwhile;
    endif;
?>

これでカスタム投稿タイプでも先頭に固定表示をすることが出来るようになります。

解説

ここからはコードの解説です。

メタボックスを作成する

まずは、管理画面に先頭に固定表示にするためのメタボックスを作成します。

/* メタボックス追加 */
function add_sticky_meta_box() {
    add_meta_box(
        'sticky_meta_box',
        '先頭に固定表示',
        'sticky_meta_box_callback',
        'XXX',
        'side',
        'high'
    );
}
add_action('add_meta_boxes', 'add_sticky_meta_box');

「XXX」に指定したカスタム投稿タイプの記事登録画面に「先頭に固定表示」というメタボックスをサイドバーに作成し、コールバック関数でsticky_meta_box_callback()の名前の自作関数を呼び出します。

function sticky_meta_box_callback($post) {
    $is_sticky = is_sticky($post->ID) ? 'checked' : '';
    echo '<input type="checkbox" id="sticky" name="sticky" value="sticky" ' . $is_sticky . ' />';
    echo '<label for="sticky">先頭に固定表示にする</label>';
}

作成したメタボックスに「先頭に固定表示にする」というチェックボックスを追加します。
さらに、投稿がすでに固定表示されている場合、チェックボックスは最初からチェックされた状態で表示されます。

クイック編集を非表示にする

次に管理画面の記事一覧ページにあるクイック編集を非表示にします。

/* クイック編集を非表示(クイック編集すると「先頭に固定表示にする」が外れてしまうため) */
function remove_quick_edit_for_XXX($actions, $post) {
    if ($post->post_type === 'XXX') {
        unset($actions['inline hide-if-no-js']);
    }
    return $actions;
}
add_filter('post_row_actions', 'remove_quick_edit_for_XXX', 10, 2);

クイック編集をすると「先頭に固定表示にする」のチェックが強制的に外れてしまうからです。

もし、クイック編集でも正しく動作する方法をご存じの方は是非教えてほしいです。

クエリを作成する

最後に、「先頭に固定表示にする」を正しく動作させるためのクエリを作成します。

/* クエリ表示 */
function add_sticky_posts_to_custom_post_type($query) {
    if (!is_admin() && $query->is_main_query() && is_post_type_archive('XXX')) {
        $sticky_posts = get_option('sticky_posts');

        if ($sticky_posts) {
            // 処理を記述

        }
    }
}
add_action('pre_get_posts', 'add_sticky_posts_to_custom_post_type');

アクションフックのpre_get_postsを使用し、管理画面以外で、指定したカスタム投稿(この例では「XXX」)のメインクエリをカスタマイズします。
さらに、「先頭に固定表示」されている投稿が存在する場合にのみ、このカスタマイズが実行されます。

$query->set('post__not_in', $sticky_posts);
$query->set('ignore_sticky_posts', 1);

「先頭に固定表示」の記事を一時的にクエリから除外し、固定投稿の優先表示を無効にします。

$query->set('posts_per_page', get_option('posts_per_page'));
$query->set('orderby', 'post_date');

1ページに取得する記事数の指定(この場合は管理画面の表示設定 > 1ページに表示する最大投稿数の設定値)と、投稿日順に並び替えを指定します。

add_filter('the_posts', function($posts) use ($sticky_posts) {
    $sticky_posts_array = get_posts(array(
        'post__in' => $sticky_posts,
        'post_type' => 'news',
        'orderby' => 'post_date',
        'order' => 'DESC'
    ));
    return array_merge($sticky_posts_array, $posts);
});

フィルターフックでthe_postsを指定し、get_post();を使って「先頭に固定表示」の記事を再度取得し、日付順に並び替えます。
最後に、array_merge($sticky_posts_array, $posts);で、取得した「先頭に固定表示」の記事を通常の投稿リストの前に追加し、最終的な投稿リストを作成します。

あとはテンプレートファイルでメインクエリを呼び出せばOKです。

<?php
    if( have_posts() ):
        while( have_posts() ):
            the_post();
?>
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
<?php
        endwhile;
    endif;
?>

まとめ

いかがでしたか?
カスタム投稿はデフォルトのままだと「先頭に固定表示」を使うことは出来ません。
もしカスタム投稿で「先頭に固定表示」を使いたい場合は、今回ご紹介したコードをコピペして使用してみて下さい。

最後にもう一度完成コードを記載しておきます。

以下をfunctions.phpに記述してご使用ください。

/* メタボックス追加 */
function add_sticky_meta_box() {
    add_meta_box(
        'sticky_meta_box',
        '先頭に固定表示',
        'sticky_meta_box_callback',
        'XXX',
        'side',
        'high'
    );
}
add_action('add_meta_boxes', 'add_sticky_meta_box');

function sticky_meta_box_callback($post) {
    $is_sticky = is_sticky($post->ID) ? 'checked' : '';
    echo '<input type="checkbox" id="sticky" name="sticky" value="sticky" ' . $is_sticky . ' />';
    echo '<label for="sticky">先頭に固定表示にする</label>';
}


/* クイック編集を非表示(クイック編集すると「先頭に固定表示にする」が外れてしまうため) */
function remove_quick_edit_for_XXX($actions, $post) {
    if ($post->post_type === 'XXX') {
        unset($actions['inline hide-if-no-js']);
    }
    return $actions;
}
add_filter('post_row_actions', 'remove_quick_edit_for_XXX', 10, 2);


/* クエリ表示 */
function add_sticky_posts_to_custom_post_type($query) {
    if (!is_admin() && $query->is_main_query() && is_post_type_archive('XXX')) {
        $sticky_posts = get_option('sticky_posts');

        if ($sticky_posts) {
            // 固定投稿を最初に表示するためにクエリを修正
            $query->set('post__not_in', $sticky_posts);
            $query->set('ignore_sticky_posts', 1);

            // 固定投稿を最初に追加してマージ
            $query->set('posts_per_page', $sticky_posts);
            $query->set('orderby', 'post_date');
            add_filter('the_posts', function($posts) use ($sticky_posts) {
                $sticky_posts_array = get_posts(array(
                    'post__in' => $sticky_posts,
                    'post_type' => 'XXX',
                    'orderby' => 'post_date',
                    'order' => 'DESC'
                ));
                return array_merge($sticky_posts_array, $posts);
            });
        }
    }
}
add_action('pre_get_posts', 'add_sticky_posts_to_custom_post_type');

テンプレートファイルでメインクエリを呼び出します。

<?php
    if( have_posts() ):
        while( have_posts() ):
            the_post();
?>
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
<?php
        endwhile;
    endif;
?>