/**
  * Save meta box data
  */
 public static function save($post_id, $post)
 {
     if ('shop_subscription' == $post->post_type && !empty($_POST['woocommerce_meta_nonce']) && wp_verify_nonce($_POST['woocommerce_meta_nonce'], 'woocommerce_save_data')) {
         if (isset($_POST['_billing_interval'])) {
             update_post_meta($post_id, '_billing_interval', $_POST['_billing_interval']);
         }
         if (!empty($_POST['_billing_period'])) {
             update_post_meta($post_id, '_billing_period', $_POST['_billing_period']);
         }
         $subscription = wcs_get_subscription($post_id);
         $dates = array();
         foreach (wcs_get_subscription_date_types() as $date_key => $date_label) {
             if ('last_payment' == $date_key) {
                 continue;
             }
             $utc_timestamp_key = $date_key . '_timestamp_utc';
             // A subscription needs a start date, even if it wasn't set
             if (isset($_POST[$utc_timestamp_key])) {
                 $datetime = $_POST[$utc_timestamp_key];
             } elseif ('start' === $date_key) {
                 $datetime = current_time('timestamp', true);
             } else {
                 // No date to set
                 continue;
             }
             $dates[$date_key] = date('Y-m-d H:i:s', $datetime);
         }
         try {
             $subscription->update_dates($dates, 'gmt');
             wp_cache_delete($post_id, 'posts');
         } catch (Exception $e) {
             wcs_add_admin_notice($e->getMessage(), 'error');
         }
     }
 }
 public function __construct()
 {
     $this->date_types_to_schedule = apply_filters('woocommerce_subscriptions_date_types_to_schedule', array_keys(wcs_get_subscription_date_types()));
     add_action('woocommerce_subscription_date_updated', array(&$this, 'update_date'), 10, 3);
     add_action('woocommerce_subscription_date_deleted', array(&$this, 'delete_date'), 10, 2);
     add_action('woocommerce_subscription_status_updated', array(&$this, 'update_status'), 10, 3);
 }
} else {
    ?>
		<strong><?php 
    esc_html_e('Recurring:', 'woocommerce-subscriptions');
    ?>
</strong>
		<?php 
    printf('%s %s', esc_html(wcs_get_subscription_period_interval_strings($the_subscription->billing_interval)), esc_html(wcs_get_subscription_period_strings(1, $the_subscription->billing_period)));
    ?>
	<?php 
}
?>
	</div>

	<?php 
foreach (wcs_get_subscription_date_types() as $date_key => $date_label) {
    ?>
		<?php 
    if ('last_payment' === $date_key) {
        ?>
			<?php 
        continue;
        ?>
		<?php 
    }
    ?>
	<div id="subscription-<?php 
    echo esc_attr($date_key);
    ?>
-date" class="date-fields">
		<strong><?php 
 /**
  * Set the dates on the subscription.
  *
  * Because dates are interdependent on each other, this function will take an array of dates, make sure that all
  * dates are in the right order in the right format, that there is at least something to update.
  *
  * @param array 		$dates 			array containing dates with keys: 'start', 'trial_end', 'next_payment',
  *                           			'last_payment' or 'end'. Values are time
  * @param string 		$timezone 		The timezone of the $datetime param. Default 'gmt'.
  */
 public function update_dates($dates, $timezone = 'gmt')
 {
     global $wpdb;
     if (!is_array($dates)) {
         throw new InvalidArgumentException(__('Invalid format. First parameter needs to be an array.', 'woocommerce-subscriptions'));
     }
     if (empty($dates)) {
         throw new InvalidArgumentException(__('Invalid data. First parameter was empty when passed to update_dates().', 'woocommerce-subscriptions'));
     }
     $allowed_date_keys = array_keys(wcs_get_subscription_date_types());
     $passed_date_keys = array_keys($dates);
     $extra_keys = array_diff(str_replace('_date', '', $passed_date_keys), $allowed_date_keys);
     if (!empty($extra_keys)) {
         throw new InvalidArgumentException(__('Invalid data. First parameter has a date that is not in the registered date types.', 'woocommerce-subscriptions'));
     }
     $timestamps = array();
     foreach ($dates as $date_type => $datetime) {
         if (!empty($datetime) && false === wcs_is_datetime_mysql_format($datetime)) {
             // translators: placeholder is date type (e.g. "end", "next_payment"...)
             throw new InvalidArgumentException(sprintf(_x('Invalid %s date. The date must be of the format: "Y-m-d H:i:s".', 'appears in an error message if date is wrong format', 'woocommerce-subscriptions'), $date_type));
         }
         $date_type = str_replace('_date', '', $date_type);
         if (empty($datetime)) {
             $timestamps[$date_type] = 0;
         } else {
             if ('gmt' !== strtolower($timezone)) {
                 $datetime = get_gmt_from_date($datetime);
             }
             $timestamps[$date_type] = strtotime($datetime);
         }
     }
     foreach ($allowed_date_keys as $date_type) {
         if (!array_key_exists($date_type, $timestamps)) {
             $timestamps[$date_type] = $this->get_time($date_type);
         }
         if (0 == $timestamps[$date_type]) {
             // Last payment is not in the UI, and it should NOT be deleted as that would mess with scheduling
             if ('last_payment' != $date_type && 'start' != $date_type) {
                 $this->delete_date($date_type);
             }
             unset($timestamps[$date_type]);
             continue;
         }
     }
     $messages = array();
     // And then iterate over them. We need the two separate loops as we need a full array before we start checking
     // the relationships between them.
     foreach ($timestamps as $date_type => $datetime) {
         switch ($date_type) {
             case 'end':
                 if (array_key_exists('last_payment', $timestamps) && $datetime <= $timestamps['last_payment']) {
                     $messages[] = sprintf(__('The %s date must occur after the last payment date.', 'woocommerce-subscriptions'), $date_type);
                 }
                 if (array_key_exists('next_payment', $timestamps) && $datetime <= $timestamps['next_payment']) {
                     $messages[] = sprintf(__('The %s date must occur after the next payment date.', 'woocommerce-subscriptions'), $date_type);
                 }
             case 'next_payment':
                 // Guarantees that end is strictly after trial_end, because if next_payment and end can't be at same
                 // time
                 if (array_key_exists('trial_end', $timestamps) && $datetime < $timestamps['trial_end']) {
                     $messages[] = sprintf(__('The %s date must occur after the trial end date.', 'woocommerce-subscriptions'), $date_type);
                 }
             case 'trial_end':
                 if ($datetime <= $timestamps['start']) {
                     $messages[] = sprintf(__('The %s date must occur after the start date.', 'woocommerce-subscriptions'), $date_type);
                 }
         }
     }
     if (!empty($messages)) {
         throw new Exception(join(' ', $messages));
     }
     $is_updated = false;
     foreach ($timestamps as $date_type => $timestamp) {
         $datetime = date('Y-m-d H:i:s', $timestamp);
         if ($datetime == $this->get_date($date_type)) {
             continue;
         }
         switch ($date_type) {
             case 'next_payment':
             case 'trial_end':
             case 'end':
                 $is_updated = update_post_meta($this->id, wcs_get_date_meta_key($date_type), $datetime);
                 break;
             case 'start':
                 $wpdb->query($wpdb->prepare("UPDATE {$wpdb->posts} SET post_date = %s, post_date_gmt = %s WHERE ID = %s", get_date_from_gmt($datetime), $datetime, $this->id));
                 // Don't use wp_update_post() to avoid infinite loops here
                 $is_updated = true;
                 break;
             case 'last_payment':
                 $this->update_last_payment_date($datetime);
                 $is_updated = true;
                 break;
         }
         if ($is_updated) {
             $this->schedule->{$date_type} = $datetime;
             do_action('woocommerce_subscription_date_updated', $this, $date_type, $datetime);
         }
     }
 }
 public function set_date_types_to_schedule()
 {
     $this->date_types_to_schedule = apply_filters('woocommerce_subscriptions_date_types_to_schedule', array_keys(wcs_get_subscription_date_types()));
 }