Вывод пагинации WP_Query
Подскажите пожалуйста, можно ли без перезагрузки страницы (в рамках <div class="services__tab-item">) сделать пагинацию для <li class="posts"> сохранив нынешнюю HTML структуру? На данный момент выводится 1 2 3 вперед » но при нажатии на любую из ссылок, переходит на /page/2/ и там 404 ошибка.
<div class="tab_content">
<?php $cats = get_categories(array('taxonomy'=>'services_cat')); // get list of categories
foreach ($cats as $cat) { ?>
<div class="services__tab-item">
<ul class="services__tab-points">
<?php
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$args = array(
'post_type' => 'services',
'posts_per_page' => 8,
'paged' => $paged,
'tax_query' => array(
array(
'taxonomy' => 'services_cat',
'field' => 'id',
'terms' => array( $cat -> term_id )
),
)
);
$query = new WP_Query($args);
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
?>
<li>
<a href="<?php the_permalink(); ?>">
<p><?php the_title(); ?></p>
<span><?php the_permalink(); ?></span>
</a>
</li>
<?php
}
}
wp_reset_postdata();
?>
</ul>
<?php kama_pagenavi($before = '', $after = '', $echo = true, $args = array(), $wp_query = $query); // пагинация, функция нах-ся в function.php ?>
</div>
<?php } ?>
</div>
Ответы (1 шт):
Чтобы уйти от неясностей, где и как расположен код, я написал плагин, который содержит весь необходимый код в себе самом.
Создайте папку wp-content/plugins/so-ajax-pagination. В ней создайте файл so-ajax-pagination.php со следующим содержимым:
<?php
/**
* SO Ajax Pagination Plugin.
*
* @package so-ajax-pagination
* @author KAGG Design
* @license GPL-2.0-or-later
* @wordpress-plugin
*
* Plugin Name: So Ajax Pagination
* Plugin URI: https://ru.stackoverflow.com/questions/1251936
* Description: Pagination in taxonomies with ajax.
* Version: 1.0.0
* Requires at least: 5.1
* Requires PHP: 5.6.20
* Author: KAGG Design
* Author URI: https://kagg.eu/
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: so-ajax-pagination
* Domain Path: /languages/
*/
/**
* Class SO_Ajax_Pagination.
*/
class SO_Ajax_Pagination {
/**
* Script handle.
*/
const HANDLE = 'so-ajax-pagination';
/**
* Ajax action name.
*/
const ACTION = 'so-ajax-pagination';
/**
* Post type to show.
*
* @var string
*/
private $post_type = 'services';
/**
* Taxonomy to show.
*
* @var string
*/
private $taxonomy = 'services_cat';
/**
* Url of the page when shortcode fired.
*
* @var string
*/
private $url;
/**
* SO_Ajax_Pagination constructor.
*/
public function __construct() {
add_shortcode( 'services_cat', [ $this, 'services_cat_shortcode' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'services_cat_script' ] );
add_action( 'wp_ajax_' . self::ACTION, [ $this, 'ajax_action' ] );
add_action( 'wp_ajax_nopriv_' . self::ACTION, [ $this, 'ajax_action' ] );
}
/**
* Shortcode [services_cat]
*/
public function services_cat_shortcode() {
ob_start();
?>
<div class="tab_content">
<?php
$cats = get_categories( [ 'taxonomy' => $this->taxonomy ] ); // Get list of categories.
foreach ( $cats as $cat ) {
$paged = ( get_query_var( 'paged' ) ) ?: 1;
$this->show_cat_posts( $cat->term_id, $paged );
}
?>
</div>
<?php
return ob_get_clean();
}
/**
* Enqueue plugin script.
*/
public function services_cat_script() {
wp_enqueue_script(
self::HANDLE,
untrailingslashit( plugin_dir_url( __FILE__ ) ) . '/so-ajax-pagination.js',
[ 'jquery' ],
'1.0.0',
true
);
wp_localize_script(
self::HANDLE,
'SOAjaxPaginationObject',
[
'ajaxURL' => admin_url( 'admin-ajax.php' ),
'action' => self::ACTION,
'nonce' => wp_create_nonce( self::ACTION ),
'url' => get_the_permalink(),
]
);
}
/**
* Ajax action.
*/
public function ajax_action() {
if (
! wp_verify_nonce(
filter_input( INPUT_POST, 'nonce', FILTER_SANITIZE_STRING ),
self::ACTION
)
) {
wp_send_json_error( __( 'Bad nonce!', 'kagg-pagespeed-module' ) );
}
ob_start();
$term_id = filter_input( INPUT_POST, 'termId', FILTER_VALIDATE_INT );
$page = filter_input( INPUT_POST, 'page', FILTER_VALIDATE_INT );
$this->url = filter_input( INPUT_POST, 'url', FILTER_VALIDATE_INT );
$this->show_cat_posts( $term_id, $page );
wp_send_json_success( ob_get_clean() );
}
/**
* Show category posts.
*
* @param int $term_id Category id.
* @param int $paged Pagination page.
*/
private function show_cat_posts( $term_id, $paged ) {
?>
<div class="services__tab-item" data-cat="<?php echo esc_attr( $term_id ); ?>">
<ul class="services__tab-points">
<?php
$args = [
'post_type' => $this->post_type,
'posts_per_page' => 8,
'paged' => $paged,
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
'tax_query' => [
[
'taxonomy' => $this->taxonomy,
'field' => 'id',
'terms' => [ $term_id ],
],
],
];
$query = new WP_Query( $args );
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
?>
<li>
<a href="<?php the_permalink(); ?>">
<p><?php the_title(); ?></p>
</a>
</li>
<?php
}
}
wp_reset_postdata();
?>
</ul>
<?php
add_filter( 'get_pagenum_link', [ $this, 'get_pagenum_link_filter' ], 10, 2 );
$this->kama_pagenavi( [], $query ); // Пагинация.
remove_filter( 'get_pagenum_link', [ $this, 'get_pagenum_link_filter' ], 10 );
?>
</div>
<?php
}
/**
* Filters the page number link for the current request.
*
* @param string $result The page number link.
* @param int $pagenum The page number.
*
* @return string
*/
public function get_pagenum_link_filter( $result, $pagenum ) {
if ( ! wp_doing_ajax() ) {
return $result;
}
$result = str_replace( admin_url( 'admin-ajax.php' ), $this->url, $result );
$result = preg_replace( '/\?paged=(.+)/', '/page/$1/', $result );
return $result;
}
/**
* Альтернатива wp_pagenavi. Создает ссылки пагинации на страницах архивов.
*
* @param array $args Аргументы функции.
* @param object $wp_query Объект WP_Query на основе которого строится пагинация. По умолчанию глобальная переменная
* $wp_query.
*
* @return string
*
* @author Тимур Камаев
* @link Ссылка на страницу функции: http://wp-kama.ru/?p=8
* @version 2.7
*/
private function kama_pagenavi( $args = [], $wp_query = null ) {
// Параметры по умолчанию.
$default = [
'before' => '', // Текст до навигации.
'after' => '', // Текст после навигации.
'echo' => true, // Возвращать или выводить результат.
'text_num_page' => '',
// Текст перед пагинацией.
// {current} - текущая.
// {last} - последняя (пр: 'Страница {current} из {last}' получим: "Страница 4 из 60").
'num_pages' => 10,
// Сколько ссылок показывать.
'step_link' => 10,
// Ссылки с шагом (если 10, то: 1,2,3...10,20,30. Ставим 0, если такие ссылки не нужны.
'dotright_text' => '…',
// Промежуточный текст "до".
'dotright_text2' => '…',
// Промежуточный текст "после".
'back_text' => '« назад',
// Текст "перейти на предыдущую страницу". Ставим 0, если эта ссылка не нужна.
'next_text' => 'вперед »',
// Текст "перейти на следующую страницу". Ставим 0, если эта ссылка не нужна.
'first_page_text' => '« к началу',
// Текст "к первой странице". Ставим 0, если вместо текста нужно показать номер страницы.
'last_page_text' => 'в конец »',
// Текст "к последней странице". Ставим 0, если вместо текста нужно показать номер страницы.
];
$fargs = func_get_args();
if ( $fargs && is_string( $fargs[0] ) ) {
$default['before'] = isset( $fargs[0] ) ? $fargs[0] : '';
$default['after'] = isset( $fargs[1] ) ? $fargs[1] : '';
$default['echo'] = isset( $fargs[2] ) ? $fargs[2] : true;
$args = isset( $fargs[3] ) ? $fargs[3] : [];
$wp_query = $GLOBALS['wp_query']; // После определения $default!
}
if ( ! $wp_query ) {
wp_reset_postdata();
global $wp_query;
}
if ( ! $args ) {
$args = [];
}
if ( $args instanceof WP_Query ) {
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$wp_query = $args;
$args = [];
}
$default = apply_filters( 'kama_pagenavi_args', $default ); // Чтобы можно было установить свои значения по умолчанию.
$rg = (object) array_merge( $default, $args );
$paged = (int) $wp_query->get( 'paged' );
$max_page = $wp_query->max_num_pages;
// Проверка на надобность в навигации.
if ( $max_page <= 1 ) {
return false;
}
if ( empty( $paged ) || 0 === $paged ) {
$paged = 1;
}
$pages_to_show = (int) $rg->num_pages;
$pages_to_show_minus_1 = $pages_to_show - 1;
$half_page_start = (int) floor( $pages_to_show_minus_1 / 2 ); // Сколько ссылок до текущей страницы.
$half_page_end = (int) ceil( $pages_to_show_minus_1 / 2 ); // Сколько ссылок после текущей страницы.
$start_page = $paged - $half_page_start; // Первая страница.
$end_page = $paged + $half_page_end; // Последняя страница (условно).
if ( $start_page <= 0 ) {
$start_page = 1;
}
if ( ( $end_page - $start_page ) !== $pages_to_show_minus_1 ) {
$end_page = $start_page + $pages_to_show_minus_1;
}
if ( $end_page > $max_page ) {
$start_page = $max_page - $pages_to_show_minus_1;
$end_page = (int) $max_page;
}
if ( $start_page <= 0 ) {
$start_page = 1;
}
// Создаем базу чтобы вызвать get_pagenum_link один раз.
$link_base = str_replace( 99999999, '___', get_pagenum_link( 99999999 ) );
$first_url = get_pagenum_link( 1 );
if ( false === strpos( $first_url, '?' ) ) {
$first_url = user_trailingslashit( $first_url );
}
// Собираем елементы.
$els = [];
if ( $rg->text_num_page ) {
$rg->text_num_page = preg_replace( '!{current}|{last}!', '%s', $rg->text_num_page );
$els['pages'] = sprintf( '<span class="pages">' . $rg->text_num_page . '</span>', $paged, $max_page );
}
// Назад.
if ( $rg->back_text && 1 !== $paged ) {
$els['prev'] = '<a class="prev" href="' . ( ( $paged - 1 ) === 1 ? $first_url : str_replace( '___', ( $paged - 1 ), $link_base ) ) . '">' . $rg->back_text . '</a>';
}
// В начало.
if ( $start_page >= 2 && $pages_to_show < $max_page ) {
$els['first'] = '<a class="first" href="' . $first_url . '">' . ( $rg->first_page_text ?: 1 ) . '</a>';
if ( $rg->dotright_text && 2 !== $start_page ) {
$els[] = '<span class="extend">' . $rg->dotright_text . '</span>';
}
}
// Пагинация.
for ( $i = $start_page; $i <= $end_page; $i ++ ) {
if ( $i === $paged ) {
$els['current'] = '<span class="current">' . $i . '</span>';
} elseif ( 1 === $i ) {
$els[] = '<a href="' . $first_url . '">1</a>';
} else {
$els[] = '<a href="' . str_replace( '___', $i, $link_base ) . '">' . $i . '</a>';
}
}
// Ссылки с шагом.
$dd = 0;
if ( $rg->step_link && $end_page < $max_page ) {
for ( $i = $end_page + 1; $i <= $max_page; $i ++ ) {
if ( 0 === $i % $rg->step_link && $i !== $rg->num_pages ) {
if ( 1 === ++ $dd ) {
$els[] = '<span class="extend">' . $rg->dotright_text2 . '</span>';
}
$els[] = '<a href="' . str_replace( '___', $i, $link_base ) . '">' . $i . '</a>';
}
}
}
// В конец.
if ( $end_page < $max_page ) {
if ( $rg->dotright_text && ( $max_page - 1 ) !== $end_page ) {
$els[] = '<span class="extend">' . $rg->dotright_text2 . '</span>';
}
$els['last'] = '<a class="last" href="' . str_replace( '___', $max_page, $link_base ) . '">' . ( $rg->last_page_text ?: $max_page ) . '</a>';
}
// Вперед.
if ( $rg->next_text && $paged !== $end_page ) {
$els['next'] = '<a class="next" href="' . str_replace( '___', ( $paged + 1 ), $link_base ) . '">' . $rg->next_text . '</a>';
}
$els = apply_filters( 'kama_pagenavi_elements', $els );
$out = $rg->before . '<div class="wp-pagenavi">' . implode( ' ', $els ) . '</div>' . $rg->after;
$out = apply_filters( 'kama_pagenavi', $out );
if ( $rg->echo ) {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $out;
} else {
return $out;
}
return '';
}
}
new SO_Ajax_Pagination();
В этой же папке создайте файл so-ajax-pagination.js со следующим содержимым:
/* global SOAjaxPaginationObject */
jQuery( document ).ready(
function( $ ) {
function onCLick( event ) {
event.preventDefault();
var cat_section = event.target.closest( '.services__tab-item' );
var termId = $( cat_section ).data( 'cat' );
var href = event.target.href;
var page = href.split( '/page/' )[ 1 ];
page = page ? page : '1';
page = page.split( '/' )[ 0 ];
$.post(
SOAjaxPaginationObject.ajaxURL,
{
action: SOAjaxPaginationObject.action,
nonce: SOAjaxPaginationObject.nonce,
termId: termId,
page: page,
url: SOAjaxPaginationObject.url
},
function( response ) {
$( cat_section ).html( response.data );
$( '.wp-pagenavi' ).click( onCLick );
}
)
.fail(
function( response ) {
alert( response.data );
}
);
return false;
}
$( '.wp-pagenavi' ).click( onCLick );
}
);
Активируйте новый плагин So Ajax Pagination.
В контент нужной страницы добавьте шорткод [services_cat]. Откройте эту страницу и убедитесь, что код работает.