1
\$\begingroup\$

I've creating a working subscription workflow for my webpage, which heavily utilizes a set of functions I've created for this purpose.

However, after doing some testing (functionality works fine), I've discovered the way I've designed my system is taking a heavy toll on the web-page load speed. My current suspicions are aimed towards that the heavy amount of Stripe API calls are causing a lot of the problems.

I tried changing up the way I call variables, both as the code you see here, and where I utilize paramters instead; same result.

Any PHP gurus who can give me some pointers in how to optimize the load times of these scripts?

<?php

    use \Stripe\Stripe;

    \Stripe\Stripe::setApiKey("api_key");

    function get_stripe_sub_id() {
        global $current_user;
        $userid = $current_user->ID;

        $stripe_id = get_user_meta($userid, 'stripe_id');
        $refer_user_obj = \Stripe\Customer::retrieve($stripe_id[0]);

        if(isset($refer_user_obj->subscriptions->data[0]->id)) {
            $sub_id = $refer_user_obj->subscriptions->data[0]->id;
            return $sub_id;
        } else {
            return 'non_sub';
        }
    }

    function get_sub_status() {
         if(get_stripe_sub_id() == 'non_sub') {
             return 'deactive';
         } else {
             $sub_obj = \Stripe\Subscription::retrieve(get_stripe_sub_id());
             $sub_status = $sub_obj->status;

             if($sub_status == 'trialing' || $sub_status == 'active') {
                 return 'active';
             } else {
                 return 'deactive';
             }
         }
    }

    function is_customer() {
        global $current_user;
        $userid = $current_user->ID;

        $is_customer = get_user_meta($userid, 'is_customer');
        if(isset($is_customer[0])) {
            if($is_customer[0] == '1') {
                return true;
            } else {
                return false;
            }
        }
    }

    function redirect_if_non_sub() {
        global $current_user;
        $userid = $current_user->ID;

         if(is_customer($userid) == true) {
             if(get_sub_status() == 'deactive') {
                 $uri = $_SERVER['REQUEST_URI'];
                 if ($uri != '/cvhelpr/ingen-abonnement/') {
                     write_log('redirect me');
                     header('Location: /cvhelpr/ingen-abonnement');
                     exit;
                 } 
             }
         }
    }

    function get_next_sub_invoice() {
        if(get_stripe_sub_id() != 'non_sub') {
            $sub_obj = \Stripe\Subscription::retrieve(get_stripe_sub_id());
            $next_inv = $sub_obj->current_period_end;
            $formatted_inv = gmdate("Y-m-d", $next_inv);

            if(is_canceled() == true) {
                return 'Dit abonnement udløber ' . (string)$formatted_inv;
            } else {
                return $formatted_inv;
            }
        } else {
            return 'Denne bruger har intet abonnement.';
        }
    }

    function is_canceled() {
        $sub_obj = \Stripe\Subscription::retrieve(get_stripe_sub_id());
        $is_canceled = $sub_obj->cancel_at_period_end;
        if($is_canceled == 1) {
            return true;
        } else {
            return false;
        }
    }

    function reactivate_sub() {
        $stripe_id = get_user_meta(get_current_user_id(), 'stripe_id');
        write_log($stripe_id[0]);

        $subscription = \Stripe\Subscription::create([
            'customer' => $stripe_id[0],
            'items' => [['plan' => 'cv_195']],
            'trial_period_days' => 7
        ]);

        header("Location: /my-account");
        die();
    }
    add_action('wp_ajax_reactivate_sub', 'reactivate_sub');
    add_action('wp_ajax_nopriv_reactivate_sub', 'reactivate_sub');

    function cancel_sub() {
        if(get_stripe_sub_id() != 'non_sub') {
            $sub = \Stripe\Subscription::retrieve(get_stripe_sub_id());
            \Stripe\Subscription::update(
                get_stripe_sub_id(),
                [
                    'cancel_at_period_end' => true
                ]  
            );
        }
    }
    add_action('wp_ajax_cancel_sub', 'cancel_sub');
    add_action('wp_ajax_nopriv_cancel_sub', 'cancel_sub');

    function uncancel_sub() {
        if(get_stripe_sub_id() != 'non_sub') {
            $sub = \Stripe\Subscription::retrieve(get_stripe_sub_id());
            \Stripe\Subscription::update(
                get_stripe_sub_id(),
                [
                    'cancel_at_period_end' => false
                ]  
            );
        }
    }
    add_action('wp_ajax_uncancel_sub', 'uncancel_sub');
    add_action('wp_ajax_nopriv_uncancel_sub', 'uncancel_sub');
    ?>

Edit: After doing some further research, it seem more and more what is really causing the slow load times is the Stripe API calls. Several other Stripe users have mentioned 3-10s load times when doing API calls.

\$\endgroup\$
  • \$\begingroup\$ Is there a reason that you aren't calling get_stripe_sub_id() just one time and caching it for future script usage? What php version are you rockin'? \$\endgroup\$ – mickmackusa May 1 at 2:32
0
\$\begingroup\$

Disclaimer, I'm not a PHP guru. Just looked at your code and did a bit of optimization; I feel it needs more. By the way, you're right. The problem is in the function calls.

<?php

use Stripe\Stripe;
use Stripe\Customer;
use Stripe\Subscription;

Stripe::setApiKey("api_key");

/**
 * You could declare this at the top of the file
 * $stripeSubId = get_stripe_sub_id();
 * and then simply pass it as an argument to any function that requires it
 * e.g.,
 * function get_next_sub_invoice($stripeSubId) {
 *      // rest of code directly uses $stripeSubId
 * }
 */

function getUserId() {
    global $current_user;
    return $current_user->ID;
}

function get_stripe_sub_id() {
    $userid = getUserId();

    $stripe_id = get_user_meta($userid, 'stripe_id'); // get_user_meta() is unfortunately not in this file
    $refer_user_obj = Customer::retrieve($stripe_id[0]);

    if(isset($refer_user_obj->subscriptions->data[0]->id)) {

        return $refer_user_obj->subscriptions->data[0]->id;
    }
    return 'non_sub';

}

function get_sub_status() {
    $stripeSubId = get_stripe_sub_id(); // 1 function call is better than 3
    if($stripeSubId === 'non_sub') {
        return 'deactive';
    }

    $sub_obj = Subscription::retrieve($stripeSubId);
    $sub_status = $sub_obj->status;

    if($sub_status === 'trialing' || $sub_status === 'active') {
        return 'active';
    }
    return 'deactive';

}

function is_customer() {
    $userid = getUserId();

    $is_customer = get_user_meta($userid, 'is_customer');

    if(isset($is_customer[0])) {
        return ($is_customer[0] === '1');
    }
    return false;
}

function redirect_if_non_sub() {

    if(is_customer() && get_sub_status() === 'deactive') {
        $uri = $_SERVER['REQUEST_URI'];

        if ($uri !== '/cvhelpr/ingen-abonnement/') {
            write_log('redirect me'); // not in the file too
            header('Location: /cvhelpr/ingen-abonnement');
            exit;
        }
    }
}

function get_next_sub_invoice() {
    $stripeSubId = get_stripe_sub_id();

    if($stripeSubId !== 'non_sub') {
        $sub_obj = Subscription::retrieve($stripeSubId);
        $next_inv = $sub_obj->current_period_end;
        $formatted_inv = gmdate('Y-m-d', $next_inv);

        if(is_canceled() === true) {
            return 'Dit abonnement udløber ' . $formatted_inv;
        }
        return $formatted_inv;
    }

    return 'Denne bruger har intet abonnement.';
}

function is_canceled() {
    $sub_obj = Subscription::retrieve(get_stripe_sub_id());
    $is_canceled = $sub_obj->cancel_at_period_end;

    return $is_canceled === 1; // will return true if the expression matches, false otherwise
}

function reactivate_sub() {
    // get_current_user_id() is probably the same thing as getUserId() - see top of file
    $stripe_id = get_user_meta(get_current_user_id(), 'stripe_id');
    write_log($stripe_id[0]);

    $subscription = Subscription::create([
        'customer' => $stripe_id[0],
        'items' => [['plan' => 'cv_195']],
        'trial_period_days' => 7
    ]);

    header("Location: /my-account");
    die();
}
add_action('wp_ajax_reactivate_sub', 'reactivate_sub');
add_action('wp_ajax_nopriv_reactivate_sub', 'reactivate_sub');

function cancel_sub() {
    $stripeSubId = get_stripe_sub_id();
    if($stripeSubId !== 'non_sub') {
        $sub = Subscription::retrieve($stripeSubId); // var $sub is not used anywhere
        // you're getting an instance from the retrieve function, but not  using it - why?
        // is it even necessary? The leaner your code, the better
        Subscription::update($stripeSubId,
            [
                'cancel_at_period_end' => true
            ]
        );
    }
}
add_action('wp_ajax_cancel_sub', 'cancel_sub');
add_action('wp_ajax_nopriv_cancel_sub', 'cancel_sub');

function uncancel_sub() {
    $stripeSubId = get_stripe_sub_id();
    if($stripeSubId !== 'non_sub') {
        $sub = Subscription::retrieve($stripeSubId); // same thing here - try to comment it and see what happens
        Subscription::update($stripeSubId,
            [
                'cancel_at_period_end' => false
            ]
        );
    }
}
add_action('wp_ajax_uncancel_sub', 'uncancel_sub');
add_action('wp_ajax_nopriv_uncancel_sub', 'uncancel_sub');
?>
\$\endgroup\$
  • \$\begingroup\$ Fair answer, it could be improved by more observations about the posters code rather than re-writing the code. You might want to check out this guide codereview.stackexchange.com/help/how-to-answer. \$\endgroup\$ – pacmaninbw May 1 at 11:09
  • \$\begingroup\$ Question definitely helped me clean up the code - but had very little to no impact on the pages load time. Thanks for the effort though! \$\endgroup\$ – Stenberg May 1 at 11:32
0
\$\begingroup\$

So the high delay was a result of the Stripe API calls, as it appears they have a limit of you pulling data.

To improve this, I changed it so I pull all the data I need from the API into my database when specific actions are performed, then call the data I need from my own database instead of constantly bothering the API:

function update_stripe_meta() {
    $userid = getUserId();
    $stripe_id = get_user_meta($userid, 'stripe_id');
    update_user_meta($userid, 'customer_object', Customer::retrieve($stripe_id[0]));
    update_user_meta($userid, 'sub_object', Subscription::retrieve(get_stripe_sub_id()));
}

Result is load times went from 10-12s to 3-4s when performing actions, and less than 1s when just surfing the webpage.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.