I think that we were not handling this problem in the right way. We first tried to handle the reload page by relying on $_GET. And then we tried to handle the AJAX case. I believe we should handle the AJAX way first, and then we may find a way for the page reload case.
I discussed this with the team and run a test locally and I believe we found a way to get to what you want.
The solution relies on a hidden field inside the filters that will hold the number of posts per page, a shortcode that will get the number posts per page, and finally the hook into the query to change its number of posts per page.
First, we added a hidden field inside the filters and we named it "pager", then we added a special class to it "js-wpv-filter-trigger", which will let Toolset integrate the value of the hidden field into the AJAX call form data.
We then created a custom shortcode to get the "number of posts per page" from the AJAX form data or from the $_GET object.
add_shortcode('pager', 'my_pager_func');
function my_pager_func(){
$default_pager = 2;
if ( wp_doing_ajax() ) {
$filters = $_POST['search']['dps_general'];
foreach( $filters as $filter ) {
if ( $filter['name'] == 'pager' ) return (int) $filter['value'];
}
return $default_pager;
return print_r( $filters, true);
} else {
return isset( $_GET['pager'] ) ? (int) $_GET['pager'] : $default_pager;
}
}
We use this shortcode to populate the value of the hidden field:
<input type="hidden" name="pager" value=[pager] class="js-wpv-filter-trigger" />
Please not that the shortcode is not wrapped in single or double quotes
Then we can use it, and its function "my_pager_func" inside of our hook:
add_filter('pre_get_posts','func_include_child_terms',999);
function func_include_child_terms( $query ) {
if ( $query->is_main_query() and $query->is_tax( 'product_cat' ) ) {
$pager = my_pager_func();
if ( $pager > 0 ) {
$query->set( 'posts_per_page', $pager );
}
}
return $query;
}
Please note that we do not rely on is_admin() as it will always return true for AJAX calls
Bonus
By implementing this solution, we can integrate the buttons for the number of posts per page directly into our view without having to fully reload the page. It will require custom Javascript code that will prevent the page from reloading, takes the value of the number of posts per page, enters it into the hidden field, then triggering a change on a filter so the view will trigger an AJAX reload.
Check this pseudo code:
jQuery('.per-page a').off('click').on('click', function(event){
event.preventDefault();
var link = jQuery(this);
var nposts = link.data('pager');
var pager = jQuery('input[name="pager"]');
pager.val(nposts);
jQuery('#pa_brand-airav').trigger('change')
})
This code needs to be run at the first-page load and after each AJAX call, especially, when the search is performed or when pagination completes.
The complete Javascript code is:
function ajax_reload_with_pager(){
jQuery('.per-page a').off('click').on('click', function(event){
event.preventDefault();
var link = jQuery(this);
var nposts = link.data('pager');
var pager = jQuery('input[name="pager"]');
pager.val(nposts);
jQuery('#pa_brand-airav').trigger('change');
})
}
// execute code when the page loads
jQuery(function(){
ajax_reload_with_pager();
})
// when pagination completes.
jQuery( document ).on( 'js_event_wpv_pagination_completed', function( event, data ) {
ajax_reload_with_pager();
});
// when search results are loaded
jQuery( document ).on( 'js_event_wpv_parametric_search_results_updated', function( event, data ) {
ajax_reload_with_pager();
});
I already implemented this for you. Please test your archive page and let me know if we missed something.