Ошибка 404 при пагинации пользовательского запроса в WordPress

9 июн. 2014 г., 23:56:12
Просмотры: 14.2K
Голосов: 0

Основная проблема в том, что все страницы пагинации в моем блоге (/page/2/, /page/3/ и т.д.) ведут на страницу 404. Раньше все работало нормально, но сейчас перестало. Возможно, это связано с обновлением до версии 3.9.

Вот что я уже пробовал сделать для исправления этой проблемы (ни один из вариантов не сработал - страницы пагинации по-прежнему возвращают 404):

  • Отключал все плагины
  • Несколько раз сбрасывал настройки постоянных ссылок
  • Пробовал использовать стандартные permalinks вместо /postname
  • Проверил, что в Настройках чтения → "На странице блога отображать не более" установлено то же значение, что и в моем цикле (а также тестировал с разными значениями)
  • Пробовал два разных плагина для навигации и стандартную wordpress пагинацию ("Старые записи") - все равно 404
  • Пробовал использовать parse_query
  • Пробовал paginate_links

Вот мой код:

home.php

    <?php require dirname( __FILE__ ) . '/blog-page.php';

blog-page.php

<?php
/*
Шаблон: Blog Page - Custom
*/

get_header(); ?>

<---ПОЛЬЗОВАТЕЛЬСКИЙ КОД--->

<?php
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
   $args = array(
       'posts_per_page' => 5,
       'post_type' => 'post',
       'paged' => $paged
   );

$wp_query = new WP_Query($args);

if($wp_query->have_posts()) : 

   while($wp_query->have_posts()) : $wp_query->the_post(); ?>

<---ПОЛЬЗОВАТЕЛЬСКИЙ КОД--->


   endwhile;

wp_reset_postdata();?>

<div class="nav-previous alignleft"><?php next_posts_link( 'Старые записи' ); ?></div>
<div class="nav-next alignright"><?php previous_posts_link( 'Новые записи' ); ?></div>
<?php  endif; wp_reset_query();

Для теста я создал тестовый сайт с этой проблемой. На нем оставлена стандартная wordpress пагинация.

У меня закончились идеи. Буду благодарен за любые предложения по решению этой проблемы.

3
Комментарии

Я также попробовал этот вариант здесь, но не смог опубликовать ссылку: http://wordpress.stackexchange.com/questions/54509/query-with-pre-get-posts-to-get-pagination

jphogan jphogan
9 июн. 2014 г. 23:56:53

почему вы создаёте новый запрос в шаблоне вместо использования основного запроса по умолчанию?

Milo Milo
10 июн. 2014 г. 00:20:01

У вас не будет надёжной пагинации при переопределении основного запроса в шаблоне. Никогда. Серьёзно.

Rarst Rarst
10 июн. 2014 г. 00:52:52
Все ответы на вопрос 2
3

Есть несколько моментов, которые мне непонятны, но я постараюсь ответить на них по ходу дела.

У вас есть home.php, который, как я понимаю, является вашей главной страницей по умолчанию. В нем всего одна строка кода, которая вызывает другой шаблон страницы. Вот ваш код:

<?php require dirname( __FILE__ ) . '/blog-page.php'; 

В blog-page.php у вас полный шаблон страницы. Мой вопрос: зачем вы так делаете? Почему бы просто не добавить содержимое blog-page.php в home.php? Так было бы логичнее.

Вы не используете основной запрос для вашего цикла, а создаете кастомный, что мне тоже непонятно, так как ваш кастомный запрос делает то же самое, что и основной, за исключением количества постов на странице. Весь этот кастомный запрос можно избежать, просто используя pre_get_posts для установки нужного количества постов на главной странице.

function posts_on_homepage( $query ) {
    if ( $query->is_home() && $query->is_main_query() ) {
        $query->set( 'posts_per_page', '5' );
    }
}
add_action( 'pre_get_posts', 'posts_on_homepage' );

Вы можете просто добавить это в functions.php, что установит количество постов на главной странице равным 5, и тогда вы сможете заменить кастомный запрос обычным циклом.

Одна важная вещь: когда вы используете кастомный запрос, пагинация не будет работать, как указано в комментариях.

Вам нужно изучить параметры пагинации WP_Query.

paged (int) - номер страницы. Показывает посты, которые обычно отображаются на странице X при использовании ссылки "Старые записи".

page (int) - номер страницы для статической главной страницы. Показывает посты, которые обычно отображаются на странице X статической главной страницы.

Таким образом, ваш запрос для обычных страниц должен выглядеть так:

$paged = ( get_query_var('paged') ) ? get_query_var('paged') : 1;
$query = new WP_Query( array( 'paged' => $paged ) );

А для статических страниц - так:

$paged = ( get_query_var('page') ) ? get_query_var('page') : 1;
$query = new WP_Query( array( 'paged' => $paged ) );

Вы также дважды сбрасываете данные поста. Это нужно делать только один раз. Кстати, wp_reset_query(); использовать неверно - он предназначен только для query_posts, который вообще не рекомендуется использовать. Вместо этого используйте wp_reset_postdata();.

Наконец, при использовании кастомного запроса вы должны указать максимальное количество страниц для next_posts_link, используя параметр $max_pages, иначе он не будет работать.

next_posts_link( 'Старые записи', $the_query->max_num_pages );

Вот пример правильно работающего кастомного запроса из кодекса:

<?php
// устанавливаем параметр "paged" (используйте 'page' для статической главной страницы)
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;

// запрос
$the_query = new WP_Query( 'cat=1&paged=' . $paged ); 
?>

<?php if ( $the_query->have_posts() ) : ?>

<?php
// цикл
while ( $the_query->have_posts() ) : $the_query->the_post(); 
?>
   <?php the_title(); ?>
<?php endwhile; ?>

<?php
// использование next_posts_link() с max_num_pages
next_posts_link( 'Старые записи', $the_query->max_num_pages );
previous_posts_link( 'Новые записи' );
?>

<?php 
// очищаем данные после запроса
wp_reset_postdata(); 
?>

<?php else:  ?>
   <p><?php _e( 'Извините, нет записей, соответствующих вашим критериям.' ); ?></p>
<?php endif; ?>

Надеюсь, это прольет свет на вашу проблему.

10 июн. 2014 г. 10:16:18
Комментарии

Огромное спасибо за то, что нашли время написать такой подробный ответ. Я перепробовал так много вариантов, что, кажется, окончательно запутался. Обязательно сохраню ваши рекомендации — они мне еще не раз пригодятся. Я скопировал свой код из blog-page.php и перенес его в home.php. Перешел на стандартный запрос. Затем добавил вашу функцию для ограничения количества записей. Хотя лимит был установлен в настройках чтения, страница его игнорировала даже после переноса в home.php. Есть идеи, почему так происходило? В любом случае, теперь все работает идеально. Не могу выразить, как я благодарен за вашу помощь.

jphogan jphogan
10 июн. 2014 г. 20:44:57

Вы установили главную страницу в "Настройки чтения >> Отображение главной страницы"? Если нет, отредактируйте свой вопрос и добавьте текущий код из home.php, чтобы я мог быстро взглянуть :)

Pieter Goosen Pieter Goosen
10 июн. 2014 г. 20:57:07

Да, я это настроил. Смотрите здесь: http://imgur.com/n8YINbI Вот мой новый home.php http://pastebin.com/bTHRMFqT Если я удаляю вашу функцию, отображаются все записи и нет пагинации. Если добавляю функцию — отображается правильное количество записей, и все работает как должно.

jphogan jphogan
10 июн. 2014 г. 23:20:17
0

Я опоздал на вечеринку, но ни один из вышеперечисленных вариантов мне не помог. Мне удалось написать небольшой обходной путь для этой совершенно раздражающей ситуации.

  1. Изучите URL
  2. Если присутствует /page/2, напишите правило перенаправления, чтобы добавить строку запроса к URL
  3. Используйте этот запрос в своей пагинации.

// Установка глобальной переменной для сегментов URL (functions.php)
global $segments;
$segments = explode('/', $_SERVER['REQUEST_URI']);
$segments = array_filter($segments);
$segments['classes'] = implode(' ', $segments);

// Добавьте это правило перезаписи в functions.php для добавления строки запроса к цели
add_action( 'init', 'forum_paging_redirect', 10 );
function forum_paging_redirect( $redirect_url ) {
    global $segments;

    if($segments[1] === 'forum' && $segments[2] === 'page') {
        echo '<script>window.location = "/forum?topics_page='.$segments[3].'";</script>';
    }
}

// Вместо нативной функции пагинации выведите это:
if(!empty($query_topics)) {
    $total = $query_topics->max_num_pages;
    $page = $_GET['topics_page'];

    for($i = 1; $i < $total +1; $i++) {
        if($i == $page) {
            echo '<span aria-current="page" class="page-numbers current">'.$i.'</span>';
        } else {
            echo '<a class="page-numbers" href="/forum/?topics_page='.$i.'">'.$i.'</a>';
        }
    }   
} 
28 сент. 2018 г. 21:11:35