カテゴリーページで並べ替え(ソート)ができるボタンを作る方法

WordPressのカテゴリーページ(例: https://example.com/category/)で、
記事を「新着順」「古い順」にソートできるボタンを追加する方法を解説します。

1 実装のポイント

  • functions.php にクエリ変更用のコードを追加する
  • JavaScriptでボタンをクリックするとソート条件を切り替える
  • CSSで見やすいボタンデザインにする
  • LightningやCocoonテーマに合わせた調整サンプルも紹介
  • カテゴリ・タグページのクエリパラメータやページ分割での重複を防ぐコードも追加

2 functions.php にコードを追加

  1. カテゴリーページでのソート処理を追加します。
  2. カテゴリ・タグページのクエリパラメータやページ分割での重複を防ぐコードを追加します。詳しくは、 カテゴリ・タグページのクエリパラメータやページ分割での重複を防ぐ方法をご覧ください。

//-------------------------------------------
// カテゴリーページでソート機能を有効化
//-------------------------------------------
function my_category_order( $query ) {
    if( $query->is_main_query() && !is_admin() && is_category() ) {
        $order = isset($_GET['order']) ? $_GET['order'] : 'desc';
        $query->set( 'order', $order ); // desc:新着順, asc:古い順
    }
}
add_action( 'pre_get_posts', 'my_category_order' );

//functions.php で canonical を明示的に出力する
add_action('wp_head', function() {
    if (is_category()) {
        $canonical = get_category_link(get_queried_object_id());
        echo '' . "\n";
    }
});

//-------------------------------------------
// カテゴリ・タグ・アーカイブの重複ページ対策
//-------------------------------------------
function custom_handle_duplicate_pages($mode = 'canonical') {

    // クエリパラメータ ?order
    if ((is_category() || is_tag() || is_archive()) && isset($_GET['order'])) {
        if ($mode === 'canonical') {
            $canonical = get_queried_object()->term_id
                        ? get_term_link(get_queried_object())
                        : get_permalink();
            echo '<link rel="canonical" href="' . esc_url($canonical) . '" />' . "\n";
        } elseif ($mode === 'noindex') {
            echo '<meta name="robots" content="noindex, follow">' . "\n";
        }
    }

    // RSSフィード (/feed)
    if (is_feed()) {
        if ($mode === 'canonical') {
            $canonical = get_post_type_archive_link(get_post_type()) ?: home_url();
            echo '<link rel="canonical" href="' . esc_url($canonical) . '" />' . "\n";
        } elseif ($mode === 'noindex') {
            echo '<meta name="robots" content="noindex, follow">' . "\n";
        }
    }

    // ページ分割 (/page/2 など)
    if (is_paged()) {
        if ($mode === 'canonical') {
            $canonical = get_queried_object()->term_id
                        ? get_term_link(get_queried_object())
                        : get_permalink();
            echo '<link rel="canonical" href="' . esc_url($canonical) . '" />' . "\n";
        } elseif ($mode === 'noindex') {
            echo '<meta name="robots" content="noindex, follow">' . "\n";
        }
    }
}

// head にフックして実行
add_action('wp_head', function() {
    // サイト方針に応じて 'canonical' か 'noindex' を選択
    custom_handle_duplicate_pages('canonical');
});
  

3 テーマ別サンプルphp

アーカイブ・カテゴリーページ用ソートボタンのコードです。

3.1 Lightning用

ファイル名:main-archive.php
保存先:wp-content/themes/child-theme/g3/template-parts/main-archive.php


<?php
/**
 * Archive main template
 *
 * @package Lightning G3
 */

/* =========================================
   ソートボタン(新着順・古い順)
   検索ページでは非表示
========================================= */

// 現在の順序取得
$order = isset($_GET['order']) ? $_GET['order'] : 'DESC';
?>
<div class="category-sort-buttons">
    <a href="<?php echo esc_url( add_query_arg( 'order', 'DESC' ) ); ?>" class="sort-btn">新着順</a>
    <a href="<?php echo esc_url( add_query_arg( 'order', 'ASC' ) ); ?>" class="sort-btn">古い順</a>
</div>

<?php
/* =========================================
   アーカイブタイトルと説明文
========================================= */
if ( ! is_search() ) {

    $post_top_info = VK_Helpers::get_post_top_info();

    // タイトル表示
    if ( $post_top_info['use'] || get_post_type() !== 'post' ) {
        if ( is_year() || is_month() || is_day() || is_tag() || is_tax() || is_category() ) {
            $archive_title = get_the_archive_title();
            $archive_header_html = '<header class="archive-header"><h1 class="archive-header-title">'
                . esc_html( $archive_title ) .
                '</h1></header>';

            echo wp_kses_post( apply_filters( 'lightning_archive_header', $archive_header_html ) );
        }
    }

    // 説明文表示
    if ( is_category() || is_tax() || is_tag() ) {
        $archive_description = term_description();
        if ( ! empty( $archive_description ) && 0 === get_query_var( 'paged', 0 ) ) {
            $archive_description_html = '<div class="archive-description">' . wp_kses_post( $archive_description ) . '</div>';
            echo wp_kses_post( apply_filters( 'lightning_archive_description', $archive_description_html ) );
        }
    }
}

/* =========================================
   投稿ループ開始
========================================= */
$post_type_info = VK_Helpers::get_post_type_info();
do_action( 'lightning_loop_before' );

if ( have_posts() ) :

    if ( apply_filters( 'lightning_is_extend_loop', false ) ) :

        do_action( 'lightning_extend_loop' );

    else :

        $post_list_class = 'post-list vk_posts vk_posts-mainSection';
        echo '<div class="' . esc_attr( $post_list_class ) . '">';

        global $lightning_loop_item_count;
        $lightning_loop_item_count = 0;

        while ( have_posts() ) :
            the_post();
            // ループアイテムを読み込む
            lightning_get_template_part( 'template-parts/loop-item', $post_type_info['slug'] );
            $lightning_loop_item_count++;
            do_action( 'lightning_loop_item_after' );
        endwhile;

        echo '</div> <!-- /.post-list -->';

    endif;

    // ページネーション
    $pagination_args = array(
        'mid_size'           => 1,
        'prev_text'          => '≪',
        'next_text'          => '≫',
        'type'               => 'list',
        'before_page_number' => '<span class="meta-nav screen-reader-text">' . __( 'Page', 'lightning' ) . ' </span>',
    );
    the_posts_pagination( apply_filters( 'lightning_pagenation_array', $pagination_args ) );

else :

    echo '<div class="main-section-no-posts"><p>' . wp_kses_post( lightning_get_no_post_text() ) . '</p></div>';

endif;

do_action( 'lightning_loop_after' );
?>

3.2 ディレクトリ構造

  • child-theme/
    • g3/
      • template-parts/
        • main-archive.php
    • tmp/
      • category-content.php
    • archive.php
    • category.php
    • functions.php
    • footer.php
    • header.php
    • style.css
    • js/
      • category-sort.js
    • images/
      • logo.png

3.3 Cocoon用

ファイル名:category-content.php
保存先:wp-content/themes/child-theme/tmp/category-content.php


<?php
/**
 * Cocoon WordPress Theme
 * category.php カスタマイズ版
 *
 * カテゴリーページにソートボタンを追加し、
 * ボタン用のスタイルを同じファイル内に記述。
 *
 * - 新着順 / 古い順 のボタンを表示
 * - 検索ページでは非表示
 * - 管理画面でも見やすいようにコード整理済み
 */

if ( ! defined( 'ABSPATH' ) ) exit;


/* =========================================
   ソートボタン(新着順・古い順)
   ※検索結果ページでは非表示
========================================= */
if ( ! is_search() ) : ?>

  <!-- ソートボタン用のスタイル -->
  <style>
    .sort-buttons {
      display: flex;
      flex-wrap: wrap;
      gap: 10px;
      margin: 1.5em 0;
      justify-content: center;
    }
    .sort-buttons .sort-button {
      background: #f5f5f5;
      border: 2px solid #ddd;
      border-radius: 30px;
      padding: 10px 18px;
      font-size: 15px;
      font-weight: 600;
      color: #333;
      cursor: pointer;
      transition: all 0.25s ease;
      min-width: 110px;
      text-align: center;
    }
    .sort-buttons .sort-button:hover {
      background: #0073aa;
      color: #fff;
      border-color: #0073aa;
      transform: translateY(-2px);
      box-shadow: 0 3px 6px rgba(0,0,0,0.15);
    }
    .sort-buttons .sort-button.active {
      background: #ff6f61;
      border-color: #ff6f61;
      color: #fff;
    }
    @media (max-width: 600px) {
      .sort-buttons { gap: 8px; }
      .sort-buttons .sort-button {
        flex: 1 1 100px;
        padding: 12px 10px;
        font-size: 14px;
      }
    }
  </style>

  <!-- ソートボタン本体 -->
  <div class="sort-buttons">
    <a href="<?php echo esc_url( add_query_arg( 'order', 'DESC' ) ); ?>" class="sort-button">新着順</a>
    <a href="<?php echo esc_url( add_query_arg( 'order', 'ASC' ) ); ?>" class="sort-button">古い順</a>
  </div>

<?php endif; ?>


<?php
/* =========================================
   カテゴリーアイキャッチ・説明文の表示
========================================= */
$cat_id = get_query_var('cat');
$eye_catch_url = get_the_category_eye_catch_url($cat_id);
$content = get_the_category_content($cat_id);

if ( $eye_catch_url || $content ) : ?>

  <article class="category-content article<?php echo esc_attr(get_additional_entry_content_classes()); ?>">

    <header class="article-header category-header">

      <!-- カテゴリータイトル -->
      <?php cocoon_template_part('tmp/list-title'); ?>

      <?php if ( $eye_catch_url ) :
        $display_none = is_eyecatch_visible() ? '' : ' display-none';
        $caption = get_caption_from_image_url($eye_catch_url);
      ?>

        <div class="eye-catch-wrap<?php echo esc_attr($display_none); ?>">
          <figure class="eye-catch">
            <img src="<?php echo esc_url($eye_catch_url); ?>"
                 class="eye-catch-image wp-category-image"
                 alt="<?php echo esc_attr(get_the_category_title($cat_id)); ?>">

            <?php if ( is_eyecatch_label_visible() && apply_filters('is_eyecatch_category_label_visible', true) ) : ?>
              <span class="cat-label cat-label-<?php echo esc_attr($cat_id); ?>">
                <?php single_cat_title( '', true ); ?>
              </span>
            <?php endif; ?>

            <?php if ( is_eyecatch_caption_visible() && $caption ) : ?>
              <figcaption class="eye-catch-caption">
                <?php echo esc_html($caption); ?>
              </figcaption>
            <?php endif; ?>

          </figure>
        </div>

        <?php do_action('category_eye_catch_after'); ?>

      <?php endif; ?>

      <!-- カテゴリーシェアボタン -->
      <?php cocoon_template_part('tmp/category-sns-share-top'); ?>

      <?php if ( is_large_pr_labels_visible() ) generate_large_pr_label_tag(); ?>

    </header>

    <?php if ( $content ) : ?>
      <div class="category-page-content entry-content">
        <?php echo $content; ?>
      </div>
    <?php endif; ?>

  </article>

<?php else : ?>

  <!-- アイキャッチ・説明が無い場合 -->
  <?php cocoon_template_part('tmp/list-title'); ?>
  <?php cocoon_template_part('tmp/category-sns-share-top'); ?>
  <?php if ( is_large_pr_labels_visible() ) generate_large_pr_label_tag(); ?>

<?php endif; ?>
  

3.2 ディレクトリ構造

  • child-theme/
    • g3/
    • tmp/
      • category-content.php
    • archive.php
    • category.php
    • functions.php
    • footer.php
    • header.php
    • style.css
    • js/
      • category-sort.js
    • images/
      • logo.png

4 JavaScript にコードを追加

ソートボタンをクリックするとページをリロードしてソートを反映します。

ファイル名:category-sort.js
保存先:wp-content/themes/child-theme/js/category-sort.js


document.addEventListener('DOMContentLoaded', function() {
    document.querySelectorAll('.sort-button').forEach(function(btn) {
        btn.addEventListener('click', function() {
            const sort = this.dataset.sort;
            const url = new URL(window.location.href);
            url.searchParams.set('sort', sort);
            window.location.href = url.toString();
        });
    });
});

3.2 ディレクトリ構造

  • child-theme/
    • g3/
      • template-parts/
        • main-archive.php
    • tmp/
      • category-content.php
    • archive.php
    • category.php
    • functions.php
    • footer.php
    • header.php
    • style.css
    • js/
      • category-sort.js
    • images/
      • logo.png

5 汎用CSS


/* -----------------------------
 * カテゴリーソートボタン
 * ----------------------------- */

/* ソートボタン全体の配置 */
.category-sort-buttons {
    margin: 20px 0;          /* 上下の余白 */
    text-align: center;       /* 中央揃え */
}

/* 各ソートボタン */
.category-sort-buttons .sort-btn {
    display: inline-block;    /* 横並び可能にする */
    padding: 8px 15px;        /* 上下8px、左右15pxの内側余白 */
    margin: 5px;              /* ボタン間の隙間 */
    border: 1px solid #0073aa; /* 青の枠線 */
    border-radius: 5px;       /* 角丸5px */
    background: #f7f7f7;      /* 薄いグレー背景 */
    color: #0073aa;           /* 文字色 青 */
    cursor: pointer;          /* ホバー時に手の形に */
    transition: 0.3s;         /* ホバー時の変化を0.3秒で */
    font-size: 14px;          /* 文字サイズ */
}

/* ホバー時 */
.category-sort-buttons .sort-btn:hover {
    background: #0073aa;      /* 背景色を青に変更 */
    color: #fff;              /* 文字色を白に変更 */
}
  

6 Cocoon用

CocoonのCSSは、category-content.phpに直書きしてます。

7 完成イメージ

7.1 汎用CSS

カテゴリーページで、ソートできるボタンを作る方法

7.2 Cocoon

カテゴリーページで、ソートできるボタンを作る方法

8 代用プラグイン

コード編集が難しい場合は「Content Views」や「WP Grid Builder」などのプラグインを使って、
カテゴリーページにソート機能を実装することも可能です。

9 まとめ

  • カテゴリーページにソートボタンを追加することで、ユーザーが見たい順に記事を並べ替えることができ、回遊率アップやユーザビリティ向上につながります。ぜひ自分のテーマに合わせてカスタマイズしてみてください。
  • カテゴリ・タグページのクエリパラメータやページ分割での重複を防ぐコードを追加します。詳しくは、 カテゴリ・タグページのクエリパラメータやページ分割での重複を防ぐ方法をご覧ください。