-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Performance improvements: rendering the Subscription Relationship column and checking if order is a renewal, switch etc. #732
Performance improvements: rendering the Subscription Relationship column and checking if order is a renewal, switch etc. #732
Conversation
…object and call more performant contains functions
Breakdown of these changesChecking if an order is renewal/resubscribeOld
This branch
Important As seen, these changes will no longer load a subscription object into memory which means we're no longer checking if the subscription ID stored in To determine if this is a bug or not, we should ask ourselves whether an order should revert to a standalone/regular order if the subscription has been deleted 🤔 I can't think of good reason why we should revert an order to a regular order if the linked subscription has been removed and I believe it would still be good to know that this order was reference to a subscription renewal or resubscribe etc. If we consider this to be a bug, one way we could address this is to hook onto Checking if an order is a parentOld
This branch
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes look good to me. On a change by change comparison the changes in this PR only improve the performance of the wcs_order_contains_x
functions.
Diving into the root difference, it's essentially bypassing mid level functions to avoid a feature of those mid level functions which is to instantiate the subscription objects returned.
Your concerns around checking if those subscriptions still exist is fair, however, I don't think we need to be concerned with that too much.
Deleting subscriptions isn't something we routinely do or even expect. Even if it was a thing, the relationship stored in order meta would be incorrect and the UI's displaying of that relationship on the front end would be a reflection of incorrect data. That is, I agree with your earlier comment that the "fix" would be to make sure that meta was deleted on subscription deletion.
I left a couple of comments and questions. Let me know what you think of them.
…ription_ids() wrapper
…ake false assumptions
includes/wcs-order-functions.php
Outdated
* | ||
* @return array The subscription IDs. | ||
*/ | ||
function wcs_get_subscription_ids_for_order( $order, $order_types = [] ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the intention behind the empty []
$order_types
param?
Passing an empty array returns no results. Is it supposed to be interpreted as all order types?
It's probably worth detailing this in the function block param comment too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @james-allan. I think it makes sense for us to return 'any' subscription IDs linked to the given order so I've just implemented the any param here cd7ac49.
I also added these default details to the docblock (see 4051a4c)
includes/wcs-order-functions.php
Outdated
$subscription_ids += WCS_Related_Order_Store::instance()->get_related_subscription_ids( $order, $order_type ); | ||
} | ||
|
||
// An order cannot be both a renewal, switch or resubscribe as well as a parent order, so only fetch subscription IDs if we didn't find any in the related order store. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we can make this assumption.
If I resubscribe to a cancelled subscription, that order is a parent to the new subscription and a resubscribe to the old subscription.
wcs_get_subscription_ids_for_order( $resubscribe_order, [ 'resubscribe', 'parent' ] )
This should return 2 results, the cancelled subscription and the new one. In it's current form, it would just return the resubscribe.
I understand the intention is to avoid unnecessary expensive queries. I think callers if they were being super performance conscious, they would be be better off doing something like this:
$related_subscriptions = wcs_get_subscription_ids_for_order( $order, [ 'resubscribe', 'renewal', 'switch' ] );
// If the subscription contains a subscription
if ( ! empty( $related_subscriptions ) || wcs_is_parent_order( $order ) {
...
ie separate the related order relations from the parent check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for flagging this! I've fixed this in 5f237ab
|
||
return apply_filters( 'woocommerce_subscriptions_is_resubscribe_order', $is_resubscribe_order, $order ); | ||
$related_subscription_ids = wcs_get_subscription_ids_for_order( $order, 'resubscribe' ); | ||
return apply_filters( 'woocommerce_subscriptions_is_resubscribe_order', ! empty( $related_subscription_ids ), $order ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This applies to all the contains_x()
functions but these filters use to always receive an order object. Given these functions can accept an ID, they will now receive whatever was passed in -- ID or object.
Unfortunately I think this means we will need to return to the
if ( ! is_a( $order, 'WC_Abstract_Order' ) ) {
$order = wc_get_order( $order );
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch @james-allan!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just pushed up d492796 to address this! Going to run through some more tests on these latest changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work on this @mattallan. Thanks for working through all my feedback 😅
I think this PR is in a good place now. I particularly like the fact that we've got a good foundation for these subscription-order relationship functions.
We have a full suite of is/contains functions:
wcs_is_parent_order()
wcs_order_contains_switch()
wcs_order_contains_resubscribe()
wcs_order_contains_renewal()
When you want to check multiple types, you can use:
wcs_order_contains_subscription()
That approach is more user friendly but also performant as it runs fewer queries by the nature of its if - elseif structure and parent checking is last.
They all fall through to a base function wcs_get_subscription_ids_for_order()
which interfaces with the caches and data layer in 1 place. ❤️
Part of #731
Description
When a merchant visits the WooCommerce > Orders list table, WooCommerce Subscriptions adds a custom "Subscription Relationship" column that displays an icon based on what type of order it is:
As reported in #731, our
render_contains_subscription_column_content()
function currently performs unnecessary queries which impacts overall site performance and performance when viewing/managing orders via the WooCommerce > Orders table. After looking at this function, I noticed a couple of issues that we should address:wcs_order_contains_subscription()
unnecessarily loads subscription objects into memory.wcs_order_contains_{order_type}()
functions are doing a lot when all we really need to do is check for meta on an order.This PR targets all of these issues:
wcs_is_parent_order( $order )
function which runs a much more performant query to check if an order is a parent order.wcs_order_contains_renewal()
,wcs_order_contains_resubscribe()
andwcs_order_contains_switch()
functions to use ourWCS_Related_Order_Store
class to check if the order belongs to a renewal, resubscribe and switch, without having to load subscription objects into memory.render_contains_subscription_column_content()
to call the updated/more performantwcs_order_contains_{order_type}( $order )
functions directly instead of going throughwcs_order_contains_subscription( $order_id, {order_type} )
wcs_order_contains_subscription()
to use more performant method for checking parent order.How to test this PR
Important
The changes in this PR impact potentially a lot of critical subscription flows. We should make sure these functions are heavily unit tested and test our critical flows to assess impact.
Product impact