404 pagination error in WordPress category/archive template

image 1

/page/2/ 404 真正該查的方向, 比較可能是這幾種:

固定網址 rewrite 沒更新

到後台:

設定 → 永久網址 → 儲存變更

先做這個。

image

分頁網址產生錯了

先在模板裡輸出看看:

PHP
<?php
echo get_pagenum_link(2);
?>

看它印出的是不是預期的網址,像:

PHP
/news/page/2/

如果這裡產生就不對,後面的分頁當然會 404。

paged 抓值錯誤

請用這段:

PHP
<?php
$paged = max(1, get_query_var('paged'), get_query_var('page'));
echo 'paged=' . $paged;
?>

打開 /page/2/ 時看有沒有抓到 2。如果沒抓到,代表 rewrite 或模板結構有問題。

你是在 page/category/archive template 裡做自訂查詢

這種最容易發生:

PHP
<?php
$paged = max(1, get_query_var('paged'), get_query_var('page'));

$query = new WP_Query([
    'post_type'      => 'post',
    'posts_per_page' => 5,
    'paged'          => $paged,
    'cat'            => 12,
]);

if ($query->have_posts()) :
    while ($query->have_posts()) : $query->the_post();
        echo '<h2>' . get_the_title() . '</h2>';
    endwhile;

    $big = 999999999;

    echo paginate_links([
        'base'    => str_replace($big, '%#%', trailingslashit(get_permalink()) . 'page/%#%/'),
        'format'  => '',
        'current' => $paged,
        'total'   => $query->max_num_pages,
    ]);

    wp_reset_postdata();
else :
    echo '沒有資料';
endif;
?>
  • /news/ 第一頁正常
  • /news/page/2/ 404

這通常是因為你現在這頁是一般 page,不是 archive。

看到這個 404 訊息,結論就是

  • 404 比較像是 WordPress rewrite、paged、paginate_links、page template 的問題
  • 在 page/category/archive Template 裡做自訂查詢

category.phparchive.php 裡自己又寫了:

PHP
$query = new WP_Query([...]);

這很容易造成:

  • 畫面看起來第一頁正常
  • /page/2/ 其實是主查詢沒對上
  • 然後 WordPress 判定 404

解決方法

category/archive template,最穩的是直接用 主查詢

PHP
<?php 
/**
 * The template for displaying archive pages
 * 取得目前物件的 ID: get_queried_object_id();
 * 取得目前的物件: get_queried_object();
 * 取得目前物件的名稱: get_queried_object()->name;
 * 取得目前物件的 slug: get_queried_object()->slug;
 * 取得目前物件的類型(taxonomy): get_queried_object()->taxonomy;
 */
get_header(); 
?>

<main>
  <?php if (have_posts()) : ?>
      <?php while (have_posts()) : the_post(); ?>
          <article>
              <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
              <?php the_excerpt(); ?>
          </article>
      <?php endwhile; ?>
  
      <?php
      global $wp_query;
      $paged = max(1, get_query_var('paged'));
  
      $links = paginate_links([
          'total'      => $wp_query->max_num_pages,
          'current'    => $paged,
          'prev_text'  => 'Prev',
          'next_text'  => 'Next',
          'type'       => 'array',
      ]);
  
      if (!empty($links)) :
      ?>
          <ul class="pagination">
              <?php foreach ($links as $link) : ?>
                  <li><?php echo $link; ?></li>
              <?php endforeach; ?>
          </ul><!-- /.pagination -->
      <?php
      endif;
      ?>
  
  <?php else : ?>
      <p>沒有資料</p>
  <?php endif; ?>
</main>

<?php get_footer(); ?>

如果只是要「某分類與其子孫分類文章」,其實 category archive 主查詢本來就會處理分頁,通常不用自己再 new 一個 query。

重點

現在要記住這句就夠了:

  • 模板檔 archive.php 負責顯示
  • functions.phppre_get_posts 負責改每頁幾筆

不要在 archive.php 再寫 new WP_Query,不然很容易又把分頁弄壞。

Pagination 自定 css

paginate_links() 預設就能吐出接近想要的結構,重點是把它包成 ul > li。最簡單就是用 type => 'array',然後自己組 HTML。

PHP
<?php
global $wp_query;

$paged = max(1, get_query_var('paged'));

$links = paginate_links([
    'total'      => $wp_query->max_num_pages,
    'current'    => $paged,
    'prev_text'  => 'Prev',
    'next_text'  => 'Next',
    'type'       => 'array',
]);

if (!empty($links)) : ?>
    <ul class="pagination">
        <?php foreach ($links as $link) : ?>
            <li><?php echo $link; ?></li>
        <?php endforeach; ?>
    </ul><!-- /.pagination -->
<?php endif; ?>

產生出來會很接近你要的格式, 例如:

HTML
<ul class="pagination">
    <li><span aria-current="page" class="page-numbers current">1</span></li>
    <li><a class="page-numbers" href="/page/2/">2</a></li>
    <li><a class="next page-numbers" href="/page/3/">Next</a></li>
</ul>

CSS 也一起套

這個 class 是 .pagination,所以可以直接寫:

CSS
.pagination {
  display: flex;
  gap: 8px;
  list-style: none;
  padding: 0;
  margin: 20px 0;
}

.pagination li {
  display: inline-block;
}

.pagination a,
.pagination span {
  display: inline-block;
  padding: 8px 12px;
  border: 1px solid #ddd;
  text-decoration: none;
}

.pagination .current {
  background: #333;
  color: #fff;
  border-color: #333;
}

加上 nav 包住,語意會更完整:

PHP
<?php if (!empty($links)) : ?>
    <nav class="pagination-nav" aria-label="Pagination">
        <ul class="pagination">
            <?php foreach ($links as $link) : ?>
                <li><?php echo $link; ?></li>
            <?php endforeach; ?>
        </ul>
    </nav>
<?php endif; ?>

小提醒

paginate_links() 產生的 aspan 會自帶:

  • page-numbers
  • current
  • next
  • prev

所以通常不用自己再加工 class,直接寫 CSS 就能套。

使用 WordPress 主查詢 , archive.php 如何設定每頁多少筆

WordPress 主查詢 的話,不是在 archive.php 裡用 new WP_Query 設定每頁筆數,
而是要在 functions.phppre_get_posts 去改。

正確做法: 把下面放到 functions.php

PHP
function my_archive_posts_per_page($query) {
    if (!is_admin() && $query->is_main_query() && $query->is_category()) {
        $query->set('posts_per_page', 10); // 每頁 10 筆
    }
}
add_action('pre_get_posts', 'my_archive_posts_per_page');

如果是所有 archive 都要生效,如 category、tag、author、date archive 都一起改:

PHP
function my_archive_posts_per_page($query) {
    if (!is_admin() && $query->is_main_query() && $query->is_archive()) {
        $query->set('posts_per_page', 10); // 每頁 10 筆
    }
}
add_action('pre_get_posts', 'my_archive_posts_per_page');

如果只想指定某個分類, 例如只有 business-supplies 這個分類每頁 12 筆:

PHP
function my_archive_posts_per_page($query) {
    if (!is_admin() && $query->is_main_query() && $query->is_category('business-supplies')) {
        $query->set('posts_per_page', 12);
    }
}
add_action('pre_get_posts', 'my_archive_posts_per_page');

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *


內容索引