Paginate_links won’t create the right links on a taxonomy filtered custom post type archive

after hours and dozen of tests and messes… i’m face to the wall and fed up searching (mainly cuz my google’s answers are already all clicked !)

I’m trying to display paginate_link with a filters taxonomy form (AGAIN ????? ;).

With all solutions here, I’ve found how to get the right numbered pagination in a result of my form only on the first page of the results.

The main problem, is in the pagination links, they are using the wrong “$paged” and my filter are remove of the query (via tax_query=>….) on page/2 and the others following.

// In "archive-myCptSlug.php"
// Basicaly my genarated array of args (copy/paste of its var_dump() just before the query): 
//   $custom_query_args {
//     ["paged"]             => int(1)
//     ["posts_per_page"]    => int(3)
//     ["post_type"]         => array(1) { [0]=>string(7) "outings" }
//     ["relation"]          => string(3) "AND"
//     ["tax_query"]         => array(1) {
//                                [0]=> array(3) {
//                                   ["taxonomy"]    => string(16) "outings-category"
//                                   ["field"]       => string(4) "slug"
//                                   ["terms"]       => array(1) { [0]=> string(6) "cinema" }
//                                }
//                              }
//   }

    $custom_query_args = array( /* Parameters go here */ );
    $custom_query_args['paged'] = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
    $custom_query_args['posts_per_page'] = 3;
    $custom_query_args['post_type'] = array( 'outings');
    $custom_query_args['relation'] = 'AND';
    $custom_query_args_tax = array(); // filled with form

    $custom_query = new WP_Query( $custom_query_args );

    // A part of a solution seems to "assimilate" the custom query to the main one, so let's try
    // Backup -> Null -> replace
    $temp_query = $wp_query;
    $wp_query = null;
    $wp_query = $custom_query;

    //then some stuff
    if ( $custom_query->have_posts() ) :
        while ( $custom_query->have_posts() ) :
            $custom_query->the_post();
               // "Hello world"
        endwhile;
    endif;
    wp_reset_postdata();

    // PAGINATE LINKS
    $big = 999999999; // need an unlikely integer
    echo paginate_links( array(
        'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
        'format' => '?paged=%#%',
        'current' => max( 1, get_query_var('paged') ),
        'total' => $custom_query->max_num_pages
    ) );

    // RESTORE WP QUERY
    $wp_query = NULL;
    $wp_query = $temp_query;
  • It’s a lot based on WPSE 120407
    How to fix pagination for custom loops?
  • The filename used is “archive-outings.php”
  • Permalinks are saved each time
  • Settings > reading > numbers of posts > “10”
  • The ‘outings-category’ is use as taxonomy instead of WP category, it’s on purpose.

Result ?

  • The first page is looking good with filtered items from “cinema”.
  • There is 3 elements on the page as asked in custom query
  • The numbered pagination is good with the right “max-pages” number

The problem

  • If, for example, I click on the “2”, the page loaded as removed my taxonomy filter(s) and paginate navigation “max-page” looks like (seems to be) the number of pages non filtered by taxonomy (probably due to the use of the “archives-myCptSlug.php” template).

Solution(s) ?

  • I’ve tryed so much solutions…
  • I don’t want use a Settings > reading > numbers of posts set to 1 (I’ve made it works once) mainly because i will never remeber why I’ve done this in the future.
  • This doesn’t looks to works for me (or i don’t know how to use it, because I don’t use category – sorties was the wrewrite term but I’ve tried outings which is the name of my CPT):
    function my_pagination_rewrite() {
        add_rewrite_rule('sorties/page/?([0-9]{1,})/?$', 'index.php?category_name=blog&paged=$matches[1]', 'top');
    }
    add_action('init', 'my_pagination_rewrite');
  • This neither :
    function wpse120407_pre_get_posts( $query ) {
        // Test for category archive index
        // and ensure that the query is the main query
        // and not a secondary query (such as a nav menu
        // or recent posts widget output, etc.
        if ( is_archive() && $query->is_main_query() ) {
            // Modify posts per page
            $query->set( 'posts_per_page', 5 ); 
        }
    }
    add_action( 'pre_get_posts', 'wpse120407_pre_get_posts' );

UPDATE

My form is include with get_template_part :

    <form class="categorie-form" id="outingsFilterForm" role="categorie" action="http://thela.local:8888/eventspage" method="post" accept-charset="UTF-8" target="_self">
    
                <fieldset>
    
                    <legend>Filtres</legend>
    
            <!-- FILTERS ITEM : CATEGORIES -->
    
                    <div class="filterCategorie">
    
                <?php foreach ($termsAllForCategory as $keyCat => $valueCat) : ?>
    
                        <label>
                            <span><?php echo $valueCat->name . " (" . $valueCat->count . ")"; ?></span>
    
                    <?php if ( isset( $postedCategory ) && $postedCategory != "" ) : ?>
    
                        <?php if ( in_array($valueCat->slug, $postedCategory) ) : ?>
                            <input type="checkbox" name="categorie[]" value="<?php echo esc_attr($valueCat->slug); ?>" checked />
                        <?php else: ?>
                            <input type="checkbox" name="categorie[]" value="<?php echo esc_attr($valueCat->slug); ?>" />
                        <?php endif; ?>
    
                    <?php else: ?>
                            <input type="checkbox" name="categorie[]" value="<?php echo esc_attr($valueCat->slug); ?>" checked />
                    <?php endif; ?>
    
                        </label>
    
                <?php endforeach; ?>
    
                    </div>
    
            <!-- FILTERS ITEM : VILLE -->
    
    
                    <div class="filterCategorie">
    
                        <label>
                            <select name="city" id="city" class="select-css">
                        <?php if ( (isset($postedCity) && $postedCity != "") || (isset($favoriteCity) && $favoriteCity != "") ) : ?>
                                <option value="" ><?php _e('All outings cities', 'thela'); ?></option>
                        <?php else : ?>
                                <option value="" selected="selected"><?php _e('All outings cities', 'thela'); ?></option>
                        <?php endif; ?>
    
                        <?php $onceIsHere = ""; ?>
    
                        <?php foreach ($termsAllForCity as $key => $value) : ?>
    
                            <?php if ( $postedCity == $value->slug || $favoriteCity == $value->slug) : ?>
                                <?php $onceIsHere = ( isset($favoriteCity) )? "checked" : "" ?>
                                <option value="<?php echo esc_attr($value->slug); ?>" selected="selected"><?php echo esc_html($value->name); ?> (<?php echo esc_html($value->count); ?>)</option>
                            <?php else : ?>
                                <option value="<?php echo esc_attr($value->slug); ?>"><?php echo esc_html($value->name); ?> (<?php echo esc_html($value->count); ?>)</option>
                            <?php endif; ?>
    
                        <?php endforeach; ?>
                            </select>
                        </label>
    
                    </div>
    
                    <button type="submit"><?php esc_html_e("Display result(s)", "thela"); ?><span></span></button>
    
                </fieldset>
    
                </form>

The actual outings-archive.php is like so :

  • Header

  • Custom code for $_POST vars (obviously to feed Query args Array)

  • get_template_part(‘outings’, ‘filters’, $getTemplateVars );
    (here is loaded the filters form with inside)

  • get_template_part(‘outings’, ‘header’, $getTemplateVars );
    (here is loaded the “resume of the query”)

  • wp_query request

  • if / while / $the_post

  • enfwhile / endif

  • wp_reset_postdata;

  • paginate_links

  • $wp_query = NULL;

  • $wp_query = $temp_query;

  • Footer

In order to help -or not-, i’ve found this thread where he could make it works by calling paginate_links in “success” of its ajax function. (he try the same but in ajax).

https://grafikart.fr/forum/23564

JSFIDDLE

  • The custom post type & taxonomy(s) function(s) :
    https://jsfiddle.net/gelcin/8hx5vqe4/1/
  • The Filters block inserted througth get_template_file :
    https://jsfiddle.net/gelcin/myodq3up/
  • The header of the page content (outings-header.php, resume of informations selected in filter form) inserted througth get_template_file :
    https://jsfiddle.net/gelcin/wmgr5s20/1/

FINALY (or close to)

Thanks Sally-CJ
https://wordpress.stackexchange.com/users/137402/sally-cj
As soon as can vote, i do it one for you.

I could get rid of My problem Because of 2 main things :

  • Using $_POST instead of $_GET for my filters form
  • Using pre_get_posts to modify WP_Query looks better than making a custom query

Thanks for help !
Nicolas.

1 Answer
1

If, for example, I click on the “2”, the page loaded as removed my
taxonomy filter(s) and paginate navigation “max-page” looks like
(seems to be) the number of pages non filtered by taxonomy

It’s not that the (taxonomy) filters are removed from the pagination links, but instead, the filters are actually never added because the form data is being submitted using the (HTTP) POST method, hence paginate_links() does not read the data (the function only parses data in the URL query string) and therefore does not add the filters into the pagination links.

And you could manually add the filters by using the add_args argument in the first (and the only) parameter for paginate_links(), but instead of having to set that argument, it’s actually simpler if you just set your form’s method to get — that way, the browser will automatically add the filters as query string in the form’s action URL and so paginate_links() will also then add the filters into the pagination links.

<form class="categorie-form" id="outingsFilterForm" role="categorie"
    action="http://thela.local:8888/eventspage" method="get"
    accept-charset="UTF-8" target="_self">

However, if the form uses the GET method, then in your outings-archive.php (post type archive) template, you’ll need to make sure the filters are read from $_GET. E.g.

// Note: Here I'm using the PHP 7's null coalescing operator (the "??" symbol).
$getTemplateVars['postedCategory'] = (array) ( $_GET['categorie'] ?? array() );
$getTemplateVars['postedCity']     = $_GET['city'] ?? '';

So apply those two changes (set the form’s method to get and use the above PHP code to read the submitted data) and check if the pagination links now includes the filters from your form.

The actual outings-archive.php is like so :

If you use the same code in a page template, then the “wp_query request” part in your code is fine.

However, on the post type archive page (e.g. the one you’ve got at /sorties), you shouldn’t be making the secondary WP_Query request because pagination will conflict with the one for the main WordPress query which runs on page load (before the archive template is loaded).

  • E.g. If your custom/secondary WordPress query had 3 (max number of) pages, yet the main query had only 2 pages, then going to page 3 would result in the error 404 (“not/nothing found”).

  • Therefore, your archive template should just display the posts in the main loop/query. I.e. Without the “wp_query request“, “$wp_query = NULL;” and “$wp_query = $temp_query;” parts..

Nonetheless, for now, just apply the two changes I said earlier above and see how things goes. 🙂

Leave a Comment