Example #1
0
/**
 * Return the product price. 
 *
 * @param   int     $download_id
 * @param   array   $args
 * @return  string
 * @since   1.0.0
 */
function reach_get_edd_product_price($download_id, $args = array())
{
    $download = new EDD_Download($download_id);
    if (!$download->has_variable_prices() || false === $args['price_id']) {
        return $download->price;
    }
    $price_id = $args['price_id'];
    $prices = $download->prices;
    $price = isset($prices[$price_id]) ? $prices[$price_id] : false;
    return $price;
}
/**
 * Gets the Price ID that can download a file
 *
 * @since 1.0.9
 * @param int $download_id Download ID
 * @param string $file_key File Key
 * @return string - the price ID if restricted, "all" otherwise
 */
function edd_get_file_price_condition($download_id = 0, $file_key)
{
    $download = new EDD_Download($download_id);
    return $download->get_file_price_condition($file_key);
}
/**
 * Add To Cart
 *
 * Adds a download ID to the shopping cart.
 *
 * @since 1.0
 *
 * @param int $download_id Download IDs to be added to the cart
 * @param array $options Array of options, such as variable price
 *
 * @return string Cart key of the new item
 */
function edd_add_to_cart($download_id, $options = array())
{
    $download = new EDD_Download($download_id);
    if (empty($download->ID)) {
        return;
        // Not a download product
    }
    if (!$download->can_purchase()) {
        return;
        // Do not allow draft/pending to be purchased if can't edit. Fixes #1056
    }
    do_action('edd_pre_add_to_cart', $download_id, $options);
    $cart = apply_filters('edd_pre_add_to_cart_contents', edd_get_cart_contents());
    if (edd_has_variable_prices($download_id) && !isset($options['price_id'])) {
        // Forces to the first price ID if none is specified and download has variable prices
        $options['price_id'] = '0';
    }
    if (isset($options['quantity'])) {
        if (is_array($options['quantity'])) {
            $quantity = array();
            foreach ($options['quantity'] as $q) {
                $quantity[] = absint(preg_replace('/[^0-9\\.]/', '', $q));
            }
        } else {
            $quantity = absint(preg_replace('/[^0-9\\.]/', '', $options['quantity']));
        }
        unset($options['quantity']);
    } else {
        $quantity = 1;
    }
    // If the price IDs are a string and is a coma separted list, make it an array (allows custom add to cart URLs)
    if (isset($options['price_id']) && !is_array($options['price_id']) && false !== strpos($options['price_id'], ',')) {
        $options['price_id'] = explode(',', $options['price_id']);
    }
    $items = array();
    if (isset($options['price_id']) && is_array($options['price_id'])) {
        // Process multiple price options at once
        foreach ($options['price_id'] as $key => $price) {
            $items[] = array('id' => $download_id, 'options' => array('price_id' => preg_replace('/[^0-9\\.-]/', '', $price)), 'quantity' => $quantity[$key]);
        }
    } else {
        // Sanitize price IDs
        foreach ($options as $key => $option) {
            if ('price_id' == $key) {
                $options[$key] = preg_replace('/[^0-9\\.-]/', '', $option);
            }
        }
        // Add a single item
        $items[] = array('id' => $download_id, 'options' => $options, 'quantity' => $quantity);
    }
    foreach ($items as &$item) {
        $item = apply_filters('edd_add_to_cart_item', $item);
        $to_add = $item;
        if (!is_array($to_add)) {
            return;
        }
        if (!isset($to_add['id']) || empty($to_add['id'])) {
            return;
        }
        if (edd_item_in_cart($to_add['id'], $to_add['options']) && edd_item_quantities_enabled()) {
            $key = edd_get_item_position_in_cart($to_add['id'], $to_add['options']);
            if (is_array($quantity)) {
                $cart[$key]['quantity'] += $quantity[$key];
            } else {
                $cart[$key]['quantity'] += $quantity;
            }
        } else {
            $cart[] = $to_add;
        }
    }
    unset($item);
    EDD()->session->set('edd_cart', $cart);
    do_action('edd_post_add_to_cart', $download_id, $options, $items);
    // Clear all the checkout errors, if any
    edd_clear_errors();
    return count($cart) - 1;
}
/**
 * Get Purchase Link
 *
 * Builds a Purchase link for a specified download based on arguments passed.
 * This function is used all over EDD to generate the Purchase or Add to Cart
 * buttons. If no arguments are passed, the function uses the defaults that have
 * been set by the plugin. The Purchase link is built for simple and variable
 * pricing and filters are available throughout the function to override
 * certain elements of the function.
 *
 * $download_id = null, $link_text = null, $style = null, $color = null, $class = null
 *
 * @since 1.0
 * @param array $args Arguments for display
 * @return string $purchase_form
 */
function edd_get_purchase_link($args = array())
{
    global $post, $edd_displayed_form_ids;
    $purchase_page = edd_get_option('purchase_page', false);
    if (!$purchase_page || $purchase_page == 0) {
        edd_set_error('set_checkout', sprintf(__('No checkout page has been configured. Visit <a href="%s">Settings</a> to set one.', 'easy-digital-downloads'), admin_url('edit.php?post_type=download&page=edd-settings')));
        edd_print_errors();
        return false;
    }
    $post_id = is_object($post) ? $post->ID : 0;
    $button_behavior = edd_get_download_button_behavior($post_id);
    $defaults = apply_filters('edd_purchase_link_defaults', array('download_id' => $post_id, 'price' => (bool) true, 'price_id' => isset($args['price_id']) ? $args['price_id'] : false, 'direct' => $button_behavior == 'direct' ? true : false, 'text' => $button_behavior == 'direct' ? edd_get_option('buy_now_text', __('Buy Now', 'easy-digital-downloads')) : edd_get_option('add_to_cart_text', __('Purchase', 'easy-digital-downloads')), 'style' => edd_get_option('button_style', 'button'), 'color' => edd_get_option('checkout_color', 'blue'), 'class' => 'edd-submit'));
    $args = wp_parse_args($args, $defaults);
    // Override the stright_to_gateway if the shop doesn't support it
    if (!edd_shop_supports_buy_now()) {
        $args['direct'] = false;
    }
    $download = new EDD_Download($args['download_id']);
    if (empty($download->ID)) {
        return false;
    }
    if ('publish' !== $download->post_status && !current_user_can('edit_product', $download->ID)) {
        return false;
        // Product not published or user doesn't have permission to view drafts
    }
    // Override color if color == inherit
    $args['color'] = $args['color'] == 'inherit' ? '' : $args['color'];
    $options = array();
    $variable_pricing = $download->has_variable_prices();
    $data_variable = $variable_pricing ? ' data-variable-price="yes"' : 'data-variable-price="no"';
    $type = $download->is_single_price_mode() ? 'data-price-mode=multi' : 'data-price-mode=single';
    $show_price = $args['price'] && $args['price'] !== 'no';
    $data_price_value = 0;
    $price = false;
    if ($variable_pricing && false !== $args['price_id']) {
        $price_id = $args['price_id'];
        $prices = $download->prices;
        $options['price_id'] = $args['price_id'];
        $found_price = isset($prices[$price_id]) ? $prices[$price_id]['amount'] : false;
        $data_price_value = $found_price;
        if ($show_price) {
            $price = $found_price;
        }
    } elseif (!$variable_pricing) {
        $data_price_value = $download->price;
        if ($show_price) {
            $price = $download->price;
        }
    }
    $args['display_price'] = $data_price_value;
    $data_price = 'data-price="' . $data_price_value . '"';
    $button_text = !empty($args['text']) ? '&nbsp;&ndash;&nbsp;' . $args['text'] : '';
    if (false !== $price) {
        if (0 == $price) {
            $args['text'] = __('Free', 'easy-digital-downloads') . $button_text;
        } else {
            $args['text'] = edd_currency_filter(edd_format_amount($price)) . $button_text;
        }
    }
    if (edd_item_in_cart($download->ID, $options) && (!$variable_pricing || !$download->is_single_price_mode())) {
        $button_display = 'style="display:none;"';
        $checkout_display = '';
    } else {
        $button_display = '';
        $checkout_display = 'style="display:none;"';
    }
    // Collect any form IDs we've displayed already so we can avoid duplicate IDs
    if (isset($edd_displayed_form_ids[$download->ID])) {
        $edd_displayed_form_ids[$download->ID]++;
    } else {
        $edd_displayed_form_ids[$download->ID] = 1;
    }
    $form_id = !empty($args['form_id']) ? $args['form_id'] : 'edd_purchase_' . $download->ID;
    // If we've already generated a form ID for this download ID, apped -#
    if ($edd_displayed_form_ids[$download->ID] > 1) {
        $form_id .= '-' . $edd_displayed_form_ids[$download->ID];
    }
    $args = apply_filters('edd_purchase_link_args', $args);
    ob_start();
    ?>
	<form id="<?php 
    echo $form_id;
    ?>
" class="edd_download_purchase_form edd_purchase_<?php 
    echo absint($download->ID);
    ?>
" method="post">

		<?php 
    do_action('edd_purchase_link_top', $download->ID, $args);
    ?>

		<div class="edd_purchase_submit_wrapper">
			<?php 
    $class = implode(' ', array($args['style'], $args['color'], trim($args['class'])));
    if (!edd_is_ajax_disabled()) {
        echo '<a href="#" class="edd-add-to-cart ' . esc_attr($class) . '" data-action="edd_add_to_cart" data-download-id="' . esc_attr($download->ID) . '" ' . $data_variable . ' ' . $type . ' ' . $data_price . ' ' . $button_display . '><span class="edd-add-to-cart-label">' . $args['text'] . '</span> <span class="edd-loading"><i class="edd-icon-spinner edd-icon-spin"></i></span></a>';
    }
    echo '<input type="submit" class="edd-add-to-cart edd-no-js ' . esc_attr($class) . '" name="edd_purchase_download" value="' . esc_attr($args['text']) . '" data-action="edd_add_to_cart" data-download-id="' . esc_attr($download->ID) . '" ' . $data_variable . ' ' . $type . ' ' . $button_display . '/>';
    echo '<a href="' . esc_url(edd_get_checkout_uri()) . '" class="edd_go_to_checkout ' . esc_attr($class) . '" ' . $checkout_display . '>' . __('Checkout', 'easy-digital-downloads') . '</a>';
    ?>

			<?php 
    if (!edd_is_ajax_disabled()) {
        ?>
				<span class="edd-cart-ajax-alert">
					<span class="edd-cart-added-alert" style="display: none;">
						<?php 
        echo '<i class="edd-icon-ok"></i> ' . __('Added to cart', 'easy-digital-downloads');
        ?>
					</span>
				</span>
			<?php 
    }
    ?>
			<?php 
    if (!$download->is_free($args['price_id'])) {
        ?>
				<?php 
        if (edd_display_tax_rate() && edd_prices_include_tax()) {
            echo '<span class="edd_purchase_tax_rate">' . sprintf(__('Includes %1$s&#37; tax', 'easy-digital-downloads'), edd_get_tax_rate() * 100) . '</span>';
        } elseif (edd_display_tax_rate() && !edd_prices_include_tax()) {
            echo '<span class="edd_purchase_tax_rate">' . sprintf(__('Excluding %1$s&#37; tax', 'easy-digital-downloads'), edd_get_tax_rate() * 100) . '</span>';
        }
        ?>
			<?php 
    }
    ?>
		</div><!--end .edd_purchase_submit_wrapper-->

		<input type="hidden" name="download_id" value="<?php 
    echo esc_attr($download->ID);
    ?>
">
		<?php 
    if ($variable_pricing && isset($price_id) && isset($prices[$price_id])) {
        ?>
			<input type="hidden" name="edd_options[price_id][]" id="edd_price_option_<?php 
        echo $download->ID;
        ?>
_1" class="edd_price_option_<?php 
        echo $download->ID;
        ?>
" value="<?php 
        echo $price_id;
        ?>
">
		<?php 
    }
    ?>
		<?php 
    if (!empty($args['direct']) && !$download->is_free($args['price_id'])) {
        ?>
			<input type="hidden" name="edd_action" class="edd_action_input" value="straight_to_gateway">
		<?php 
    } else {
        ?>
			<input type="hidden" name="edd_action" class="edd_action_input" value="add_to_cart">
		<?php 
    }
    ?>

		<?php 
    if (apply_filters('edd_download_redirect_to_checkout', edd_straight_to_checkout(), $download->ID, $args)) {
        ?>
			<input type="hidden" name="edd_redirect_to_checkout" id="edd_redirect_to_checkout" value="1">
		<?php 
    }
    ?>

		<?php 
    do_action('edd_purchase_link_end', $download->ID, $args);
    ?>

	</form><!--end #<?php 
    echo esc_attr($form_id);
    ?>
-->
<?php 
    $purchase_form = ob_get_clean();
    return apply_filters('edd_purchase_download_form', $purchase_form, $args);
}
theme_object()->excerpt->length(30);
?>
<div class="promoblock theme-academy checkout-cross-sell">
	<p>
		<span class="h3"><?php 
the_title();
?>
 &raquo;</span>

		<?php 
the_excerpt();
?>
	</p>

	<?php 
$download = new \EDD_Download(get_the_ID());
?>
	<form id="buy-<?php 
the_ID();
?>
" class="edd_download_purchase_form edd_purchase_<?php 
the_ID();
?>
" method="post">
		<?php 
if ($download->has_variable_prices()) {
    ?>
			<?php 
    get_template_part('html_includes/shop/pricing-options', array('name' => 'edd_options[price_id][]', 'id_prefix' => 'csau_download_'));
    ?>
		<?php 
 /**
  * One items have been set, an update is needed to save them to the database.
  *
  * @return bool  True of the save occured, false if it failed or wasn't needed
  */
 public function save()
 {
     $saved = false;
     if (empty($this->ID)) {
         $payment_id = $this->insert_payment();
         if (false === $payment_id) {
             $saved = false;
         } else {
             $this->ID = $payment_id;
         }
     }
     if ($this->ID !== $this->_ID) {
         $this->ID = $this->_ID;
     }
     // If we have something pending, let's save it
     if (!empty($this->pending)) {
         $total_increase = 0;
         $total_decrease = 0;
         foreach ($this->pending as $key => $value) {
             switch ($key) {
                 case 'downloads':
                     // Update totals for pending downloads
                     foreach ($this->pending[$key] as $item) {
                         switch ($item['action']) {
                             case 'add':
                                 $price = $item['price'];
                                 $taxes = $item['tax'];
                                 if ('publish' === $this->status || 'complete' === $this->status || 'revoked' === $this->status) {
                                     // Add sales logs
                                     $log_date = date('Y-m-d G:i:s', current_time('timestamp', true));
                                     $price_id = isset($item['item_number']['options']['price_id']) ? $item['item_number']['options']['price_id'] : 0;
                                     $y = 0;
                                     while ($y < $item['quantity']) {
                                         edd_record_sale_in_log($item['id'], $this->ID, $price_id, $log_date);
                                         $y++;
                                     }
                                     $download = new EDD_Download($item['id']);
                                     $download->increase_sales($item['quantity']);
                                     $download->increase_earnings($price);
                                     $total_increase += $price;
                                 }
                                 break;
                             case 'remove':
                                 $log_args = array('post_type' => 'edd_log', 'post_parent' => $item['id'], 'numberposts' => $item['quantity'], 'meta_query' => array(array('key' => '_edd_log_payment_id', 'value' => $this->ID, 'compare' => '='), array('key' => '_edd_log_price_id', 'value' => $item['price_id'], 'compare' => '=')));
                                 $found_logs = get_posts($log_args);
                                 foreach ($found_logs as $log) {
                                     wp_delete_post($log->ID, true);
                                 }
                                 if ('publish' === $this->status || 'complete' === $this->status || 'revoked' === $this->status) {
                                     $download = new EDD_Download($item['id']);
                                     $download->decrease_sales($item['quantity']);
                                     $download->decrease_earnings($item['amount']);
                                     $total_decrease += $item['amount'];
                                 }
                                 break;
                         }
                     }
                     break;
                 case 'fees':
                     if (!empty($this->pending[$key])) {
                         foreach ($this->pending[$key] as $fee) {
                             switch ($fee['action']) {
                                 case 'add':
                                     $total_increase += $fee['amount'];
                                     break;
                                 case 'remove':
                                     $total_decrease += $fee['amount'];
                                     break;
                             }
                         }
                     }
                     break;
                 case 'status':
                     $this->update_status($this->status);
                     break;
                 case 'gateway':
                     $this->update_meta('_edd_payment_gateway', $this->gateway);
                     break;
                 case 'mode':
                     $this->update_meta('_edd_payment_mode', $this->mode);
                     break;
                 case 'transaction_id':
                     $this->update_meta('_edd_payment_transaction_id', $this->transaction_id);
                     break;
                 case 'ip':
                     $this->update_meta('_edd_payment_user_ip', $this->ip);
                     break;
                 case 'customer_id':
                     $this->update_meta('_edd_payment_customer_id', $this->customer_id);
                     break;
                 case 'user_id':
                     $this->update_meta('_edd_payment_user_id', $this->user_id);
                     break;
                 case 'first_name':
                     $this->user_info['first_name'] = $this->first_name;
                     break;
                 case 'last_name':
                     $this->user_info['last_name'] = $this->last_name;
                     break;
                 case 'discounts':
                     $this->user_info['discount'] = $this->discounts;
                     break;
                 case 'address':
                     $this->user_info['address'] = $this->address;
                     break;
                 case 'email':
                     $this->update_meta('_edd_payment_user_email', $this->email);
                     break;
                 case 'key':
                     $this->update_meta('_edd_payment_purchase_key', $this->key);
                     break;
                 case 'number':
                     $this->update_meta('_edd_payment_number', $this->number);
                     break;
                 case 'completed_date':
                     $this->update_meta('_edd_completed_date', $this->completed_date);
                     break;
                 case 'has_unlimited_downloads':
                     $this->update_meta('_edd_payment_unlimited_downloads', $this->has_unlimited_downloads);
                     break;
                 case 'parent_payment':
                     $args = array('ID' => $this->ID, 'post_parent' => $this->parent_payment);
                     wp_update_post($args);
                     break;
                 default:
                     do_action('edd_payment_save', $this, $key);
                     break;
             }
         }
         if ('pending' !== $this->status) {
             $customer = new EDD_Customer($this->customer_id);
             $total_change = $total_increase - $total_decrease;
             if ($total_change < 0) {
                 $total_chnage = -$total_change;
                 // Decrease the customer's purchase stats
                 $customer->decrease_value($total_change);
                 edd_decrease_total_earnings($total_change);
             } else {
                 if ($total_change > 0) {
                     // Increase the customer's purchase stats
                     $customer->increase_value($total_change);
                     edd_increase_total_earnings($total_change);
                 }
             }
         }
         $this->update_meta('_edd_payment_total', $this->total);
         $this->update_meta('_edd_payment_tax', $this->tax);
         $new_meta = array('downloads' => $this->downloads, 'cart_details' => $this->cart_details, 'fees' => $this->fees, 'currency' => $this->currency, 'user_info' => $this->user_info);
         $meta = $this->get_meta();
         $merged_meta = array_merge($meta, $new_meta);
         // Only save the payment meta if it's changed
         if (md5(serialize($meta)) !== md5(serialize($merged_meta))) {
             $updated = $this->update_meta('_edd_payment_meta', $merged_meta);
             if (false !== $updated) {
                 $saved = true;
             }
         }
         $this->pending = array();
         $saved = true;
     }
     if (true === $saved) {
         $this->setup_payment($this->ID);
     }
     return $saved;
 }
 /**
  * One items have been set, an update is needed to save them to the database.
  *
  * @return bool  True of the save occurred, false if it failed or wasn't needed
  */
 public function save()
 {
     $saved = false;
     if (empty($this->ID)) {
         $payment_id = $this->insert_payment();
         if (false === $payment_id) {
             $saved = false;
         } else {
             $this->ID = $payment_id;
         }
     }
     if ($this->ID !== $this->_ID) {
         $this->ID = $this->_ID;
     }
     // If we have something pending, let's save it
     if (!empty($this->pending)) {
         $total_increase = 0;
         $total_decrease = 0;
         foreach ($this->pending as $key => $value) {
             switch ($key) {
                 case 'downloads':
                     // Update totals for pending downloads
                     foreach ($this->pending[$key] as $item) {
                         switch ($item['action']) {
                             case 'add':
                                 $price = $item['price'];
                                 $taxes = $item['tax'];
                                 if ('publish' === $this->status || 'complete' === $this->status || 'revoked' === $this->status) {
                                     // Add sales logs
                                     $log_date = date_i18n('Y-m-d G:i:s', current_time('timestamp'));
                                     $price_id = isset($item['item_number']['options']['price_id']) ? $item['item_number']['options']['price_id'] : 0;
                                     $y = 0;
                                     while ($y < $item['quantity']) {
                                         edd_record_sale_in_log($item['id'], $this->ID, $price_id, $log_date);
                                         $y++;
                                     }
                                     $increase_earnings = $price;
                                     if (!empty($item['fees'])) {
                                         foreach ($item['fees'] as $fee) {
                                             // Only let negative fees affect the earnings
                                             if ($fee['amount'] > 0) {
                                                 continue;
                                             }
                                             $increase_earnings += (double) $fee['amount'];
                                         }
                                     }
                                     $download = new EDD_Download($item['id']);
                                     $download->increase_sales($item['quantity']);
                                     $download->increase_earnings($increase_earnings);
                                     $total_increase += $price;
                                 }
                                 break;
                             case 'remove':
                                 $log_args = array('post_type' => 'edd_log', 'post_parent' => $item['id'], 'numberposts' => $item['quantity'], 'meta_query' => array(array('key' => '_edd_log_payment_id', 'value' => $this->ID, 'compare' => '='), array('key' => '_edd_log_price_id', 'value' => $item['price_id'], 'compare' => '=')));
                                 $found_logs = get_posts($log_args);
                                 foreach ($found_logs as $log) {
                                     wp_delete_post($log->ID, true);
                                 }
                                 if ('publish' === $this->status || 'complete' === $this->status || 'revoked' === $this->status) {
                                     $download = new EDD_Download($item['id']);
                                     $download->decrease_sales($item['quantity']);
                                     $decrease_amount = $item['amount'];
                                     if (!empty($item['fees'])) {
                                         foreach ($item['fees'] as $fee) {
                                             // Only let negative fees affect the earnings
                                             if ($fee['amount'] > 0) {
                                                 continue;
                                             }
                                             $decrease_amount += $fee['amount'];
                                         }
                                     }
                                     $download->decrease_earnings($decrease_amount);
                                     $total_decrease += $item['amount'];
                                 }
                                 break;
                         }
                     }
                     break;
                 case 'fees':
                     if ('publish' !== $this->status && 'complete' !== $this->status && 'revoked' !== $this->status) {
                         break;
                     }
                     if (empty($this->pending[$key])) {
                         break;
                     }
                     foreach ($this->pending[$key] as $fee) {
                         switch ($fee['action']) {
                             case 'add':
                                 $total_increase += $fee['amount'];
                                 break;
                             case 'remove':
                                 $total_decrease += $fee['amount'];
                                 break;
                         }
                     }
                     break;
                 case 'status':
                     $this->update_status($this->status);
                     break;
                 case 'gateway':
                     $this->update_meta('_edd_payment_gateway', $this->gateway);
                     break;
                 case 'mode':
                     $this->update_meta('_edd_payment_mode', $this->mode);
                     break;
                 case 'transaction_id':
                     $this->update_meta('_edd_payment_transaction_id', $this->transaction_id);
                     break;
                 case 'ip':
                     $this->update_meta('_edd_payment_user_ip', $this->ip);
                     break;
                 case 'customer_id':
                     $this->update_meta('_edd_payment_customer_id', $this->customer_id);
                     break;
                 case 'user_id':
                     $this->update_meta('_edd_payment_user_id', $this->user_id);
                     break;
                 case 'first_name':
                     $this->user_info['first_name'] = $this->first_name;
                     break;
                 case 'last_name':
                     $this->user_info['last_name'] = $this->last_name;
                     break;
                 case 'discounts':
                     if (!is_array($this->discounts)) {
                         $this->discounts = explode(',', $this->discounts);
                     }
                     $this->user_info['discount'] = implode(',', $this->discounts);
                     break;
                 case 'address':
                     $this->user_info['address'] = $this->address;
                     break;
                 case 'email':
                     $this->update_meta('_edd_payment_user_email', $this->email);
                     break;
                 case 'key':
                     $this->update_meta('_edd_payment_purchase_key', $this->key);
                     break;
                 case 'number':
                     $this->update_meta('_edd_payment_number', $this->number);
                     break;
                 case 'date':
                     $args = array('ID' => $this->ID, 'post_date' => $this->date, 'edit_date' => true);
                     wp_update_post($args);
                     break;
                 case 'completed_date':
                     $this->update_meta('_edd_completed_date', $this->completed_date);
                     break;
                 case 'has_unlimited_downloads':
                     $this->update_meta('_edd_payment_unlimited_downloads', $this->has_unlimited_downloads);
                     break;
                 case 'parent_payment':
                     $args = array('ID' => $this->ID, 'post_parent' => $this->parent_payment);
                     wp_update_post($args);
                     break;
                 default:
                     /**
                      * Used to save non-standard data. Developers can hook here if they want to save
                      * specific payment data when $payment->save() is run and their item is in the $pending array
                      */
                     do_action('edd_payment_save', $this, $key);
                     break;
             }
         }
         if ('pending' !== $this->status) {
             $customer = new EDD_Customer($this->customer_id);
             $total_change = $total_increase - $total_decrease;
             if ($total_change < 0) {
                 $total_change = -$total_change;
                 // Decrease the customer's purchase stats
                 $customer->decrease_value($total_change);
                 edd_decrease_total_earnings($total_change);
             } else {
                 if ($total_change > 0) {
                     // Increase the customer's purchase stats
                     $customer->increase_value($total_change);
                     edd_increase_total_earnings($total_change);
                 }
             }
         }
         $this->update_meta('_edd_payment_total', $this->total);
         $this->update_meta('_edd_payment_tax', $this->tax);
         $this->downloads = array_values($this->downloads);
         $new_meta = array('downloads' => $this->downloads, 'cart_details' => $this->cart_details, 'fees' => $this->fees, 'currency' => $this->currency, 'user_info' => is_array($this->user_info) ? array_filter($this->user_info) : array(), 'date' => $this->date);
         // Do some merging of user_info before we merge it all, to honor the edd_payment_meta filter
         if (!empty($this->payment_meta['user_info'])) {
             $stored_discount = !empty($new_meta['user_info']['discount']) ? $new_meta['user_info']['discount'] : '';
             $new_meta['user_info'] = array_replace_recursive((array) $this->payment_meta['user_info'], $new_meta['user_info']);
             if ('none' !== $stored_discount) {
                 $new_meta['user_info']['discount'] = $stored_discount;
             }
         }
         $meta = $this->get_meta();
         $merged_meta = array_merge($meta, $new_meta);
         // Only save the payment meta if it's changed
         if (md5(serialize($meta)) !== md5(serialize($merged_meta))) {
             $updated = $this->update_meta('_edd_payment_meta', $merged_meta);
             if (false !== $updated) {
                 $saved = true;
             }
         }
         $this->pending = array();
         $saved = true;
     }
     if (true === $saved) {
         $this->setup_payment($this->ID);
         /**
          * This action fires anytime that $payment->save() is run, allowing developers to run actions
          * when a payment is updated
          */
         do_action('edd_payment_saved', $this->ID, $this);
     }
     return $saved;
 }
 /**
  * Checkout sale price.
  *
  * Display the sale price, and the regular price with a strike at the checkout.
  * This requires a hook added in EDD 2.3.0
  *
  * @since 1.0.0, EDD 2.4.0
  *
  * @param	double 	$price 			Regular price of the product.
  * @param	int		$download_id	ID of the download we're changing the price for.
  * @return	double					The new price, if the product is in sale this will be the sale price.
  */
 public function checkout_maybe_display_sale_price($label, $item_id, $options)
 {
     global $edd_options;
     $download = new EDD_Download($item_id);
     $regular_price = get_post_meta($item_id, 'edd_price', true);
     $price = edd_get_cart_item_price($item_id, $options);
     // Get sale price if it exists
     if ($download->has_variable_prices()) {
         $prices = $download->get_prices();
         $regular_price = isset($prices[$options['price_id']]['regular_amount']) ? $prices[$options['price_id']]['regular_amount'] : $regular_price;
         $sale_price = $prices[$options['price_id']]['sale_price'];
     } else {
         $sale_price = get_post_meta($item_id, 'edd_sale_price', true);
     }
     // Bail if no sale price is set
     if (empty($sale_price)) {
         return $label;
     }
     $label = '';
     $price_id = isset($options['price_id']) ? $options['price_id'] : false;
     if (!edd_is_free_download($item_id, $price_id) && !edd_download_is_tax_exclusive($item_id)) {
         if (edd_prices_show_tax_on_checkout() && !edd_prices_include_tax()) {
             $regular_price += edd_get_cart_item_tax($item_id, $options, $regular_price);
             $price += edd_get_cart_item_tax($item_id, $options, $price);
         }
         if (!edd_prices_show_tax_on_checkout() && edd_prices_include_tax()) {
             $regular_price -= edd_get_cart_item_tax($item_id, $options, $regular_price);
             $price -= edd_get_cart_item_tax($item_id, $options, $price);
         }
         if (edd_display_tax_rate()) {
             $label = '&nbsp;&ndash;&nbsp;';
             if (edd_prices_show_tax_on_checkout()) {
                 $label .= sprintf(__('includes %s tax', 'edd'), edd_get_formatted_tax_rate());
             } else {
                 $label .= sprintf(__('excludes %s tax', 'edd'), edd_get_formatted_tax_rate());
             }
             $label = apply_filters('edd_cart_item_tax_description', $label, $item_id, $options);
         }
     }
     $regular_price = '<del>' . edd_currency_filter(edd_format_amount($regular_price)) . '</del>';
     $price = edd_currency_filter(edd_format_amount($price));
     return $regular_price . ' ' . $price . $label;
 }