Paginate Link generate additional #038; whenever my Url have multiple Query String

My generated paginate link results will have additional #038; in the url, may I know how to get rid of it?


Blog page url :
http://localhost/wordpress/blog/

I had already setup pagination with function paginate_links, when I press page [2] :

Blog page Page 2 url :
http://localhost/wordpress/blog/page/2/

( everything is fine above )


However, whenever my Blog page URL have certain parameters which is for my filter/sorting purposes for WP_Query, the paginate_link result will have additional #038 params , please refer below for the URL

Blog page with Params Url :
http://localhost/wordpress/blog/?filter=23&orderby=oldest

Blog page with Params Page 2 Url :
http://localhost/wordpress/blog/page/2/?filter=23&orderby=oldest#038;orderby=oldest


The URL I need to achieve is
http://localhost/wordpress/blog/page/2/?filter=23&orderby=oldest

below are my paginate_links functions:

global $wp_query;
$big = 99999999999;    

paginate_links([
    'base'      => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
    'format'    => '?paged=%#%',
    'prev_text' => __('<'),
    'next_text' => __('>'),
    'current'   => max( 1, get_query_var('paged') ),
    'type'      => 'list',
    'total'     => $wp_query->max_num_pages,
    ]);

2 s
2

There’s no need to escape the URL twice – get_pagenum_link() by default returns an escaped URL — when the second parameter is true, esc_url() is used; else, esc_url_raw() is used:

  • With esc_url(): http://localhost/wordpress/blog/?filter=23&orderby=oldest

  • With esc_url_raw(): http://localhost/wordpress/blog/?filter=23&orderby=oldest

And the problem occurs when the base contains ?, or a query string, and that the URL is escaped (e.g. using esc_url()).

Because esc_url() converts & (ampersand) to its HTML entity, which is &, and when the base contains a query string, paginate_links() will parse the base value/URL, and when the & is escaped, anything after each & and the nearest = is treated as a query string name/key, and added to the base‘s query string:

http://localhost/wordpress/blog/?filter=23&orderby=oldest#038;orderby=oldest

In the above example, the URL is like that because paginate_links() (or more precisely, wp_parse_str() used in paginate_links()) interpreted #038;orderby as the key of oldest; i.e. #038;orderby=oldest — it should be &orderby=oldest where the key is orderby.

(But of course, the browser sees anything after the # as a URL fragment. And if you follow the link, on the next page, $_GET will not have an entry for #038;orderby; i.e. $_GET['#038;orderby'] doesn’t exist.)

So here are several ways to fix/avoid the problem:

  1. Use html_entity_decode() just as WordPress does via paginate_links():

    'base' => str_replace( $big, '%#%', html_entity_decode( get_pagenum_link( $big ) ) )
    
  2. When you call get_pagenum_link(), set the second parameter set to false:

    'base' => str_replace( $big, '%#%', get_pagenum_link( $big, false ) )
    
  3. Use str_replace() to replace the & with &:

    'base' => str_replace( [ $big, '&' ], [ '%#%', '&' ], get_pagenum_link( $big ) )
    

Don’t worry about not escaping the base because paginate_links() actually escapes all the links/URLs in the returned result.

Friendly Warning: Some of the links in this answer point you to a huge HTML file / web page..

Leave a Comment