Альтернатива фукнции пагинации paginate_links()

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

/**
 * Generates array of pagination links.
 *
 * @author Kama (wp-kama.com)
 * @varsion 2.5
 *
 * @param array $args {
 *
 *     @type int    $total        Maximum allowable pagination page.
 *     @type int    $current      Current page number.
 *     @type string $url_base     URL pattern. Use `{pagenum}` placeholder.
 *     @type string $first_url    URL to first page. Default: '' - taken automaticcaly from $url_base.
 *     @type int    $mid_size     Number of links before/after current: 1 ... 1 2 [3] 4 5 ... 99. Default: 2.
 *     @type int    $end_size     Number of links at the edges: 1 2 ... 3 4 [5] 6 7 ... 98 99. Default: 1.
 *     @type bool   $show_all     true - Show all links. Default: false.
 *     @type string $a_text_patt  `%s` will be replaced with number of pagination page. Default: `'%s'`.
 *     @type bool   $is_prev_next Whether to show prev/next links. « Previou 1 2 [3] 4 ... 99 Next ». Default: false.
 *     @type string $prev_text    Default: `« Previous`.
 *     @type string $next_text    Default: `Next »`.
 * }
 *
 * @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'    => '« Previous',
		'next_text'    => 'Next »',
	];

	$rg = (object) $args;

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

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

	// fix working parameters

	$rg->total = $total_pages;
	$rg->current = max( 1, abs( $rg->current ?: get_query_var( 'paged', 1 ) ) );

	$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 ){
		// /foo/page(d)/2 >>> /foo/ /foo?page(d)=2 >>> /foo/
		$rg->first_url = preg_replace( '~/paged?/{pagenum}/?|[?]paged?={pagenum}|/{pagenum}/?~', '', $rg->url_base );
		$rg->first_url = user_trailingslashit( $rg->first_url );
	}

	// core array

	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 ); // reset keys
	}

	// fill by core array

	$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 );

		// set dots
		$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] => « Previous
			[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] =>
		)

)
*/

Теперь используем эту функцию в цикле:

<?php

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

if( $links_data ){
	?>

	<ul>
		<?php foreach( $links_data as $link ) { ?>
		<li>
			<?php if ( $link->is_dots ) { ?>
				<span><?= $link->link_text ?></span>
			<?php } elseif ( $link->is_current ) { ?>
				<strong><?= $link->link_text ?></strong>
			<?php } else { ?>
				<a href="<?php esc_attr_e( $link->url ) ?>"><?php _e( $link->link_text ) ?></a>
			<?php } ?>
		</li>
		<?php } ?>
	</ul>

	<?php
}

Получим:

<ul>
	<li>
		<a href="http://site.com/page-name/paged/1">1</a>
	</li>
	<li>
		<strong>2</strong>
	</li>
	<li>
		<a href="http://site.com/page-name/paged/3">3</a>
	</li>
</ul>

Эта заметка встроена в: paginate_links()