Альтернатива paginate_links() для постраничной навигации

Альтернатива функции paginate_links() для постраничной навигации

Функция paginate_links() всегда возвращает HTML-код. Даже если вы укажете параметр type=array, в результате получите массив готовых тегов <a>. Это может не подойти, если вам нужно полностью изменить структуру HTML для постраничной навигации. Ниже приведена небольшая функция, которая возвращает массив объектов вместо HTML.

Функция для генерации ссылок постраничной навигации

/**
 * Генерирует массив ссылок для постраничной навигации.
 *
 * @param array $args {
 *
 *     @type int    $total        Максимально допустимое количество страниц.
 *     @type int    $current      Номер текущей страницы.
 *     @type string $url_base     Шаблон URL. Ис��ользуйте {pagenum} в качестве заглушки.
 *     @type string $first_url    URL для первой страницы. По умолчанию: '' - автоматически берётся из $url_base.
 *     @type int    $mid_size     Количество ссылок до и после текущей: 1 ... 1 2 [3] 4 5 ... 99. По умолчанию: 2.
 *     @type int    $end_size     Количество ссылок в начале и в конце: 1 2 ... 3 4 [5] 6 7 ... 98 99. По умолчанию: 1.
 *     @type bool   $show_all     true - Показывать все ссылки. По умолчанию: false.
 *     @type string $a_text_patt  %s будет заменено на номер страницы. По умолчанию: '%s'.
 *     @type bool   $is_prev_next  Нужно ли показывать ссылки на предыдущую и следующую страницы. По умолчанию: false.
 *     @type string $prev_text    По умолчанию: « Предыдущая.
 *     @type string $next_text    По умолчанию: Следующая ».
 * }
 *
 * @return array
 */
function kama_paginate_links_data( array $args ): array {
    global $wp_query;

    // Устанавливаем значения по умолчанию
    $args += [
        'total'        => 1,
        'current'      => 0,
        'url_base'     => '/{pagenum}',
        'first_url'    => '',
        'mid_size'     => 2,
        'end_size'     => 1,
        'show_all'     => false,
        'a_text_patt'  => '%s',
        'is_prev_next' => false,
        'prev_text'    => '« Предыдущая',
        'next_text'    => 'Следующая »',
    ];

    $rg = (object) $args;

    $total_pages = max( 1, (int) ( $rg->total ?: $wp_query->max_num_pages ) );

    if( $total_pages === 1 ){
        return [];
    }

    // Корректируем параметры
    $rg->total = $total_pages;
    $rg->current = max( 1, abs( $rg->current ?: get_query_var( 'paged', 1 ) ) );

    // Определяем базовый URL
    $rg->url_base = $rg->url_base ?: str_replace( PHP_INT_MAX, '{pagenum}', get_pagenum_link( PHP_INT_MAX ) );
    $rg->url_base = wp_normalize_path( $rg->url_base );

    if( ! $rg->first_url ){
        $rg->first_url = preg_replace( '~/paged?/{pagenum}/?|[?]paged?={pagenum}|/{pagenum}/?~', '', $rg->url_base );
        $rg->first_url = user_trailingslashit( $rg->first_url );
    }

    // Основной массив
    if( $rg->show_all ){
        $active_nums = range( 1, $rg->total );
    }
    else {
        // Расчет активных номеров
        if( $rg->end_size > 1 ){
            $start_nums = range( 1, $rg->end_size );
            $end_nums = range( $rg->total - ($rg->end_size - 1), $rg->total );
        }
        else {
            $start_nums = [ 1 ];
            $end_nums = [ $rg->total ];
        }

        $from = $rg->current - $rg->mid_size;
        $to = $rg->current + $rg->mid_size;

        if( $from < 1 ){
            $to = min( $rg->total, $to + absint( $from ) );
            $from = 1;
        }
        if( $to > $rg->total ){
            $from = max( 1, $from - ($to - $rg->total) );
            $to = $rg->total;
        }

        $active_nums = array_merge( $start_nums, range( $from, $to ), $end_nums );
        $active_nums = array_unique( $active_nums );
        $active_nums = array_values( $active_nums ); // Обнуляем ключи
    }

    // Заполнение основного массива
    $pages = [];

    if( 1 === count( $active_nums ) ){
        return $pages;
    }

    // Функция для получения информации о странице
    $item_data = static function( $num ) use ( $rg ){
        $data = [
            'is_current'   => false,
            'page_num'     => null,
            'url'          => null,
            'link_text'    => null,
            'is_prev_next' => false,
            'is_dots'      => false,
        ];

        if( 'dots' === $num ){
            return (object) ( [
               'is_dots' => true,
               'link_text' => '…',
            ] + $data );
        }

        // Проверка на предыдущую и следующую страницы
        $is_prev = 'prev' === $num && ( $num = max( 1, $rg->current - 1 ) );
        $is_next = 'next' === $num && ( $num = min( $rg->total, $rg->current + 1 ) );

        $data = [
            'is_current'   => ! ( $is_prev || $is_next ) && $num === $rg->current,
            'page_num'     => $num,
            'url'          => 1 === $num ? $rg->first_url : str_replace( '{pagenum}', $num, $rg->url_base ),
            'is_prev_next' => $is_prev || $is_next,
        ] + $data;

        if( $is_prev ){
            $data['link_text'] = $rg->prev_text;
        }
        elseif( $is_next ) {
            $data['link_text'] = $rg->next_text;
        }
        else {
            $data['link_text'] = sprintf( $rg->a_text_patt, $num );
        }

        return (object) $data;
    };

    foreach( $active_nums as $indx => $num ){
        $pages[] = $item_data( $num );

        // Установка точек
        $next = $active_nums[ $indx + 1 ] ?? null;
        if( $next && ($num + 1) !== $next ){
            $pages[] = $item_data( 'dots' );
        }
    }

    if( $rg->is_prev_next ){
        $rg->current !== 1 && array_unshift( $pages, $item_data( 'prev' ) );
        $rg->current !== $rg->total && $pages[] = $item_data( 'next' );
    }

    return $pages;
}

Пример работы функции

$links_data = kama_paginate_links_data( [
    'total'    => 3,
    'current'  => 2,
    'url_base' => 'http://site.com/page-name/paged/{pagenum}',
    'mid_size' => 2,
] );

print_r( $links_data );

/*
Array
(
    [0] => stdClass Object
        (
            [is_current] =>
            [page_num] => 288
            [url] => http://site.com/page-name/paged/288
            [is_prev_next] => 1
            [link_text] => « Предыдущая
            [is_dots] =>
        )
    [1] => stdClass Object
        (
            [is_current] =>
            [page_num] => 1
            [url] => http://site.com/page-name/
            [is_prev_next] =>
            [link_text] => 1
            [is_dots] =>
        )
    [2] => stdClass Object
        (
            [is_dots] => 1
            [link_text] => …
            [is_current] =>
            [page_num] =>
            [url] =>
            [is_prev_next] =>
        )
    [3] => stdClass Object
        (
            [is_current] =>
            [page_num] => 285
            [url] => http://site.com/page-name/paged/285
            [is_prev_next] =>
            [link_text] => 285
            [is_dots] =>
        )
    [4] => stdClass Object
        (
            [is_current] =>
            [page_num] => 286
            [url] => http://site.com/page-name/paged/286
            [is_prev_next] =>
            [link_text] => 286
            [is_dots] =>
        )
    [5] => stdClass Object
        (
            [is_current] => 1
            [page_num] => 287
            [url] => http://site.com/page-name/paged/287
            [is_prev_next] =>
            [link_text] => 287
            [is_dots] =>
        )
)
*/

Использование функции в цикле

 3,
    'current' => 2,
    'url_base' => 'http://site.com/page-name/paged/{pagenum}',
] );

if( $links_data ){
    ?>

    

    

Результат работы

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

Leave a Reply

Ваш адрес email не будет опубликован. Обязательные поля помечены *