The WC_Product::set_default_attributes function uses an array_filter (using the default callback for filtration)
to remove null and false values from the defaults array for a given product. The issue here is that, in the above use case,
the array_filter will evaluate '0' as 0 and therefore as false. Ultimately, array_filter then prevents the value from being
recorded, moving forward.
I've added a new filter callback to includes/wc-attribute-functions which will disregard all FALSE PHP equivalents except for
'0' (as a a string). Also, I've updated the filter_array call in WC_Product::set_default_attributes so that it uses this new callback,
instead of the PHP default. Finally, I've added a phpunit test to assert that, when storing default variations / attributes on a product,
the false/true PHP synonyms are evaluating and storing like one would normally expect, with the exception that (string) '0'
evaluates as true in this special case.
This solution could potentially be broadened to facililate similar rules elsewhere, but the need raised in the bug is specific and
this is a specific solution.
See #14620 for more context. In there I thought this was the desired behaviour and I enhanced it. After talking with @mikejolley he explained to me that it was not by designed.
This commit makes sure the meta data cache is not shared among instances
Right now get_item() is loading an item from the database directly. It doesn't
take advantage of our cache and it doesn't check if the item is already loaded in memory.
There is also another bug (or feature?) that it will let you load any item, even if the item is not related to the current order. I believe this is a bug, if somebody really wants to load any item regardless of the order they should use `WC_Order_Factory::get_order_item`.
Another bug is that items loaded with get_item() are not related to the order object, therefore any calls to Order::save() won't persist the changes made to the item.
This commits makes sure the item returned by get_item is loaded similarly like get_items() does, taking advantage of the cache and the $items protected property (chances are the item is already in memory, ready to be used).
If a given item is not found false will be returned. If item exists but it is not related to the current object it will return false as well (If this behaviour is wanted, I can easily change it load the item anyways instead of returning false).