This bug was introduced in #26260. The sequence is:
1. WC_Query::adjust_posts_count runs, to handle found_posts filter,
this indirectly executes wc_setup_loop.
2. At this point $GLOBALS['wp_query']->max_num_pages hasn't been set
yet, and has a value of 0. Thus the loop variable total_pages
is set to 0.
3. Later wc_setup_loop runs again and this time
$GLOBALS['wp_query']->max_num_pages is already set, but since
the loop variable total_pages already exists, it keeps its
value of 0.
4. The pagination controls never show if total_pages is less than 2.
The fix consists of hooking into the_posts to set the value of
total_pages again, at that point $GLOBALS['wp_query']->max_num_pages
is already set.
PR #26260 introduced a handler for 'found_posts' filter in WC_Query
class in order to adjust the count depending on the visibility
of variation products. However the handler incorrectly assumed
that the filter was triggered only when listing products, when
actually it's also triggered for any post type e.g. pages.
In these cases the post count was set to zero, which caused bugs.
Now the handler starts with the originally supplied posts count,
and only decrements it when a post is a product AND is not visible.
Two adjustments were needed:
- Adjust the count even when there's no nav filtering in the query.
This is necessary to present the proper products count.
even when the woocommerce_product_is_visible filter is used.
- Account for the case where $GLOBALS['wp_query']->posts
returns objects instead of ids (for example when viewing
a product page).
The layered nav filtering doesn't work well with variable products
when some variations have stock and other don't. When a term is
selected in the widget, a variable product having no stock for
the variation corresponding to that term but having stock for
other variations will be displayed, but it shouldn't.
This commit fixes that by introducing two changes:
- A new override of "is_visible" for WC_Product_Variable that
looks at the supplied filters, compares them against the corresponding
available variations and calculates the visibility based on
the query type (OR or AND).
- A hook on the "found_posts" filter in WC_Query, that adjusts
the posts count based on the found products visibility
when there are filters available; this is needed to sync the
"displaying X posts" messages and the paging when variable
products are hidden due to stock status.
Additionally, the visibility calculated in "found_posts" is cached
as loop variables so that it isn't calculated again when actually
displaying the products.
- Add methods to temporarily disable and reenable the code hacker.
The code hacker is causing issues in some tests that perform
write operations to the local filesystem. Since this happens only
in a few cases, the easiest fix is to temporarily disable the
code hacker when that happens. This commit adds two new methods
for that in `WC_Unit_Test_Case`: `disable_code_hacker` and
`reenable_code_hacker`.
These methods use a disabling requests count so that the hacker
isn't enabled before it should. E.g. you call `disable`, then
a helper method that does `disable` and `enable`, then `enable` -
then only the last `enable` will have effect.
- `CodeHacker::add_hack` has now a boolean `persistent` parameter.
Persistent hacks won't be cleared by `clear_hacks`.
- `CodeHackerTestHook::executeAfterTest` will now disable the hacker
only if no persistent hacks are registered.
- The existing `file_copy` method is made static for consistency.
- `CodeHacker::restore` method renamed to `disable` for clarity.
- Fix how CodeHackerTestHook::executeBeforeTest parses the test name,
to account for warnings and tests with data sets.
- CodeHackerTestHook now includes a executeAfterTest hook that
disables the code hacker (needed to prevent it from inadvertently
altering further tests). Also, clear_hacks is executed in
executeBeforeTest for the same reason.
- CodeHacker gets restore, clear_hacks and is_enabled methods
to support the changes in CodeHackerTestHook.
- FunctionsMockerHack fixed so that it doesn't modify strings
that are class method definitions.
- Added the WC_Unit_Test_Case::file_copy method, it must be used
instead of the PHP built-in "copy" in tests, otherwise tests
that run with the code hacker active will fail.
This is something to investigate.