The code in this article is considered a customisation. It's provided as is, without guarantees or support. Should you need assistance implementing the code, please feel free to contact us to request a consultation.
When the "hide unavailable products" option is enabled, the Prices by Country plugin hooks into the product_is_visible filter provided by WooCommerce to change the visibility of products dynamically. The counters displayed on the catalogue page may be generated by calling raw database queries, which don't trigger such filter. Due to that, the queries might return the total of all products found, whether they are visible or not, and show more pages than should be displayed if the invisible products were taken into account.
The code below shows how this behaviour can be rectified, by altering how the posts are retrieved to populate the catalogue. To use the code, simply add it to your theme's functions.php file. See How to Safely Add Custom Code to WordPress Sites for more information on how to do that.
Code example - Alter the counters and pagination elements on WooCommerce catalogue pages
/** * Alters the number of posts founds by the main WooCommerce query, to exclude * products that are not visible. The function also removes invisible products * from the result and corrects the totals for the pagination function. * * @param int found_posts * @param WP_Query wp_query * @return int */ add_filter('found_posts', function($found_posts, $wp_query) { if(!is_shop() || !$wp_query->is_main_query()) { return $found_posts; } // Loop through all products to find the not visible ones. This is the only // way to get an accurate count foreach($wp_query->posts as $idx => $post) { if(!wc_products_array_filter_visible(wc_get_product($post->ID))) { unset($wp_query->posts[$idx]); } } // Set the amount of found products (visible products only) $found_posts = count($wp_query->posts); $wp_query->set_found_posts($found_posts); // Set posts per page $posts_per_page = 12; $wp_query->set('posts_per_page', $posts_per_page); // Extract the posts that should be displayed for current page $current_page = max(max(1, get_query_var('paged')) - 1, 0); $wp_query->posts = array_slice($wp_query->posts, $current_page * $posts_per_page, $posts_per_page); // Reset the array index $wp_query->posts = array_values($wp_query->posts); // Set the counter of visible pages $wp_query->max_num_pages = (int)ceil($found_posts / $posts_per_page); return $found_posts; }, 10, 2); /** * Removes the "posts per page" limit, to allow fetching all posts. This is * necessary to be able to check the visibility of each product. * * @param WP_Query wp_query */ add_action('pre_get_posts', function($wp_query) { if(!is_shop()) { return; } // Remove the "posts per page" to fetch all posts. This will allow to check // which products are not visible if($wp_query->is_main_query()) { $wp_query->set('posts_per_page', '-1'); } }, 100, 1);
Important - Read before using the code
- This code is provided as an example, to be used as a reference and adapted to your specific site. As indicated at the beginning of the article, it's provided as is, and it's not covered by our support service.
- The only way to determine if a product is visible for a user is to perform such check on a product by product basis. This operation requires a significantly heavier processing than the normal queries used on the WooCommerce catalogue.
We strongly recommend to test the code on a development copy of your site before deploying it on a production site.
You can purchase the Prices by Country plugin from our online shop.