/** * The heart of the Stripe API integration * * Everything that Stripe does gets communicated back here. * * @return bool */ public static function webhook_handler() { global $wpdb, $psts, $current_site; $site_name = $current_site->site_name; $domain = ''; $blog_id = false; try { // retrieve the request's body and parse it as JSON $body = @file_get_contents('php://input'); $event_json = json_decode($body); if (!isset($event_json->data->object->customer)) { return false; } $event_type = $event_json->type; $customer_id = $event_json->data->object->customer; $subscription = self::get_subscription($event_json); if ('invoice.payment_succeeded' == $event_type) { self::record_transaction($event_json); } //If invoice has been created, activate user blog trial if ('invoiceitem.updated' == $event_type || 'invoiceitem.created' == $event_type || 'invoice.created' == $event_type || 'invoice.payment_succeeded' == $event_type) { // Create generic class from Stripe\Subscription class // Convert 3.4 -> 3.5+ if (!isset($subscription->metadata->blog_id)) { $blog_id = ProSites_Gateway_Stripe::get_blog_id($customer_id); self::set_subscription_blog_id($subscription, $customer_id, $blog_id, $blog_id); $subscription->blog_id = $blog_id; self::set_subscription_meta($subscription, $customer_id); } if (!empty($subscription->blog_id)) { $blog_id = (int) $subscription->blog_id; } else { if (!empty($subscription)) { // activate to get ID $result = ProSites_Helper_Registration::activate_blog($subscription->activation, $subscription->is_trial, $subscription->period, $subscription->level, $subscription->trial_end); $blog_id = $result['blog_id']; // set new ID self::set_subscription_blog_id($subscription, $customer_id, $blog_id); } } //Set Customer data if (!empty($blog_id) && isset($subscription->id) && !empty($subscription->id)) { self::set_customer_data($blog_id, $customer_id, $subscription->id); } } if (empty($blog_id) && isset($subscription) && isset($subscription->blog_id) && !empty($subscription->blog_id)) { $blog_id = $subscription->blog_id; } if ($blog_id || $domain) { // In case the blog has since been removed from the database, just exit $details = get_blog_details($blog_id); if (empty($details)) { return false; } $date = date_i18n(get_option('date_format'), $event_json->created); $amount = $amount_formatted = $plan_amount = 0; $level = $period = $plan = ''; $is_trial = false; $plan_end = false; switch ($event_type) { case 'invoice.payment_succeeded': case 'invoice.payment_failed': $plan = $subscription->plan->id; $is_trial = $subscription->is_trial; $plan_end = $subscription->period_end; $plan_amount = $subscription->plan_amount; $amount = $subscription->subscription_amount; $invoice_items = $subscription->invoice_items; $setup_fee_amt = $subscription->setup_fee; $has_setup_fee = $subscription->has_setup_fee; $plan_change_amount = $subscription->plan_change_amount; $has_plan_change = $subscription->plan_change; $plan_change_mode = $subscription->plan_change_mode; $discount_amount = $subscription->discount_amount; $has_discount = $subscription->has_discount; break; case 'customer.subscription.created': case 'customer.subscription.updated': $plan = $subscription->plan->id; $amount = $plan_amount = $subscription->plan->amount / 100; $is_trial = $subscription->is_trial; $plan_end = $is_trial ? $subscription->trial_end : $subscription->period_end; break; } // Should be Stripe regardless if its a trial, we need the proper information returned later $gateway = self::get_slug(); // ... but we should record that it is a trial. if ($is_trial) { ProSites_Helper_Registration::set_trial($blog_id, 1); } $amount_formatted = $psts->format_currency(false, $amount); $charge_id = isset($event_json->data->object->charge) ? $event_json->data->object->charge : $event_json->data->object->id; if (!empty($plan)) { $plan_parts = explode('_', $plan); $period = array_pop($plan_parts); $level = array_pop($plan_parts); } if (!empty($blog_id)) { /* reset the waiting status (this is used on the checkout screen to display a notice to customers that actions are pending on their account) */ update_blog_option($blog_id, 'psts_stripe_waiting', 0); } elseif (!empty($domain)) { /** * @todo redundant now */ //Update signup meta // $signup_meta = $psts->get_signup_meta( $domain ); // $signup_meta['psts_stripe_waiting'] = 0; // $psts->update_signup_meta( $signup_meta, $domain ); } switch ($event_type) { case 'invoice.payment_succeeded': $psts->log_action($blog_id, sprintf(__('Stripe webhook "%s" received: The %s payment was successfully received. Date: "%s", Charge ID "%s"', 'psts'), $event_type, $amount_formatted, $date, $charge_id)); $charge_amount = $plan_amount; $args = array(); // if ( $has_setup_fee ) { // $args['setup_amount'] = $setup_fee_amt; // } // if( $has_discount ) { // $args['discount_amount'] = $discount_amount; // } // if( $has_plan_change ) { // $args['plan_change_amount'] = $plan_change_amount; // $args['plan_change_mode'] = $plan_change_mode; // } if ($invoice_items) { $args['items'] = $invoice_items; } self::maybe_extend($blog_id, $period, $gateway, $level, $charge_amount, $plan_end, true, true, $args); break; case 'customer.subscription.created': $period_string = $period == 1 ? 'month' : 'months'; $psts->record_stat($blog_id, 'signup'); $psts->log_action($blog_id, sprintf(__('Stripe webhook "%1$s" received: Customer successfully subscribed to %2$s %3$s: %4$s every %5$s %6$s.', 'psts'), $event_type, $site_name, $psts->get_level_setting($level, 'name'), $psts->format_currency(false, $plan_amount), number_format_i18n($period), $period_string), $domain); self::maybe_extend($blog_id, $period, $gateway, $level, $plan_amount, $plan_end); break; case 'customer.subscription.updated': $period_string = $period == 1 ? 'month' : 'months'; $current_plan = self::get_current_plan($blog_id); $plan_parts = explode('_', $current_plan); $current_plan_period = array_pop($plan_parts); $current_plan_level = array_pop($plan_parts); if ($current_plan_period != $period || $current_plan_level != $level) { if ($current_plan_level < $level) { $psts->record_stat($blog_id, 'upgrade'); } else { $psts->record_stat($blog_id, 'modify'); } } $psts->log_action($blog_id, sprintf(__('Stripe webhook "%s" received. The customer\'s subscription was successfully updated to %2$s %3$s: %4$s every %5$s %6$s.', 'psts'), $event_type, $site_name, $psts->get_level_setting($level, 'name'), $psts->format_currency(false, $plan_amount), number_format_i18n($period), $period_string)); self::maybe_extend($blog_id, $period, $gateway, $level, $plan_amount, $plan_end); break; case 'invoice.payment_failed': $psts->log_action($blog_id, sprintf(__('Stripe webhook "%s" received: The %s payment has failed. Date: "%s", Charge ID "%s"', 'psts'), $event_type, $amount_formatted, $date, $charge_id)); $psts->email_notification($blog_id, 'failed'); break; case 'charge.disputed': $psts->log_action($blog_id, sprintf(__('Stripe webhook "%s" received: The customer disputed a charge with their bank (chargeback), Charge ID "%s"', 'psts'), $event_type, $charge_id)); $psts->withdraw($blog_id); break; case 'customer.subscription.deleted': update_blog_option($blog_id, 'psts_stripe_canceled', 1); $psts->log_action($blog_id, sprintf(__('Stripe webhook "%s" received: The subscription has been canceled', 'psts'), $event_type)); break; default: $text = sprintf(__('Stripe webhook "%s" received', 'psts'), $event_type); if ($customer_id) { $text .= sprintf(__(': Customer ID: %s', 'psts'), $customer_id); } $psts->log_action($blog_id, $text); break; } } die(1); } catch (Exception $ex) { $message = $ex->getMessage(); die($message); } }