/** * trigger function. * * @access public * @return void */ function trigger($subscription_key) { global $woocommerce; $this->subscription_key = $subscription_key; $this->object = WC_Subscriptions_Manager::get_subscription($subscription_key); if (!$this->is_enabled() || !$this->get_recipient()) { return; } $this->send($this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments()); }
/** * Customise which actions are shown against a subscriptions order on the My Account page. * * @since 1.3 */ public static function filter_woocommerce_my_account_my_orders_actions($actions, $order) { if (WC_Subscriptions_Order::order_contains_subscription($order) || WC_Subscriptions_Renewal_Order::is_renewal($order)) { unset($actions['cancel']); if (is_numeric(get_post_meta($order->id, '_failed_order_replaced_by', true))) { unset($actions['pay']); } $original_order = WC_Subscriptions_Renewal_Order::get_parent_order($order); $order_items = WC_Subscriptions_Order::get_recurring_items($original_order); $first_order_item = reset($order_items); $product_id = WC_Subscriptions_Order::get_items_product_id($first_order_item); $subscription_key = WC_Subscriptions_Manager::get_subscription_key($original_order->id, $product_id); $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key); if (empty($subscription) || !in_array($subscription['status'], array('on-hold', 'pending'))) { unset($actions['pay']); } } return $actions; }
function wc_subs_exporter_get_filtered_subscriptions($export) { global $wpdb; $subscriptions = $filtered_subscriptions = array(); $sql = "SELECT DISTINCT i.order_id, m.product_id, p.meta_value\n\t\t\t\tFROM\n\t\t\t\t(\n\t\t\t\tSELECT order_item_id,\n\t\t\t\tMAX(CASE WHEN meta_key = '_product_id' THEN meta_value END) product_id\n\t\t\t\tFROM {$wpdb->prefix}woocommerce_order_itemmeta\n\t\t\t\tWHERE meta_key LIKE '_subscription%' \n\t\t\t\t\tOR meta_key LIKE '_recurring%'\n\t\t\t\t\tOR meta_key = '_product_id'\n\t\t\t\tGROUP BY order_item_id\n\t\t\t\tHAVING MAX(meta_key LIKE '_subscription%')\n\t\t\t\t\t+ MAX(meta_key LIKE '_recurring%') > 0\n\t\t\t\t) m JOIN {$wpdb->prefix}woocommerce_order_items i \n\t\t\t\tON m.order_item_id = i.order_item_id \n\t\t\t\tLEFT JOIN {$wpdb->prefix}postmeta p \n\t\t\t\tON i.order_id = p.post_id \n\t\t\t\tAND p.meta_key = '_customer_user'\n\t\t\t\tLEFT JOIN {$wpdb->prefix}posts po \n\t\t\t\tON p.post_id = po.ID\n\t\t\t\tWHERE po.post_type = 'shop_order' AND po.post_parent = 0"; $order_ids_and_product_ids = $wpdb->get_results($sql); foreach ($order_ids_and_product_ids as $order_id_and_product_id) { if (empty($order_id_and_product_id->product_id)) { continue; } $subscription_key = $order_id_and_product_id->order_id . '_' . $order_id_and_product_id->product_id; $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key); if (empty($subscription)) { continue; } // filter status if (!array_key_exists($subscription['status'], $export->status)) { continue; } // filter dates if ($export->dates_from && strtotime($subscription['start_date']) < strtotime($export->dates_from)) { continue; } elseif ($export->dates_to && strtotime($subscription['start_date']) > strtotime($export->dates_to)) { continue; } $subscriptions[$order_id_and_product_id->meta_value][$subscription_key] = $subscription; } $processed_rows = 0; foreach ($subscriptions as $user => $user_subscriptions) { if (++$processed_rows <= $export->offset) { continue; } foreach ($user_subscriptions as $key => $subscription) { $filtered_subscriptions[$user][$key] = $subscription; } if ($processed_rows == $export->limit_volume) { break; } } return $filtered_subscriptions; }
/** * If requesting a payment method change, replace the woocommerce_pay_shortcode() with a change payment form. * * @since 1.4 */ public static function maybe_replace_pay_shortcode() { global $woocommerce; if (!self::$is_request_to_change_payment) { return; } ob_clean(); do_action('before_woocommerce_pay'); echo '<div class="woocommerce">'; if (!empty(self::$woocommerce_errors)) { foreach (self::$woocommerce_errors as $error) { WC_Subscriptions::add_notice($error, 'error'); } } if (!empty(self::$woocommerce_messages)) { foreach (self::$woocommerce_messages as $message) { WC_Subscriptions::add_notice($message, 'success'); } } $subscription_key = $_GET['change_payment_method']; $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key); if (wp_verify_nonce($_GET['_wpnonce'], __FILE__) === false) { WC_Subscriptions::add_notice(__('There was an error with your request. Please try again.', 'woocommerce-subscriptions'), 'error'); WC_Subscriptions::print_notices(); } elseif (!WC_Subscriptions_Manager::user_owns_subscription($subscription_key)) { WC_Subscriptions::add_notice(__('That doesn\'t appear to be one of your subscriptions.', 'woocommerce-subscriptions'), 'error'); WC_Subscriptions::print_notices(); } elseif (empty($subscription)) { WC_Subscriptions::add_notice(__('Invalid subscription.', 'woocommerce-subscriptions'), 'error'); WC_Subscriptions::print_notices(); } elseif (!WC_Subscriptions_Manager::can_subscription_be_changed_to('new-payment-method', $subscription_key, get_current_user_id())) { WC_Subscriptions::add_notice(__('The payment method can not be changed for that subscription.', 'woocommerce-subscriptions'), 'error'); WC_Subscriptions::print_notices(); } else { $order = new WC_Order($subscription['order_id']); $order_id = absint($_GET['order_id']); $order_key = isset($_GET['key']) ? $_GET['key'] : $_GET['order']; $product_id = $subscription['product_id']; $next_payment_timestamp = WC_Subscriptions_Order::get_next_payment_timestamp($order, $product_id); if (!empty($next_payment_timestamp)) { $next_payment_string = sprintf(__(' Next payment is due %s.', 'woocommerce-subscriptions'), date_i18n(woocommerce_date_format(), $next_payment_timestamp)); } else { $next_payment_string = ''; } WC_Subscriptions::add_notice(sprintf(__('Choose a new payment method.%s', 'woocommerce-subscriptions'), $next_payment_string), 'notice'); WC_Subscriptions::print_notices(); if ($order->order_key == $order_key) { // Set customer location to order location if ($order->billing_country) { $woocommerce->customer->set_country($order->billing_country); } if ($order->billing_state) { $woocommerce->customer->set_state($order->billing_state); } if ($order->billing_postcode) { $woocommerce->customer->set_postcode($order->billing_postcode); } // Show form WC_Subscriptions_Order::$recurring_only_price_strings = true; woocommerce_get_template('checkout/form-change-payment-method.php', array('order' => $order, 'subscription_key' => $subscription_key), '', plugin_dir_path(WC_Subscriptions::$plugin_file) . 'templates/'); WC_Subscriptions_Order::$recurring_only_price_strings = false; } else { WC_Subscriptions::add_notice(__('Invalid order.', 'woocommerce-subscriptions'), 'error'); WC_Subscriptions::print_notices(); } } }
/** * Make sure anything requesting the first payment date for a synced subscription on the front-end receives * a date which takes into account the day on which payments should be processed. * * This is necessary as the self::calculate_first_payment_date() is not called when the subscription is active * (which it isn't until the first payment is completed and the subscription is activated). * * @since 1.5 */ public static function get_first_payment_date($first_payment_date, $order, $product_id, $type) { $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order->id, $product_id); if (self::order_contains_synced_subscription($order->id) && 1 >= WC_Subscriptions_Manager::get_subscriptions_completed_payment_count($subscription_key)) { $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key); // Don't prematurely set the first payment date when manually adding a subscription from the admin if (defined('WOOCOMMERCE_CHECKOUT') && true === WOOCOMMERCE_CHECKOUT || !is_admin() || 'active' == $subscription['status']) { $id_for_calculation = !empty($subscription['variation_id']) ? $subscription['variation_id'] : $subscription['product_id']; $first_payment_timestamp = self::calculate_first_payment_date($id_for_calculation, 'timestamp', $order->order_date); if (0 != $first_payment_timestamp) { $first_payment_date = 'mysql' == $type ? date('Y-m-d H:i:s', $first_payment_timestamp) : $first_payment_timestamp; } } } return $first_payment_date; }
/** * Gets all the active and inactive subscriptions for all users. * * @return array An associative array containing all users with subscriptions and the details of their subscriptions: 'user_id' => $subscriptions * @since 1.0 */ public static function get_all_users_subscriptions() { global $wpdb; $subscriptions = array(); $sql = "SELECT DISTINCT i.order_id, m.product_id, p.meta_value\n\t\t\t\tFROM\n\t\t\t\t(\n\t\t\t\tSELECT order_item_id,\n\t\t\t\tMAX(CASE WHEN meta_key = '_product_id' THEN meta_value END) product_id\n\t\t\t\tFROM {$wpdb->prefix}woocommerce_order_itemmeta\n\t\t\t\tWHERE meta_key LIKE '_subscription%' \n\t\t\t\t\tOR meta_key LIKE '_recurring%'\n\t\t\t\t\tOR meta_key = '_product_id'\n\t\t\t\tGROUP BY order_item_id\n\t\t\t\tHAVING MAX(meta_key LIKE '_subscription%')\n\t\t\t\t\t+ MAX(meta_key LIKE '_recurring%') > 0\n\t\t\t\t) m JOIN {$wpdb->prefix}woocommerce_order_items i \n\t\t\t\tON m.order_item_id = i.order_item_id \n\t\t\t\tLEFT JOIN {$wpdb->prefix}postmeta p \n\t\t\t\tON i.order_id = p.post_id \n\t\t\t\tAND p.meta_key = '_customer_user'\n\t\t\t\tLEFT JOIN {$wpdb->prefix}posts po \n\t\t\t\tON p.post_id = po.ID\n\t\t\t\tWHERE po.post_type = 'shop_order' AND po.post_parent = 0"; $order_ids_and_product_ids = $wpdb->get_results($sql); foreach ($order_ids_and_product_ids as $order_id_and_product_id) { if (empty($order_id_and_product_id->product_id)) { continue; } $subscription_key = $order_id_and_product_id->order_id . '_' . $order_id_and_product_id->product_id; $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key); $subscriptions[$order_id_and_product_id->meta_value][$subscription_key] = $subscription; } return apply_filters('woocommerce_all_users_subscriptions', $subscriptions); }
/** * Get the subscription for a membership * * @since 1.0.0 * @param int $user_membership_id User Membership ID * @return array|null Subscription or null, if not found */ public function get_user_membership_subscription($user_membership_id) { // 2.0 onwards if ($this->is_subscriptions_gte_2_0()) { $subscription_id = $this->get_user_membership_subscription_id($user_membership_id); if (!$subscription_id) { return null; } return wcs_get_subscription($subscription_id); } else { $subscription_key = $this->get_user_membership_subscription_key($user_membership_id); if (!$subscription_key) { return null; } $user_membership = wc_memberships_get_user_membership($user_membership_id); // It seems that the order has been deleted if (false === get_post_status($user_membership->get_order_id())) { return null; } // It seems the subscription product has been removed from the order if (!WC_Subscriptions_Order::get_item_id_by_subscription_key($subscription_key)) { return null; } return WC_Subscriptions_Manager::get_subscription($subscription_key); } }
/** * Check if a given subscription can be renewed. * * For a subscription to be renewable, it must be inactive (expired or cancelled) and its parent order * must not have already been superseded by a renewal order. This last part is mainly just to prevent * displaying "Renew" links on subscriptions that have already been renewed. * * @param $subscription_key string A subscription key of the form created by @see self::get_subscription_key() * @param $user_id int The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @since 1.2 */ public static function can_subscription_be_renewed($subscription_key, $user_id = '') { $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key, $user_id); if (empty($subscription)) { $subscription_can_be_renewed = false; } else { $renewal_orders = get_posts(array('meta_key' => '_original_order', 'meta_value' => $subscription['order_id'], 'post_type' => 'shop_order', 'post_parent' => 0)); if (empty($renewal_orders) && in_array($subscription['status'], array('cancelled', 'expired', 'trash', 'failed'))) { $subscription_can_be_renewed = true; } else { $subscription_can_be_renewed = false; } } return apply_filters('woocommerce_can_subscription_be_renewed', $subscription_can_be_renewed, $subscription, $subscription_key, $user_id); }
public function maybe_update_subscription_order_addresses($user_id, $load_address) { global $woocommerce, $wp; if (!WC_Subscriptions_Manager::user_has_subscription($user_id)) { return; } if ($load_address != 'shipping') { return; } $subscription_ids = array(); if (isset($_POST['update_all_subscriptions_addresses'])) { $users_subscriptions = WC_Subscriptions_Manager::get_users_subscriptions($user_id); foreach ($users_subscriptions as $subscription) { array_push($subscription_ids, $subscription['order_id']); } } elseif (isset($_POST['update_subscription_address'])) { $subscription = WC_Subscriptions_Manager::get_subscription($_POST['update_subscription_address']); // Update the address only if the user actually owns the subscription if (!empty($subscription)) { array_push($subscription_ids, $subscription['order_id']); } } if (count($subscription_ids) > 0) { $base_order = $order = wc_get_order($subscription_ids[0]); $args = array('numberposts' => -1, 'post_type' => 'shop_order', 'post_status' => 'publish', 'tax_query' => array(array('taxonomy' => 'shop_order_status', 'field' => 'slug', 'terms' => array('processing'))), 'meta_query' => array(array('key' => '_customer_user', 'value' => $user_id), array('key' => '_original_order', 'value' => $subscription_ids))); $posts = get_posts($args); $address = array('first_name' => $base_order->shipping_first_name, 'last_name' => $base_order->shipping_last_name, 'address_1' => $base_order->shipping_address_1, 'address_2' => $base_order->shipping_address_2, 'city' => $base_order->shipping_city, 'state' => $base_order->shipping_state, 'postcode' => $base_order->shipping_postcode, 'country' => $base_order->shipping_country); foreach ($posts as $post) { $order = wc_get_order($post->ID); $order->set_address($address, 'shipping'); } } }
/** * Checks if a user (by email) has bought an item. * @access public * @since 1.0.0 * @param string $customer_email * @param int $user_id * @param int $product_id * @return bool */ public static function sensei_customer_bought_product($customer_email, $user_id, $product_id) { global $wpdb; $emails = array(); if ($user_id) { $user = get_user_by('id', intval($user_id)); $emails[] = $user->user_email; } if (is_email($customer_email)) { $emails[] = $customer_email; } if (sizeof($emails) == 0) { return false; } $orders = get_posts(array('posts_per_page' => -1, 'meta_key' => '_customer_user', 'meta_value' => intval($user_id), 'post_type' => 'shop_order', 'post_status' => array('wc-processing', 'wc-completed'))); foreach ($orders as $order_id) { $order = new WC_Order($order_id->ID); if ($order->post_status == 'wc-completed') { if (0 < sizeof($order->get_items())) { foreach ($order->get_items() as $item) { // Allow product ID to be filtered $product_id = apply_filters('sensei_bought_product_id', $product_id, $order); // Check if user has bought product if ($item['product_id'] == $product_id || $item['variation_id'] == $product_id) { // Check if user has an active subscription for product if (class_exists('WC_Subscriptions_Manager')) { $sub_key = WC_Subscriptions_Manager::get_subscription_key($order_id->ID, $product_id); if ($sub_key) { $sub = WC_Subscriptions_Manager::get_subscription($sub_key); if ($sub && isset($sub['status'])) { if ('active' == $sub['status']) { return true; } else { return false; } } } } // Customer has bought product return true; } // End If Statement } // End For Loop } // End If Statement } // End If Statement } // End For Loop }
/** * Records the initial payment against a subscription. * * This function is called when a gateway calls @see WC_Order::payment_complete() and payment * is completed on an order. It is also called when an orders status is changed to completed or * processing for those gateways which never call @see WC_Order::payment_complete(), like the * core WooCommerce Cheque and Bank Transfer gateways. * * @param $order WC_Order | int A WC_Order object or ID of a WC_Order order. * @since 1.1.2 */ public static function maybe_record_order_payment($order) { if (!is_object($order)) { $order = new WC_Order($order); } $subscriptions_in_order = self::get_recurring_items($order); foreach ($subscriptions_in_order as $subscription_item) { $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order->id, $subscription_item['id']); $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key, $order->customer_user); // No payments have been recorded yet if (empty($subscription['completed_payments'])) { // Don't duplicate orders remove_action('processed_subscription_payment', 'WC_Subscriptions_Renewal_Order::generate_paid_renewal_order', 10, 2); WC_Subscriptions_Manager::process_subscription_payments_on_order($order->id); WC_Subscriptions_Manager::safeguard_scheduled_payments($order->customer_user, $subscription_key); // Make sure orders are still generated for other payments in the same request add_action('processed_subscription_payment', 'WC_Subscriptions_Renewal_Order::generate_paid_renewal_order', 10, 2); } } }
/** * When a subscriber's billing or shipping address is successfully updated, check if the subscriber * has also requested to update the addresses on existing subscriptions and if so, go ahead and update * the addresses on the initial order for each subscription. * * @param int $user_id The ID of a user who own's the subscription (and address) * @since 1.3 */ public static function maybe_update_subscription_addresses($user_id) { global $woocommerce; if (!WC_Subscriptions_Manager::user_has_subscription($user_id) || !isset($_GET['address'])) { return; } $load_address = isset($_GET['address']) ? esc_attr($_GET['address']) : ''; $load_address = $load_address == 'billing' || $load_address == 'shipping' ? $load_address : ''; $address_fields = $woocommerce->countries->get_address_fields(esc_attr($_POST[$load_address . '_country']), $load_address . '_'); if (isset($_POST['update_all_subscriptions_addresses'])) { $users_subscriptions = WC_Subscriptions_Manager::get_users_subscriptions($user_id); foreach ($users_subscriptions as $subscription) { self::maybe_update_order_address($subscription, $address_fields); } } elseif (isset($_POST['update_subscription_address'])) { $subscription = WC_Subscriptions_Manager::get_subscription($_POST['update_subscription_address']); // Update the address only if the user actually owns the subscription if (!empty($subscription)) { self::maybe_update_order_address($subscription, $address_fields); } } }
/** * On the scheduled action hook, run the function. */ function ps_do_this_daily() { global $wpdb; // if(date('l') == "Saturday") { // Cron run daily but execute only in sunday $allUser = $wpdb->get_results('SELECT * FROM wp_users WHERE 1;'); // if(date('l') != "Tuesday" || date('l') != "Wednesday") $nxtTues = date_i18n('Ymd', strtotime('next tuesday')); // Get the Next Tuesday to run cron /* else $nxtTues = date('Ymd', strtotime('next tuesday')); // Get the Next Tuesday to run cron*/ //$nxtTues = $nxtTues + 7; $wsm = new WC_Subscriptions_Manager(); foreach ($allUser as $auK => $auV) { $userID = $auV->ID; $parmanent_cancel_delivery = get_user_meta($userID, 'permanent_pause', true); if (empty($parmanent_cancel_delivery)) { $susPendedData = get_user_meta($userID, 'suspended', false); $cur_user_subscription = get_user_meta($userID, 'wp_woocommerce_subscriptions', true); foreach ($cur_user_subscription as $suk => $suv) { //$subscriptionID = $suv['order_id'] . '_' . $suv['product_id']; $subscriptionID = $suk; break; /* use because one time subscription */ } if (in_array($nxtTues, $susPendedData)) { $wsm->put_subscription_on_hold($userID, $subscriptionID); } else { $s = WC_Subscriptions_Manager::get_subscription($subscriptionID, $userID); if (!empty($s['status']) && $s['status'] == 'on-hold') { $wsm->reactivate_subscription($userID, $subscriptionID); } } wp_mail('*****@*****.**', 'The subject', 'nxtTues=>' . $nxtTues . "susPendedData=>" . json_encode($cur_user_subscription) . "u=>" . $userID); } } // } }
/** * Handles the display of builder sections. */ public function get_builder_display($field, $where, $args, $form_prefix = "", $product_id = 0) { /* $form_prefix shoud be passed with _ if not empty */ $columns = array("w25" => array("col-3", 25), "w33" => array("col-4", 33), "w50" => array("col-6", 50), "w66" => array("col-8", 66), "w75" => array("col-9", 75), "w100" => array("col-12", 100)); extract($args, EXTR_OVERWRITE); if (isset($field['sections']) && is_array($field['sections'])) { $args = array('field_id' => 'tm-epo-field-' . $unit_counter); wc_get_template('tm-builder-start.php', $args, $this->_namespace, $this->template_path); $_section_totals = 0; foreach ($field['sections'] as $section) { if (!isset($section['sections_placement']) || $section['sections_placement'] != $where) { continue; } if (isset($section['sections_size']) && isset($columns[$section['sections_size']])) { $size = $columns[$section['sections_size']][0]; } else { $size = "col-12"; } $_section_totals = $_section_totals + $columns[$section['sections_size']][1]; if ($_section_totals > 100) { $_section_totals = $columns[$section['sections_size']][1]; echo '<div class="cpfclear"></div>'; } $divider = ""; if (isset($section['divider_type'])) { switch ($section['divider_type']) { case "hr": $divider = '<hr>'; break; case "divider": $divider = '<div class="tm_divider"></div>'; break; case "padding": $divider = '<div class="tm_padding"></div>'; break; } } $label_size = 'h3'; if (!empty($section['label_size'])) { switch ($section['label_size']) { case "1": $label_size = 'h1'; break; case "2": $label_size = 'h2'; break; case "3": $label_size = 'h3'; break; case "4": $label_size = 'h4'; break; case "5": $label_size = 'h5'; break; case "6": $label_size = 'h6'; break; case "7": $label_size = 'p'; break; case "8": $label_size = 'div'; break; case "9": $label_size = 'span'; break; } } $args = array('column' => $size, 'style' => $section['sections_style'], 'uniqid' => $section['sections_uniqid'], 'logic' => esc_html(json_encode((array) json_decode($section['sections_clogic']))), 'haslogic' => $section['sections_logic'], 'sections_class' => $section['sections_class'], 'sections_type' => $section['sections_type'], 'title_size' => $label_size, 'title' => !empty($section['label']) ? $section['label'] : "", 'title_color' => !empty($section['label_color']) ? $section['label_color'] : "", 'description' => !empty($section['description']) ? $section['description'] : "", 'description_color' => !empty($section['description_color']) ? $section['description_color'] : "", 'description_position' => !empty($section['description_position']) ? $section['description_position'] : "", 'divider' => $divider); // custom variations check if (isset($section['elements']) && is_array($section['elements']) && isset($section['elements'][0]) && is_array($section['elements'][0]) && isset($section['elements'][0]['type']) && $section['elements'][0]['type'] == 'variations') { $args['sections_class'] = $args['sections_class'] . " tm-epo-variation-section"; } wc_get_template('tm-builder-section-start.php', $args, $this->_namespace, $this->template_path); if (isset($section['elements']) && is_array($section['elements'])) { $totals = 0; $slide_counter = 0; $use_slides = false; $doing_slides = false; if ($section['sections_slides'] !== "" && $section['sections_type'] == "slider") { $sections_slides = explode(",", $section['sections_slides']); $use_slides = true; } foreach ($section['elements'] as $element) { $empty_rules = ""; if (isset($element['rules_filtered'])) { $empty_rules = esc_html(json_encode($element['rules_filtered'])); } $empty_rules_type = ""; if (isset($element['rules_type'])) { $empty_rules_type = esc_html(json_encode($element['rules_type'])); } if (isset($element['size']) && isset($columns[$element['size']])) { $size = $columns[$element['size']][0]; } else { $size = "col-12"; } $test_for_first_slide = false; if ($use_slides && isset($sections_slides[$slide_counter])) { $sections_slides[$slide_counter] = intval($sections_slides[$slide_counter]); if ($sections_slides[$slide_counter] > 0 && !$doing_slides) { echo '<div class="tm-slide">'; $doing_slides = true; $test_for_first_slide = true; } } $fee_name = $this->fee_name; $cart_fee_name = $this->cart_fee_name; $totals = $totals + $columns[$element['size']][1]; if ($totals > 100 && !$test_for_first_slide) { $totals = $columns[$element['size']][1]; echo '<div class="cpfclear"></div>'; } $divider = ""; if (isset($element['divider_type'])) { $divider_class = ""; if ($element['type'] == 'divider' && !empty($element['class'])) { $divider_class = " " . $element['class']; } switch ($element['divider_type']) { case "hr": $divider = '<hr' . $divider_class . '>'; break; case "divider": $divider = '<div class="tm_divider' . $divider_class . '"></div>'; break; case "padding": $divider = '<div class="tm_padding' . $divider_class . '"></div>'; break; } } $label_size = 'h3'; if (!empty($element['label_size'])) { switch ($element['label_size']) { case "1": $label_size = 'h1'; break; case "2": $label_size = 'h2'; break; case "3": $label_size = 'h3'; break; case "4": $label_size = 'h4'; break; case "5": $label_size = 'h5'; break; case "6": $label_size = 'h6'; break; case "7": $label_size = 'p'; break; case "8": $label_size = 'div'; break; case "9": $label_size = 'span'; break; case "10": $label_size = 'label'; break; } } $variations_builder_element_start_args = array(); $tm_validation = $this->get_tm_validation_rules($element); $args = array('tm_element_settings' => $element, 'column' => $size, 'class' => !empty($element['class']) ? $element['class'] : "", 'title_size' => $label_size, 'title' => !empty($element['label']) ? $element['label'] : "", 'title_position' => !empty($element['label_position']) ? $element['label_position'] : "", 'title_color' => !empty($element['label_color']) ? $element['label_color'] : "", 'description' => !empty($element['description']) ? $element['description'] : "", 'description_color' => !empty($element['description_color']) ? $element['description_color'] : "", 'description_position' => !empty($element['description_position']) ? $element['description_position'] : "", 'divider' => $divider, 'required' => $element['required'], 'type' => $element['type'], 'use_images' => $element['use_images'], 'use_url' => $element['use_url'], 'rules' => $empty_rules, 'rules_type' => $empty_rules_type, 'element' => $element['type'], 'class_id' => "tm-element-ul-" . $element['type'] . " element_" . $element_counter . $form_prefix, 'uniqid' => $element['uniqid'], 'logic' => esc_html(json_encode((array) json_decode($element['clogic']))), 'haslogic' => $element['logic'], 'clear_options' => empty($element['clear_options']) ? "" : $element['clear_options'], 'exactlimit' => empty($element['exactlimit']) ? "" : 'tm-exactlimit', 'minimumlimit' => empty($element['minimumlimit']) ? "" : 'tm-minimumlimit', 'tm_validation' => esc_html(json_encode($tm_validation))); if ($element['type'] != "variations") { wc_get_template('tm-builder-element-start.php', $args, $this->_namespace, $this->template_path); } else { $variations_builder_element_start_args = $args; } $field_counter = 0; $init_class = "TM_EPO_FIELDS_" . $element['type']; if (!class_exists($init_class) && !empty($this->tm_builder_elements[$element['type']]["_is_addon"])) { $init_class = "TM_EPO_FIELDS"; } if (isset($this->tm_builder_elements[$element['type']]) && ($this->tm_builder_elements[$element['type']]["is_post"] == "post" || $this->tm_builder_elements[$element['type']]["is_post"] == "display") && class_exists($init_class)) { $field_obj = new $init_class(); if ($this->tm_builder_elements[$element['type']]["is_post"] == "post") { if ($this->tm_builder_elements[$element['type']]["type"] == "single" || $this->tm_builder_elements[$element['type']]["type"] == "multiplesingle") { $tabindex++; $name_inc = $this->tm_builder_elements[$element['type']]["post_name_prefix"] . "_" . $element_counter . $form_prefix; if ($this->tm_builder_elements[$element['type']]["type"] == "single") { $is_fee = !empty($element['rules_type']) && $element['rules_type'][0][0] == "subscriptionfee"; $is_cart_fee = !empty($element['rules_type']) && isset($element['rules_type'][0]) && isset($element['rules_type'][0][0]) && $element['rules_type'][0][0] == "fee"; } elseif ($this->tm_builder_elements[$element['type']]["type"] == "multiplesingle") { $is_fee = !empty($element['selectbox_fee']) && $element['selectbox_fee'][0][0] == "subscriptionfee"; $is_cart_fee = !empty($element['selectbox_cart_fee']) && $element['selectbox_cart_fee'][0][0] == "fee"; } if ($is_fee) { $name_inc = $fee_name . $name_inc; } elseif ($is_cart_fee) { $name_inc = $cart_fee_name . $name_inc; } if (isset($_GET['switch-subscription']) && (function_exists('wcs_get_subscription') || class_exists('WC_Subscriptions_Manager') && class_exists('WC_Subscriptions_Order'))) { $item = false; if (function_exists('wcs_get_subscription')) { $subscription = wcs_get_subscription($_GET['switch-subscription']); if ($subscription instanceof WC_Subscription) { $original_order = new WC_Order($subscription->order->id); $item = WC_Subscriptions_Order::get_item_by_product_id($original_order, $subscription->id); } } else { $subscription = WC_Subscriptions_Manager::get_subscription($_GET['switch-subscription']); $original_order = new WC_Order($subscription['order_id']); $item = WC_Subscriptions_Order::get_item_by_product_id($original_order, $subscription['product_id']); } if ($item) { $saved_data = maybe_unserialize($item["item_meta"]["_tmcartepo_data"][0]); foreach ($saved_data as $key => $val) { if (isset($val["key"])) { if ($element['uniqid'] == $val["section"]) { $_GET['tmcp_' . $name_inc] = $val["key"]; if (isset($val['quantity'])) { $_GET['tmcp_' . $name_inc . '_quantity'] = $val['quantity']; } } } else { if ($element['uniqid'] == $val["section"]) { $_GET['tmcp_' . $name_inc] = $val["value"]; if (isset($val['quantity'])) { $_GET['tmcp_' . $name_inc . '_quantity'] = $val['quantity']; } } } } } } elseif (!empty($this->cart_edit_key) && isset($_GET['_wpnonce']) && wp_verify_nonce($_GET['_wpnonce'], 'tm-edit')) { $_cart = WC()->cart; if (isset($_cart->cart_contents) && isset($_cart->cart_contents[$this->cart_edit_key])) { if (!empty($_cart->cart_contents[$this->cart_edit_key]['tmcartepo'])) { $saved_epos = $_cart->cart_contents[$this->cart_edit_key]['tmcartepo']; foreach ($saved_epos as $key => $val) { if (isset($val["key"])) { if ($element['uniqid'] == $val["section"]) { $_GET['tmcp_' . $name_inc] = $val["key"]; if (isset($val['quantity'])) { $_GET['tmcp_' . $name_inc . '_quantity'] = $val['quantity']; } } } else { if ($element['uniqid'] == $val["section"]) { $_GET['tmcp_' . $name_inc] = $val["value"]; if (isset($val['quantity'])) { $_GET['tmcp_' . $name_inc . '_quantity'] = $val['quantity']; } } } } } if (!empty($_cart->cart_contents[$this->cart_edit_key]['tmcartfee'])) { $saved_fees = $_cart->cart_contents[$this->cart_edit_key]['tmcartfee']; foreach ($saved_fees as $key => $val) { if (isset($val["key"])) { if ($element['uniqid'] == $val["section"]) { $_GET['tmcp_' . $name_inc] = $val["key"]; if (isset($val['quantity'])) { $_GET['tmcp_' . $name_inc . '_quantity'] = $val['quantity']; } } } else { if ($element['uniqid'] == $val["section"]) { $_GET['tmcp_' . $name_inc] = $val["value"]; if (isset($val['quantity'])) { $_GET['tmcp_' . $name_inc . '_quantity'] = $val['quantity']; } } } } } if (!empty($_cart->cart_contents[$this->cart_edit_key]['tmsubscriptionfee'])) { $saved_subscriptionfees = $_cart->cart_contents[$this->cart_edit_key]['tmsubscriptionfee']; foreach ($saved_subscriptionfees as $key => $val) { if (isset($val["key"])) { if ($element['uniqid'] == $val["section"]) { $_GET['tmcp_' . $name_inc] = $val["key"]; if (isset($val['quantity'])) { $_GET['tmcp_' . $name_inc . '_quantity'] = $val['quantity']; } } } else { if ($element['uniqid'] == $val["section"]) { $_GET['tmcp_' . $name_inc] = $val["value"]; if (isset($val['quantity'])) { $_GET['tmcp_' . $name_inc . '_quantity'] = $val['quantity']; } } } } } } } $display = $field_obj->display_field($element, array('name_inc' => $name_inc, 'element_counter' => $element_counter, 'tabindex' => $tabindex, 'form_prefix' => $form_prefix, 'field_counter' => $field_counter)); if (is_array($display)) { $args = array('tm_element_settings' => $element, 'id' => 'tmcp_' . $this->tm_builder_elements[$element['type']]["post_name_prefix"] . '_' . $tabindex . $form_prefix, 'name' => 'tmcp_' . $name_inc, 'class' => !empty($element['class']) ? $element['class'] : "", 'tabindex' => $tabindex, 'rules' => isset($element['rules_filtered']) ? esc_html(json_encode($element['rules_filtered'])) : '', 'rules_type' => isset($element['rules_type']) ? esc_html(json_encode($element['rules_type'])) : '', 'amount' => '0 ' . $_currency, 'fieldtype' => $is_fee ? $this->fee_name_class : ($is_cart_fee ? $this->cart_fee_class : "tmcp-field"), 'field_counter' => $field_counter); $args = array_merge($args, $display); if ($this->tm_builder_elements[$element['type']]["_is_addon"]) { do_action("tm_epo_display_addons", $element, $args, array('name_inc' => $name_inc, 'element_counter' => $element_counter, 'tabindex' => $tabindex, 'form_prefix' => $form_prefix, 'field_counter' => $field_counter), $this->tm_builder_elements[$element['type']]["namespace"]); } elseif (is_readable($this->template_path . 'tm-' . $element['type'] . '.php')) { wc_get_template('tm-' . $element['type'] . '.php', $args, $this->_namespace, $this->template_path); } } } elseif ($this->tm_builder_elements[$element['type']]["type"] == "multipleall" || $this->tm_builder_elements[$element['type']]["type"] == "multiple") { $field_obj->display_field_pre($element, array('element_counter' => $element_counter, 'tabindex' => $tabindex, 'form_prefix' => $form_prefix, 'field_counter' => $field_counter, 'product_id' => isset($product_id) ? $product_id : 0)); foreach ($element['options'] as $value => $label) { $tabindex++; if ($this->tm_builder_elements[$element['type']]["type"] == "multipleall") { $name_inc = $this->tm_builder_elements[$element['type']]["post_name_prefix"] . "_" . $element_counter . "_" . $field_counter . $form_prefix; } else { $name_inc = $this->tm_builder_elements[$element['type']]["post_name_prefix"] . "_" . $element_counter . $form_prefix; } $is_fee = isset($element['rules_type'][$value]) && $element['rules_type'][$value][0] == "subscriptionfee"; $is_cart_fee = isset($element['rules_type'][$value]) && $element['rules_type'][$value][0] == "fee"; if ($is_fee) { $name_inc = $fee_name . $name_inc; } elseif ($is_cart_fee) { $name_inc = $cart_fee_name . $name_inc; } $display = $field_obj->display_field($element, array('name_inc' => $name_inc, 'value' => $value, 'label' => $label, 'element_counter' => $element_counter, 'tabindex' => $tabindex, 'form_prefix' => $form_prefix, 'field_counter' => $field_counter)); if (is_array($display)) { $args = array('tm_element_settings' => $element, 'id' => 'tmcp_' . $this->tm_builder_elements[$element['type']]["post_name_prefix"] . '_' . $element_counter . "_" . $field_counter . "_" . $tabindex . $form_prefix, 'name' => 'tmcp_' . $name_inc, 'class' => !empty($element['class']) ? $element['class'] : "", 'tabindex' => $tabindex, 'rules' => isset($element['rules_filtered'][$value]) ? esc_html(json_encode($element['rules_filtered'][$value])) : '', 'rules_type' => isset($element['rules_type'][$value]) ? esc_html(json_encode($element['rules_type'][$value])) : '', 'amount' => '0 ' . $_currency, 'fieldtype' => $is_fee ? $this->fee_name_class : ($is_cart_fee ? $this->cart_fee_class : "tmcp-field"), 'border_type' => $this->tm_epo_css_selected_border, 'field_counter' => $field_counter); $args = array_merge($args, $display); if (isset($_GET['switch-subscription']) && (function_exists('wcs_get_subscription') || class_exists('WC_Subscriptions_Manager') && class_exists('WC_Subscriptions_Order'))) { $item = false; if (function_exists('wcs_get_subscription')) { $subscription = wcs_get_subscription($_GET['switch-subscription']); if ($subscription instanceof WC_Subscription) { $original_order = new WC_Order($subscription->order->id); $item = WC_Subscriptions_Order::get_item_by_product_id($original_order, $subscription->id); } } else { $subscription = WC_Subscriptions_Manager::get_subscription($_GET['switch-subscription']); $original_order = new WC_Order($subscription['order_id']); $item = WC_Subscriptions_Order::get_item_by_product_id($original_order, $subscription['product_id']); } if ($item) { $saved_data = maybe_unserialize($item["item_meta"]["_tmcartepo_data"][0]); foreach ($saved_data as $key => $val) { if ($element['uniqid'] == $val["section"] && $args["value"] == $val["key"]) { $_GET[$args['name']] = $val["key"]; if (isset($val['quantity'])) { $_GET[$args['name'] . '_quantity'] = $val['quantity']; } } } } } elseif (!empty($this->cart_edit_key) && isset($_GET['_wpnonce']) && wp_verify_nonce($_GET['_wpnonce'], 'tm-edit')) { //add_filter('woocommerce_product_single_add_to_cart_text',array($this,'tm_woocommerce_product_single_add_to_cart_text'),9999); $_cart = WC()->cart; if (isset($_cart->cart_contents) && isset($_cart->cart_contents[$this->cart_edit_key])) { if (!empty($_cart->cart_contents[$this->cart_edit_key]['tmcartepo'])) { $saved_epos = $_cart->cart_contents[$this->cart_edit_key]['tmcartepo']; foreach ($saved_epos as $key => $val) { if ($element['uniqid'] == $val["section"] && $args["value"] == $val["key"]) { $_GET[$args['name']] = $val["key"]; if (isset($val['quantity'])) { $_GET[$args['name'] . '_quantity'] = $val['quantity']; } } } } if (!empty($_cart->cart_contents[$this->cart_edit_key]['tmcartfee'])) { $saved_fees = $_cart->cart_contents[$this->cart_edit_key]['tmcartfee']; foreach ($saved_fees as $key => $val) { if ($element['uniqid'] == $val["section"] && $args["value"] == $val["key"]) { $_GET[$args['name']] = $val["key"]; if (isset($val['quantity'])) { $_GET[$args['name'] . '_quantity'] = $val['quantity']; } } } } if (!empty($_cart->cart_contents[$this->cart_edit_key]['tmsubscriptionfee'])) { $saved_subscriptionfees = $_cart->cart_contents[$this->cart_edit_key]['tmsubscriptionfee']; foreach ($saved_subscriptionfees as $key => $val) { if ($element['uniqid'] == $val["section"] && $args["value"] == $val["key"]) { $_GET[$args['name']] = $val["key"]; if (isset($val['quantity'])) { $_GET[$args['name'] . '_quantity'] = $val['quantity']; } } } } } } if ($this->tm_builder_elements[$element['type']]["_is_addon"]) { do_action("tm_epo_display_addons", $element, $args, array('name_inc' => $name_inc, 'element_counter' => $element_counter, 'tabindex' => $tabindex, 'form_prefix' => $form_prefix, 'field_counter' => $field_counter, 'border_type' => $this->tm_epo_css_selected_border), $this->tm_builder_elements[$element['type']]["namespace"]); } elseif (is_readable($this->template_path . 'tm-' . $element['type'] . '.php')) { wc_get_template('tm-' . $element['type'] . '.php', $args, $this->_namespace, $this->template_path); } } $field_counter++; } } $element_counter++; } elseif ($this->tm_builder_elements[$element['type']]["is_post"] == "display") { $display = $field_obj->display_field($element, array('element_counter' => $element_counter, 'tabindex' => $tabindex, 'form_prefix' => $form_prefix, 'field_counter' => $field_counter)); if (is_array($display)) { $args = array('tm_element_settings' => $element, 'class' => !empty($element['class']) ? $element['class'] : "", 'form_prefix' => $form_prefix, 'field_counter' => $field_counter, 'tm_element' => $element, 'tm__namespace' => $this->_namespace, 'tm_template_path' => $this->template_path, 'tm_product_id' => $product_id); if ($element['type'] == "variations") { $args["variations_builder_element_start_args"] = $variations_builder_element_start_args; $args["variations_builder_element_end_args"] = array('tm_element_settings' => $element, 'element' => $element['type'], 'description' => !empty($element['description']) ? $element['description'] : "", 'description_color' => !empty($element['description_color']) ? $element['description_color'] : "", 'description_position' => !empty($element['description_position']) ? $element['description_position'] : ""); } $args = array_merge($args, $display); if ($this->tm_builder_elements[$element['type']]["_is_addon"]) { do_action("tm_epo_display_addons", $element, $args, array('name_inc' => '', 'element_counter' => $element_counter, 'tabindex' => $tabindex, 'form_prefix' => $form_prefix, 'field_counter' => $field_counter), $this->tm_builder_elements[$element['type']]["namespace"]); } elseif (is_readable($this->template_path . 'tm-' . $element['type'] . '.php')) { wc_get_template('tm-' . $element['type'] . '.php', $args, $this->_namespace, $this->template_path); } } } unset($field_obj); // clear memory } if ($element['type'] != "variations") { wc_get_template('tm-builder-element-end.php', array('tm_element_settings' => $element, 'element' => $element['type'], 'description' => !empty($element['description']) ? $element['description'] : "", 'description_color' => !empty($element['description_color']) ? $element['description_color'] : "", 'description_position' => !empty($element['description_position']) ? $element['description_position'] : ""), $this->_namespace, $this->template_path); } if ($use_slides && isset($sections_slides[$slide_counter])) { $sections_slides[$slide_counter] = $sections_slides[$slide_counter] - 1; if ($sections_slides[$slide_counter] <= 0) { echo '</div>'; $slide_counter++; $doing_slides = false; } } } } $args = array('column' => $size, 'style' => $section['sections_style'], 'sections_type' => $section['sections_type']); wc_get_template('tm-builder-section-end.php', $args, $this->_namespace, $this->template_path); } wc_get_template('tm-builder-end.php', array(), $this->_namespace, $this->template_path); $unit_counter++; } return array('tabindex' => $tabindex, 'unit_counter' => $unit_counter, 'field_counter' => $field_counter, 'element_counter' => $element_counter, '_currency' => $_currency); }
/** * Returns an array of order IDs for valid orders that grant group * membership for the given group to the user related to the order. * * @param int $user_id * @param int $group_id * @return array of int, order IDs */ public static function get_valid_order_ids_granting_group_membership_from_order_items($user_id, $group_id) { $order_ids = array(); if (!empty($user_id)) { $base_statuses = array('processing', 'completed'); $statuses = array('completed'); $options = get_option('groups-woocommerce', array()); $order_status = isset($options[GROUPS_WS_MEMBERSHIP_ORDER_STATUS]) ? $options[GROUPS_WS_MEMBERSHIP_ORDER_STATUS] : GROUPS_WS_DEFAULT_MEMBERSHIP_ORDER_STATUS; if ($order_status == 'processing') { $statuses[] = 'processing'; } // DO NOT use groups_ws_order_status( $statuses ) for $statuses or $base_statuses here, // $order->status doesn't provide the wc- prefix. $groups_product_groups = get_user_meta($user_id, '_groups_product_groups', true); if (empty($groups_product_groups)) { $groups_product_groups = array(); } foreach ($groups_product_groups as $order_id => $product_ids) { if ($order = Groups_WS_Helper::get_order($order_id)) { // If this is a completed/processing order, consider group assignments. // We check the order status for non-subscription products below, // for subscriptions the subscription status is checked. if (in_array($order->status, $base_statuses)) { // Note that for orders placed with versions up to 1.4.1, the following won't give the results we might expect if the product group-related information has changed since the order was placed. // As we don't store that information (WC doesn't store the whole lot of the product when purchased, nor does GW) checking the duration based on the product is the best effort at // finding out about the group membership duration we can make. // Use the order items (only existing order items are taken into account). if ($items = $order->get_items()) { foreach ($items as $item) { if ($product = $order->get_product_from_item($item)) { // Use the groups that were stored for the product when it was ordered, // this avoids hickups when the product's groups were changed since. if (isset($product_ids[$product->id]) && isset($product_ids[$product->id]['groups'])) { $product_groups = $product_ids[$product->id]['groups']; if (in_array($group_id, $product_groups)) { // non-subscriptions if (!class_exists('WC_Subscriptions_Product') || !WC_Subscriptions_Product::is_subscription($product->id)) { if (in_array($order->status, $statuses)) { if (isset($product_ids[$product->id]) && isset($product_ids[$product->id]['version'])) { $has_duration = isset($product_ids[$product->id]['duration']) && $product_ids[$product->id]['duration'] && isset($product_ids[$product->id]['duration_uom']); } else { $has_duration = Groups_WS_Product::has_duration($product); } // unlimited membership if (!$has_duration) { if (!in_array($order_id, $order_ids)) { $order_ids[] = $order_id; } } else { if (isset($product_ids[$product->id]) && isset($product_ids[$product->id]['version'])) { $duration = Groups_WS_Product::calculate_duration($product_ids[$product->id]['duration'], $product_ids[$product->id]['duration_uom']); } else { // <= 1.4.1 $duration = Groups_WS_Product::get_duration($product); } // time-limited membership if ($duration) { $start_date = $order->order_date; if ($paid_date = get_post_meta($order_id, '_paid_date', true)) { $start_date = $paid_date; } $end = strtotime($start_date) + $duration; if (time() < $end) { if (!in_array($order_id, $order_ids)) { $order_ids[] = $order_id; } } } } } } else { // include active subscriptions ( subscriptions >= 2.x ) if (function_exists('wcs_get_subscriptions_for_order')) { if ($subscriptions = wcs_get_subscriptions_for_order($order_id)) { if (is_array($subscriptions)) { foreach ($subscriptions as $subscription) { if ($subscription->has_product($product->id)) { $valid = false; if ($subscription->get_status() == 'active') { $valid = true; } else { if ($subscription->get_status() == 'cancelled') { $hook_args = array('subscription_id' => $subscription->id); $end_timestamp = wp_next_scheduled('scheduled_subscription_end_of_prepaid_term', $hook_args); if ($end_timestamp !== false && $end_timestamp > time()) { $valid = true; } } } if ($valid) { if (!in_array($order_id, $order_ids)) { $order_ids[] = $order_id; break; } } } } } } } else { $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order_id, $product->id); $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key); if (isset($subscription['status'])) { $valid = false; if ($subscription['status'] == 'active') { $valid = true; } else { if ($subscription['status'] == 'cancelled') { $hook_args = array('user_id' => (int) $user_id, 'subscription_key' => $subscription_key); $end_timestamp = wp_next_scheduled('scheduled_subscription_end_of_prepaid_term', $hook_args); if ($end_timestamp !== false && $end_timestamp > time()) { $valid = true; } } } if ($valid) { if (!in_array($order_id, $order_ids)) { $order_ids[] = $order_id; } } } } } } } } } } } } } } return $order_ids; }
/** * Prepopulate the address fields on a subscription item * * @param array $address A WooCommerce address array * @since 1.5 */ public static function maybe_populate_subscription_addresses($address) { global $woocommerce; if (isset($_GET['subscription'])) { $subscription = WC_Subscriptions_Manager::get_subscription($_GET['subscription']); $order = new WC_Order($subscription['order_id']); foreach (array_keys($address) as $key) { $address[$key]['value'] = $order->{$key}; } } return $address; }
/** * When a PayPal IPN messaged is received for a subscription transaction, * check the transaction details and * * @since 1.0 */ public static function process_paypal_ipn_request($transaction_details) { global $wpdb; $transaction_details = stripslashes_deep($transaction_details); if (!in_array($transaction_details['txn_type'], array('subscr_signup', 'subscr_payment', 'subscr_cancel', 'subscr_eot', 'subscr_failed', 'subscr_modify'))) { return; } if (empty($transaction_details['custom']) || empty($transaction_details['invoice'])) { return; } // Get the $order_id & $order_key with backward compatibility extract(self::get_order_id_and_key($transaction_details)); $transaction_details['txn_type'] = strtolower($transaction_details['txn_type']); if (self::$debug) { self::$log->add('paypal', 'Subscription Transaction Type: ' . $transaction_details['txn_type']); } if (self::$debug) { self::$log->add('paypal', 'Subscription transaction details: ' . print_r($transaction_details, true)); } $order = new WC_Order($order_id); // We have an invalid $order_id, probably because invoice_prefix has changed since the subscription was first created, so get the order by order key if (!isset($order->id)) { $order_id = function_exists('woocommerce_get_order_id_by_order_key') ? woocommerce_get_order_id_by_order_key($order_key) : $wpdb->get_var("SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = '_order_key' AND meta_value = '{$order_key}'"); $order = new WC_Order($order_id); } if ($order->order_key !== $order_key) { if (self::$debug) { self::$log->add('paypal', 'Subscription IPN Error: Order Key does not match invoice.'); } return; } if ('paypal' != $order->recurring_payment_method) { if (self::$debug) { self::$log->add('paypal', 'IPN ignored, recurring payment method has changed.'); } return; } if (isset($transaction_details['ipn_track_id'])) { // Make sure the IPN request has not already been handled $handled_ipn_requests = get_post_meta($order_id, '_paypal_ipn_tracking_ids', true); if (empty($handled_ipn_requests)) { $handled_ipn_requests = array(); } // The 'ipn_track_id' is not a unique ID and is shared between different transaction types, so create a unique ID by prepending the transaction type $transaction_id = $transaction_details['txn_type'] . '_' . $transaction_details['ipn_track_id']; if (in_array($transaction_id, $handled_ipn_requests)) { if (self::$debug) { self::$log->add('paypal', 'Subscription IPN Error: This IPN message has already been correctly handled.'); } return; } } if (isset($transaction_details['subscr_id'])) { update_post_meta($order_id, 'PayPal Subscriber ID', $transaction_details['subscr_id']); } // Get the subscription this IPN message relates to $subscriptions_in_order = WC_Subscriptions_Order::get_recurring_items($order); $subscription_item = array_pop($subscriptions_in_order); $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order->id, WC_Subscriptions_Order::get_items_product_id($subscription_item)); $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key); $is_first_payment = empty($subscription['completed_payments']) ? true : false; if ('switched' === $subscription['status']) { if (self::$debug) { self::$log->add('paypal', 'IPN ignored, subscription has been switched.'); } return; } switch ($transaction_details['txn_type']) { case 'subscr_signup': // Store PayPal Details update_post_meta($order_id, 'Payer PayPal address', $transaction_details['payer_email']); update_post_meta($order_id, 'Payer PayPal first name', $transaction_details['first_name']); update_post_meta($order_id, 'Payer PayPal last name', $transaction_details['last_name']); $default_invoice_string = self::$paypal_settings['invoice_prefix'] . ltrim($order->get_order_number(), '#'); // If the invoice ID doesn't match the default invoice ID and contains the string '-wcscpm-', the IPN is for a subscription payment method change if ($default_invoice_string != $transaction_details['invoice'] && false !== strpos($transaction_details['invoice'], '-wcscpm-')) { $is_payment_change = true; } else { $is_payment_change = false; } $switched_subscription_key = get_post_meta($order_id, '_switched_subscription_key', true); $no_initial_payment = 0 == WC_Subscriptions_Order::get_total_initial_payment($order) && WC_Subscriptions_Order::get_subscription_trial_length($order) > 0 ? true : false; // When there is a free trial & no initial payment amount, we need to mark the order as paid and activate the subscription if (!$is_payment_change && (!empty($switched_subscription_key) || $no_initial_payment)) { $order->payment_complete(); WC_Subscriptions_Manager::activate_subscriptions_for_order($order); } // Payment completed if ($is_payment_change) { $order->add_order_note(__('IPN subscription payment method changed.', WC_Subscriptions::$text_domain)); } else { $order->add_order_note(__('IPN subscription sign up completed.', WC_Subscriptions::$text_domain)); } if (self::$debug) { if ($is_payment_change) { self::$log->add('paypal', 'IPN subscription payment method changed for order ' . $order_id); } else { self::$log->add('paypal', 'IPN subscription sign up completed for order ' . $order_id); } } break; case 'subscr_payment': if ('completed' == strtolower($transaction_details['payment_status'])) { // Store PayPal Details update_post_meta($order_id, 'PayPal Transaction ID', $transaction_details['txn_id']); update_post_meta($order_id, 'Payer PayPal first name', $transaction_details['first_name']); update_post_meta($order_id, 'Payer PayPal last name', $transaction_details['last_name']); update_post_meta($order_id, 'PayPal Payment type', $transaction_details['payment_type']); // Subscription Payment completed $order->add_order_note(__('IPN subscription payment completed.', WC_Subscriptions::$text_domain)); if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment completed for order ' . $order_id); } // First payment on order, process payment & activate subscription if ($is_first_payment) { $order->payment_complete(); WC_Subscriptions_Manager::activate_subscriptions_for_order($order); } else { // We don't need to reactivate the subscription because Subs didn't suspend it remove_action('reactivated_subscription_paypal', __CLASS__ . '::reactivate_subscription_with_paypal', 10, 2); WC_Subscriptions_Manager::process_subscription_payments_on_order($order); add_action('reactivated_subscription_paypal', __CLASS__ . '::reactivate_subscription_with_paypal', 10, 2); } } elseif ('failed' == strtolower($transaction_details['payment_status'])) { // Subscription Payment completed $order->add_order_note(__('IPN subscription payment failed.', WC_Subscriptions::$text_domain)); if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment failed for order ' . $order_id); } // First payment on order, don't generate a renewal order if ($is_first_payment) { remove_action('processed_subscription_payment_failure', 'WC_Subscriptions_Renewal_Order::generate_failed_payment_renewal_order', 10, 2); } WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($order); } else { if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment notification received for order ' . $order_id . ' with status ' . $transaction_details['payment_status']); } } break; case 'subscr_cancel': if ('true' == get_post_meta($order_id, '_wcs_changing_payment_from_paypal_to_paypal', true)) { // The flag has served its purpose delete_post_meta($order_id, '_wcs_changing_payment_from_paypal_to_paypal'); if (self::$debug) { self::$log->add('paypal', 'IPN subscription cancellation request ignored as changing PayPal to PayPal, for order ' . $order_id); } } else { WC_Subscriptions_Manager::cancel_subscriptions_for_order($order); // Subscription Cancellation Completed $order->add_order_note(__('IPN subscription cancelled for order.', WC_Subscriptions::$text_domain)); if (self::$debug) { self::$log->add('paypal', 'IPN subscription cancelled for order ' . $order_id); } } break; case 'subscr_eot': // Subscription ended, either due to failed payments or expiration $subscription_length = WC_Subscriptions_Order::get_subscription_length($order); // PayPal fires the 'subscr_eot' notice immediately if a subscription is only for one billing period, so ignore the request when we only have one billing period if (1 != $subscription_length && $subscription_length != WC_Subscriptions_Order::get_subscription_interval($order)) { if (self::$debug) { self::$log->add('paypal', 'IPN subscription end-of-term for order ' . $order_id); } // Record subscription ended $order->add_order_note(__('IPN subscription end-of-term for order.', WC_Subscriptions::$text_domain)); // Ended due to failed payments so cancel the subscription if (gmdate('U') + 24 * 60 * 60 < strtotime(WC_Subscriptions_Manager::get_subscription_expiration_date(WC_Subscriptions_Manager::get_subscription_key($order->id), $order->customer_user))) { WC_Subscriptions_Manager::cancel_subscriptions_for_order($order); } else { WC_Subscriptions_Manager::expire_subscriptions_for_order($order); } } break; case 'subscr_failed': // Subscription sign up failed if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment failure for order ' . $order_id); } // Subscription Payment completed $order->add_order_note(__('IPN subscription payment failure.', WC_Subscriptions::$text_domain)); // First payment on order, don't generate a renewal order if ($is_first_payment) { remove_action('processed_subscription_payment_failure', 'WC_Subscriptions_Renewal_Order::generate_failed_payment_renewal_order', 10, 2); } WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($order_id); break; } // Store the transaction ID to avoid handling requests duplicated by PayPal if (isset($transaction_details['ipn_track_id'])) { $handled_ipn_requests[] = $transaction_id; update_post_meta($order_id, '_paypal_ipn_tracking_ids', $handled_ipn_requests); } // Prevent default IPN handling for subscription txn_types exit; }
/** * Checks if a user has bought a product item. * * @since 1.9.0 * * @param int $user_id * @param int $product_id * * @return bool */ public static function has_customer_bought_product($user_id, $product_id) { $orders = get_posts(array('posts_per_page' => -1, 'meta_key' => '_customer_user', 'meta_value' => intval($user_id), 'post_type' => 'shop_order', 'post_status' => array('wc-processing', 'wc-completed'))); foreach ($orders as $order_id) { $order = new WC_Order($order_id->ID); if ($order->post_status != 'wc-completed' && $order->post_status != 'wc-processing') { continue; } if (!(0 < sizeof($order->get_items()))) { continue; } foreach ($order->get_items() as $item) { // Check if user has bought product if ($item['product_id'] == $product_id || $item['variation_id'] == $product_id) { // Check if user has an active subscription for product if (class_exists('WC_Subscriptions_Manager')) { $sub_key = WC_Subscriptions_Manager::get_subscription_key($order_id->ID, $product_id); if ($sub_key) { $sub = WC_Subscriptions_Manager::get_subscription($sub_key); if ($sub && isset($sub['status'])) { if ('active' == $sub['status']) { return true; } else { return false; } } } } // Customer has bought product return true; } // End If Statement } // End For each item } // End For each order }
/** * Trigger a hook when a subscription suspended due to a failed renewal payment is reactivated * * @since 1.3 */ public static function trigger_processed_failed_renewal_order_payment_hook($user_id, $subscription_key) { $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key); $original_order = new WC_Order($subscription['order_id']); do_action('woocommerce_subscriptions_processed_failed_renewal_order_payment', $subscription_key, $original_order); }
/** * When a PayPal IPN messaged is received for a subscription transaction, * check the transaction details and * * @since 1.0 */ public static function process_paypal_ipn_request($transaction_details) { global $wpdb; $transaction_details = stripslashes_deep($transaction_details); if (!in_array($transaction_details['txn_type'], array('subscr_signup', 'subscr_payment', 'subscr_cancel', 'subscr_eot', 'subscr_failed', 'subscr_modify', 'recurring_payment_suspended_due_to_max_failed_payment'))) { return; } if ('recurring_payment_suspended_due_to_max_failed_payment' == $transaction_details['txn_type'] && isset($transaction_details['rp_invoice_id'])) { self::$log->add('paypal', 'Returning as "recurring_payment_suspended_due_to_max_failed_payment" transaction is for a subscription created with Express Checkout'); return; } // Get the $order_id & $order_key with backward compatibility extract(self::get_order_id_and_key($transaction_details)); $transaction_details['txn_type'] = strtolower($transaction_details['txn_type']); if (self::$debug) { self::$log->add('paypal', 'Subscription Transaction Type: ' . $transaction_details['txn_type']); } if (self::$debug) { self::$log->add('paypal', 'Subscription transaction details: ' . print_r($transaction_details, true)); } $order = new WC_Order($order_id); // We have an invalid $order_id, probably because invoice_prefix has changed since the subscription was first created, so get the order by order key if (!isset($order->id)) { $order_id = function_exists('woocommerce_get_order_id_by_order_key') ? woocommerce_get_order_id_by_order_key($order_key) : $wpdb->get_var("SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = '_order_key' AND meta_value = '{$order_key}'"); $order = new WC_Order($order_id); } if ($order->order_key !== $order_key) { if (self::$debug) { self::$log->add('paypal', 'Subscription IPN Error: Order Key does not match invoice.'); } exit; } $is_renewal_sign_up_after_failure = false; // If the invoice ID doesn't match the default invoice ID and contains the string '-wcsfrp-', the IPN is for a subscription payment to fix up a failed payment if (false !== strpos($transaction_details['invoice'], '-wcsfrp-') && in_array($transaction_details['txn_type'], array('subscr_signup', 'subscr_payment'))) { $renewal_order = new WC_Order(substr($transaction_details['invoice'], strrpos($transaction_details['invoice'], '-') + 1)); // check if the failed signup has been previously recorded if ($renewal_order->id != get_post_meta($order->id, '_paypal_failed_sign_up_recorded', true)) { $is_renewal_sign_up_after_failure = true; } } // If the invoice ID doesn't match the default invoice ID and contains the string '-wcscpm-', the IPN is for a subscription payment method change if (false !== strpos($transaction_details['invoice'], '-wcscpm-') && 'subscr_signup' == $transaction_details['txn_type']) { $is_payment_change = true; } else { $is_payment_change = false; } if ($is_renewal_sign_up_after_failure || $is_payment_change) { // Store the old profile ID on the order (for the first IPN message that comes through) $existing_profile_id = self::get_subscriptions_paypal_id($order); if (empty($existing_profile_id) || $existing_profile_id !== $transaction_details['subscr_id']) { update_post_meta($order->id, '_old_paypal_subscriber_id', $existing_profile_id); update_post_meta($order->id, '_old_recurring_payment_method', $order->recurring_payment_method); } } if ('paypal' != $order->recurring_payment_method && false === $is_renewal_sign_up_after_failure && false === $is_payment_change) { if (self::$debug) { self::$log->add('paypal', 'IPN ignored, recurring payment method has changed.'); } exit; } if (isset($transaction_details['ipn_track_id'])) { // Make sure the IPN request has not already been handled $handled_ipn_requests = get_post_meta($order_id, '_paypal_ipn_tracking_ids', true); if (empty($handled_ipn_requests)) { $handled_ipn_requests = array(); } // The 'ipn_track_id' is not a unique ID and is shared between different transaction types, so create a unique ID by prepending the transaction type $ipn_id = $transaction_details['txn_type'] . '_' . $transaction_details['ipn_track_id']; if (in_array($ipn_id, $handled_ipn_requests)) { if (self::$debug) { self::$log->add('paypal', 'Subscription IPN Error: IPN ' . $ipn_id . ' message has already been correctly handled.'); } exit; } } if (isset($transaction_details['txn_id'])) { // Make sure the IPN request has not already been handled $handled_transactions = get_post_meta($order_id, '_paypal_transaction_ids', true); if (empty($handled_transactions)) { $handled_transactions = array(); } $transaction_id = $transaction_details['txn_id']; if (isset($transaction_details['txn_type'])) { $transaction_id .= '_' . $transaction_details['txn_type']; } // The same transaction ID is used for different payment statuses, so make sure we handle it only once. See: http://stackoverflow.com/questions/9240235/paypal-ipn-unique-identifier if (isset($transaction_details['payment_status'])) { $transaction_id .= '_' . $transaction_details['payment_status']; } if (in_array($transaction_id, $handled_transactions)) { if (self::$debug) { self::$log->add('paypal', 'Subscription IPN Error: transaction ' . $transaction_id . ' has already been correctly handled.'); } exit; } } // Save the profile ID if it's not a cancellation/expiration request if (isset($transaction_details['subscr_id']) && !in_array($transaction_details['txn_type'], array('subscr_cancel', 'subscr_eot'))) { update_post_meta($order_id, 'PayPal Subscriber ID', $transaction_details['subscr_id']); if ('S-' == substr($transaction_details['subscr_id'], 0, 2) && 'disabled' != get_option('wcs_paypal_invalid_profile_id')) { update_option('wcs_paypal_invalid_profile_id', 'yes'); } } // Get the subscription this IPN message relates to $subscriptions_in_order = WC_Subscriptions_Order::get_recurring_items($order); $subscription_item = array_pop($subscriptions_in_order); $product_id = WC_Subscriptions_Order::get_items_product_id($subscription_item); $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order->id, $product_id); $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key); $is_first_payment = empty($subscription['completed_payments']) ? true : false; if ('switched' === $subscription['status']) { if (self::$debug) { self::$log->add('paypal', 'IPN ignored, subscription has been switched.'); } exit; } switch ($transaction_details['txn_type']) { case 'subscr_signup': // Store PayPal Details update_post_meta($order_id, 'Payer PayPal address', $transaction_details['payer_email']); update_post_meta($order_id, 'Payer PayPal first name', $transaction_details['first_name']); update_post_meta($order_id, 'Payer PayPal last name', $transaction_details['last_name']); $switched_subscription_key = get_post_meta($order_id, '_switched_subscription_key', true); $no_initial_payment = 0 == WC_Subscriptions_Order::get_total_initial_payment($order) ? true : false; // When there is a free trial & no initial payment amount, we need to mark the order as paid and activate the subscription if (!$is_payment_change && !$is_renewal_sign_up_after_failure && (!empty($switched_subscription_key) || $no_initial_payment)) { $order->payment_complete($transaction_details['txn_id']); } // Payment completed if ($is_payment_change) { // Set PayPal as the new payment method WC_Subscriptions_Change_Payment_Gateway::update_recurring_payment_method($subscription_key, $order, 'paypal'); $old_payment_method = get_post_meta($order->id, '_old_recurring_payment_method', true); // We need to cancel the subscription now that the method has been changed successfully if ('paypal' == $old_payment_method) { $existing_profile_id = get_post_meta($order->id, '_old_paypal_subscriber_id', true); self::cancel_subscription_with_paypal($order, $product_id, $existing_profile_id); } $order->add_order_note(__('IPN subscription payment method changed to PayPal.', 'woocommerce-subscriptions')); } else { $order->add_order_note(__('IPN subscription sign up completed.', 'woocommerce-subscriptions')); } if (self::$debug) { if ($is_payment_change) { self::$log->add('paypal', 'IPN subscription payment method changed for order ' . $order_id); } else { self::$log->add('paypal', 'IPN subscription sign up completed for order ' . $order_id); } } break; case 'subscr_payment': if ('completed' == strtolower($transaction_details['payment_status'])) { // Store PayPal Details update_post_meta($order_id, '_transaction_id', $transaction_details['txn_id']); update_post_meta($order_id, 'PayPal Transaction ID', $transaction_details['txn_id']); update_post_meta($order_id, 'Payer PayPal first name', $transaction_details['first_name']); update_post_meta($order_id, 'Payer PayPal last name', $transaction_details['last_name']); update_post_meta($order_id, 'PayPal Payment type', $transaction_details['payment_type']); // Subscription Payment completed $order->add_order_note(__('IPN subscription payment completed.', 'woocommerce-subscriptions')); if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment completed for order ' . $order_id); } // First payment on order, process payment & activate subscription if ($is_first_payment) { $order->payment_complete($transaction_details['txn_id']); WC_Subscriptions_Manager::activate_subscriptions_for_order($order); // Ignore the first IPN message if the PDT should have handled it (if it didn't handle it, it will have been dealt with as first payment), but set a flag to make sure we only ignore it once } elseif (count($subscription['completed_payments']) == 1 && !empty(self::$paypal_settings['identity_token']) && 'true' != get_post_meta($order_id, '_paypal_first_ipn_ignored_for_pdt', true) && false === $is_renewal_sign_up_after_failure) { if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment ignored for order ' . $order_id . ' due to PDT previously handling the payment.'); } update_post_meta($order_id, '_paypal_first_ipn_ignored_for_pdt', 'true'); // Process the payment if the subscription is active } elseif (!in_array($subscription['status'], array('cancelled', 'expired', 'switched', 'trash'))) { // We don't need to reactivate the subscription because Subs didn't suspend it remove_action('reactivated_subscription_paypal', __CLASS__ . '::reactivate_subscription_with_paypal', 10, 2); if (true === $is_renewal_sign_up_after_failure && is_object($renewal_order)) { $old_payment_method = get_post_meta($order->id, '_old_recurring_payment_method', true); update_post_meta($order->id, '_paypal_failed_sign_up_recorded', $renewal_order->id); // We need to cancel the old subscription now that the method has been changed successfully if ('paypal' == $old_payment_method) { $profile_id = get_post_meta($order->id, '_old_paypal_subscriber_id', true); // Make sure we don't cancel the current profile if ($profile_id !== $transaction_details['subscr_id']) { self::cancel_subscription_with_paypal($order, $product_id, $profile_id); } $order->add_order_note(__('IPN subscription failing payment method changed.', 'woocommerce-subscriptions')); } $renewal_order->payment_complete($transaction_details['txn_id']); // WC_Subscriptions_Manager::process_subscription_payments_on_order will be called with by WC_Subscriptions_Renewal_Order::process_subscription_payment_on_child_order() update_post_meta($renewal_order->id, 'PayPal Subscriber ID', $transaction_details['subscr_id']); } else { WC_Subscriptions_Manager::process_subscription_payments_on_order($order); } // Make sure the next payment date is synchronised with when PayPal processes the payments WC_Subscriptions_Manager::set_next_payment_date($subscription_key, $order->customer_user); add_action('reactivated_subscription_paypal', __CLASS__ . '::reactivate_subscription_with_paypal', 10, 2); } } elseif ('failed' == strtolower($transaction_details['payment_status'])) { // Subscription Payment completed $order->add_order_note(__('IPN subscription payment failed.', 'woocommerce-subscriptions')); if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment failed for order ' . $order_id); } // First payment on order, don't generate a renewal order if ($is_first_payment) { remove_action('processed_subscription_payment_failure', 'WC_Subscriptions_Renewal_Order::generate_failed_payment_renewal_order', 10, 2); } WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($order); } else { if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment notification received for order ' . $order_id . ' with status ' . $transaction_details['payment_status']); } } break; case 'subscr_cancel': // Make sure the subscription hasn't been linked to a new payment method if ($transaction_details['subscr_id'] != self::get_subscriptions_paypal_id($order)) { if (self::$debug) { self::$log->add('paypal', 'IPN subscription cancellation request ignored - new PayPal Profile ID linked to this subscription, for order ' . $order_id); } } else { WC_Subscriptions_Manager::cancel_subscriptions_for_order($order); // Subscription Cancellation Completed $order->add_order_note(__('IPN subscription cancelled for order.', 'woocommerce-subscriptions')); if (self::$debug) { self::$log->add('paypal', 'IPN subscription cancelled for order ' . $order_id); } } break; case 'subscr_eot': // Subscription ended, either due to failed payments or expiration if (self::$debug) { self::$log->add('paypal', 'IPN EOT request ignored for order ' . $order_id); } break; case 'subscr_failed': // Subscription sign up failed // Subscription sign up failed case 'recurring_payment_suspended_due_to_max_failed_payment': // Subscription sign up failed if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment failure for order ' . $order_id); } // Subscription Payment completed $order->add_order_note(__('IPN subscription payment failure.', 'woocommerce-subscriptions')); // First payment on order, don't generate a renewal order if ($is_first_payment) { remove_action('processed_subscription_payment_failure', 'WC_Subscriptions_Renewal_Order::generate_failed_payment_renewal_order', 10, 2); } WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($order); break; } // Store the transaction IDs to avoid handling requests duplicated by PayPal if (isset($transaction_details['ipn_track_id'])) { $handled_ipn_requests[] = $ipn_id; update_post_meta($order_id, '_paypal_ipn_tracking_ids', $handled_ipn_requests); } if (isset($transaction_details['txn_id'])) { $handled_transactions[] = $transaction_id; update_post_meta($order_id, '_paypal_transaction_ids', $handled_transactions); } // Prevent default IPN handling for subscription txn_types exit; }
/** * Checks if an order contains an in active subscription and if it does, denies download acces * to files purchased on the order. * * @return bool False if the order contains a subscription that has expired or is cancelled/on-hold, otherwise, the original value of $download_permitted * @since 1.3 */ public static function is_download_permitted($download_permitted, $order) { if (self::order_contains_subscription($order)) { foreach (self::get_recurring_items($order) as $order_item) { $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order->id, self::get_items_product_id($order_item)); $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key); if (!isset($subscription['status']) || 'active' !== $subscription['status']) { $download_permitted = false; break; } } } return $download_permitted; }
public function get_email_address_to_send($email_data, $email_order, $email) { if ($email->email_type != 'subscription') { return $email_data; } $meta = maybe_unserialize($email_order->meta); if (isset($meta['subs_key'])) { $subscription = WC_Subscriptions_Manager::get_subscription($meta['subs_key']); if (!empty($subscription)) { $order = new WC_Order($subscription['order_id']); $user = new WP_User($order->user_id); $email_data['email_to'] = $user->user_email; $email_data['first_name'] = $user->first_name; $email_data['last_name'] = $user->last_name; $email_data['cname'] = $user->first_name . ' ' . $user->last_name; } } return $email_data; }
/** * Fire a gateway specific hook when a subscription expires. * * @since 1.0 */ public static function trigger_gateway_subscription_expired_hook($user_id, $subscription_key) { $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key); $order = new WC_Order($subscription['order_id']); if (!WC_Subscriptions_Order::requires_manual_renewal($order)) { do_action('subscription_expired_' . $order->recurring_payment_method, $order, $subscription['product_id']); } }
/** * When switching a subscription we need to update old listings. * * No need to give the user a new package; thats still handled by the orders class. */ public function switched_subscription($user_id, $original_subscription_key, $new_subscription_key) { global $wpdb; // Get subscription details $old_subscription = WC_Subscriptions_Manager::get_subscription($original_subscription_key); $old_subscription_type = get_post_meta($old_subscription['product_id'], '_package_subscription_type', true); $old_subscription_type = empty($old_subscription_type) ? 'package' : $old_subscription_type; $new_subscription = WC_Subscriptions_Manager::get_subscription($new_subscription_key); $new_subscription_type = get_post_meta($new_subscription['product_id'], '_package_subscription_type', true); $new_subscription_type = empty($new_subscription_type) ? 'package' : $new_subscription_type; // Get the user package $user_package = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}wcpl_user_packages WHERE user_id = %d AND order_id = %d AND product_id = %d;", $user_id, $old_subscription['order_id'], $old_subscription['product_id'])); if ($user_package) { $switching_to_package = wc_get_product($new_subscription['product_id']); // If invalid, abort if (!$switching_to_package->is_type(array('job_package', 'resume_package', 'job_package_subscription', 'resume_package_subscription'))) { return false; } $switching_to_package_id = wc_paid_listings_give_user_package($user_id, $new_subscription['product_id'], $new_subscription['order_id']); // Ensure package is not given twice update_post_meta($new_subscription['order_id'], 'wc_paid_listings_packages_processed', true); // Upgrade? $upgrading = $switching_to_package->get_limit() >= $user_package->package_limit; // Delete the old package $wpdb->delete("{$wpdb->prefix}wcpl_user_packages", array('id' => $user_package->id)); // Update old listings if ('listing' === $new_subscription_type && $switching_to_package_id) { $listing_ids = $wpdb->get_col($wpdb->prepare("\n\t\t\t\t\tSELECT post_id FROM {$wpdb->postmeta}\n\t\t\t\t\tLEFT JOIN {$wpdb->posts} ON {$wpdb->postmeta}.post_id = {$wpdb->posts}.ID\n\t\t\t\t\tWHERE meta_key = '_user_package_id'\n\t\t\t\t\tAND meta_value = %s;\n\t\t\t\t", $user_package->id)); foreach ($listing_ids as $listing_id) { // If we are not upgrading, expire the old listing if (!$upgrading) { $listing = array('ID' => $listing_id, 'post_status' => 'expired'); wp_update_post($listing); } else { wc_paid_listings_increase_package_count($user_id, $switching_to_package_id); // Change the user package ID and package ID update_post_meta($listing_id, '_user_package_id', $switching_to_package_id); update_post_meta($listing_id, '_package_id', $new_subscription['product_id']); } // Featured or not update_post_meta($listing_id, '_featured', $switching_to_package->is_featured() ? 1 : 0); // Fire action do_action('wc_paid_listings_switched_subscription', $listing_id, $user_package); } } } }
/** * Make sure anything requesting the first payment date for a switched subscription receives a date which * takes into account the switch (i.e. prepaid days and possibly a downgrade). * * This is necessary as the self::calculate_first_payment_date() is not called when the subscription is active * (which it isn't until the first payment is completed and the subscription is activated). * * @since 1.4 */ public static function get_first_payment_date($next_payment_date, $subscription_key, $user_id, $type) { $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key); if ('active' == $subscription['status'] && self::order_contains_subscription_switch($subscription['order_id']) && 1 >= WC_Subscriptions_Manager::get_subscriptions_completed_payment_count($subscription_key)) { $first_payment_timestamp = get_post_meta($subscription['order_id'], '_switched_subscription_first_payment_timestamp', true); if (0 != $first_payment_timestamp) { $next_payment_date = 'mysql' == $type ? date('Y-m-d H:i:s', $first_payment_timestamp) : $first_payment_timestamp; } } return $next_payment_date; }
/** * If a subscription has the status of active, this function checks to make sure that a payment was completed * within the last couple of days. It is hooked to the 'paypal_check_subscription_payment' action triggered by * WP-Cron and scheduled with @see self::scheduled_subscription_payment() to run 24 hours after the payment was due. * * @since 1.4.3 */ public static function check_subscription_payment($subscription_key) { $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key); $order = new WC_Order($subscription['order_id']); if ('active' === $subscription['status']) { $last_payment_plus_two_days = 60 * 60 * 24 * 2 + WC_Subscriptions_Manager::get_last_payment_date($subscription_key, $order->user_id, 'timestamp'); // If the last payment was more than 2 days ago, then we're missing a payment because this function is called 24 hours after payment was due if ($last_payment_plus_two_days < gmdate('U')) { // @TODO process a subscription payment failure when this has been reliably tested //remove_action( 'subscription_put_on-hold_paypal', __CLASS__ . '::suspend_subscription_with_paypal', 10, 2 ); //WC_Subscriptions_Manager::process_subscription_payment_failure( $order->user_id, $subscription_key ); //$order->add_order_note( __( 'Subscription payment failure triggered as no recurring payment has been processed by PayPal.', 'woocommerce-subscriptions' ) ); //add_action( 'subscription_put_on-hold_paypal', __CLASS__ . '::suspend_subscription_with_paypal', 10, 2 ); } } }
function paymill_webhooks() { global $wpdb; // is there a webhook from Paymill? if (class_exists('WC_Subscriptions_Manager')) { // grab data from webhook $body = @file_get_contents('php://input'); $event_json = json_decode($body, true); // retrieve sub ID if (isset($event_json['event']['event_resource']['id']) && strlen($event_json['event']['event_resource']['id']) > 0) { $paymill_sub_id = $event_json['event']['event_resource']['id']; } elseif (isset($event_json['event']['event_resource']['subscription']['id']) && strlen($event_json['event']['event_resource']['subscription']['id']) > 0) { $paymill_sub_id = $event_json['event']['event_resource']['subscription']['id']; } error_log("\n\n########################################################################################################################\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log'); error_log(date(DATE_RFC822) . ' - Webhook ' . $event_json['event']['event_type'] . ' (Resource-ID: ' . $paymill_sub_id . ') triggered - start processing' . "\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log'); /* output example: array(1) { ["event"]=> array(4) { ["event_type"]=> string(20) "subscription.deleted" ["event_resource"]=> array(13) { ["id"]=> string(24) "sub_b71adbf5....." ["offer"]=> array(10) { ["id"]=> string(26) "offer_8083a5b....." ["name"]=> string(39) "woo_91_73da6....." ["amount"]=> int(100) ["currency"]=> string(3) "EUR" ["interval"]=> string(5) "1 DAY" ["trial_period_days"]=> int(0) ["created_at"]=> int(1389547028) ["updated_at"]=> int(1389547028) ["subscription_count"]=> array(2) { ["active"]=> string(1) "1" ["inactive"]=> string(1) "1" } ["app_id"]=> NULL } ["livemode"]=> bool(false) ["cancel_at_period_end"]=> bool(false) ["trial_start"]=> NULL ["trial_end"]=> NULL ["next_capture_at"]=> int(1389836717) ["created_at"]=> int(1389663382) ["updated_at"]=> int(1389750317) ["canceled_at"]=> NULL ["app_id"]=> NULL ["payment"]=> array(12) { ["id"]=> string(28) "pay_4e3759f....." ["type"]=> string(10) "creditcard" ["client"]=> string(27) "client_dbe164....." ["card_type"]=> string(4) "visa" ["country"]=> NULL ["expire_month"]=> string(2) "12" ["expire_year"]=> string(4) "2020" ["card_holder"]=> string(13) "dfgdfgdfgdfgd" ["last4"]=> string(4) "1111" ["created_at"]=> int(1389663369) ["updated_at"]=> int(1389663380) ["app_id"]=> NULL } ["client"]=> array(8) { ["id"]=> string(27) "client_dbe164....." ["email"]=> string(22) "*****@*****.**" ["description"]=> string(15) "Matthias Reuter" ["created_at"]=> int(1389547027) ["updated_at"]=> int(1389547027) ["app_id"]=> NULL ["payment"]=> array(2) { [0]=> array(12) { ["id"]=> string(28) "pay_1a5ff8....." ["type"]=> string(10) "creditcard" ["client"]=> string(27) "client_dbe16....." ["card_type"]=> string(4) "visa" ["country"]=> NULL ["expire_month"]=> string(2) "12" ["expire_year"]=> string(4) "2020" ["card_holder"]=> string(10) "dfgdfgdfgd" ["last4"]=> string(4) "1111" ["created_at"]=> int(1389547027) ["updated_at"]=> int(1389547028) ["app_id"]=> NULL } [1]=> array(12) { ["id"]=> string(28) "pay_4e375....." ["type"]=> string(10) "creditcard" ["client"]=> string(27) "client_dbe164....." ["card_type"]=> string(4) "visa" ["country"]=> NULL ["expire_month"]=> string(2) "12" ["expire_year"]=> string(4) "2020" ["card_holder"]=> string(13) "dfgdfgdfgdfgd" ["last4"]=> string(4) "1111" ["created_at"]=> int(1389663369) ["updated_at"]=> int(1389663380) ["app_id"]=> NULL } } ["subscription"]=> array(2) { [0]=> string(24) "sub_fcc4....." [1]=> string(24) "sub_b71a....." } } } ["created_at"]=> int(1389816435) ["app_id"]=> NULL } } */ //error_log(var_export($event_json,true)."\n\n", 3, PAYMILL_DIR.'lib/debug/PHP_errors.log'); // get subscription info, if available if (isset($paymill_sub_id) && strlen($paymill_sub_id) > 0) { $sql = $wpdb->prepare('SELECT * FROM ' . $wpdb->prefix . 'paymill_subscriptions WHERE paymill_sub_id=%s', array($paymill_sub_id)); $sub_cache = $wpdb->get_results($sql, ARRAY_A); $sub_cache = $sub_cache[0]; /* output example: SELECT * FROM wp_paymill_subscriptions WHERE paymill_sub_id="sub_b71adbf5e097bbe5ba80" */ error_log("\n\n" . $sql . "\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log'); /* output example: 1 30 */ //error_log($sub_cache['woo_user_id']."\n\n".$sub_cache['woo_offer_id']."\n\n", 3, PAYMILL_DIR.'lib/debug/PHP_errors.log'); $subscription = WC_Subscriptions_Manager::get_subscription($sub_cache['woo_offer_id']); // update subscriptions when webhook is triggered if (isset($sub_cache['woo_offer_id']) && strlen($sub_cache['woo_offer_id']) > 0) { // subscription successfully created if ($event_json['event']['event_type'] == 'subscription.created') { } // tell WooCommerce when payment for subscription is successfully processed if ($event_json['event']['event_type'] == 'subscription.succeeded') { /* example data WC_Subscriptions_Manager::get_subscription: array(15) { ["order_id"]=> string(3) "201" ["product_id"]=> string(2) "91" ["variation_id"]=> string(0) "" ["status"]=> string(6) "active" ["period"]=> string(3) "day" ["interval"]=> string(1) "1" ["length"]=> string(2) "12" ["start_date"]=> string(19) "2014-01-12 17:17:10" ["expiry_date"]=> string(19) "2014-01-24 17:17:10" ["end_date"]=> string(1) "0" ["trial_expiry_date"]=> string(1) "0" ["failed_payments"]=> string(1) "0" ["completed_payments"]=> array(1) { [0]=> string(19) "2014-01-12 17:17:10" } ["suspension_count"]=> string(1) "0" ["last_payment_date"]=> string(19) "2014-01-12 17:17:10" } */ error_log(var_export($subscription, true) . "\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log'); // prevent multiple subscription renewals because of multiple webhook attempts. $whole_period = 0; switch ($subscription['period']) { case 'day': default: $whole_period = intval($subscription['interval']) * 86400; break; case 'week': $whole_period = intval($subscription['interval']) * 604800; break; case 'month': $whole_period = intval($subscription['interval']) * 2160000; // using 25 days to prevent problems with shorter months break; case 'year': $whole_period = intval($subscription['interval']) * 30240000; // using 350 days to prevent any timezone problems whatsoever break; } if (count($subscription['completed_payments']) >= 1) { if (strtotime(date(DATE_RFC822)) > strtotime($subscription['last_payment_date']) + $whole_period - 18000) { // minus 5 hours to prevent any problems with pending triggers $order = new WC_Order($subscription['order_id']); //WC_Subscriptions_Manager::process_subscription_payments_on_order($order, $subscription['product_id']); WC_Subscriptions_Manager::process_subscription_payments_on_order($order); } } else { $order = new WC_Order($subscription['order_id']); $order->payment_complete(); WC_Subscriptions_Manager::activate_subscriptions_for_order($subscription['order_id']); } WC_Subscriptions_Manager::set_next_payment_date($sub_cache['woo_offer_id'], $order->customer_user); } // cancel subscription, as it was deleted through Paymill dashboard if ($event_json['event']['event_type'] == 'subscription.deleted') { $sql = $wpdb->prepare('DELETE FROM ' . $wpdb->prefix . 'paymill_subscriptions WHERE woo_user_id=%s AND woo_offer_id=%s', array($sub_cache['woo_user_id'], $sub_cache['woo_offer_id'])); $wpdb->query($sql); error_log("\n\n" . $sql . "\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log'); //WC_Subscriptions_Manager::cancel_subscriptions_for_order( $order ); WC_Subscriptions_Manager::cancel_subscription($sub_cache['woo_user_id'], $sub_cache['woo_offer_id']); } // tell WC that payment failure occured if ($event_json['event']['event_type'] == 'subscription.failed') { WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($subscription['order_id'], $subscription['product_id']); } } } error_log(date(DATE_RFC822) . ' - Webhook ' . $event_json['event']['event_type'] . ' finished - end processing' . "\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log'); error_log("\n\n########################################################################################################################\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log'); } }
/** * Calculate the timestamp for the next payment * * @param WC_Order $order * @param int $product_id * * @return mixed|void */ private static function calculate_next_payment_timestamp($order, $product_id) { $type = 'timestamp'; $from_date = ''; $from_date_arg = $from_date; $subscription = WC_Subscriptions_Manager::get_subscription(WC_Subscriptions_Manager::get_subscription_key($order->id, $product_id)); $subscription_period = WC_Subscriptions_Order::get_subscription_period($order, $product_id); $subscription_interval = WC_Subscriptions_Order::get_subscription_interval($order, $product_id); $subscription_trial_length = WC_Subscriptions_Order::get_subscription_trial_length($order, $product_id); $subscription_trial_period = WC_Subscriptions_Order::get_subscription_trial_period($order, $product_id); $trial_end_time = !empty($subscription['trial_expiry_date']) ? $subscription['trial_expiry_date'] : WC_Subscriptions_Product::get_trial_expiration_date($product_id, get_gmt_from_date($order->order_date)); $trial_end_time = strtotime($trial_end_time); // If the subscription has a free trial period, and we're still in the free trial period, the next payment is due at the end of the free trial if ($subscription_trial_length > 0 && $trial_end_time > gmdate('U') + 60 * 60 * 23 + 120) { // Make sure trial expiry is more than 23+ hours in the future to account for trial expiration dates incorrectly stored in non-UTC/GMT timezone (and also for any potential changes to the site's timezone) $next_payment_timestamp = $trial_end_time; // The next payment date is {interval} billing periods from the from date } else { // We have a timestamp if (!empty($from_date) && is_numeric($from_date)) { $from_date = date('Y-m-d H:i:s', $from_date); } if (empty($from_date)) { if (!empty($subscription['completed_payments'])) { $from_date = array_pop($subscription['completed_payments']); $add_failed_payments = true; } else { if (!empty($subscription['start_date'])) { $from_date = $subscription['start_date']; $add_failed_payments = true; } else { $from_date = gmdate('Y-m-d H:i:s'); $add_failed_payments = false; } } $failed_payment_count = WC_Subscriptions_Order::get_failed_payment_count($order, $product_id); // Maybe take into account any failed payments if (true === $add_failed_payments && $failed_payment_count > 0) { $failed_payment_periods = $failed_payment_count * $subscription_interval; $from_timestamp = strtotime($from_date); if ('month' == $subscription_period) { $from_date = date('Y-m-d H:i:s', WC_Subscriptions::add_months($from_timestamp, $failed_payment_periods)); } else { // Safe to just add the billing periods $from_date = date('Y-m-d H:i:s', strtotime("+ {$failed_payment_periods} {$subscription_period}", $from_timestamp)); } } } $from_timestamp = strtotime($from_date); if ('month' == $subscription_period) { // Workaround potential PHP issue $next_payment_timestamp = WC_Subscriptions::add_months($from_timestamp, $subscription_interval); } else { $next_payment_timestamp = strtotime("+ {$subscription_interval} {$subscription_period}", $from_timestamp); } // Make sure the next payment is in the future $i = 1; while ($next_payment_timestamp < gmdate('U') && $i < 30) { if ('month' == $subscription_period) { $next_payment_timestamp = WC_Subscriptions::add_months($next_payment_timestamp, $subscription_interval); } else { // Safe to just add the billing periods $next_payment_timestamp = strtotime("+ {$subscription_interval} {$subscription_period}", $next_payment_timestamp); } $i = $i + 1; } } // If the subscription has an expiry date and the next billing period comes after the expiration, return 0 if (isset($subscription['expiry_date']) && 0 != $subscription['expiry_date'] && $next_payment_timestamp + 120 > strtotime($subscription['expiry_date'])) { $next_payment_timestamp = 0; } $next_payment = 'mysql' == $type && 0 != $next_payment_timestamp ? date('Y-m-d H:i:s', $next_payment_timestamp) : $next_payment_timestamp; return apply_filters('woocommerce_subscriptions_calculated_next_payment_date', $next_payment, $order, $product_id, $type, $from_date, $from_date_arg); }
/** * Checks if a subscription has an unpaid renewal order. * * @param $subscription_key string A subscription key of the form created by @see self::get_subscription_key() * @param $user_id int The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @return bool True if the subscription has an unpaid renewal order, false if the subscription has no unpaid renewal orders. * @since 1.2 */ public static function subscription_requires_payment($subscription_key, $user_id) { global $wpdb; $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key, $user_id); if (empty($subscription)) { $subscription_requires_payment = true; } else { $subscription_requires_payment = false; $statuses_requiring_payment = array('pending', 'on-hold', 'failed'); $order = new WC_Order($subscription['order_id']); if (in_array($order->status, $statuses_requiring_payment)) { $subscription_requires_payment = true; } else { $renewal_order_ids = $wpdb->get_col($wpdb->prepare("SELECT ID FROM {$wpdb->posts} WHERE post_parent = %s", $subscription['order_id'])); foreach ($renewal_order_ids as $renewal_order_id) { $renewal_order = new WC_Order($renewal_order_id); if (in_array($renewal_order->status, $statuses_requiring_payment)) { $subscription_requires_payment = true; break; } } } } return apply_filters('woocommerce_subscription_requires_payment', $subscription_requires_payment, $subscription, $subscription_key, $user_id); }
/** * When a PayPal IPN messaged is received for a subscription transaction, * check the transaction details and * * @since 1.0 */ public static function process_paypal_ipn_request($transaction_details) { if (!in_array($transaction_details['txn_type'], array('subscr_signup', 'subscr_payment', 'subscr_cancel', 'subscr_eot', 'subscr_failed', 'subscr_modify'))) { return; } if (empty($transaction_details['custom']) || empty($transaction_details['invoice'])) { return; } // Get the $order_id & $order_key with backward compatibility extract(self::get_order_id_and_key($transaction_details)); $transaction_details['txn_type'] = strtolower($transaction_details['txn_type']); if (self::$debug) { self::$log->add('paypal', 'Subscription Transaction Type: ' . $transaction_details['txn_type']); } if (self::$debug) { self::$log->add('paypal', 'Subscription transaction details: ' . print_r($transaction_details, true)); } $order = new WC_Order($order_id); // We have an invalid $order_id, probably because invoice_prefix has changed since the subscription was first created, so get the if (!isset($order->id)) { $order_id = function_exists('woocommerce_get_order_id_by_order_key') ? woocommerce_get_order_id_by_order_key($order_key) : $wpdb->get_var("SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = '_order_key' AND meta_value = '{$order_key}'"); $order = new WC_Order($order_id); } if ($order->order_key !== $order_key) { if (self::$debug) { self::$log->add('paypal', 'Subscription IPN Error: Order Key does not match invoice.'); } return; } switch ($transaction_details['txn_type']) { case 'subscr_signup': // Store PayPal Details update_post_meta($order_id, 'Payer PayPal address', $transaction_details['payer_email']); update_post_meta($order_id, 'Payer PayPal first name', $transaction_details['first_name']); update_post_meta($order_id, 'Payer PayPal last name', $transaction_details['last_name']); update_post_meta($order_id, 'PayPal Subscriber ID', $transaction_details['subscr_id']); // Payment completed $order->add_order_note(__('IPN subscription sign up completed.', WC_Subscriptions::$text_domain)); if (self::$debug) { self::$log->add('paypal', 'IPN subscription sign up completed for order ' . $order_id); } // When there is a free trial & no initial payment amount, we need to mark the order as paid and activate the subscription if (0 == WC_Subscriptions_Order::get_total_initial_payment($order) && WC_Subscriptions_Order::get_subscription_trial_length($order) > 0) { $order->payment_complete(); WC_Subscriptions_Manager::activate_subscriptions_for_order($order); } break; case 'subscr_payment': if ('completed' == strtolower($transaction_details['payment_status'])) { // Store PayPal Details update_post_meta($order_id, 'PayPal Transaction ID', $transaction_details['txn_id']); update_post_meta($order_id, 'Payer PayPal first name', $transaction_details['first_name']); update_post_meta($order_id, 'Payer PayPal last name', $transaction_details['last_name']); update_post_meta($order_id, 'PayPal Payment type', $transaction_details['payment_type']); // Subscription Payment completed $order->add_order_note(__('IPN subscription payment completed.', WC_Subscriptions::$text_domain)); if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment completed for order ' . $order_id); } $subscriptions_in_order = WC_Subscriptions_Order::get_recurring_items($order); $subscription_item = array_pop($subscriptions_in_order); $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order->id, $subscription_item['id']); $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key, $order->customer_user); // First payment on order, process payment & activate subscription if (empty($subscription['completed_payments'])) { $order->payment_complete(); WC_Subscriptions_Manager::activate_subscriptions_for_order($order); } else { WC_Subscriptions_Manager::process_subscription_payments_on_order($order); } } elseif ('failed' == strtolower($transaction_details['payment_status'])) { // Subscription Payment completed $order->add_order_note(__('IPN subscription payment failed.', WC_Subscriptions::$text_domain)); if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment failed for order ' . $order_id); } WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($order); } else { if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment notification received for order ' . $order_id . ' with status ' . $transaction_details['payment_status']); } } break; case 'subscr_cancel': if (self::$debug) { self::$log->add('paypal', 'IPN subscription cancelled for order ' . $order_id); } // Subscription Payment completed $order->add_order_note(__('IPN subscription cancelled for order.', WC_Subscriptions::$text_domain)); WC_Subscriptions_Manager::cancel_subscriptions_for_order($order); break; case 'subscr_eot': // Subscription ended, either due to failed payments or expiration // PayPal fires the 'subscr_eot' notice immediately if a subscription is only for one billing period, so ignore the request when we only have one billing period if (1 != WC_Subscriptions_Order::get_subscription_length($order)) { if (self::$debug) { self::$log->add('paypal', 'IPN subscription end-of-term for order ' . $order_id); } // Record subscription ended $order->add_order_note(__('IPN subscription end-of-term for order.', WC_Subscriptions::$text_domain)); // Ended due to failed payments so cancel the subscription if (time() < strtotime(WC_Subscriptions_Manager::get_subscription_expiration_date(WC_Subscriptions_Manager::get_subscription_key($order->id), $order->customer_user))) { WC_Subscriptions_Manager::cancel_subscriptions_for_order($order); } else { WC_Subscriptions_Manager::expire_subscriptions_for_order($order); } } break; case 'subscr_failed': // Subscription sign up failed if (self::$debug) { self::$log->add('paypal', 'IPN subscription sign up failure for order ' . $order_id); } // Subscription Payment completed $order->add_order_note(__('IPN subscription sign up failure.', WC_Subscriptions::$text_domain)); WC_Subscriptions_Manager::failed_subscription_sign_ups_for_order($order); break; } // Prevent default IPN handling for subscription txn_types exit; }