Support » Plugin: License Manager for WooCommerce » Subscription renewal created new License Keys each month

  • Resolved botprophet

    (@botprophet)


    Hi,

    Love your plugin in works fantastic. Two thumbs up!

    One caveat though, we use monthly subscriptions and I noticed that on each renewal, a new license key is issued as well, which means the buyer gets a free new key each month. On a renewal, there should not be a new key obviously.

    Technically it is not an error, since a key is issued on an order complete status, which a renewal technically is. It is however not supposed to be that way.

    Any ideas how to tackle this? I know you haven’t “integrated” it with Woocommerce subscriptions (yet), but maybe you have a hint on where to look for a fix.

    Thanks,
    Paul.

Viewing 15 replies - 1 through 15 (of 22 total)
  • I have given it some more thought and browsed through the code.

    I think we need to be able to implement a check to see if a parent order exists, then skip the creation of the new subscription code.

    The WC order grid does show if an order is a Renewal. Any hint as to where I could find the code that created the code on a Completed order (or any other status for that matter).

    Thanks again.

    Plugin Author Drazen Bebic

    (@drazenbebic)

    Hello @botprophet

    thank you for your message and for using my plugin.

    This issue is probably the oldest “TODO” feature that I’ve been putting off for quite a while now. I’m not really familiar with the WooCommerce Subscription plugin nor its code.

    But basically what I want to achieve is that the subscription renewal doesn’t generate a new license key, but instead prolongs the expiration date by the subscription period.

    I’ll be honest: I have no idea how to do this, and little to no time to do it. If you feel up to the task let me know 😀

    Sorry I couldn’t provide a more satisfying answer.

    I can give you a hint 🙂

    The WooCommerce API meta_data (https://woocommerce.github.io/woocommerce-rest-api-docs/#update-an-order) has a record of it, which is called:

    ...
     [meta_data] => Array
                    (
    ...
                        [4] => stdClass Object
                            (
                                [id] => 158733
                                [key] => _subscription_renewal
                                [value] => 25894
                            )
    ...

    If you can find out how to call that (just check for the array key and skip the new license) in your script, you’re half way 🙂

    I’m not sure where that API meta info is stored, I did not see any in the database anywhere so I think it is stored as serialized data somewhere.

    If I could hack my way to your great system I would, but you’re way ahead of me buddy. I’m surely open to co-op on it, if you can give pointers as to where I can find it, I’ll try and see if I can do it.

    I found it, it is actually in table wp_postmeta.

    meta_id post_id meta_key meta_value
    15733 29840 _subscription_renewal 25894

    PostID is the new order number, also in your grid, meta_value is the parent subscription issued order.

    HTH

    Plugin Author Drazen Bebic

    (@drazenbebic)

    @botprophet

    thanks for digging! I’ll take a look when I get the chance.

    botprophet

    (@botprophet)

    No problem, if you need help let me know where I can find the code in your plugin that issues the coupon and I will try and see if I run a query before it.

    Plugin Author Drazen Bebic

    (@drazenbebic)

    botprophet

    (@botprophet)

    @drazenbebic, what if you just add this to line #74

            // This order is a subscription renewal, thus no new key has to be issued
            if (get_post_meta($orderId, '_subscription_renewal')) {
                return;
            }  

    That would solve the issuing of another key, right?
    A renewal is basicly just a new payment on an existing key, although it is a new ORDER, it is not a new Subscription key purchase.

    I think that should work. The meta_key “_subscription_renewal” does not exist on the original order in the database. I checked and can verify that.

    botprophet

    (@botprophet)

    Or, alternatively, if you can confirm and if you need to do it your way, like you said re-issue the same key again, use this at the end of the function, near line 222?:

                
    ...
    // Get existing key
                // This order is a subscription renewal, thus no new key has to be issued
                if (get_post_meta($orderId, '_subscription_renewal')) {
                    $orderId = get_post_meta($orderId, '_subscription_renewal', true);
                }
    
                $orderedLicenseKeys = LicenseResourceRepository::instance()->findAllBy(
                        array(
                            'order_id' => $orderId
                        )
                );
    
                /** Plugin event, Type: post, Name: order_license_keys */
                do_action(
                        'lmfwc_event_post_order_license_keys',
                        array(
                            'orderId'  => $orderId,
                            'licenses' => $orderedLicenseKeys
                        )
                );

    That said, I think for my case my First suggestion if fine.

    • This reply was modified 3 weeks ago by botprophet.
    Plugin Author Drazen Bebic

    (@drazenbebic)

    @botprophet

    hmm not bad actually, it’s just that it’s usually not good practice to access meta information directly, because it can change over time. There must be a plugin specific function which tells you if an order is a subscription renewal or not.

    Once I know that, I also need to know the subscription period and the original order ID.

    Then I can retrieve the original license and extend it’s expiry date.

    However, some plugin users might want to create a new license key with each order, so this should be a setting on the product level (I think).

    What do you think of this?

    botprophet

    (@botprophet)

    Ok, the class and functions are in this file, i think:
    \wp-content\plugins\woocommerce-subscriptions\includes\class-wc-subscriptions-renewal-order.php

    Not sure if there’s a public repository, I once wrote and published a ManyChat plugin and I think all plugins are visible in the repository when you publish your own, correct?

    I understand what you are saying and of course it makes sense. A plugin is truly never finished, right. You can add so many features, options and checks you’d never see the light of day anymore :-). The subscription plugin alone has a ton of checks that if you want to close all gaps, it would mean a lot of (extra) work.

    The ‘fix’ in my earlier post might work for me, because we do a lookup on subscription level. The License is only used to check if it is issued and has no expiry or limted time usage. We then do a check for the ACTIVE subscription to give access. We have a seperate custom table which contains sub validity and licensekey etc which is being used on a custom platform, not in WP.

    That said, here’s something I found in that file mentioned at the start (simplified), since we’re only looking for Complete Status (although that is also an optin in your plugin (to make things more complicated haha)), this might be the call you need?

    class WC_Subscriptions_Renewal_Order {
    	public static function init() {
    
    		// Trigger special hook when payment is completed on renewal orders
    		add_action( 'woocommerce_payment_complete', array( __CLASS__, 'trigger_renewal_payment_complete' ), 10 );
    
    	public static function trigger_renewal_payment_complete( $order_id ) {
    		if ( wcs_order_contains_renewal( $order_id ) ) {
    			do_action( 'woocommerce_renewal_order_payment_complete', $order_id );
    		}
    	}
    ...

    Here’s a list of all methods in that class:

    
    Array
    (
        [0] => ReflectionMethod Object
            (
                [name] => init
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [1] => ReflectionMethod Object
            (
                [name] => trigger_renewal_payment_complete
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [2] => ReflectionMethod Object
            (
                [name] => get_failed_order_replaced_by
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [3] => ReflectionMethod Object
            (
                [name] => maybe_record_subscription_payment
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [4] => ReflectionMethod Object
            (
                [name] => add_order_note
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [5] => ReflectionMethod Object
            (
                [name] => prevent_cancelling_renewal_orders
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [6] => ReflectionMethod Object
            (
                [name] => remove_switch_item_meta_keys
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [7] => ReflectionMethod Object
            (
                [name] => generate_paid_renewal_order
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [8] => ReflectionMethod Object
            (
                [name] => generate_failed_payment_renewal_order
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [9] => ReflectionMethod Object
            (
                [name] => maybe_generate_manual_renewal_order
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [10] => ReflectionMethod Object
            (
                [name] => get_parent_order_id
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [11] => ReflectionMethod Object
            (
                [name] => get_parent_order
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [12] => ReflectionMethod Object
            (
                [name] => get_renewal_order_count
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [13] => ReflectionMethod Object
            (
                [name] => get_users_renewal_link
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [14] => ReflectionMethod Object
            (
                [name] => get_users_renewal_link_for_product
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [15] => ReflectionMethod Object
            (
                [name] => can_subscription_be_renewed
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [16] => ReflectionMethod Object
            (
                [name] => maybe_create_renewal_order_for_user
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [17] => ReflectionMethod Object
            (
                [name] => product_addons_adjust_price
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [18] => ReflectionMethod Object
            (
                [name] => generate_renewal_order
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [19] => ReflectionMethod Object
            (
                [name] => is_purchasable
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [20] => ReflectionMethod Object
            (
                [name] => is_renewal
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [21] => ReflectionMethod Object
            (
                [name] => get_renewal_orders
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [22] => ReflectionMethod Object
            (
                [name] => get_checkout_payment_url
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [23] => ReflectionMethod Object
            (
                [name] => maybe_process_failed_renewal_order_payment
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [24] => ReflectionMethod Object
            (
                [name] => process_failed_renewal_order_payment
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [25] => ReflectionMethod Object
            (
                [name] => maybe_record_renewal_order_payment
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [26] => ReflectionMethod Object
            (
                [name] => maybe_record_renewal_order_payment_failure
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [27] => ReflectionMethod Object
            (
                [name] => process_subscription_payment_on_child_order
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [28] => ReflectionMethod Object
            (
                [name] => renewal_orders_meta_box_section
                [class] => WC_Subscriptions_Renewal_Order
            )
    
        [29] => ReflectionMethod Object
            (
                [name] => trigger_processed_failed_renewal_order_payment_hook
                [class] => WC_Subscriptions_Renewal_Order
            )
    
    )
    Plugin Author Drazen Bebic

    (@drazenbebic)

    @botprophet

    I got it to work after all this time!

    I’ll polish the feature up and push to the develop branch on GitHub, could you test it out and see if it works?

    Plugin Author Drazen Bebic

    (@drazenbebic)

    botprophet

    (@botprophet)

    Cool, that’s awesome! Congrats, a new feature is always good for your plugin!
    I hope I motivated you to just get it off your to do list finally:-).

    I can install the new files and changes, but I do not have a dev server for this so we’d have to wait until our next renewal in a few weeks.

    Does that work for you?

    Plugin Author Drazen Bebic

    (@drazenbebic)

    @botprophet

    In that case, I’ll test it out myself. It’s a bit long to wait and a lot of people are waiting on this one. I’ll try to create a custom subscription interval, perhaps every 5 minutes or so to test everything out. Should be possible.

Viewing 15 replies - 1 through 15 (of 22 total)
  • You must be logged in to reply to this topic.