/**
  * 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));
     }
 }