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');
    }
}
 /**
  * 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;
     }
     // 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;
     }
     if ('paypal' != $order->recurring_payment_method) {
         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: This IPN 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: This transaction 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']);
     }
     // 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']);
             $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();
             }
             // Payment completed
             if ($is_payment_change) {
                 $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) {
                     $profile_id = get_post_meta($order->id, '_old_paypal_subscriber_id', true);
                     self::cancel_subscription_with_paypal($order, $product_id, $profile_id);
                 }
                 $order->add_order_note(__('IPN subscription payment method changed.', '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, '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();
                     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)) {
                     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);
                     WC_Subscriptions_Manager::process_subscription_payments_on_order($order);
                     // Make sure the next payment date is sync 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
             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;
 }
 /**
  * Work around a bug in WooCommerce which ignores order item meta values of 0.
  *
  * Code in this function is identical to a section of the @see woocommerce_process_shop_order_meta() function, except
  * that it doesn't include the bug which ignores item meta with a 0 value.
  *
  * @param int $post_id The ID of the post which is the WC_Order object.
  * @param Object $post The post object of the order.
  * @since 1.2.4
  */
 public static function process_shop_order_item_meta($post_id, $post)
 {
     global $woocommerce;
     $product_ids = array();
     if (isset($_POST['order_item_id'])) {
         foreach ($_POST['order_item_id'] as $order_item_id) {
             // WC 2.0+ has unique order item IDs and the product ID is a piece of meta
             $product_ids[$order_item_id] = woocommerce_get_order_item_meta($order_item_id, '_product_id');
         }
     }
     // Now that meta has been updated, we can update the schedules (if there were any changes to schedule related meta)
     if (!empty($product_ids)) {
         $user_id = (int) $_POST['customer_user'];
         foreach ($product_ids as $product_id) {
             $subscription_key = WC_Subscriptions_Manager::get_subscription_key($post_id, $product_id);
             // Order is important here, expiration date takes into account trial expriation date and next payment date takes into account expiration date
             if (in_array($product_id, self::$requires_update['trial_expiration'])) {
                 WC_Subscriptions_Manager::set_trial_expiration_date($subscription_key, $user_id);
             }
             if (in_array($product_id, self::$requires_update['expiration_date'])) {
                 WC_Subscriptions_Manager::set_expiration_date($subscription_key, $user_id);
             }
             if (in_array($product_id, self::$requires_update['next_billing_date'])) {
                 WC_Subscriptions_Manager::set_next_payment_date($subscription_key, $user_id);
             }
         }
     }
 }
 /**
  * Work around a bug in WooCommerce which ignores order item meta values of 0.
  *
  * Code in this function is identical to a section of the @see woocommerce_process_shop_order_meta() function, except
  * that it doesn't include the bug which ignores item meta with a 0 value.
  *
  * @param $post_id int The ID of the post which is the WC_Order object.
  * @param $post Object The post object of the order.
  * @since 1.2.4
  */
 public static function process_shop_order_item_meta($post_id, $post)
 {
     global $woocommerce;
     // Only needs to function on WC 1.x where the bug existed
     if (isset($_POST['item_id'])) {
         $order_items = array();
         $item_id = $_POST['item_id'];
         $item_variation = $_POST['item_variation'];
         $item_name = $_POST['item_name'];
         $item_quantity = $_POST['item_quantity'];
         $line_subtotal = $_POST['line_subtotal'];
         $line_subtotal_tax = $_POST['line_subtotal_tax'];
         $line_total = $_POST['line_total'];
         $line_tax = $_POST['line_tax'];
         $item_meta_names = isset($_POST['meta_name']) ? $_POST['meta_name'] : '';
         $item_meta_values = isset($_POST['meta_value']) ? $_POST['meta_value'] : '';
         $item_tax_class = $_POST['item_tax_class'];
         $item_id_count = sizeof($item_id);
         for ($i = 0; $i < $item_id_count; $i++) {
             if (!isset($item_id[$i]) || !$item_id[$i]) {
                 continue;
             }
             if (!isset($item_name[$i])) {
                 continue;
             }
             if (!isset($item_quantity[$i]) || $item_quantity[$i] < 1) {
                 continue;
             }
             if (!isset($line_total[$i])) {
                 continue;
             }
             if (!isset($line_tax[$i])) {
                 continue;
             }
             // Meta
             $item_meta = new WC_Order_Item_Meta();
             if (isset($item_meta_names[$i]) && isset($item_meta_values[$i])) {
                 $meta_names = $item_meta_names[$i];
                 $meta_values = $item_meta_values[$i];
                 $meta_names_count = sizeof($meta_names);
                 for ($ii = 0; $ii < $meta_names_count; $ii++) {
                     $meta_name = esc_attr($meta_names[$ii]);
                     $meta_value = esc_attr($meta_values[$ii]);
                     if (isset($meta_name) && isset($meta_value)) {
                         $item_meta->add($meta_name, $meta_value);
                     }
                 }
             }
             // Add to array
             $order_items[] = apply_filters('update_order_item', array('id' => htmlspecialchars(stripslashes($item_id[$i])), 'variation_id' => (int) $item_variation[$i], 'name' => htmlspecialchars(stripslashes($item_name[$i])), 'qty' => (int) $item_quantity[$i], 'line_total' => rtrim(rtrim(number_format(woocommerce_clean($line_total[$i]), 4, '.', ''), '0'), '.'), 'line_tax' => rtrim(rtrim(number_format(woocommerce_clean($line_tax[$i]), 4, '.', ''), '0'), '.'), 'line_subtotal' => rtrim(rtrim(number_format(woocommerce_clean($line_subtotal[$i]), 4, '.', ''), '0'), '.'), 'line_subtotal_tax' => rtrim(rtrim(number_format(woocommerce_clean($line_subtotal_tax[$i]), 4, '.', ''), '0'), '.'), 'item_meta' => $item_meta->meta, 'tax_class' => woocommerce_clean($item_tax_class[$i])));
         }
         update_post_meta($post_id, '_order_items', $order_items);
     }
     // WC <> 2.0 compatible posted product IDs
     $product_ids = array();
     if (isset($_POST['order_item_id'])) {
         foreach ($_POST['order_item_id'] as $order_item_id) {
             // WC 2.0+ has unique order item IDs and the product ID is a piece of meta
             $product_ids[$order_item_id] = woocommerce_get_order_item_meta($order_item_id, '_product_id');
         }
     } elseif (isset($_POST['item_id'])) {
         $product_ids = $_POST['item_id'];
     }
     // WC 1.x treated order item IDs as product IDs
     // Now that meta has been updated, we can update the schedules (if there were any changes to schedule related meta)
     if (!empty($product_ids)) {
         $user_id = (int) $_POST['customer_user'];
         foreach ($product_ids as $product_id) {
             $subscription_key = WC_Subscriptions_Manager::get_subscription_key($post_id, $product_id);
             // Order is important here, expiration date takes into account trial expriation date and next payment date takes into account expiration date
             if (in_array($product_id, self::$requires_update['trial_expiration'])) {
                 WC_Subscriptions_Manager::set_trial_expiration_date($subscription_key, $user_id);
             }
             if (in_array($product_id, self::$requires_update['expiration_date'])) {
                 WC_Subscriptions_Manager::set_expiration_date($subscription_key, $user_id);
             }
             if (in_array($product_id, self::$requires_update['next_billing_date'])) {
                 WC_Subscriptions_Manager::set_next_payment_date($subscription_key, $user_id);
             }
         }
     }
 }