- Passing a string that represents a number but has spaces (e.g. ' 1 ')
now works as expected (the number is properly interpreted)
- Passing the boolean true now returns 1, not 0
- Passing an object throws an error, instead of returning 0
After the League's Container package has been reintroduced, all the
code that implements the dependency injection mechanism in woocommerce
can be brought back as well.
The assertion is useless (the constant is already tested a few Lines
above), and it was failing in PHP 8 because 'auto' < 2 is evaluated
as false, while it's evaluated to true in PHP 7.
In PHP 8 required parameters after optional parameters in
function/method signatures trigger a deprecation notice. These type
of parameters are pointless since a value needs to always be
provided for them anyway, so they are actually de-facto required.
This commit converts all these not-so-optional parameters into
truly required parameters by removing their default values.
There's a number of places in the WooCommerce codebase where the
built-in function 'round' is executed passing a non-numeric value
(not a number and not a string that can be parsed as a number),
for example round(''). In PHP 7 this yields a value of 0, but in
PHP 8 this throws an error.
This commit adds a 'NumberUtil' class with a static 'round' method,
this method checks if the passed value is numeric and if so it just
executes the built-in function, otherwise it returns 0. And all the
calls to 'round' in the codebase are replaced with 'NumberUtil::round'.
A mechanism for improved filtering by attribute for variations was
introduced some time ago. This mechanism implied maintaining term
relationships for variations, where the terms were the attributes
that defined the variation.
The mechanism was reverted because it was complex and presented many
issues, but the code that created those term relationships was kept.
This pull request removes that code and the associated unit tests.
Since it's possible that the latest git tag isn't a Docker page we should get the latest version directly from Docker instead. This commit adds support for the `/v2/repositories/library/<image>/tags` endpoint and figures out the latest version from the response.
This commit reverts the functionality introduced in PR #26260
(later refined by #27175, #27190, #27508) in which filtering by
attribute using the layered nav widget was improved to handle the
cases of variations out of stock. The revert is a response to the
numerous problems reported by users in Woo 4.4 and 4.5
Not all the code has been reverted, only the code that resulted in
visible functionality changes. Thus, the code that generates
term relationships for variations is still in place to keep database
consistency and to keep the reverting changes to the minimum needed.
Since we're going to be adding more services and CRUD actions it makes sense for our HTTP services to be less tied to the specific REST API implementation.
The new query fixes a bug where variations were being counted twice:
if a product was included in both the queries then it would be counted
differently and added; e.g. when a product had two variations,
one with "Any" attribute and other with a attribute that has a value.
The new query also optimizes performance, so that filter conditions
can be improved and better indexes can be used.
The new query doesn't need empty attribute entries in the meta table,
therefore the code that generates them and the migration to backfill
the missing existing ones have been removed.
Right now the filter by attributes widget counts available variations
(for variation products). This is confusing since the counter shows
numbers that are higher than the actual count of products displayed.
This commit changes the query used by the widget so that instead
of counting variations it returns the parent product ids, and then
counts the distinct values. This also covers the case of products
where some of the variations have concrete values and some have
"Any..." values.
When a new variation attribute is added, the corresponding 'attribute_'
meta entries are added for all variations with an empty value;
and when an existing variation attribute is removed, the existing
'attribute_' meta entries are deleted for all variations.
This is necessary for the filter by attribute widget to work properly
when variations exist with a value of "Any..." for attributes.
When a variation product has an attribute with a value of "Any...",
and there's a filter by attribute widget for that attribute, then
that product won't be included in the counts displayed in the widget
(and if the count ends up being zero, the attribute won't be shown
in the widget).
This happens before since Woo 4.4, this widget works by looking at
entries in the term relationships table for varitions too
(used to do so for simple products and for "main" variable products
only), see PR #26260; but there are no such entries for
"Any..." attributes.
This commit fixes that by extending the SQL query used by the widget
to look for variations that have empty attribute values in the meta
table too.
Since reverting the PR at this point would be a mess I've gone ahead and removed the internals of the container. We should aim to keep the class since it's now part of our public API but it won't work as expected anymore. This is fine for now since we don't actually have anything in it!
1. Since our code style dictates that these be `final` methods, we shouldn't be concerned about overlap.
2. There is precedent for `init` methods as requirements before using class instances.
Since we need to maintain backwards compatibility for class constructors we should settle on using method injection instead of constructor injection. I've replaced the `Definition` class we're using with one that doesn't support constructor arguments and added a check for auto_arg addition. Note that we don't check for method existence in the extended container. This is because reflection is unnecessarily expensive and we should avoid it if at all possible.
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.
Now, if there are filters present the logic is as follows:
- For multiple filtering values of the same attribute:
the product is visible if there's at least one variation
that has one of the filtering values associated to the attribute,
or if there's at least one variation having the attribute
with a value of "Any".
- For filtering by more than one attribute:
the product is visible if there's at least one variation that
is visible for ALL the attributes according to the above rule.
Note that this is irrespective of the type of logic configured for
the filter (OR or AND).
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).
After the change that registers variation attributes as terms
(in addition to reigstering them as post meta) it is now time
to modify the get_filtered_term_product_counts methods in
WC_Widget_Layered_Nav so that it works consistently for both
variable and non-variable products. The logic for the counters
is now as follows:
with OR operator:
- Simple products: count the attributes of all visible products
(unchanged behavior).
- Variable products: count attributes corresponding to
visible variations.
with AND operator:
- Simple products: count the attributes of visible products but only
for products that have all the selected (unchanged behavior).
- Variable products: find all the products for which all the variations
corresponding to the selected attributes exist and are visible,
then count the attributes corresponding to the visible variations
of those products.
A product is "visible" if it's published, not excluded for catalog,
and has stock. Additionally, a variable product will not be considered
visible if the parent product is not.
Product attributes are currently recorded as terms in
wp_term_relationships (product attributes are actually taxonomies).
In the case of variable products this is true for the main product,
but not for the variations. The attributes used to define variations
are stored as post meta, but nothing is recorded in the term
relationships table.
This is a problem when using the layered nav filtering plugin,
since the attribute counters displayed are calculated based solely
on the contents of the term relationships table. Adding meta queries
would be really messy (especially when the widget is configured
with AND operator) and would probably also hurt performance.
This commit adds a change to store the attributes for variations
as term relationships, additionally to storing them as post meta.
Terms are stored on variation creation, and updated/deleted together
with the variation as appropriate. "Any" variations (stored in meta
as empty values) are not stored as terms.
Additionally, a database upgrade is included in order to backfill
terms for already existing products.
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.
It is possible for a later duplicate webhook to be fired too early if
the same webhook triggers in one request more than once with the updated
changes from the second one missing if it happens too quickly.
This queues all webhook to be register on shutdown instead of just
syncronous ones to make sure all data from the request is updated first
before the webhook gets queued.
test_static_mocks_can_be_used_via_injected_legacy_proxy_and_woocommerce_object
was failing in PHP 7.0, this replacement fixes it.
Suspected cause: https://bugs.php.net/bug.php?id=76505
- src/README.md largely expanded
- tests/README.md expanded
- includes/README.md added
- src/Internal/REAMDE.md added
src/README.md and includes/README.md have TODO placeholders to add
guidelines regarding to actions and filters.
If a class name is passed as a concrete, check that the class
constructor is public if it exists. If another type of concrete is
passed, check that it's valid (a callback or an object).
Also update the autoloader to check if the class file exists,
otherwise class_exists fails if a namespaced class doesn't exist.
The following methods are added and can be invoked using `WC()`,
they just redirect to the same methods in LegacyProxy:
call_function
call_static
get_instance_of
Since we need to load all of these files before WooCommerce has initialized we can't rely on Composer to handle the autoloading. We should take this namespace out of Composer altogether and just have our test autoloader take care of it.
- Method and class renames.
- Removed unnecessary autoloader registration.
- Add a unit test for classes with non-object type hints
in constructor arguments.
- `get_instance_of` accepts now arguments to be passed to the
class constructor if necessary.
- `get_special_instance_of` method removed, instead, now if a method
named `get_instance_of_<lowercased class name>` exists in the class,
it is used to get the instance of the class.
- A couple more unit tests added.
Also:
- Make the methods in `AbstractServiceProvider` protected.
- Add an autoloader for files in the `tests/php/src` directory.
- Fix a bug in the provisional (?) autoloader.
- camelCase methods changed to snake_case for consistency with WP.
- Added a check in `ExtendedContainer::get` that throws an informative
exception if a non-namespaced class name is passed.
- `container->reset_resolved()` is called during unit testing bootstrap.
- Added some utility methods in `WC_Unit_Test_Case`.
- Added a new class `ExtendedContainer` that extends League's container.
- `add` modified to reject classes not in the root Woo namespace.
- Has two new methods, `replace` and `reset_resolved`.
- It's used as the underlying container instead of League's one
in `Container`, but the new methods are not exposed.
- At unit test bootstrap time the globally registered container is
replaced with the extended one that `Container` stores
(grabbed from private property using reflection).
- A new `MockableLegacyProxy` is added. It inherits from `LegacyProxy`
and allows to mock functions, static methods and legacy classes.
- The registeed `LegacyProxy` is replaced with the mockable version
during unit test bootstrap.
- A PHPUnit hook is added to reset the mockable proxy to its initial
state (so that nothing is mocked) before each test.
- `WC_Unit_Test_Case` gets helper methods to mock functions, static
methods and classes without having to retrieve the proxy class.
At some point the 'change_stock' key is assumed to be present
in the request data, but it might not. Fixed to test for existence
before using the value.
The test added checks that stock status of variations when saving
a variable product is changed or not appropriately depending on
the request data supplied.
Those methods are a convenient replacement for
"this->factory->user->create". Tests that were using that to
simulate user login have been modified to use the new methods.
Some of our endpoints don't have an "<id>" parameter but we're expecting one in the CLI. Since the `id` is already part of the supported IDs we don't actually need this since it will pull it from the route.