Пагинация с пользовательским SQL-запросом
У меня есть собственный SQL-запрос для выборки записей Custom Post Type с определенным условием WHERE. Я использовал offset и limit для возврата нужных записей в зависимости от отображаемой страницы. Это работает нормально.
Теперь я хочу, чтобы функции previous_posts_link()
и next_posts_link()
работали. Обе они вызываются из get_posts_nav_link
, который использует global $wp_query
.
Есть ли способ переопределить global $wp_query
с моим SQL-запросом или результатами $wpdb->get_results
или чем-то еще? Чтобы нативные функции WordPress previous_posts_link()
и next_posts_link()
работали.
Если нет, как я могу воспроизвести функции ссылок на предыдущие и следующие записи?
Буду очень признателен за любую помощь и совет! Я совсем застрял на этом.
Спасибо :)
ПРИМЕЧАНИЕ: Я только что заметил, что previous_posts_link()
работает корректно на всех страницах, но не понимаю почему
и в этом случае, почему next_posts_link
не работает :S
Вот код:
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$post_per_page = intval(get_query_var('posts_per_page'));
$offset = ($paged - 1)*$post_per_page;
$sql = "
SELECT SQL_CALC_FOUND_ROWS wp_posts.*, wp_postmeta.*
FROM wp_posts
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
WHERE 1=1
AND wp_posts.post_type = 'movie'
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')
AND ((wp_postmeta.meta_key = '_expiry_date' AND CAST(wp_postmeta.meta_value AS DATE) >= '".$current_date."')
OR (mt1.meta_key = '_expiry_date' AND CAST(mt1.meta_value AS CHAR) = ''))
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT ".$offset.", ".$post_per_page;
$movies_all_current = $wpdb->get_results( $sql, OBJECT);
if($movies_all_current) {
global $post;
// цикл
foreach( $movies_all_current as $key=>$post ) {
setup_postdata($post);
// отображение каждой записи
//...
} // конец foreach ?>
// навигация
<div class="navigation">
<div class="previous panel"><?php previous_posts_link('« новее') ?></div>
<div class="next panel"><?php next_posts_link('старее »') ?></div>
</div>
}
Ок, я наконец-то разобралась. Я не могла использовать класс WP_Query
, так как мне действительно нужно было написать свой довольно большой и сложный SQL-запрос. Вот что у меня получилось:
В functions.php
у меня находится мой кастомный SQL и логика для подсчета значений, необходимых для пагинации в WordPress:
function vacancies_current( ){
global $wpdb, $paged, $max_num_pages, $current_date;
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$post_per_page = intval(get_query_var('posts_per_page'));
$offset = ($paged - 1)*$post_per_page;
/* Кастомный SQL здесь. Я опустила важные части и удалила тело,
так как оно будет специфичным для вашего случая. */
$sql = "
SELECT SQL_CALC_FOUND_ROWS {$wpdb->posts}.*
FROM {$wpdb->posts}
....
GROUP BY {$wpdb->posts}.ID
ORDER BY {$wpdb->posts}.post_date DESC
LIMIT ".$offset.", ".$post_per_page."; ";
$sql_result = $wpdb->get_results( $sql, OBJECT);
/* Определяем общее количество результатов, чтобы вычислить max_num_pages
для навигации next_posts_link */
$sql_posts_total = $wpdb->get_var( "SELECT FOUND_ROWS();" );
$max_num_pages = ceil($sql_posts_total / $post_per_page);
return $sql_result;
}
Затем в моем файле шаблона я использую:
<?php
$vacancies_current = vacancies_current();
/* далее стандартный цикл для вывода результатов */
?>
<div class="navigation">
<div class="previous panel"><?php previous_posts_link('« предыдущие вакансии',$max_num_pages) ?></div>
<div class="next panel"><?php next_posts_link('больше вакансий »',$max_num_pages) ?></div>
</div>
Секрет заключался в передаче значения $max_num_pages
в функции previous_posts_link()
и next_posts_link
, а также, очевидно, в его правильном расчете.
Это работает очень хорошо. Надеюсь, это кому-то поможет :)
Даша

+1 отличная работа. Я наткнулся на это (и активно заимствовал, спасибо) во время исследования своего ответа на http://stackoverflow.com/questions/16057059/wordpress-order-by-author-if-different-than-admin. Мне было интересно, знаете ли вы способ использовать подобный пользовательский SQL-запрос, но в действии pre_get_posts() согласно https://codex.wordpress.org/Pagination#Removing_query_posts_from_the_main_loop? Я обнаружил, что это решение подвержено проблеме 404 на последней странице, как указано в http://wordpress.org/support/topic/explanation-and-workaround-for-error-404-on-category-pagination?replies=14. Как вы решили эту проблему?

Ознакомьтесь с Пользовательскими запросами — они позволяют модифицировать вызов wp_query множеством интересных и полезных способов, а затем передавать результаты обратно в глобальный объект запроса.

Расширяя ответ Ану. Вместо того, чтобы полагаться на ваш собственный SQL-запрос, вы можете использовать класс WP_Query и позволить WordPress выполнять всю сложную работу с SQL. Это точно решит вашу проблему с навигацией.
Пример запроса для типа записи movie с метаполем _expiry_date:
$today = getdate(); // Получаем текущую дату
$args = array(
'post_type' => 'movie', // Тип записи - фильмы
'meta_query' => array(
'meta_key' => '_expiry_date', // Метаполе с датой истечения
'meta_value' => $today, // Сравниваем с текущей датой
'meta_compare' => '< ' // Ищем записи, где дата истекла
),
'posts_per_page' => -1, // Выводим все записи
'order' => 'DESC' // Сортировка по убыванию
);
$movie_query = new WP_Query( $args ); // Создаем новый запрос
while ( $movie_query->have_posts() ) : $movie_query->the_post();
// Здесь ваш код для вывода записей
endwhile; ?>
<div class="navigation">
<div class="previous panel"><?php previous_posts_link('« новее') ?></div>
<div class="next panel"><?php next_posts_link('старее »') ?></div>
</div>

<?php
global $wpdb, $paged;
query_posts($query_string . '&posts_per_page=9');
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$author = isset($_GET['author_name']) ? get_userdatabylogin($author_name) : get_userdata(intval($author));
query_posts($query_string . '&posts_per_page=9');
$args = array(
'post_type' => 'post',
'meta_query' => array(
'meta_key' => 'autor',
'post_status' => 'publish',
'meta_value' => $author->id,
),
'paged' => $paged,
'posts_per_page' => 9,
'order' => 'DESC'
);
$postsQuery = new WP_Query( $args );
?>
Шаблон:
<h1>Статьи от <?php echo $author->display_name; ?></h1>
<ul class="thumbnails">
<?php while ( $postsQuery->have_posts() ) : $postsQuery->the_post(); ?>
<li class="span3">
<div class="thumbnail">
<a href="<?php the_permalink(); ?>">
<?php the_post_thumbnail(array(260, 259)); ?>
</a>
<?php
$class = '';
if (in_category('fashion')) {
$class = "link-fashion";
} else if (in_category('beauty')) {
$class = "link-beauty";
} else if (in_category('gourmet')) {
$class = "link-gourmet";
} else if (in_category('lifestyle')) {
$class = "link-lifestyle";
} else if (in_category('about-us')) {
$class = "link-about";
}
?>
<a href="<?php the_permalink(); ?>">
<h2 class="<?= $class ?>">
<span></span>
<?php
// short_title('...', 25);
echo get_the_title();
?>
</h2>
</a>
<?php the_excerpt(); ?>
<hr>
</div>
</li>
<?php endwhile; ?>
</ul>
<?php wp_pagenavi(); ?>
