/** * Clear entries from the upgrade log. */ public static function clear() { if (empty(self::$log)) { self::$log = new WC_Logger(); } self::$log->clear(self::$handle); }
/** * The '_switched_subscription_key' and '_switched_subscription_new_order' post meta values are no longer used to relate orders * and switched subscriptions, instead, we need to set a '_subscription_switch' value on the switch order and depreacted the old * meta keys by prefixing them with '_wcs_migrated'. * * Subscriptions also sets a '_switched_subscription_item_id' value on the new line item of for the switched item and a item meta * value of '_switched_subscription_new_item_id' on the old line item on the subscription, but the old switching process didn't * change order items, it just created a new order with the new item, so we won't bother setting this as it is purely for record * keeping. * * @param WC_Subscription $new_subscription A subscription object * @param WC_Order $switch_order The original order used to purchase the subscription * @param int $subscription_item_id The order item ID of the item added to the subscription by self::add_product() * @return null * @since 2.0 */ private static function migrate_switch_meta($new_subscription, $switch_order, $subscription_item_id) { global $wpdb; // If the order doesn't contain a switch, we don't need to do anything if ('' == get_post_meta($switch_order->id, '_switched_subscription_key', true)) { return; } $wpdb->query($wpdb->prepare("UPDATE {$wpdb->postmeta} SET `meta_key` = concat( '_wcs_migrated', `meta_key` )\n\t\t\tWHERE `post_id` = %d AND `meta_key` IN ('_switched_subscription_first_payment_timestamp','_switched_subscription_key')", $switch_order->id)); // Select the orders which had the items which were switched by this order $previous_order_id = get_posts(array('post_type' => 'shop_order', 'post_status' => 'any', 'fields' => 'ids', 'posts_per_page' => -1, 'meta_query' => array(array('key' => '_switched_subscription_new_order', 'value' => $switch_order->id)))); if (!empty($previous_order_id)) { $previous_order_id = $previous_order_id[0]; $wpdb->query($wpdb->prepare("UPDATE {$wpdb->postmeta} SET `meta_key` = concat( '_wcs_migrated', `meta_key` )\n\t\t\t\tWHERE `post_id` = %d AND `meta_key` = '_switched_subscription_new_order'", $previous_order_id)); // Because self::get_subscriptions() orders by order ID, it's safe to use wcs_get_subscriptions_for_order() here because the subscription in the new format will have been created for the original order (because its ID will be < the switch order's ID) $old_subscriptions = wcs_get_subscriptions_for_order($previous_order_id); $old_subscription = array_shift($old_subscriptions); // there can be only one if (wcs_is_subscription($old_subscription)) { // Link the old subscription's ID to the switch order using the new switch meta key update_post_meta($switch_order->id, '_subscription_switch', $old_subscription->id); // Now store the new/old item IDs for record keeping foreach ($old_subscription->get_items() as $item_id => $item) { wc_add_order_item_meta($item_id, '_switched_subscription_new_item_id', $subscription_item_id, true); wc_add_order_item_meta($subscription_item_id, '_switched_subscription_item_id', $item_id, true); } WCS_Upgrade_Logger::add(sprintf('For subscription %d: migrated switch data for subscription %d purchased in order %d', $new_subscription->id, $old_subscription->id, $previous_order_id)); } } }
/** * Logs an entry for the store owner to review an issue. * * @param array $subscription subscription data */ protected static function log_store_owner_review($subscription) { WCS_Upgrade_Logger::add(sprintf('-- For order %d: shop owner please review subscription.', $subscription['order_id'])); }
/** * If the subscription has expired since upgrading and the end date is not the original expiration date, * we need to unexpire it, which in the case of a previously active subscription means activate it, and * in any other case, leave it as on-hold (a cancelled subscription wouldn't have been expired, so the * status must be on-hold or active). * * @param WC_Subscription $subscription data about the subscription * @return bool true if the trial date was repaired, otherwise false */ protected static function maybe_repair_status($subscription, $former_order_item_meta, $dates_to_update) { if ($subscription->has_status('expired') && 'expired' != $former_order_item_meta['_wcs_migrated_subscription_status'][0] && isset($dates_to_update['end'])) { try { // we need to bypass the update_status() method here because normally an expired subscription can't have it's status changed, we also don't want normal status change hooks to be fired wp_update_post(array('ID' => $subscription->id, 'post_status' => 'wc-on-hold')); // if the payment method doesn't support date changes, we still want to reactivate the subscription but we also need to process a special failed payment at the next renewal to fix up the payment method so we'll set a special flag in post meta to handle that if (!$subscription->payment_method_supports('subscription_date_changes') && $subscription->get_total() > 0) { update_post_meta($subscription->id, '_wcs_repaired_2_0_2_needs_failed_payment', 'true'); WCS_Upgrade_Logger::add(sprintf('For subscription %d: payment method does not support "subscription_date_changes" and total > 0, setting "_wcs_repaired_2_0_2_needs_failed_payment" post meta flag.', $subscription->id)); } if ('active' == $former_order_item_meta['_wcs_migrated_subscription_status'][0] && $subscription->can_be_updated_to('active')) { $subscription->update_status('active'); } WCS_Upgrade_Logger::add(sprintf('For subscription %d: repaired status. Status was "expired", it is now "%s".', $subscription->id, $subscription->get_status())); $repair_status = true; } catch (Exception $e) { WCS_Upgrade_Logger::add(sprintf('!!! For subscription %d: unable to repair status, exception "%s"', $subscription->id, $e->getMessage())); $repair_status = false; } } else { WCS_Upgrade_Logger::add(sprintf('For subscription %d: no need to repair status, current status: %s; former status: %s.', $subscription->id, $subscription->get_status(), $former_order_item_meta['_wcs_migrated_subscription_status'][0])); $repair_status = false; } return $repair_status; }
/** * While the upgrade is in progress, we need to block IPN messages to avoid renewals failing to process correctly. * * PayPal will retry the IPNs for up to a day or two until it has a successful request, so the store will continue to receive * IPN messages during the upgrade process, then once it is completed, the IPN will be successfully processed. * * The method returns a 409 Conflict HTTP response code to indicate that the IPN is conflicting with the upgrader. * * @since 2.0 */ public static function maybe_block_paypal_ipn() { if (false !== get_option('wc_subscriptions_is_upgrading', false)) { WCS_Upgrade_Logger::add('*** PayPal IPN Request blocked: ' . print_r(wp_unslash($_POST), true)); // No CSRF needed as it's from outside wp_die('PayPal IPN Request Failure', 'PayPal IPN', array('response' => 409)); } }