1674 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			1674 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /**
 | |
|  * Download Functions
 | |
|  *
 | |
|  * @package     EDD
 | |
|  * @subpackage  Functions
 | |
|  * @copyright   Copyright (c) 2018, Easy Digital Downloads, LLC
 | |
|  * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
 | |
|  * @since       1.0
 | |
|  */
 | |
| 
 | |
| // Exit if accessed directly
 | |
| defined( 'ABSPATH' ) || exit;
 | |
| 
 | |
| /**
 | |
|  * Retrieve a download by a given field.
 | |
|  *
 | |
|  * @since 2.0
 | |
|  *
 | |
|  * @param string $field Field to retrieve the download with.
 | |
|  * @param mixed  $value Value of the row.
 | |
|  *
 | |
|  * @return WP_Post|false WP_Post object if download found, false otherwise.
 | |
|  */
 | |
| function edd_get_download_by( $field = '', $value = '' ) {
 | |
| 
 | |
| 	// Bail if empty values passed.
 | |
| 	if ( empty( $field ) || empty( $value ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	switch ( strtolower( $field ) ) {
 | |
| 		case 'id':
 | |
| 			$download = get_post( $value );
 | |
| 
 | |
| 			if ( 'download' !== get_post_type( $download ) ) {
 | |
| 				return false;
 | |
| 			}
 | |
| 
 | |
| 			break;
 | |
| 
 | |
| 		case 'slug':
 | |
| 		case 'name':
 | |
| 			$download = get_posts( array(
 | |
| 				'post_type'      => 'download',
 | |
| 				'name'           => $value,
 | |
| 				'posts_per_page' => 1,
 | |
| 				'post_status'    => 'any',
 | |
| 			) );
 | |
| 
 | |
| 			if ( $download ) {
 | |
| 				$download = $download[0];
 | |
| 			}
 | |
| 
 | |
| 			break;
 | |
| 
 | |
| 		case 'sku':
 | |
| 			$download = get_posts( array(
 | |
| 				'post_type'      => 'download',
 | |
| 				'meta_key'       => 'edd_sku',
 | |
| 				'meta_value'     => $value,
 | |
| 				'posts_per_page' => 1,
 | |
| 				'post_status'    => 'any',
 | |
| 			) );
 | |
| 
 | |
| 			if ( $download ) {
 | |
| 				$download = $download[0];
 | |
| 			}
 | |
| 
 | |
| 			break;
 | |
| 
 | |
| 		default:
 | |
| 			return false;
 | |
| 	}
 | |
| 
 | |
| 	return $download ?: false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Retrieves a download post object by ID or slug.
 | |
|  *
 | |
|  * @since 1.0
 | |
|  * @since 2.9 - Return an EDD_Download object.
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return EDD_Download|null EDD_Download object if found, null otherwise.
 | |
|  */
 | |
| function edd_get_download( $download_id = 0 ) {
 | |
| 	$download = null;
 | |
| 
 | |
| 	if ( is_numeric( $download_id ) ) {
 | |
| 		$found_download = new EDD_Download( $download_id );
 | |
| 
 | |
| 		if ( ! empty( $found_download->ID ) ) {
 | |
| 			$download = $found_download;
 | |
| 		}
 | |
| 
 | |
| 	// Fetch download by name.
 | |
| 	} else {
 | |
| 		$args = array(
 | |
| 			'post_type'     => 'download',
 | |
| 			'name'          => $download_id,
 | |
| 			'post_per_page' => 1,
 | |
| 			'fields'        => 'ids',
 | |
| 		);
 | |
| 
 | |
| 		$downloads = new WP_Query( $args );
 | |
| 
 | |
| 		if ( is_array( $downloads->posts ) && ! empty( $downloads->posts ) ) {
 | |
| 			$download_id = $downloads->posts[0];
 | |
| 
 | |
| 			$download = new EDD_Download( $download_id );
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return $download;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Checks whether or not a download is free.
 | |
|  *
 | |
|  * @since 2.1
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @param int $price_id    Optional. Price ID.
 | |
|  * @return bool $is_free True if the product is free, false if the product is not free or the check fails
 | |
|  */
 | |
| function edd_is_free_download( $download_id = 0, $price_id = false ) {
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->is_free( $price_id )
 | |
| 		: false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Return the name of a download.
 | |
|  *
 | |
|  * Pass a price ID to append the specific price variation name.
 | |
|  *
 | |
|  * @since 3.0
 | |
|  *
 | |
|  * @param int $download_id
 | |
|  * @param int|null $price_id
 | |
|  *
 | |
|  * @return false|string
 | |
|  */
 | |
| function edd_get_download_name( $download_id = 0, $price_id = null ) {
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) || ! is_numeric( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	// Bail if the download cannot be retrieved.
 | |
| 	if ( ! $download instanceof EDD_Download ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	// Get the download title
 | |
| 	$retval = $download->get_name();
 | |
| 
 | |
| 	// Check for variable pricing
 | |
| 	if ( $download->has_variable_prices() && is_numeric( $price_id ) ) {
 | |
| 
 | |
| 		// Check for price option name
 | |
| 		$price_name = edd_get_price_option_name( $download_id, $price_id );
 | |
| 
 | |
| 		// Product has prices
 | |
| 		if ( ! empty( $price_name ) ) {
 | |
| 			$retval .= ' — ' . $price_name;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Override the download name.
 | |
| 	 *
 | |
| 	 * @since 3.0
 | |
| 	 *
 | |
| 	 * @param string $retval   The download name.
 | |
| 	 * @param int    $id       The download ID.
 | |
| 	 * @param int    $price_id The price ID, if any.
 | |
| 	 */
 | |
| 	return apply_filters( 'edd_get_download_name', $retval, $download_id, $price_id );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Returns the price of a download, but only for non-variable priced downloads.
 | |
|  *
 | |
|  * @since 1.0
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return string|int Price of the download.
 | |
|  */
 | |
| function edd_get_download_price( $download_id = 0 ) {
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->get_price()
 | |
| 		: 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Displays a formatted price for a download.
 | |
|  *
 | |
|  * @since 1.0
 | |
|  *
 | |
|  * @param int  $download_id Download ID.
 | |
|  * @param bool $echo        Optional. Whether to echo or return the result. Default true.
 | |
|  * @param int  $price_id    Optional. Price ID.
 | |
|  *
 | |
|  * @return string Download price if $echo set to false.
 | |
|  */
 | |
| function edd_price( $download_id = 0, $echo = true, $price_id = false ) {
 | |
| 
 | |
| 	// Attempt to get the ID of the current item in the WordPress loop.
 | |
| 	if ( empty( $download_id ) || ! is_numeric( $download_id ) ) {
 | |
| 		$download_id = get_the_ID();
 | |
| 	}
 | |
| 
 | |
| 	// Variable prices
 | |
| 	if ( edd_has_variable_prices( $download_id ) ) {
 | |
| 
 | |
| 		// Get the price variations
 | |
| 		$prices = edd_get_variable_prices( $download_id );
 | |
| 
 | |
| 		// Use the amount for the price ID
 | |
| 		if ( is_numeric( $price_id ) && isset( $prices[ $price_id ] ) ) {
 | |
| 			$price = edd_get_price_option_amount( $download_id, $price_id );
 | |
| 
 | |
| 		// Maybe use the default variable price
 | |
| 		} elseif ( $default = edd_get_default_variable_price( $download_id ) ) {
 | |
| 			$price = edd_get_price_option_amount( $download_id, $default );
 | |
| 
 | |
| 		// Maybe guess the lowest price
 | |
| 		} else {
 | |
| 			$price = edd_get_lowest_price_option( $download_id );
 | |
| 		}
 | |
| 
 | |
| 	// Single price (not variable)
 | |
| 	} else {
 | |
| 		$price = edd_get_download_price( $download_id );
 | |
| 	}
 | |
| 
 | |
| 	// Filter the price (already sanitized)
 | |
| 	$price           = apply_filters( 'edd_download_price', $price, $download_id, $price_id );
 | |
| 
 | |
| 	// Format the price (do not escape $price)
 | |
| 	$formatted_price = '<span class="edd_price" id="edd_price_' . esc_attr( $download_id ) . '">' . $price . '</span>';
 | |
| 	$formatted_price = apply_filters( 'edd_download_price_after_html', $formatted_price, $download_id, $price, $price_id );
 | |
| 
 | |
| 	// Echo or return
 | |
| 	if ( ! empty( $echo ) ) {
 | |
| 		echo $formatted_price; // WPCS: XSS ok.
 | |
| 	} else {
 | |
| 		return $formatted_price;
 | |
| 	}
 | |
| }
 | |
| add_filter( 'edd_download_price', 'edd_format_amount',   10 );
 | |
| add_filter( 'edd_download_price', 'edd_currency_filter', 20 );
 | |
| 
 | |
| /**
 | |
|  * Retrieves the final price of a downloadable product after purchase.
 | |
|  * This price includes any necessary discounts that were applied
 | |
|  *
 | |
|  * @since 1.0
 | |
|  * @param int $download_id ID of the download
 | |
|  * @param array $user_purchase_info - an array of all information for the payment
 | |
|  * @param string $amount_override a custom amount that over rides the 'edd_price' meta, used for variable prices
 | |
|  * @return string - the price of the download
 | |
|  */
 | |
| function edd_get_download_final_price( $download_id, $user_purchase_info, $amount_override = null ) {
 | |
| 	if ( is_null( $amount_override ) ) {
 | |
| 		$original_price = get_post_meta( $download_id, 'edd_price', true );
 | |
| 	} else {
 | |
| 		$original_price = $amount_override;
 | |
| 	}
 | |
| 
 | |
| 	if ( isset( $user_purchase_info['discount'] ) && 'none' !== $user_purchase_info['discount'] ) {
 | |
| 
 | |
| 		// If the discount was a percentage, we modify the amount.
 | |
| 		// Flat rate discounts are ignored
 | |
| 		if ( EDD_Discount::FLAT !== edd_get_discount_type( edd_get_discount_id_by_code( $user_purchase_info['discount'] ) ) ) {
 | |
| 			$price = edd_get_discounted_amount( $user_purchase_info['discount'], $original_price );
 | |
| 		} else {
 | |
| 			$price = $original_price;
 | |
| 		}
 | |
| 	} else {
 | |
| 		$price = $original_price;
 | |
| 	}
 | |
| 
 | |
| 	// Filter & return.
 | |
| 	return apply_filters( 'edd_final_price', $price, $download_id, $user_purchase_info );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Retrieves the variable prices for a download.
 | |
|  *
 | |
|  * @since 1.2
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return array|false Variable prices if found, false otherwise.
 | |
|  */
 | |
| function edd_get_variable_prices( $download_id = 0 ) {
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->get_prices()
 | |
| 		: false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Checks to see if a download has variable prices enabled.
 | |
|  *
 | |
|  * @since 1.0.7
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return bool True if the download has variable prices, false otherwise.
 | |
|  */
 | |
| function edd_has_variable_prices( $download_id = 0 ) {
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$download = new EDD_Download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->has_variable_prices()
 | |
| 		: false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Returns the default price ID for variable pricing, or the first price if
 | |
|  * none set.
 | |
|  *
 | |
|  * @since 2.2
 | |
|  *
 | |
|  * @param  int $download_id Download ID.
 | |
|  * @return int Price ID.
 | |
|  */
 | |
| function edd_get_default_variable_price( $download_id = 0 ) {
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	// Bail if download has no variable prices.
 | |
| 	if ( ! edd_has_variable_prices( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$prices           = edd_get_variable_prices( $download_id );
 | |
| 	$default_price_id = get_post_meta( $download_id, '_edd_default_price_id', true );
 | |
| 
 | |
| 	if ( '' === $default_price_id || ! isset( $prices[ $default_price_id ] ) ) {
 | |
| 		$default_price_id = current( array_keys( $prices ) );
 | |
| 	}
 | |
| 
 | |
| 	// Filter & return.
 | |
| 	return apply_filters( 'edd_variable_default_price_id', absint( $default_price_id ), $download_id );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Retrieves the name of a variable price option.
 | |
|  *
 | |
|  * @since 1.0.9
 | |
|  * @since 3.0 Renamed $payment_id parameter to $order_id.
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @param int $price_id    Price ID.
 | |
|  * @param int $order_id    Optional. Order ID for use in filters.
 | |
|  *
 | |
|  * @return string $price_name Name of the price option.
 | |
|  */
 | |
| function edd_get_price_option_name( $download_id = 0, $price_id = 0, $order_id = 0 ) {
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	// Fetch variable prices.
 | |
| 	$prices = edd_get_variable_prices( $download_id );
 | |
| 
 | |
| 	$price_name = '';
 | |
| 
 | |
| 	if ( $prices && is_array( $prices ) ) {
 | |
| 		if ( isset( $prices[ $price_id ] ) ) {
 | |
| 			$price_name = $prices[ $price_id ]['name'];
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return apply_filters( 'edd_get_price_option_name', $price_name, $download_id, $order_id, $price_id );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Retrieves the amount for a variable price option.
 | |
|  *
 | |
|  * @since 1.8.2
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @param int $price_id    Price ID.
 | |
|  *
 | |
|  * @return float $amount Price option amount.
 | |
|  */
 | |
| function edd_get_price_option_amount( $download_id = 0, $price_id = 0 ) {
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	// Fetch variable prices.
 | |
| 	$prices = edd_get_variable_prices( $download_id );
 | |
| 
 | |
| 	// Set default prices.
 | |
| 	$amount = 0.00;
 | |
| 
 | |
| 	if ( $prices && is_array( $prices ) ) {
 | |
| 		if ( isset( $prices[ $price_id ] ) ) {
 | |
| 			$amount = $prices[ $price_id ]['amount'];
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Filter & return.
 | |
| 	return apply_filters( 'edd_get_price_option_amount', edd_sanitize_amount( $amount ), $download_id, $price_id );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Retrieve the lowest price option of a variable priced download.
 | |
|  *
 | |
|  * @since 1.4.4
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return float Amount of the lowest price option.
 | |
|  */
 | |
| function edd_get_lowest_price_option( $download_id = 0 ) {
 | |
| 
 | |
| 	// Attempt to get the ID of the current item in the WordPress loop.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		$download_id = get_the_ID();
 | |
| 	}
 | |
| 
 | |
| 	// Bail if download ID is still empty.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	// Return download price if variable prices do not exist for download.
 | |
| 	if ( ! edd_has_variable_prices( $download_id ) ) {
 | |
| 		return edd_get_download_price( $download_id );
 | |
| 	}
 | |
| 
 | |
| 	// Fetch variables prices.
 | |
| 	$prices = edd_get_variable_prices( $download_id );
 | |
| 
 | |
| 	// Set lowest to 0.
 | |
| 	$lowest = 0.00;
 | |
| 
 | |
| 	// Loop through all the prices.
 | |
| 	if ( ! empty( $prices ) ) {
 | |
| 		foreach ( $prices as $key => $price ) {
 | |
| 
 | |
| 			// Skip if amount doesn't exist.
 | |
| 			if ( empty( $price['amount'] ) ) {
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			if ( ! isset( $min ) ) {
 | |
| 				$min = $price['amount'];
 | |
| 			} else {
 | |
| 				$min = min( $min, $price['amount'] );
 | |
| 			}
 | |
| 
 | |
| 			if ( $price['amount'] == $min ) {
 | |
| 				$min_id = $key;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		$lowest = $prices[ $min_id ]['amount'];
 | |
| 	}
 | |
| 
 | |
| 	return edd_sanitize_amount( $lowest );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Retrieves the ID for the cheapest price option of a variable priced download.
 | |
|  *
 | |
|  * @since 2.2
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return int|false ID of the lowest price, false if download does not exist.
 | |
|  */
 | |
| function edd_get_lowest_price_id( $download_id = 0 ) {
 | |
| 
 | |
| 	// Attempt to get the ID of the current item in the WordPress loop.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		$download_id = get_the_ID();
 | |
| 	}
 | |
| 
 | |
| 	// Bail if download ID is still empty.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	// Return download price if variable prices do not exist for download.
 | |
| 	if ( ! edd_has_variable_prices( $download_id ) ) {
 | |
| 		return edd_get_download_price( $download_id );
 | |
| 	}
 | |
| 
 | |
| 	// Fetch variable prices.
 | |
| 	$prices = edd_get_variable_prices( $download_id );
 | |
| 
 | |
| 	// Loop through all the prices.
 | |
| 	if ( ! empty( $prices ) ) {
 | |
| 		foreach ( $prices as $key => $price ) {
 | |
| 
 | |
| 			// Skip if amount doesn't exist.
 | |
| 			if ( empty( $price['amount'] ) ) {
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			if ( ! isset( $min ) ) {
 | |
| 				$min = $price['amount'];
 | |
| 			} else {
 | |
| 				$min = min( $min, $price['amount'] );
 | |
| 			}
 | |
| 
 | |
| 			if ( $price['amount'] == $min ) {
 | |
| 				$min_id = $key;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return absint( $min_id );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Retrieves most expensive price option of a variable priced download
 | |
|  *
 | |
|  * @since 1.4.4
 | |
|  * @param int $download_id ID of the download
 | |
|  * @return float Amount of the highest price
 | |
|  */
 | |
| function edd_get_highest_price_option( $download_id = 0 ) {
 | |
| 
 | |
| 	// Attempt to get the ID of the current item in the WordPress loop.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		$download_id = get_the_ID();
 | |
| 	}
 | |
| 
 | |
| 	// Bail if download ID is still empty.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	// Return download price if variable prices do not exist for download.
 | |
| 	if ( ! edd_has_variable_prices( $download_id ) ) {
 | |
| 		return edd_get_download_price( $download_id );
 | |
| 	}
 | |
| 
 | |
| 	// Fetch variables prices.
 | |
| 	$prices = edd_get_variable_prices( $download_id );
 | |
| 
 | |
| 	// Set highest to 0.
 | |
| 	$highest = 0.00;
 | |
| 
 | |
| 	// Loop through all the prices.
 | |
| 	if ( ! empty( $prices ) ) {
 | |
| 		$max = 0;
 | |
| 
 | |
| 		foreach ( $prices as $key => $price ) {
 | |
| 
 | |
| 			// Skip if amount doesn't exist.
 | |
| 			if ( empty( $price['amount'] ) ) {
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			$max = max( $max, $price['amount'] );
 | |
| 
 | |
| 			if ( $price['amount'] == $max ) {
 | |
| 				$max_id = $key;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		$highest = $prices[ $max_id ]['amount'];
 | |
| 	}
 | |
| 
 | |
| 	return edd_sanitize_amount( $highest );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Retrieves a price from from low to high of a variable priced download.
 | |
|  *
 | |
|  * @since 1.4.4
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return string $range A fully formatted price range.
 | |
|  */
 | |
| function edd_price_range( $download_id = 0 ) {
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$low    = edd_get_lowest_price_option( $download_id );
 | |
| 	$high   = edd_get_highest_price_option( $download_id );
 | |
| 	$range  = '<span class="edd_price edd_price_range_low" id="edd_price_low_' . $download_id . '">' . edd_currency_filter( edd_format_amount( $low ) ) . '</span>';
 | |
| 	$range .= '<span class="edd_price_range_sep"> – </span>';
 | |
| 	$range .= '<span class="edd_price edd_price_range_high" id="edd_price_high_' . $download_id . '">' . edd_currency_filter( edd_format_amount( $high ) ) . '</span>';
 | |
| 
 | |
| 	return apply_filters( 'edd_price_range', $range, $download_id, $low, $high );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Checks to see if multiple price options can be purchased at once.
 | |
|  *
 | |
|  * @since 1.4.2
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return bool True if multiple price options can be purchased at once, false otherwise.
 | |
|  */
 | |
| function edd_single_price_option_mode( $download_id = 0 ) {
 | |
| 
 | |
| 	// Attempt to get the ID of the current item in the WordPress loop.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		$download_id = get_the_ID();
 | |
| 	}
 | |
| 
 | |
| 	// Bail if download ID is still empty.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 	return $download
 | |
| 		? $download->is_single_price_mode()
 | |
| 		: false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Get product types.
 | |
|  *
 | |
|  * @since 1.8
 | |
|  *
 | |
|  * @return array $types Download types.
 | |
|  */
 | |
| function edd_get_download_types() {
 | |
| 	$types = array(
 | |
| 		'0'      => __( 'Default', 'easy-digital-downloads' ),
 | |
| 		'bundle' => __( 'Bundle', 'easy-digital-downloads' ),
 | |
| 	);
 | |
| 
 | |
| 	return apply_filters( 'edd_download_types', $types );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Get the download type: either `default` or `bundled`.
 | |
|  *
 | |
|  * @since 1.6
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return string $type Download type.
 | |
|  */
 | |
| function edd_get_download_type( $download_id = 0 ) {
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->type
 | |
| 		: false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Determines if a product is a bundle.
 | |
|  *
 | |
|  * @since 1.6
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return bool True if a bundle, false otherwise.
 | |
|  */
 | |
| function edd_is_bundled_product( $download_id = 0 ) {
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->is_bundled_download()
 | |
| 		: false;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Retrieves the product IDs of bundled products.
 | |
|  *
 | |
|  * @since 1.6
 | |
|  * @since 2.7 Added $price_id parameter.
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @param int $price_id    Optional. Price ID. Default null.
 | |
|  *
 | |
|  * @return array|false Products in the bundle, false if download does not exist.
 | |
|  */
 | |
| function edd_get_bundled_products( $download_id = 0, $price_id = null ) {
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	// Bail if download does not exist.
 | |
| 	if ( ! $download ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	if ( null !== $price_id ) {
 | |
| 		return $download->get_variable_priced_bundled_downloads( $price_id );
 | |
| 	} else {
 | |
| 		return $download->bundled_downloads;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Returns the total earnings for a download.
 | |
|  *
 | |
|  * @since 1.0
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return float|false $earnings Download earnings, false if download not found.
 | |
|  */
 | |
| function edd_get_download_earnings_stats( $download_id = 0 ) {
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->earnings
 | |
| 		: false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Return the sales number for a download.
 | |
|  *
 | |
|  * @since 1.0
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return int|false Number of sales, false if download was not found.
 | |
|  */
 | |
| function edd_get_download_sales_stats( $download_id = 0 ) {
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->sales
 | |
| 		: false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Record a file download.
 | |
|  *
 | |
|  * @since 1.0
 | |
|  * @since 3.0 Refactored to use new query methods.
 | |
|  *
 | |
|  * @param int    $download_id Download ID.
 | |
|  * @param int    $file_id     File ID.
 | |
|  * @param array  $user_info   User information (deprecated).
 | |
|  * @param string $ip          User IP.
 | |
|  * @param int    $order_id    Order ID.
 | |
|  * @param int    $price_id    Optional. Price ID,
 | |
|  * @return void
 | |
|  */
 | |
| function edd_record_download_in_log( $download_id = 0, $file_id = 0, $user_info = array(), $ip = '', $order_id = 0, $price_id = 0 ) {
 | |
| 	$order = edd_get_order( $order_id );
 | |
| 
 | |
| 	if ( ! class_exists( 'Browser' ) ) {
 | |
| 		require_once EDD_PLUGIN_DIR . 'includes/libraries/browser.php';
 | |
| 	}
 | |
| 
 | |
| 	$browser = new Browser();
 | |
| 
 | |
| 	$user_agent = $browser->getBrowser() . ' ' . $browser->getVersion() . '/' . $browser->getPlatform();
 | |
| 
 | |
| 	edd_add_file_download_log( array(
 | |
| 		'product_id'  => absint( $download_id ),
 | |
| 		'file_id'     => absint( $file_id ),
 | |
| 		'order_id'    => absint( $order_id ),
 | |
| 		'price_id'    => absint( $price_id ),
 | |
| 		'customer_id' => $order->customer_id,
 | |
| 		'ip'          => sanitize_text_field( $ip ),
 | |
| 		'user_agent'  => $user_agent,
 | |
| 	) );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Delete log entries when deleting downloads.
 | |
|  *
 | |
|  * Removes all related log entries when a download is completely deleted.
 | |
|  * (Does not run when a download is trashed)
 | |
|  *
 | |
|  * @since 1.3.4
 | |
|  * @since 3.0 Updated to use new query methods.
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  */
 | |
| function edd_remove_download_logs_on_delete( $download_id = 0 ) {
 | |
| 	global $wpdb;
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	// Ensure download ID is an integer.
 | |
| 	$download_id = absint( $download_id );
 | |
| 
 | |
| 	// Bail if the post type is not `download`.
 | |
| 	if ( 'download' !== get_post_type( $download_id ) ) {
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	// Delete file download logs.
 | |
| 	$wpdb->delete( $wpdb->edd_logs_file_downloads, array(
 | |
| 		'product_id' => $download_id,
 | |
| 	), array( '%d' ) );
 | |
| 
 | |
| 	// Delete logs.
 | |
| 	$wpdb->delete( $wpdb->edd_logs, array(
 | |
| 		'object_id'   => $download_id,
 | |
| 		'object_type' => 'download',
 | |
| 	), array( '%d', '%s' ) );
 | |
| }
 | |
| add_action( 'delete_post', 'edd_remove_download_logs_on_delete' );
 | |
| 
 | |
| /**
 | |
|  * Recalculates both the net and gross sales and earnings for a download.
 | |
|  *
 | |
|  * @since 3.0
 | |
|  * @param int $download_id
 | |
|  * @return void
 | |
|  */
 | |
| function edd_recalculate_download_sales_earnings( $download_id ) {
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 	if ( ! $download instanceof \EDD_Download ) {
 | |
| 		return;
 | |
| 	}
 | |
| 	$download->recalculate_net_sales_earnings();
 | |
| 	$download->recalculate_gross_sales_earnings();
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Retrieves the average monthly earnings for a specific download.
 | |
|  *
 | |
|  * @since 1.3
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return float $earnings Average monthly earnings.
 | |
|  */
 | |
| function edd_get_average_monthly_download_earnings( $download_id = 0 ) {
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	$earnings     = edd_get_download_earnings_stats( $download_id );
 | |
| 	$release_date = get_post_field( 'post_date', $download_id );
 | |
| 
 | |
| 	$diff = abs( current_time( 'timestamp' ) - strtotime( $release_date ) );
 | |
| 
 | |
| 	// Number of months since publication
 | |
| 	$months = floor( $diff / ( 30 * 60 * 60 * 24 ) );
 | |
| 
 | |
| 	if ( $months > 0 ) {
 | |
| 		$earnings = ( $earnings / $months );
 | |
| 	}
 | |
| 
 | |
| 	return $earnings < 0
 | |
| 		? 0
 | |
| 		: $earnings;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Retrieves the average monthly sales for a specific download.
 | |
|  *
 | |
|  * @since 1.3
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return float $sales Average monthly sales.
 | |
|  */
 | |
| function edd_get_average_monthly_download_sales( $download_id = 0 ) {
 | |
| 	$sales        = edd_get_download_sales_stats( $download_id );
 | |
| 	$release_date = get_post_field( 'post_date', $download_id );
 | |
| 
 | |
| 	$diff = abs( current_time( 'timestamp' ) - strtotime( $release_date ) );
 | |
| 
 | |
| 	// Number of months since publication
 | |
| 	$months = floor( $diff / ( 30 * 60 * 60 * 24 ) );
 | |
| 
 | |
| 	if ( $months > 0 ) {
 | |
| 		$sales = ( $sales / $months );
 | |
| 	}
 | |
| 
 | |
| 	return $sales;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Gets all download files for a product.
 | |
|  *
 | |
|  * @since 1.0
 | |
|  * @since 3.0 Renamed $variable_price_id parameter to $price)id for consistency.
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @param int $price_id    Optional. Price ID. Default null.
 | |
|  *
 | |
|  * @return array|false Download files, false if invalid data was passed.
 | |
|  */
 | |
| function edd_get_download_files( $download_id = 0, $price_id = null ) {
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->get_files( $price_id )
 | |
| 		: false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Retrieves a file name for a file attached to a download. Defaults to the
 | |
|  * file's actual name if no 'name' key is present.
 | |
|  *
 | |
|  * @since 1.6
 | |
|  *
 | |
|  * @param array $file File information.
 | |
|  * @return string Filename.
 | |
|  */
 | |
| function edd_get_file_name( $file = array() ) {
 | |
| 
 | |
| 	// Bail if no data was passed.
 | |
| 	if ( empty( $file ) || ! is_array( $file ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$name = ! empty( $file['name'] )
 | |
| 		? esc_html( $file['name'] )
 | |
| 		: basename( $file['file'] );
 | |
| 
 | |
| 	return $name;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Gets the number of times a file has been downloaded for a specific order.
 | |
|  *
 | |
|  * @since 1.6
 | |
|  * @since 3.0 Renamed parameters for consistency across new query methods
 | |
|  *            introduced.
 | |
|  *            Refactored to use new query methods.
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @param int $file_id     File ID.
 | |
|  * @param int $order_id    Order ID.
 | |
|  *
 | |
|  * @return int Number of times the file has been downloaded for the order.
 | |
|  */
 | |
| function edd_get_file_downloaded_count( $download_id = 0, $file_id = 0, $order_id = 0 ) {
 | |
| 
 | |
| 	// Bail if no download ID or order ID was passed.
 | |
| 	if ( empty( $download_id ) || empty( $order_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	// Ensure arguments passed are valid.
 | |
| 	$download_id = absint( $download_id );
 | |
| 	$file_id     = absint( $file_id );
 | |
| 	$order_id    = absint( $order_id );
 | |
| 
 | |
| 	return edd_count_file_download_logs( array(
 | |
| 		'product_id' => $download_id,
 | |
| 		'order_id'   => $order_id,
 | |
| 		'file_id'    => $file_id,
 | |
| 	) );
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Gets the file download file limit for a particular download. This limit refers
 | |
|  * to the maximum number of times files connected to a product can be downloaded.
 | |
|  *
 | |
|  * @since 1.3.1
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return int|false File download limit, false if invalid download ID passed.
 | |
|  */
 | |
| function edd_get_file_download_limit( $download_id = 0 ) {
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->get_file_download_limit()
 | |
| 		: false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Gets the file refund window for a particular download
 | |
|  *
 | |
|  * This window refers to the maximum number of days it can be refunded after
 | |
|  * it has been purchased.
 | |
|  *
 | |
|  * @since 3.0
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return int Refund window.
 | |
|  */
 | |
| function edd_get_download_refund_window( $download_id = 0 ) {
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->get_refund_window()
 | |
| 		: false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Get the refundability status for a download.
 | |
|  *
 | |
|  * @since 3.0
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return string `refundable` or `nonrefundable`.
 | |
|  */
 | |
| function edd_get_download_refundability( $download_id = 0 ) {
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->get_refundability()
 | |
| 		: false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Gets the file download file limit override for a particular download.
 | |
|  * The override allows the main file download limit to be bypassed.
 | |
|  *
 | |
|  * @since 1.3.2
 | |
|  * @since 3.0 Renamed $payment_id parameter to $order_id.
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @param int $order_id    Order ID.
 | |
|  *
 | |
|  * @return int|false New file download limit, false if invalid download ID passed.
 | |
| */
 | |
| function edd_get_file_download_limit_override( $download_id = 0, $order_id = 0 ) {
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$limit_override = get_post_meta( $download_id, '_edd_download_limit_override_' . $order_id, true );
 | |
| 
 | |
| 	return $limit_override
 | |
| 		? absint( $limit_override )
 | |
| 		: 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Sets the file download file limit override for a particular download.
 | |
|  *
 | |
|  * The override allows the main file download limit to be bypassed.
 | |
|  * If no override is set yet, the override is set to the main limit + 1.
 | |
|  * If the override is already set, then it is simply incremented by 1.
 | |
|  *
 | |
|  * @since 1.3.2
 | |
|  * @since 3.0 Renamed $payment_id parameter to $order_id.
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @param int $order_id    Order ID.
 | |
|  *
 | |
|  * @return false False if invalid download ID or order ID was passed.
 | |
|  */
 | |
| function edd_set_file_download_limit_override( $download_id = 0, $order_id = 0 ) {
 | |
| 
 | |
| 	// Bail if no download ID or order ID was passed.
 | |
| 	if ( empty( $download_id ) || empty( $order_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$override = edd_get_file_download_limit_override( $download_id, $order_id );
 | |
| 	$limit    = edd_get_file_download_limit( $download_id );
 | |
| 
 | |
| 	if ( ! empty( $override ) ) {
 | |
| 		$override = $override += 1;
 | |
| 	} else {
 | |
| 		$override = $limit += 1;
 | |
| 	}
 | |
| 
 | |
| 	update_post_meta( $download_id, '_edd_download_limit_override_' . $order_id, $override );
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Checks if a file is at its download limit
 | |
|  *
 | |
|  * This limit refers to the maximum number of times files connected to a product
 | |
|  * can be downloaded.
 | |
|  *
 | |
|  * @since 1.3.1
 | |
|  * @since 3.0 Refactored to use new query methods.
 | |
|  *            Renamed $payment_id parameter to $order_id.
 | |
|  *            Set default value of $price_id to 0.
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @param int $order_id    Order ID.
 | |
|  * @param int $file_id     File ID.
 | |
|  * @param int $price_id    Price ID.
 | |
|  *
 | |
|  * @return bool True if at limit, false otherwise.
 | |
|  */
 | |
| function edd_is_file_at_download_limit( $download_id = 0, $order_id = 0, $file_id = 0, $price_id = 0 ) {
 | |
| 
 | |
| 	// Bail if invalid data was passed.
 | |
| 	if ( empty( $download_id ) || empty( $order_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	// Sanitize parameters.
 | |
| 	$download_id = absint( $download_id );
 | |
| 	$order_id    = absint( $order_id );
 | |
| 	$file_id     = absint( $file_id );
 | |
| 	$price_id    = absint( $price_id );
 | |
| 
 | |
| 	// Default to false.
 | |
| 	$ret            = false;
 | |
| 	$download_limit = edd_get_file_download_limit( $download_id );
 | |
| 
 | |
| 	if ( ! empty( $download_limit ) ) {
 | |
| 		$unlimited_purchase = edd_payment_has_unlimited_downloads( $order_id );
 | |
| 
 | |
| 		if ( empty( $unlimited_purchase ) ) {
 | |
| 			// Retrieve the file download count.
 | |
| 			$download_count = edd_count_file_download_logs( array(
 | |
| 				'product_id' => $download_id,
 | |
| 				'file_id'    => $file_id,
 | |
| 				'order_id'   => $order_id,
 | |
| 				'price_id'   => $price_id,
 | |
| 			) );
 | |
| 
 | |
| 			if ( $download_count >= $download_limit ) {
 | |
| 				$ret = true;
 | |
| 
 | |
| 				// Check to make sure the limit isn't overwritten.
 | |
| 				// A limit is overwritten when purchase receipt is resent.
 | |
| 				$limit_override = edd_get_file_download_limit_override( $download_id, $order_id );
 | |
| 
 | |
| 				if ( ! empty( $limit_override ) && $download_count < $limit_override ) {
 | |
| 					$ret = false;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Filters whether or not a file is at its download limit.
 | |
| 	 *
 | |
| 	 * @param bool $ret
 | |
| 	 * @param int  $download_id
 | |
| 	 * @param int  $payment_id
 | |
| 	 * @param int  $file_id
 | |
| 	 * @param int  $price_id
 | |
| 	 *
 | |
| 	 * @since 2.10 Added `$price_id` parameter.
 | |
| 	 */
 | |
| 	return (bool) apply_filters( 'edd_is_file_at_download_limit', $ret, $download_id, $order_id, $file_id, $price_id );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Retrieve the price option that has access to the specified file.
 | |
|  *
 | |
|  * @since 1.0.9
 | |
|  *
 | |
|  * @param int    $download_id Download ID.
 | |
|  * @param string $file_key    File key.
 | |
|  *
 | |
|  * @return string|false Price ID if restricted, "all" otherwise, false if no download ID was passed.
 | |
|  */
 | |
| function edd_get_file_price_condition( $download_id = 0, $file_key = '' ) {
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->get_file_price_condition( $file_key )
 | |
| 		: false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Constructs a secure file download url for a specific file.
 | |
|  *
 | |
|  * @since 1.0
 | |
|  * @since 3.0  Updated to use new query methods.
 | |
|  *
 | |
|  * @param string    $order_or_key The order object or payment key. Using the payment key will eventually be deprecated.
 | |
|  * @param string    $email        Customer email address. Use edd_get_payment_user_email() to get user email.
 | |
|  * @param int       $filekey      Index of array of files returned by edd_get_download_files() that this download link is for.
 | |
|  * @param int       $download_id  Optional. ID of download this download link is for. Default is 0.
 | |
|  * @param bool|int  $price_id     Optional. Price ID when using variable prices. Default is false.
 | |
|  *
 | |
|  * @return string Secure download URL.
 | |
|  */
 | |
| function edd_get_download_file_url( $order_or_key, $email, $filekey, $download_id = 0, $price_id = false ) {
 | |
| 	$hours = absint( edd_get_option( 'download_link_expiration', 24 ) );
 | |
| 
 | |
| 	if ( ! ( $date = strtotime( '+' . $hours . 'hours', current_time( 'timestamp' ) ) ) ) {
 | |
| 		$date = 2147472000; // Highest possible date, January 19, 2038
 | |
| 	}
 | |
| 
 | |
| 	// Fetch order.
 | |
| 	if ( $order_or_key instanceof EDD\Orders\Order ) {
 | |
| 		$order = $order_or_key;
 | |
| 		$key   = $order->payment_key;
 | |
| 	} else {
 | |
| 		$key   = $order_or_key;
 | |
| 		$order = edd_get_order_by( 'payment_key', $key );
 | |
| 	}
 | |
| 
 | |
| 	// Leaving in this array and the filter for backwards compatibility now
 | |
| 	$old_args = array(
 | |
| 		'download_key' => rawurlencode( $key ),
 | |
| 		'email'        => rawurlencode( $email ),
 | |
| 		'file'         => rawurlencode( $filekey ),
 | |
| 		'price_id'     => (int) $price_id,
 | |
| 		'download_id'  => $download_id,
 | |
| 		'expire'       => rawurlencode( $date ),
 | |
| 	);
 | |
| 
 | |
| 	$params = apply_filters( 'edd_download_file_url_args', $old_args );
 | |
| 
 | |
| 	// Bail if order wasn't found.
 | |
| 	if ( ! $order ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	// Get the array of parameters in the same order in which they will be validated.
 | |
| 	$args = array_fill_keys( edd_get_url_token_parameters(), '' );
 | |
| 
 | |
| 	// Simply the URL by concatenating required data using a colon as a delimiter.
 | |
| 	if ( ! is_numeric( $price_id ) ) {
 | |
| 		$eddfile = sprintf( '%d:%d:%d', $order->id, $params['download_id'], $params['file'] );
 | |
| 	} else {
 | |
| 		$eddfile = sprintf( '%d:%d:%d:%d', $order->id, $params['download_id'], $params['file'], $price_id );
 | |
| 	}
 | |
| 	$args['eddfile'] = rawurlencode( $eddfile );
 | |
| 
 | |
| 	if ( isset( $params['expire'] ) ) {
 | |
| 		$args['ttl'] = $params['expire'];
 | |
| 	}
 | |
| 
 | |
| 	// Ensure all custom args registered with extensions through edd_download_file_url_args get added to the URL, but without adding all the old args
 | |
| 	$args = array_merge( $args, array_diff_key( $params, $old_args ) );
 | |
| 
 | |
| 	/**
 | |
| 	 * Allow the file download args to be filtered.
 | |
| 	 *
 | |
| 	 * @since 3.1.1 Includes the order object as the fourth parameter.
 | |
| 	 * @param array            $args     The full array of parameters.
 | |
| 	 * @param int              $order_id The order ID.
 | |
| 	 * @param array            $params   The original array of parameters.
 | |
| 	 * @param EDD\Orders\Order $order    The order object.
 | |
| 	 */
 | |
| 	$args = apply_filters( 'edd_get_download_file_url_args', $args, $order->id, $params, $order );
 | |
| 
 | |
| 	$args['file']  = $params['file'];
 | |
| 	$args['token'] = edd_get_download_token( add_query_arg( array_filter( $args ), untrailingslashit( site_url() ) ) );
 | |
| 
 | |
| 	return add_query_arg( array_filter( $args ), site_url( 'index.php' ) );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Gets the array of parameters to be used for the URL token generation and validation.
 | |
|  * Used by `edd_get_download_file_url` and `edd_validate_url_token` so that their parameters are ordered the same.
 | |
|  *
 | |
|  * @since 2.11.4
 | |
|  * @return array
 | |
|  */
 | |
| function edd_get_url_token_parameters() {
 | |
| 	return apply_filters(
 | |
| 		'edd_url_token_allowed_params',
 | |
| 		array(
 | |
| 			'eddfile',
 | |
| 			'ttl',
 | |
| 			'file',
 | |
| 			'token',
 | |
| 		)
 | |
| 	);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Get product notes.
 | |
|  *
 | |
|  * @since 1.2.1
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return string|false Product notes, false if invalid data was passed.
 | |
|  */
 | |
| function edd_get_product_notes( $download_id = 0 ) {
 | |
| 
 | |
| 	// Bail if download ID was not passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->notes
 | |
| 		: false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Retrieves a download SKU by ID.
 | |
|  *
 | |
|  * @since 1.6
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return string|false Download SKU, false if invalid data was passed.
 | |
|  */
 | |
| function edd_get_download_sku( $download_id = 0 ) {
 | |
| 
 | |
| 	// Bail if download ID was not passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->sku
 | |
| 		: false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Retrieve the download button behavior: either add to cart or direct.
 | |
|  *
 | |
|  * @since 1.7
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return string|false `add_to_cart` or `direct`, false if invalid data was passed.
 | |
|  */
 | |
| function edd_get_download_button_behavior( $download_id = 0 ) {
 | |
| 
 | |
| 	// Bail if download ID was not passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->button_behavior
 | |
| 		: false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Is quantity input disabled on this product?
 | |
|  *
 | |
|  * @since 2.7
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return bool
 | |
|  */
 | |
| function edd_download_quantities_disabled( $download_id = 0 ) {
 | |
| 
 | |
| 	// Bail if download ID was not passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->quantities_disabled()
 | |
| 		: false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Get the file download method.
 | |
|  *
 | |
|  * @since 1.6
 | |
|  *
 | |
|  * @return string File download method.
 | |
|  */
 | |
| function edd_get_file_download_method() {
 | |
| 	$method = edd_get_option( 'download_method', 'direct' );
 | |
| 
 | |
| 	return apply_filters( 'edd_file_download_method', $method );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Returns a random download.
 | |
|  *
 | |
|  * @since 1.7
 | |
|  *
 | |
|  * @param bool $post_ids Optional. True for of download IDs, false for WP_Post
 | |
|  *                       objects. Default true.
 | |
|  * @return array Download IDs/WP_Post objects.
 | |
|  */
 | |
| function edd_get_random_download( $post_ids = true ) {
 | |
| 	return edd_get_random_downloads( 1, $post_ids );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Returns random downloads.
 | |
|  *
 | |
|  * @since 1.7
 | |
|  *
 | |
|  * @param int  $num      Number of downloads to return. Default 3.
 | |
|  * @param bool $post_ids Optional. True for array of WP_Post objects, else
 | |
|  *                       array of IDs. Default true.
 | |
|  *
 | |
|  * @return array Download IDs/WP_Post objects.
 | |
|  */
 | |
| function edd_get_random_downloads( $num = 3, $post_ids = true ) {
 | |
| 	$args = array(
 | |
| 		'post_type'   => 'download',
 | |
| 		'orderby'     => 'rand',
 | |
| 		'numberposts' => $num,
 | |
| 	);
 | |
| 
 | |
| 	if ( $post_ids ) {
 | |
| 		$args['fields'] = 'ids';
 | |
| 	}
 | |
| 
 | |
| 	$args = apply_filters( 'edd_get_random_downloads', $args );
 | |
| 
 | |
| 	return get_posts( $args );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Generates a token for a given URL.
 | |
|  *
 | |
|  * An 'o' query parameter on a URL can include optional variables to test
 | |
|  * against when verifying a token without passing those variables around in
 | |
|  * the URL. For example, downloads can be limited to the IP that the URL was
 | |
|  * generated for by adding 'o=ip' to the query string.
 | |
|  *
 | |
|  * Or suppose when WordPress requested a URL for automatic updates, the user
 | |
|  * agent could be tested to ensure the URL is only valid for requests from
 | |
|  * that user agent.
 | |
|  *
 | |
|  * @since 2.3
 | |
|  *
 | |
|  * @param string $url URL to generate a token for.
 | |
|  * @return string Token for the URL.
 | |
|  */
 | |
| function edd_get_download_token( $url = '' ) {
 | |
| 	$args   = array();
 | |
| 	$hash   = apply_filters( 'edd_get_url_token_algorithm', 'sha256' );
 | |
| 	$secret = apply_filters( 'edd_get_url_token_secret', hash( $hash, wp_salt() ) );
 | |
| 
 | |
| 	/*
 | |
| 	 * Add additional args to the URL for generating the token.
 | |
| 	 * Allows for restricting access to IP and/or user agent.
 | |
| 	 */
 | |
| 	$parts   = wp_parse_url( $url );
 | |
| 	$options = array();
 | |
| 
 | |
| 	if ( isset( $parts['query'] ) ) {
 | |
| 		wp_parse_str( $parts['query'], $query_args );
 | |
| 
 | |
| 		// o = option checks (ip, user agent).
 | |
| 		if ( ! empty( $query_args['o'] ) ) {
 | |
| 
 | |
| 			// Multiple options can be checked by separating them with a colon in the query parameter.
 | |
| 			$options = explode( ':', rawurldecode( $query_args['o'] ) );
 | |
| 
 | |
| 			if ( in_array( 'ip', $options, true ) ) {
 | |
| 				$args['ip'] = edd_get_ip();
 | |
| 			}
 | |
| 
 | |
| 			if ( in_array( 'ua', $options, true ) ) {
 | |
| 				$ua = isset( $_SERVER['HTTP_USER_AGENT'] )
 | |
| 					? $_SERVER['HTTP_USER_AGENT']
 | |
| 					: '';
 | |
| 
 | |
| 				$args['user_agent'] = rawurlencode( $ua );
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Filter to modify arguments and allow custom options to be tested.
 | |
| 	 * Be sure to rawurlencode any custom options for consistent results.
 | |
| 	 */
 | |
| 	$args = apply_filters( 'edd_get_url_token_args', $args, $url, $options );
 | |
| 
 | |
| 	$args['secret'] = $secret;
 | |
| 	$args['token']  = false; // Removes a token if present.
 | |
| 
 | |
| 	$url   = add_query_arg( $args, $url );
 | |
| 	$parts = wp_parse_url( $url );
 | |
| 
 | |
| 	// In the event there isn't a path, set an empty one so we can MD5 the token
 | |
| 	if ( ! isset( $parts['path'] ) ) {
 | |
| 		$parts['path'] = '';
 | |
| 	}
 | |
| 
 | |
| 	$token = hash_hmac( 'sha256', $parts['path'] . '?' . $parts['query'], wp_salt( 'edd_file_download_link' ) );
 | |
| 	return $token;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Generate a token for a URL and match it against the existing token to make
 | |
|  * sure the URL hasn't been tampered with.
 | |
|  *
 | |
|  * @since 2.3
 | |
|  *
 | |
|  * @param string $url URL to test.
 | |
|  * @return bool
 | |
|  */
 | |
| function edd_validate_url_token( $url = '' ) {
 | |
| 	$ret          = false;
 | |
| 	$parts        = parse_url( $url );
 | |
| 	$query_args   = array();
 | |
| 	$original_url = $url;
 | |
| 
 | |
| 	if ( isset( $parts['query'] ) ) {
 | |
| 		wp_parse_str( $parts['query'], $query_args );
 | |
| 
 | |
| 		// If the TTL is in the past, die out before we go any further.
 | |
| 		if ( isset( $query_args['ttl'] ) && current_time( 'timestamp' ) > $query_args['ttl'] ) {
 | |
| 			wp_die( apply_filters( 'edd_download_link_expired_text', esc_html__( 'Sorry but your download link has expired.', 'easy-digital-downloads' ) ), esc_html__( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) );
 | |
| 		}
 | |
| 
 | |
| 		// These are the only URL parameters that are allowed to affect the token validation.
 | |
| 		$allowed_args = edd_get_url_token_parameters();
 | |
| 
 | |
| 		// Collect the allowed tags in proper order, remove all tags, and re-add only the allowed ones.
 | |
| 		$validated_query_args = array();
 | |
| 
 | |
| 		foreach ( $allowed_args as $key ) {
 | |
| 			if ( true === array_key_exists( $key, $query_args ) ) {
 | |
| 				$validated_query_args[ $key ] = $query_args[ $key ];
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// strtok allows a quick clearing of existing query string parameters, so we can re-add the allowed ones.
 | |
| 		$url = add_query_arg( $validated_query_args, strtok( $url, '?' ) );
 | |
| 
 | |
| 		if ( isset( $query_args['token'] ) && hash_equals( $query_args['token'], edd_get_download_token( $url ) ) ) {
 | |
| 			$ret = true;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Filters the URL token validation.
 | |
| 	 *
 | |
| 	 * @param bool   $ret          Whether the URL has validated or not.
 | |
| 	 * @param string $url          The URL used for validation.
 | |
| 	 * @param array  $query_args   The array of query parameters.
 | |
| 	 * @param string $original_url The original URL (added 2.11.3).
 | |
| 	 */
 | |
| 	return apply_filters( 'edd_validate_url_token', $ret, $url, $query_args, $original_url );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Allows parsing of the values saved by the product drop down.
 | |
|  *
 | |
|  * @since 2.6.9
 | |
|  *
 | |
|  * @param array $values Parse the values from the product dropdown into a readable array.
 | |
|  * @return array A parsed set of values for download_id and price_id.
 | |
|  */
 | |
| function edd_parse_product_dropdown_values( $values = array() ) {
 | |
| 	$parsed_values = array();
 | |
| 
 | |
| 	if ( is_array( $values ) ) {
 | |
| 		foreach ( $values as $value ) {
 | |
| 			$value = edd_parse_product_dropdown_value( $value );
 | |
| 
 | |
| 			$parsed_values[] = array(
 | |
| 				'download_id' => $value['download_id'],
 | |
| 				'price_id'    => $value['price_id'],
 | |
| 			);
 | |
| 		}
 | |
| 	} else {
 | |
| 		$value           = edd_parse_product_dropdown_value( $values );
 | |
| 		$parsed_values[] = array(
 | |
| 			'download_id' => $value['download_id'],
 | |
| 			'price_id'    => $value['price_id'],
 | |
| 		);
 | |
| 	}
 | |
| 
 | |
| 	return $parsed_values;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Given a value from the product dropdown array, parse its parts.
 | |
|  *
 | |
|  * @since 2.6.9
 | |
|  *
 | |
|  * @param string $value A value saved in a product dropdown array
 | |
|  * @return array A parsed set of values for download_id and price_id.
 | |
|  */
 | |
| function edd_parse_product_dropdown_value( $value ) {
 | |
| 	$parts       = explode( '_', $value );
 | |
| 	$download_id = $parts[0];
 | |
| 	$price_id    = isset( $parts[1] )
 | |
| 		? $parts[1]
 | |
| 		: false;
 | |
| 
 | |
| 	return array(
 | |
| 		'download_id' => $download_id,
 | |
| 		'price_id'    => $price_id,
 | |
| 	);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Get bundle pricing variations
 | |
|  *
 | |
|  * @since 2.7
 | |
|  *
 | |
|  * @param int $download_id Download ID.
 | |
|  * @return array|false Bundle pricing variations, false if invalid data was passed.
 | |
|  */
 | |
| function edd_get_bundle_pricing_variations( $download_id = 0 ) {
 | |
| 
 | |
| 	// Bail if no download ID was passed.
 | |
| 	if ( empty( $download_id ) ) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	$download = edd_get_download( $download_id );
 | |
| 
 | |
| 	return $download
 | |
| 		? $download->get_bundle_pricing_variations()
 | |
| 		: false;
 | |
| }
 |