-
Notifications
You must be signed in to change notification settings - Fork 36
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
Cache subscription last order date #819
base: trunk
Are you sure you want to change the base?
Conversation
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 @alefesouza for picking up this issue!
I like your approach with only using this new cached date value for display purposes and not in calculations as that reduces the risk of any serious breakages 😅 I think this is a good starting position.
Taking a look at the last_order_date_created
date, it's currently calculated each time by fetching the list of parent, renewal, switch orders linked to the subscription, and then gets maximum order ID from this list. Reads the order into memory and then returns the data_created
value.
In the crazy world of subscriptions, some subscriptions don't have parent orders, some renewal orders can be created manually & the link between subscription and related orders can be freely added and removed using code like:
WCS_Related_Order_Store::instance()->add_relation( $order, $subscription, 'renewal' ); // Manually connects a renewal order to a subscription.
...
WCS_Related_Order_Store::instance()->delete_relation( $order, $subscription, 'switch' ); // Unlinks a switch order from a subscription.
With that all said, to ensure we're displaying the most up-to-date Last Order Data value on the WooCommerce > Subscriptions table, we'll need to make sure we're updating/recalculating the cache for each of the following cases:
Parent order changes
- When someone manually assigns a new parent order to a subscription i.e
$subscription->set_parent_id( 1234 );
$subscription->save();
- When creating a pending order via the Subscription Actions
- When purchasing a new subscription through the checkout
Renewal order changes
- When a new renewal order is manually created via the Subscription Actions
- When a new renewal is automatically created via action scheduler
- When a payment gateway manually creates a renewal order for gateway scheduled renewals (i.e stripe billing, paypal subscriptions)
- When an existing renewal order is manually linked to a subscription via
WCS_Related_Order_Store::instance()->add_relation()
- When a renewal order is deleted via any means
- When a renewal order is unlinked
WCS_Related_Order_Store::instance()->delete_relation()
Switch order changes
- When a customer processes a upgrade/downgrade via the My Account
- When an order is manually linked as a switch on a subscription
WCS_Related_Order_Store::instance()->add_relation()
- When a switch order is deleted or unlinked via
delete_relation
Having to support this list of cases may seem a bit intimidating but I think one way we could achieve this is to have a new class that makes use of our WCS_Object_Data_Cache_Manager
(for HPOS) and WCS_Post_Meta_Cache_Manager
(WP Posts).
I haven't explored this yet myself, but I think we should be able to instantiate a new WCS_Object_Data_Cache_Manager|WCS_Post_Meta_Cache_Manager
class and pass it 'subscription' order type and then a list of meta keys that we want to "watch". Something like:
$cache_manager = new WCS_Object_Data_Cache_Manager( 'subscription', [
'parent_id', // don't know if this works.
'_subscription_renewal_order_ids_cache', // don't know if this will work for internal meta keys.
'_subscription_switch_order_ids_cache',
] );
$cache_manager->init();
The thinking behind this idea is that our related orders cache handler is already watching for all of these changes to renewal and switch orders and keeping the related order cache up-to-date. So in theory, we should be able to watch for changes to these related orders cache and then trigger recalculating the Last Order Date.
The only meta changes we're currently not watching which also affects the last order date, is the parent ID. I'm curious if we can watch for updates to the parent_id
meta on the subscription to know when a new parent order is set (?) 🤔
There's a high chance I'm over complicating this, or it simply doesn't work, and so very simple approach might be to just to hook onto the woocommerce_update_subscription
hook and delete the date cache. This will then trigger us to recalculate the date the next time it's fetched.
Keen to hear your thoughts on this! :)
🥚 Hope you guys are all good and good luck with everything! <3
@leonardola this PR is ready to review |
|
||
add_action( 'wcs_orders_add_relation', [ __CLASS__, 'add_relation_update_order_related_subscriptions_last_order_date_created' ], 10, 3 ); | ||
|
||
add_action( 'wcs_orders_delete_relation', [ __CLASS__, 'delete_relation_update_order_related_subscriptions_last_order_date_created' ], 10, 3 ); |
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 function name seems weird to me. Also it does not actually delete the order just update it
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.
@leonardola it deletes the order relation, not the order itself.
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.
Under Manual parent ID changes
If the new subscription parent order id is higher than the other others, its date should show up on the Last Order Date column.
Shouldn't it update the latest order every time independently if the new parent is newer or older?
To me even when I update the parent order to a newer one it doesn't update the last order date
Under Add order relation
In this case the newest order was used to calculate the last order date even though I added an older order. In this case I think the current behavior is correct.
|
||
add_action( 'wcs_orders_add_relation', [ __CLASS__, 'add_relation_update_order_related_subscriptions_last_order_date_created' ], 10, 3 ); | ||
|
||
add_action( 'wcs_orders_delete_relation', [ __CLASS__, 'delete_relation_update_order_related_subscriptions_last_order_date_created' ], 10, 3 ); |
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 function name seems weird to me. Also it does not actually delete the order just updates it
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.
@leonardola the delete_
is the function names comes from WCS_Related_Order_Store::instance()->delete_relation(
, it's not related to delete an order but delete a relation.
* @param WC_Order $subscription A subscription or order to unlink the order with, if a relation exists. | ||
* @param string $relation_type The relationship between the subscription and the order. Must be 'renewal', 'switch' or 'resubscribe' unless custom relationships are implemented. | ||
*/ | ||
public static function delete_relation_update_order_related_subscriptions_last_order_date_created( $order, $subscription, $relation_type ) { |
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 function is also not deleting anything is it?
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.
The function name comes from WCS_Related_Order_Store::instance()->delete_relation(
, would you suggest a better name?
includes/wcs-order-functions.php
Outdated
@@ -277,6 +277,11 @@ function wcs_create_order_from_subscription( $subscription, $type ) { | |||
throw new Exception( sprintf( __( 'There was an error fetching the new order (%1$s) for subscription %2$d.', 'woocommerce-subscriptions' ), $type, $subscription->get_id() ) ); | |||
} | |||
|
|||
// Update the subscription last_order_date_created on every time |
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.
make the comment a one liner or change to /* */ style
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.
Fixed on ef28be8.
Fixes #782
Description
This PR improves the subscription list performance by caching the subscription last order date when new renewals are created or when the last order is deleted.
How to test this PR
Subscriptions list (existing subscription handling)
WooCommerce > Subscriptions
._last_order_date_created
item for every loaded subscription on the subscriptions page._last_order_date_created
) and it's not loading the all subscription orders as before.Last Order Date
column should be correctly rendered.Subscription renewal
_last_order_date_created
value for the chosen subscription on phpMyAdmin.Order actions
, runProcess renewal
._last_order_date_created
value for the chosen subscription should be updated.Last Order Date
column for the chosen subscription should show the correct date.Subscription order deletion
_last_order_date_created
value for the chosen subscription on phpMyAdmin._last_order_date_created
value for the chosen subscription should be updated to the new latest order.Last Order Date
column for the chosen subscription should show the correct date.Manual parent ID changes
Last Order Date
column.Last Order Date
column for the old parent id should also be updated.Add order relation
Last Order Date
column.Delete order relation
Last Order Date
column should show the date of the new latest order.Product impact