2012 lines
52 KiB
PHP
2012 lines
52 KiB
PHP
<?php
|
|
/**
|
|
* Payment Functions
|
|
*
|
|
* @package EDD
|
|
* @subpackage Payments
|
|
* @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;
|
|
|
|
/**
|
|
* Retrieves an instance of EDD_Payment for a specified ID.
|
|
*
|
|
* @since 2.7
|
|
*
|
|
* @param mixed int|EDD_Payment|WP_Post $payment Payment ID, EDD_Payment object or WP_Post object.
|
|
* @param bool $by_txn Is the ID supplied as the first parameter
|
|
*
|
|
* @return EDD_Payment|false false|object EDD_Payment if a valid payment ID, false otherwise.
|
|
*/
|
|
function edd_get_payment( $payment_or_txn_id = null, $by_txn = false ) {
|
|
if ( $payment_or_txn_id instanceof WP_Post || $payment_or_txn_id instanceof EDD_Payment ) {
|
|
$payment_id = $payment_or_txn_id->ID;
|
|
} elseif ( $by_txn ) {
|
|
if ( empty( $payment_or_txn_id ) ) {
|
|
return false;
|
|
}
|
|
|
|
$payment_id = edd_get_order_id_from_transaction_id( $payment_or_txn_id );
|
|
|
|
if ( empty( $payment_id ) ) {
|
|
return false;
|
|
}
|
|
} else {
|
|
$payment_id = $payment_or_txn_id;
|
|
}
|
|
|
|
if ( empty( $payment_id ) ) {
|
|
return false;
|
|
}
|
|
|
|
$payment = new EDD_Payment( $payment_id );
|
|
|
|
if ( empty( $payment->ID ) || ( ! $by_txn && (int) $payment->ID !== (int) $payment_id ) ) {
|
|
return false;
|
|
}
|
|
|
|
return $payment;
|
|
}
|
|
|
|
/**
|
|
* Retrieve payments from the database.
|
|
*
|
|
* Since 1.2, this function takes an array of arguments, instead of individual
|
|
* parameters. All of the original parameters remain, but can be passed in any
|
|
* order via the array.
|
|
*
|
|
* $offset = 0, $number = 20, $mode = 'live', $orderby = 'ID', $order = 'DESC',
|
|
* $user = null, $status = 'any', $meta_key = null
|
|
*
|
|
* @since 1.0
|
|
* @since 1.8 Refactored to be a wrapper for EDD_Payments_Query.
|
|
*
|
|
* @param array $args Arguments passed to get payments.
|
|
* @return EDD_Payment[]|int $payments Payments retrieved from the database.
|
|
*/
|
|
function edd_get_payments( $args = array() ) {
|
|
$args = apply_filters( 'edd_get_payments_args', $args );
|
|
$payments = new EDD_Payments_Query( $args );
|
|
return $payments->get_payments();
|
|
}
|
|
|
|
/**
|
|
* Retrieve payment by a given field.
|
|
*
|
|
* @since 2.0
|
|
*
|
|
* @param string $field The field to retrieve the payment with.
|
|
* @param mixed $value The value for $field.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
function edd_get_payment_by( $field = '', $value = '' ) {
|
|
$payment = false;
|
|
|
|
if ( ! empty( $field ) && ! empty( $value ) ) {
|
|
switch ( strtolower( $field ) ) {
|
|
case 'id':
|
|
$payment = edd_get_payment( $value );
|
|
|
|
if ( ! $payment->ID > 0 ) {
|
|
$payment = false;
|
|
}
|
|
break;
|
|
case 'key':
|
|
$order = edd_get_order_by( 'payment_key', $value );
|
|
|
|
if ( $order ) {
|
|
$payment = edd_get_payment( $order->id );
|
|
|
|
if ( ! $payment->ID > 0 ) {
|
|
$payment = false;
|
|
}
|
|
}
|
|
break;
|
|
case 'payment_number':
|
|
$order = edd_get_order_by( 'order_number', $value );
|
|
|
|
if ( $order ) {
|
|
$payment = edd_get_payment( $order->id );
|
|
|
|
if ( ! $payment->ID > 0 ) {
|
|
$payment = false;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $payment;
|
|
}
|
|
|
|
/**
|
|
* Insert an order into the database.
|
|
*
|
|
* @since 1.0
|
|
* @since 3.0 Refactored to add orders using new methods.
|
|
*
|
|
* @param array $order_data Order data to process.
|
|
* @return int|bool Order ID if the order was successfully inserted, false otherwise.
|
|
*/
|
|
function edd_insert_payment( $order_data = array() ) {
|
|
if ( empty( $order_data ) ) {
|
|
return false;
|
|
}
|
|
|
|
return edd_build_order( $order_data );
|
|
}
|
|
|
|
/**
|
|
* Updates a payment status.
|
|
*
|
|
* @since 1.0
|
|
* @since 3.0 Updated to use new order methods.
|
|
*
|
|
* @param int $order_id Order ID.
|
|
* @param string $new_status order status (default: publish)
|
|
*
|
|
* @return bool True if the status was updated successfully, false otherwise.
|
|
*/
|
|
function edd_update_payment_status( $order_id = 0, $new_status = 'complete' ) {
|
|
return edd_update_order_status( $order_id, $new_status );
|
|
}
|
|
|
|
/**
|
|
* Deletes a Purchase
|
|
*
|
|
* @since 1.0
|
|
* @since 3.0 Added logic to bail early if order not found in database.
|
|
*
|
|
* @param int $payment_id Payment ID. Default 0.
|
|
* @param bool $update_customer If we should update the customer stats. Default true.
|
|
* @param bool $delete_download_logs If we should remove all file download logs associated with the payment. Default false.
|
|
*/
|
|
function edd_delete_purchase( $payment_id = 0, $update_customer = true, $delete_download_logs = false ) {
|
|
$payment = edd_get_payment( $payment_id );
|
|
|
|
// Bail if an order does not exist.
|
|
if ( ! $payment ) {
|
|
return;
|
|
}
|
|
|
|
// Update sale counts and earnings for all purchased products
|
|
edd_undo_purchase( false, $payment_id );
|
|
|
|
$amount = edd_get_payment_amount( $payment_id );
|
|
$status = $payment->post_status;
|
|
$customer_id = edd_get_payment_customer_id( $payment_id );
|
|
|
|
$customer = edd_get_customer( $customer_id );
|
|
|
|
// Only decrease earnings if they haven't already been decreased (or were never increased for this payment).
|
|
if ( 'revoked' === $status || 'complete' === $status ) {
|
|
edd_decrease_total_earnings( $amount );
|
|
|
|
// Clear the This Month earnings (this_monththis_month is NOT a typo)
|
|
delete_transient( md5( 'edd_earnings_this_monththis_month' ) );
|
|
}
|
|
|
|
do_action( 'edd_payment_delete', $payment_id );
|
|
|
|
if ( $customer && $customer->id && $update_customer ) {
|
|
|
|
// Remove the payment ID from the customer
|
|
$customer->remove_payment( $payment_id );
|
|
}
|
|
|
|
// Remove the order.
|
|
edd_delete_order( $payment_id );
|
|
|
|
// Delete file download logs.
|
|
if ( $delete_download_logs ) {
|
|
$logs = edd_get_file_download_logs( array(
|
|
'order_id' => $payment_id,
|
|
) );
|
|
|
|
if ( $logs ) {
|
|
foreach ( $logs as $log ) {
|
|
edd_delete_file_download_log( $log->id );
|
|
}
|
|
}
|
|
}
|
|
|
|
do_action( 'edd_payment_deleted', $payment_id );
|
|
}
|
|
|
|
/**
|
|
* Undo a purchase, including the decrease of sale and earning stats. Used for
|
|
* when refunding or deleting a purchase.
|
|
*
|
|
* @since 1.0.8.1
|
|
* @since 3.0 Updated to use new refunds API and new query methods.
|
|
* Updated to use new nomenclature.
|
|
* Set default value of order ID to 0.
|
|
* Method now returns the refunded order ID.
|
|
*
|
|
* @param int $download_id Download ID.
|
|
* @param int $order_id Order ID.
|
|
*
|
|
* @return int|false Refunded order ID, false otherwise.
|
|
*/
|
|
function edd_undo_purchase( $download_id = 0, $order_id = 0 ) {
|
|
|
|
/**
|
|
* In 2.5.7, a bug was found that $download_id was an incorrect usage. Passing it in
|
|
* now does nothing, but we're holding it in place for legacy support of the argument order.
|
|
*/
|
|
|
|
if ( ! empty( $download_id ) ) {
|
|
_edd_deprected_argument( 'download_id', 'edd_undo_purchase', '2.5.7' );
|
|
}
|
|
|
|
// Bail if no order ID was passed.
|
|
if ( empty( $order_id ) ) {
|
|
return false;
|
|
}
|
|
|
|
// Refund the order.
|
|
return edd_refund_order( $order_id );
|
|
}
|
|
|
|
/**
|
|
* Count Payments
|
|
*
|
|
* Returns the total number of payments recorded.
|
|
*
|
|
* @since 1.0
|
|
* @since 3.0 Refactored to work with edd_orders table.
|
|
*
|
|
* @param array $args List of arguments to base the payments count on.
|
|
*
|
|
* @return object $stats Number of orders grouped by order status.
|
|
*/
|
|
function edd_count_payments( $args = array() ) {
|
|
global $wpdb;
|
|
|
|
$args = wp_parse_args( $args, array(
|
|
'user' => null,
|
|
'customer' => null,
|
|
's' => null,
|
|
'start-date' => null,
|
|
'end-date' => null,
|
|
'download' => null,
|
|
'gateway' => null,
|
|
'type' => 'sale',
|
|
) );
|
|
|
|
$select = 'SELECT edd_o.status, COUNT(*) AS count';
|
|
$from = "FROM {$wpdb->edd_orders} edd_o";
|
|
$join = '';
|
|
$where = 'WHERE 1=1';
|
|
$orderby = '';
|
|
$groupby = 'GROUP BY edd_o.status';
|
|
|
|
// Hold the query arguments passed to edd_count_orders().
|
|
$query_args = array();
|
|
|
|
// Count orders for a specific user.
|
|
if ( ! empty( $args['user'] ) ) {
|
|
if ( is_email( $args['user'] ) ) {
|
|
$where .= $wpdb->prepare( ' AND edd_o.email = %s', sanitize_email( $args['user'] ) );
|
|
} elseif ( is_numeric( $args['user'] ) ) {
|
|
$where .= $wpdb->prepare( ' AND edd_o.user_id = %d', absint( $args['user'] ) );
|
|
}
|
|
|
|
// Count orders for a specific customer.
|
|
} elseif ( ! empty( $args['customer'] ) ) {
|
|
$where .= $wpdb->prepare( ' AND edd_o.customer_id = %d', absint( $args['customer'] ) );
|
|
|
|
// Count payments for a search
|
|
} elseif ( ! empty( $args['s'] ) ) {
|
|
$args['s'] = sanitize_text_field( $args['s'] );
|
|
|
|
// Filter by email address
|
|
if ( is_email( $args['s'] ) ) {
|
|
$where .= $wpdb->prepare( ' AND edd_o.email = %s', sanitize_email( $args['s'] ) );
|
|
|
|
// Filter by payment key.
|
|
} elseif ( 32 === strlen( $args['s'] ) ) {
|
|
$where .= $wpdb->prepare( ' AND edd_o.payment_key = %s', sanitize_email( $args['s'] ) );
|
|
|
|
// Filter by download ID.
|
|
} elseif ( '#' === substr( $args['s'], 0, 1 ) ) {
|
|
$search = str_replace( '#:', '', $args['s'] );
|
|
$search = str_replace( '#', '', $search );
|
|
|
|
$join = "INNER JOIN {$wpdb->edd_order_items} edd_oi ON edd_o.id = edd_oi.order_id";
|
|
$where .= $wpdb->prepare( ' AND edd_oi.product_id = %d', $search );
|
|
|
|
// Filter by user ID.
|
|
} elseif ( is_numeric( $args['s'] ) ) {
|
|
$query_args['user_id'] = absint( $args['s'] );
|
|
|
|
// Filter by discount code.
|
|
} elseif ( 0 === strpos( $args['s'], 'discount:' ) ) {
|
|
$search = str_replace( 'discount:', '', $args['s'] );
|
|
|
|
$join = "INNER JOIN {$wpdb->edd_order_adjustments} edd_oa ON edd_o.id = edd_oa.order_id";
|
|
$where .= $wpdb->prepare( " AND edd_oa.description = %s AND edd_oa.type = 'discount'", $search );
|
|
}
|
|
}
|
|
|
|
if ( ! empty( $args['download'] ) && is_numeric( $args['download'] ) ) {
|
|
$join = "INNER JOIN {$wpdb->edd_order_items} edd_oi ON edd_o.id = edd_oi.order_id";
|
|
$where .= $wpdb->prepare( ' AND edd_oi.product_id = %d', absint( $args['download'] ) );
|
|
}
|
|
|
|
if ( ! empty( $args['gateway'] ) ) {
|
|
$where .= $wpdb->prepare( ' AND edd_o.gateway = %s', sanitize_text_field( $args['gateway'] ) );
|
|
}
|
|
|
|
if ( ! empty( $args['type'] ) ) {
|
|
$where .= $wpdb->prepare( ' AND edd_o.type = %s', sanitize_text_field( $args['type'] ) );
|
|
}
|
|
|
|
if ( ! empty( $args['start-date'] ) && false !== strpos( $args['start-date'], '/' ) ) {
|
|
$date_parts = explode( '/', $args['start-date'] );
|
|
$month = ! empty( $date_parts[0] ) && is_numeric( $date_parts[0] ) ? $date_parts[0] : 0;
|
|
$day = ! empty( $date_parts[1] ) && is_numeric( $date_parts[1] ) ? $date_parts[1] : 0;
|
|
$year = ! empty( $date_parts[2] ) && is_numeric( $date_parts[2] ) ? $date_parts[2] : 0;
|
|
|
|
$is_date = checkdate( $month, $day, $year );
|
|
if ( false !== $is_date ) {
|
|
$date = new DateTime( $args['start-date'] );
|
|
$where .= $wpdb->prepare( ' AND edd_o.date_created >= %s', $date->format( 'Y-m-d 00:00:00' ) );
|
|
}
|
|
|
|
// Fixes an issue with the payments list table counts when no end date is specified (partly with stats class).
|
|
if ( empty( $args['end-date'] ) ) {
|
|
$args['end-date'] = $args['start-date'];
|
|
}
|
|
}
|
|
|
|
if ( ! empty( $args['end-date'] ) && false !== strpos( $args['end-date'], '/' ) ) {
|
|
$date_parts = explode( '/', $args['end-date'] );
|
|
|
|
$month = ! empty( $date_parts[0] ) ? $date_parts[0] : 0;
|
|
$day = ! empty( $date_parts[1] ) ? $date_parts[1] : 0;
|
|
$year = ! empty( $date_parts[2] ) ? $date_parts[2] : 0;
|
|
|
|
$is_date = checkdate( $month, $day, $year );
|
|
if ( false !== $is_date ) {
|
|
$date = date( 'Y-m-d', strtotime( '+1 day', mktime( 0, 0, 0, $month, $day, $year ) ) );
|
|
$where .= $wpdb->prepare( ' AND edd_o.date_created < %s', $date );
|
|
}
|
|
}
|
|
|
|
$where = apply_filters( 'edd_count_payments_where', $where );
|
|
$join = apply_filters( 'edd_count_payments_join', $join );
|
|
|
|
$query = "{$select} {$from} {$join} {$where} {$orderby} {$groupby}";
|
|
|
|
$cache_key = md5( $query );
|
|
|
|
$count = wp_cache_get( $cache_key, 'counts' );
|
|
if ( false !== $count ) {
|
|
return $count;
|
|
}
|
|
|
|
$counts = $wpdb->get_results( $query, ARRAY_A );
|
|
|
|
// Here for backwards compatibility.
|
|
$statuses = array_merge( get_post_stati(), edd_get_payment_status_keys() );
|
|
if ( isset( $statuses['private'] ) && empty( $args['s'] ) ) {
|
|
unset( $statuses['private'] );
|
|
}
|
|
|
|
$stats = array();
|
|
foreach ( $statuses as $status ) {
|
|
$stats[ $status ] = 0;
|
|
}
|
|
|
|
foreach ( (array) $counts as $row ) {
|
|
|
|
// Here for backwards compatibility.
|
|
if ( 'private' === $row['status'] && empty( $args['s'] ) ) {
|
|
continue;
|
|
}
|
|
|
|
$stats[ $row['status'] ] = absint( $row['count'] );
|
|
}
|
|
|
|
$stats = (object) $stats;
|
|
wp_cache_set( $cache_key, $stats, 'counts' );
|
|
|
|
return $stats;
|
|
}
|
|
|
|
|
|
/**
|
|
* Check for existing payment.
|
|
*
|
|
* @since 1.0
|
|
* @since 3.0 Refactored to use EDD\Orders\Order.
|
|
*
|
|
* @param int $order_id Order ID.
|
|
* @return bool True if payment exists, false otherwise.
|
|
*/
|
|
function edd_check_for_existing_payment( $order_id ) {
|
|
$exists = false;
|
|
|
|
$order = edd_get_order( $order_id );
|
|
|
|
// Bail if an order was not found.
|
|
if ( ! $order ) {
|
|
return false;
|
|
}
|
|
|
|
if ( (int) $order_id === (int) $order->id && $order->is_complete() ) {
|
|
$exists = true;
|
|
}
|
|
|
|
return $exists;
|
|
}
|
|
|
|
/**
|
|
* Get order status.
|
|
*
|
|
* @since 1.0
|
|
* @since 3.0 Updated to use new EDD\Order\Order class.
|
|
*
|
|
* @param mixed $order Payment post object, EDD_Payment object, or payment/post ID.
|
|
* @param bool $return_label Whether to return the payment status or not
|
|
*
|
|
* @return bool|mixed if payment status exists, false otherwise
|
|
*/
|
|
function edd_get_payment_status( $order, $return_label = false ) {
|
|
if ( is_numeric( $order ) ) {
|
|
$order = edd_get_order( $order );
|
|
|
|
if ( ! $order ) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if ( $order instanceof EDD_Payment ) {
|
|
/** @var EDD_Payment $order */
|
|
$order = edd_get_order( $order->id );
|
|
}
|
|
|
|
if ( $order instanceof WP_Post ) {
|
|
/** @var WP_Post $order */
|
|
$order = edd_get_order( $order->ID );
|
|
}
|
|
|
|
if ( ! is_object( $order ) ) {
|
|
return false;
|
|
}
|
|
|
|
$status = $order->status;
|
|
|
|
if ( empty( $status ) ) {
|
|
return false;
|
|
}
|
|
|
|
if ( true === $return_label ) {
|
|
$status = edd_get_payment_status_label( $status );
|
|
} else {
|
|
$keys = edd_get_payment_status_keys();
|
|
$found_key = array_search( strtolower( $status ), $keys );
|
|
$status = false !== $found_key && array_key_exists( $found_key, $keys ) ? $keys[ $found_key ] : false;
|
|
}
|
|
|
|
return ! empty( $status ) ? $status : false;
|
|
}
|
|
|
|
/**
|
|
* Given a payment status string, return the label for that string.
|
|
*
|
|
* @since 2.9.2
|
|
* @param string $status
|
|
*
|
|
* @return bool|mixed
|
|
*/
|
|
function edd_get_payment_status_label( $status = '' ) {
|
|
$default = str_replace( '_', ' ', $status );
|
|
$default = ucwords( $default );
|
|
$statuses = edd_get_payment_statuses();
|
|
|
|
if ( ! is_array( $statuses ) || empty( $statuses ) ) {
|
|
return $default;
|
|
}
|
|
|
|
if ( array_key_exists( $status, $statuses ) ) {
|
|
return $statuses[ $status ];
|
|
}
|
|
|
|
return $default;
|
|
}
|
|
|
|
/**
|
|
* Retrieves all available statuses for payments.
|
|
*
|
|
* @since 1.0.8.1
|
|
* @since 3.0 Updated 'publish' status to be 'Completed' for consistency with other statuses.
|
|
*
|
|
* @return array $payment_status All the available payment statuses.
|
|
*/
|
|
function edd_get_payment_statuses() {
|
|
return apply_filters( 'edd_payment_statuses', array(
|
|
'pending' => __( 'Pending', 'easy-digital-downloads' ),
|
|
'processing' => __( 'Processing', 'easy-digital-downloads' ),
|
|
'complete' => __( 'Completed', 'easy-digital-downloads' ),
|
|
'refunded' => __( 'Refunded', 'easy-digital-downloads' ),
|
|
'partially_refunded' => __( 'Partially Refunded', 'easy-digital-downloads' ),
|
|
'revoked' => __( 'Revoked', 'easy-digital-downloads' ),
|
|
'failed' => __( 'Failed', 'easy-digital-downloads' ),
|
|
'abandoned' => __( 'Abandoned', 'easy-digital-downloads' )
|
|
) );
|
|
}
|
|
|
|
/**
|
|
* Retrieves keys for all available statuses for payments.
|
|
*
|
|
* @since 2.3
|
|
*
|
|
* @return array $payment_status All the available payment statuses.
|
|
*/
|
|
function edd_get_payment_status_keys() {
|
|
$statuses = array_keys( edd_get_payment_statuses() );
|
|
asort( $statuses );
|
|
|
|
return array_values( $statuses );
|
|
}
|
|
|
|
/**
|
|
* Checks whether a payment has been marked as complete.
|
|
*
|
|
* @since 1.0.8
|
|
* @since 3.0 Refactored to use EDD\Orders\Order.
|
|
*
|
|
* @param int $order_id Order ID to check against.
|
|
* @return bool True if complete, false otherwise.
|
|
*/
|
|
function edd_is_payment_complete( $order_id = 0 ) {
|
|
$order = edd_get_order( $order_id );
|
|
|
|
$ret = false;
|
|
$status = null;
|
|
|
|
if ( $order ) {
|
|
$status = $order->status;
|
|
if ( (int) $order_id === (int) $order->id && $order->is_complete() ) {
|
|
$ret = true;
|
|
}
|
|
}
|
|
|
|
return apply_filters( 'edd_is_payment_complete', $ret, $order_id, $status );
|
|
}
|
|
|
|
/**
|
|
* Retrieve total number of orders.
|
|
*
|
|
* @since 1.2.2
|
|
*
|
|
* @return int $count Total sales
|
|
*/
|
|
function edd_get_total_sales() {
|
|
$payments = edd_count_payments( array( 'type' => 'sale' ) );
|
|
|
|
return $payments->revoked + $payments->complete;
|
|
}
|
|
|
|
/**
|
|
* Calculate the total earnings of the store.
|
|
*
|
|
* @since 1.2
|
|
* @since 3.0 Refactored to work with new tables.
|
|
* @since 3.0.4 Added the $force argument, to force querying again.
|
|
*
|
|
* @param bool $include_taxes Whether taxes should be included. Default true.
|
|
* @param bool $force If we should force a new calculation.
|
|
* @return float $total Total earnings.
|
|
*/
|
|
function edd_get_total_earnings( $include_taxes = true, $force = true ) {
|
|
global $wpdb;
|
|
|
|
$key = $include_taxes ? 'edd_earnings_total' : 'edd_earnings_total_without_tax';
|
|
|
|
$total = $force ? false : get_transient( $key );
|
|
|
|
// If no total stored in the database, use old method of calculating total earnings.
|
|
if ( false === $total ) {
|
|
|
|
$stats = new EDD\Stats();
|
|
|
|
$total = $stats->get_order_earnings(
|
|
array(
|
|
'output' => 'typed',
|
|
'exclude_taxes' => ! $include_taxes,
|
|
'revenue_type' => 'net',
|
|
)
|
|
);
|
|
|
|
// Cache results for 1 day. This cache is cleared automatically when a payment is made.
|
|
set_transient( $key, $total, 86400 );
|
|
|
|
// Store as an option for backwards compatibility.
|
|
update_option( $key, $total, false );
|
|
} else {
|
|
// Always ensure that we're working with a float, since the transient comes back as a string.
|
|
$total = (float) $total;
|
|
}
|
|
|
|
// Don't ever show negative earnings.
|
|
if ( $total < 0 ) {
|
|
$total = 0;
|
|
}
|
|
|
|
$total = edd_format_amount( $total, true, edd_get_currency(), 'typed' );
|
|
|
|
return apply_filters( 'edd_total_earnings', $total );
|
|
}
|
|
|
|
/**
|
|
* Increase the store's total earnings.
|
|
*
|
|
* @since 1.8.4
|
|
*
|
|
* @param $amount int The amount you would like to increase the total earnings by.
|
|
* @return float $total Total earnings
|
|
*/
|
|
function edd_increase_total_earnings( $amount = 0 ) {
|
|
$total = floatval( edd_get_total_earnings( true, true ) );
|
|
$total += floatval( $amount );
|
|
|
|
return $total;
|
|
}
|
|
|
|
/**
|
|
* Decrease the store's total earnings.
|
|
*
|
|
* @since 1.8.4
|
|
*
|
|
* @param $amount int The amount you would like to decrease the total earnings by.
|
|
* @return float $total Total earnings.
|
|
*/
|
|
function edd_decrease_total_earnings( $amount = 0 ) {
|
|
$total = edd_get_total_earnings( true, true );
|
|
$total -= $amount;
|
|
|
|
if ( $total < 0 ) {
|
|
$total = 0;
|
|
}
|
|
|
|
return $total;
|
|
}
|
|
|
|
/**
|
|
* Retrieve order meta field for an order.
|
|
*
|
|
* @since 1.2
|
|
*
|
|
* @internal This needs to continue making a call to EDD_Payment::get_meta() as it handles the backwards compatibility for
|
|
* _edd_payment_meta if requested.
|
|
*
|
|
* @param int $payment_id Payment ID.
|
|
* @param string $key Optional. The meta key to retrieve. By default, returns data for all keys. Default '_edd_payment_meta'.
|
|
* @param bool $single Optional, default is false. If true, return only the first value of the specified meta_key.
|
|
* This parameter has no effect if meta_key is not specified.
|
|
*
|
|
* @return mixed Will be an array if $single is false. Will be value of meta data field if $single is true.
|
|
*/
|
|
function edd_get_payment_meta( $payment_id = 0, $key = '_edd_payment_meta', $single = true ) {
|
|
$payment = edd_get_payment( $payment_id );
|
|
|
|
return $payment
|
|
? $payment->get_meta( $key, $single )
|
|
: false;
|
|
}
|
|
|
|
/**
|
|
* Update order meta field based on order ID.
|
|
*
|
|
* Use the $prev_value parameter to differentiate between meta fields with the
|
|
* same key and order ID.
|
|
*
|
|
* If the meta field for the order does not exist, it will be added.
|
|
*
|
|
* @since 1.2
|
|
*
|
|
* @internal This needs to continue making a call to EDD_Payment::update_meta() as it handles the backwards compatibility for
|
|
* _edd_payment_meta.
|
|
*
|
|
* @param int $payment_id Payment ID.
|
|
* @param string $meta_key Meta data key.
|
|
* @param mixed $meta_value Meta data value. Must be serializable if non-scalar.
|
|
* @param mixed $prev_value Optional. Previous value to check before removing. Default empty.
|
|
*
|
|
* @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
|
|
*/
|
|
function edd_update_payment_meta( $payment_id = 0, $meta_key = '', $meta_value = '', $prev_value = '' ) {
|
|
$payment = edd_get_payment( $payment_id );
|
|
|
|
return $payment
|
|
? $payment->update_meta( $meta_key, $meta_value, $prev_value )
|
|
: false;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the user information associated with an order.
|
|
*
|
|
* This method exists for backwards compatibility; in future, the order query methods should be used.
|
|
*
|
|
* @since 1.2
|
|
*
|
|
* @internal This needs to continue retrieving from EDD_Payment as it handles backwards compatibility.
|
|
*
|
|
* @param int $payment_id Payment ID.
|
|
* @return array User Information.
|
|
*/
|
|
function edd_get_payment_meta_user_info( $payment_id ) {
|
|
$payment = edd_get_payment( $payment_id );
|
|
|
|
return $payment
|
|
? $payment->user_info
|
|
: array();
|
|
}
|
|
|
|
/**
|
|
* Retrieve the downloads associated with an order.
|
|
*
|
|
* This method exists for backwards compatibility; in future, the order query methods should be used.
|
|
*
|
|
* @since 1.2
|
|
*
|
|
* @param int $payment_id Payment ID.
|
|
* @return array Downloads.
|
|
*/
|
|
function edd_get_payment_meta_downloads( $payment_id ) {
|
|
$payment = edd_get_payment( $payment_id );
|
|
|
|
return $payment
|
|
? $payment->downloads
|
|
: array();
|
|
}
|
|
|
|
/**
|
|
* Retrieve the cart details.
|
|
*
|
|
* This method exists for backwards compatibility; in future, the order query methods should be used.
|
|
*
|
|
* @since 1.2
|
|
*
|
|
* @internal This needs to continue retrieving from EDD_Payment as it handles backwards compatibility.
|
|
*
|
|
* @param int $payment_id Payment ID
|
|
* @param bool $include_bundle_files Whether to retrieve product IDs associated with a bundled product and return them in the array
|
|
*
|
|
* @return array $cart_details Cart Details Meta Values
|
|
*/
|
|
function edd_get_payment_meta_cart_details( $payment_id, $include_bundle_files = false ) {
|
|
$payment = edd_get_payment( $payment_id );
|
|
$cart_details = $payment->cart_details;
|
|
|
|
$payment_currency = $payment->currency;
|
|
|
|
if ( ! empty( $cart_details ) && is_array( $cart_details ) ) {
|
|
foreach ( $cart_details as $key => $cart_item ) {
|
|
$cart_details[ $key ]['currency'] = $payment_currency;
|
|
|
|
// Ensure subtotal is set, for pre-1.9 orders.
|
|
if ( ! isset( $cart_item['subtotal'] ) ) {
|
|
$cart_details[ $key ]['subtotal'] = $cart_item['price'];
|
|
}
|
|
|
|
if ( $include_bundle_files ) {
|
|
if ( 'bundle' !== edd_get_download_type( $cart_item['id'] ) ) {
|
|
continue;
|
|
}
|
|
|
|
$price_id = edd_get_cart_item_price_id( $cart_item );
|
|
$products = edd_get_bundled_products( $cart_item['id'], $price_id );
|
|
|
|
if ( empty( $products ) ) {
|
|
continue;
|
|
}
|
|
|
|
foreach ( $products as $product_id ) {
|
|
$cart_details[] = array(
|
|
'id' => $product_id,
|
|
'name' => get_the_title( $product_id ),
|
|
'item_number' => array(
|
|
'id' => $product_id,
|
|
'options' => array(),
|
|
),
|
|
'price' => 0,
|
|
'subtotal' => 0,
|
|
'quantity' => 1,
|
|
'tax' => 0,
|
|
'in_bundle' => 1,
|
|
'parent' => array(
|
|
'id' => $cart_item['id'],
|
|
'options' => isset( $cart_item['item_number']['options'] )
|
|
? $cart_item['item_number']['options']
|
|
: array(),
|
|
),
|
|
'order_item_id' => $cart_item['order_item_id'],
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return apply_filters( 'edd_payment_meta_cart_details', $cart_details, $payment_id );
|
|
}
|
|
|
|
/**
|
|
* Get the user email associated with a payment
|
|
*
|
|
* @since 1.2
|
|
* @since 3.0 Refactored to use EDD\Orders\Order.
|
|
* @since 3.1.1 Allows passing a full EDD\Orders\Order object in, instead of just the ID
|
|
*
|
|
* @param int $order Order ID or the EDD\Orders\Order object
|
|
* @return string $email User email.
|
|
*/
|
|
function edd_get_payment_user_email( $order = 0 ) {
|
|
|
|
// Bail if nothing was passed.
|
|
if ( empty( $order ) ) {
|
|
return '';
|
|
}
|
|
|
|
if ( is_numeric( $order ) ) {
|
|
$order = edd_get_order( $order );
|
|
}
|
|
|
|
return $order
|
|
? $order->email
|
|
: '';
|
|
}
|
|
|
|
/**
|
|
* Check if the order is associated with a user.
|
|
*
|
|
* @since 2.4.4
|
|
* @since 3.0 Refactored to use EDD\Orders\Order.
|
|
* @since 3.1.1 Allows passing a full EDD\Orders\Order object in, instead of just the ID
|
|
*
|
|
* @param int $order Order ID or the EDD\Orders\Order object
|
|
* @return bool True if the payment is **not** associated with a user, false otherwise.
|
|
*/
|
|
function edd_is_guest_payment( $order = 0 ) {
|
|
|
|
// Bail if nothing was passed.
|
|
if ( empty( $order ) ) {
|
|
return false;
|
|
}
|
|
|
|
if ( is_numeric( $order ) ) {
|
|
$order = edd_get_order( $order );
|
|
}
|
|
|
|
$is_guest_payment = ! empty( $order->user_id ) && $order->user_id > 0
|
|
? false
|
|
: true;
|
|
|
|
return (bool) apply_filters( 'edd_is_guest_payment', $is_guest_payment, $order->id );
|
|
}
|
|
|
|
/**
|
|
* Get the user ID associated with an order.
|
|
*
|
|
* @since 1.5.1
|
|
* @since 3.0 Refactored to use EDD\Orders\Order.
|
|
* @since 3.1.1 Allows passing a full EDD\Orders\Order object in, instead of just the ID
|
|
*
|
|
* @param int $order Order ID or the EDD\Orders\Order object
|
|
* @return string $user_id User ID.
|
|
*/
|
|
function edd_get_payment_user_id( $order = 0 ) {
|
|
|
|
// Bail if nothing was passed.
|
|
if ( empty( $order ) ) {
|
|
return 0;
|
|
}
|
|
|
|
if ( is_numeric( $order ) ) {
|
|
$order = edd_get_order( $order );
|
|
}
|
|
|
|
return $order
|
|
? $order->user_id
|
|
: 0;
|
|
}
|
|
|
|
/**
|
|
* Get the customer ID associated with an order.
|
|
*
|
|
* @since 2.1
|
|
* @since 3.0 Refactored to use EDD\Orders\Order.
|
|
* @since 3.1.1 Allows passing a full EDD\Orders\Order object in, instead of just the ID
|
|
*
|
|
* @param int $order Order ID or the EDD\Orders\Order object
|
|
* @return int $customer_id Customer ID.
|
|
*/
|
|
function edd_get_payment_customer_id( $order = 0 ) {
|
|
|
|
// Bail if nothing was passed.
|
|
if ( empty( $order ) ) {
|
|
return 0;
|
|
}
|
|
|
|
if ( is_numeric( $order ) ) {
|
|
$order = edd_get_order( $order );
|
|
}
|
|
|
|
return $order
|
|
? $order->customer_id
|
|
: 0;
|
|
}
|
|
|
|
/**
|
|
* Get the status of the unlimited downloads flag
|
|
*
|
|
* @since 2.0
|
|
* @since 3.0 Refactored to use EDD\Orders\Order.
|
|
* @since 3.1.1 Allows passing a full EDD\Orders\Order object in, instead of just the ID
|
|
*
|
|
* @param int $order Order ID or the EDD\Orders\Order object
|
|
* @return bool True if the payment has unlimited downloads, false otherwise.
|
|
*/
|
|
function edd_payment_has_unlimited_downloads( $order = 0 ) {
|
|
|
|
// Bail if nothing was passed.
|
|
if ( empty( $order ) ) {
|
|
return false;
|
|
}
|
|
|
|
if ( is_numeric( $order ) ) {
|
|
$order = edd_get_order( $order );
|
|
}
|
|
|
|
return $order
|
|
? $order->has_unlimited_downloads()
|
|
: false;
|
|
}
|
|
|
|
/**
|
|
* Get the IP address used to make a purchase.
|
|
*
|
|
* @since 1.9
|
|
* @since 3.0 Refactored to use EDD\Orders\Order.
|
|
* @since 3.1.1 Allows passing a full EDD\Orders\Order object in, instead of just the ID
|
|
*
|
|
* @param int $order Order ID or the EDD\Orders\Order object
|
|
* @return string User's IP address.
|
|
*/
|
|
function edd_get_payment_user_ip( $order = 0 ) {
|
|
|
|
// Bail if nothing was passed.
|
|
if ( empty( $order ) ) {
|
|
return '';
|
|
}
|
|
|
|
if ( is_numeric( $order ) ) {
|
|
$order = edd_get_order( $order );
|
|
}
|
|
|
|
return $order
|
|
? $order->ip
|
|
: '';
|
|
}
|
|
|
|
/**
|
|
* Get the date an order was completed.
|
|
*
|
|
* @since 2.0
|
|
* @since 3.0 Parameter renamed to $order_id.
|
|
*
|
|
* @param int $order_id Order ID.
|
|
* @return string The date the order was completed.
|
|
*/
|
|
function edd_get_payment_completed_date( $order_id = 0 ) {
|
|
$payment = edd_get_payment( $order_id );
|
|
return $payment->completed_date;
|
|
}
|
|
|
|
/**
|
|
* Get the gateway associated with an order.
|
|
*
|
|
* @since 1.2
|
|
* @since 3.0 Refactored to use EDD\Orders\Order.
|
|
* @since 3.1.1 Allows passing a full EDD\Orders\Order object in, instead of just the ID
|
|
*
|
|
* @param int $order Order ID or the EDD\Orders\Order object
|
|
* @return string Payment gateway used for the order.
|
|
*/
|
|
function edd_get_payment_gateway( $order = 0 ) {
|
|
|
|
// Bail if nothing was passed.
|
|
if ( empty( $order ) ) {
|
|
return '';
|
|
}
|
|
|
|
if ( is_numeric( $order ) ) {
|
|
$order = edd_get_order( $order );
|
|
}
|
|
|
|
return $order
|
|
? $order->gateway
|
|
: '';
|
|
}
|
|
|
|
/**
|
|
* Get the currency code an order was made in.
|
|
*
|
|
* @since 2.2
|
|
* @since 3.0 Refactored to use EDD\Orders\Order.
|
|
* @since 3.1.1 Allows passing a full EDD\Orders\Order object in, instead of just the ID
|
|
*
|
|
* @param int $order Order ID or the EDD\Orders\Order object
|
|
* @return string $currency The currency code
|
|
*/
|
|
function edd_get_payment_currency_code( $order = 0 ) {
|
|
|
|
// Bail if nothing was passed.
|
|
if ( empty( $order ) ) {
|
|
return '';
|
|
}
|
|
|
|
if ( is_numeric( $order ) ) {
|
|
$order = edd_get_order( $order );
|
|
}
|
|
|
|
return $order
|
|
? $order->currency
|
|
: '';
|
|
}
|
|
|
|
/**
|
|
* Get the currency name a payment was made in.
|
|
*
|
|
* @since 2.2
|
|
* @since 3.0 Parameter renamed to $order_id.
|
|
*
|
|
* @param int $order_id Order ID.
|
|
* @return string $currency The currency name.
|
|
*/
|
|
function edd_get_payment_currency( $order_id = 0 ) {
|
|
$currency = edd_get_payment_currency_code( $order_id );
|
|
|
|
/**
|
|
* Allow the currency to be filtered.
|
|
*
|
|
* @since 2.2
|
|
*
|
|
* @param string $currency Currency name.
|
|
* @param int $order_id Order ID.
|
|
*/
|
|
return apply_filters( 'edd_payment_currency', edd_get_currency_name( $currency ), $order_id );
|
|
}
|
|
|
|
/**
|
|
* Get the payment key for an order.
|
|
*
|
|
* @since 1.2
|
|
* @since 3.0 Refactored to use EDD\Orders\Order.
|
|
* @since 3.1.1 Allows passing a full EDD\Orders\Order object in, instead of just the ID
|
|
*
|
|
* @param int $order Order ID or the EDD\Orders\Order object
|
|
* @return string $key Purchase key.
|
|
*/
|
|
function edd_get_payment_key( $order = 0 ) {
|
|
|
|
// Bail if nothing was passed.
|
|
if ( empty( $order ) ) {
|
|
return '';
|
|
}
|
|
|
|
if ( is_numeric( $order ) ) {
|
|
$order = edd_get_order( $order );
|
|
}
|
|
|
|
return $order
|
|
? $order->payment_key
|
|
: '';
|
|
}
|
|
|
|
/**
|
|
* Get the payment order number.
|
|
*
|
|
* This will return the order ID if sequential order numbers are not enabled or the order number does not exist.
|
|
*
|
|
* @since 2.0
|
|
* @since 3.0 Refactored to use EDD\Orders\Order.
|
|
* @since 3.1.1 Allows passing a full EDD\Orders\Order object in, instead of just the ID
|
|
*
|
|
* @param int $order Order ID or the EDD\Orders\Order object
|
|
* @return int|string Payment order number.
|
|
*/
|
|
function edd_get_payment_number( $order = 0 ) {
|
|
|
|
// Bail if nothing was passed.
|
|
if ( empty( $order ) ) {
|
|
return 0;
|
|
}
|
|
|
|
if ( is_numeric( $order ) ) {
|
|
$order = edd_get_order( $order );
|
|
}
|
|
|
|
return $order
|
|
? $order->get_number()
|
|
: 0;
|
|
}
|
|
|
|
/**
|
|
* Formats the order number with the prefix and postfix.
|
|
*
|
|
* @since 2.4
|
|
*
|
|
* @param int $number The order number to format.
|
|
* @return string The formatted order number
|
|
*/
|
|
function edd_format_payment_number( $number ) {
|
|
if ( ! edd_get_option( 'enable_sequential' ) ) {
|
|
return $number;
|
|
}
|
|
|
|
if ( ! is_numeric( $number ) ) {
|
|
return $number;
|
|
}
|
|
|
|
$prefix = edd_get_option( 'sequential_prefix' );
|
|
$number = absint( $number );
|
|
$postfix = edd_get_option( 'sequential_postfix' );
|
|
|
|
$formatted_number = $prefix . $number . $postfix;
|
|
|
|
return apply_filters( 'edd_format_payment_number', $formatted_number, $prefix, $number, $postfix );
|
|
}
|
|
|
|
/**
|
|
* Gets the next available order number.
|
|
*
|
|
* This is used when inserting a new order.
|
|
*
|
|
* @since 2.0
|
|
*
|
|
* @return string $number The next available order number.
|
|
*/
|
|
function edd_get_next_payment_number() {
|
|
if ( ! edd_get_option( 'enable_sequential' ) ) {
|
|
return false;
|
|
}
|
|
|
|
$number = get_option( 'edd_last_payment_number' );
|
|
$start = edd_get_option( 'sequential_start', 1 );
|
|
$increment_number = true;
|
|
|
|
if ( false !== $number ) {
|
|
if ( empty( $number ) ) {
|
|
$number = $start;
|
|
$increment_number = false;
|
|
}
|
|
} else {
|
|
$last_order = edd_get_orders( array(
|
|
'number' => 1,
|
|
'orderby' => 'id',
|
|
'order' => 'desc',
|
|
) );
|
|
|
|
if ( ! empty( $last_order ) && $last_order[0] instanceof EDD\Orders\Order ) {
|
|
$number = (int) $last_order[0]->get_number();
|
|
}
|
|
|
|
if ( ! empty( $number ) && $number !== (int) $last_order[0]->id ) {
|
|
$number = edd_remove_payment_prefix_postfix( $number );
|
|
} else {
|
|
$number = $start;
|
|
$increment_number = false;
|
|
}
|
|
}
|
|
|
|
$increment_number = apply_filters( 'edd_increment_payment_number', $increment_number, $number );
|
|
|
|
if ( $increment_number ) {
|
|
$number++;
|
|
}
|
|
|
|
return apply_filters( 'edd_get_next_payment_number', $number );
|
|
}
|
|
|
|
/**
|
|
* Given a given a number, remove the pre/postfix.
|
|
*
|
|
* @since 2.4
|
|
*
|
|
* @param string $number The formatted number to increment.
|
|
* @return string The new order number without prefix and postfix.
|
|
*/
|
|
function edd_remove_payment_prefix_postfix( $number ) {
|
|
$prefix = (string) edd_get_option( 'sequential_prefix' );
|
|
$postfix = (string) edd_get_option( 'sequential_postfix' );
|
|
|
|
// Remove prefix
|
|
$number = preg_replace( '/' . $prefix . '/', '', $number, 1 );
|
|
|
|
// Remove the postfix
|
|
$length = strlen( $number );
|
|
$postfix_pos = strrpos( $number, strval( $postfix ) );
|
|
if ( false !== $postfix_pos ) {
|
|
$number = substr_replace( $number, '', $postfix_pos, $length );
|
|
}
|
|
|
|
// Ensure it's a whole number
|
|
$number = intval( $number );
|
|
|
|
return apply_filters( 'edd_remove_payment_prefix_postfix', $number, $prefix, $postfix );
|
|
}
|
|
|
|
/**
|
|
* Get the fully formatted order amount. The order amount is retrieved using
|
|
* edd_get_payment_amount() and is then sent through edd_currency_filter() and
|
|
* edd_format_amount() to format the amount correctly.
|
|
*
|
|
* @since 1.4
|
|
* @since 3.0 Parameter renamed to $order_id.
|
|
* @since 3.1.1 Allows passing a full EDD\Orders\Order object in, instead of just the ID
|
|
*
|
|
* @param int $order Order ID or the EDD\Orders\Order object
|
|
*
|
|
* @return string $amount Fully formatted payment amount
|
|
*/
|
|
function edd_payment_amount( $order = 0 ) {
|
|
if ( is_numeric( $order ) && ! empty( $order ) ) {
|
|
$order = edd_get_order( $order );
|
|
}
|
|
|
|
return edd_display_amount( edd_get_payment_amount( $order ), edd_get_payment_currency_code( $order ) );
|
|
}
|
|
|
|
/**
|
|
* Get the amount associated with an order.
|
|
*
|
|
* @since 1.2
|
|
* @since 3.0 Refactored to use EDD\Orders\Order.
|
|
* @since 3.1.1 Allows passing a full EDD\Orders\Order object in, instead of just the ID
|
|
*
|
|
* @param int $order Order ID or the EDD\Orders\Order object
|
|
* @return float Order amount.
|
|
*/
|
|
function edd_get_payment_amount( $order = 0 ) {
|
|
|
|
// Bail if nothing was passed.
|
|
if ( empty( $order ) ) {
|
|
return 0.00;
|
|
}
|
|
|
|
if ( is_numeric( $order ) ) {
|
|
$order = edd_get_order( $order );
|
|
}
|
|
|
|
$total = $order
|
|
? $order->total
|
|
: 0.00;
|
|
|
|
/**
|
|
* Filter the order amount.
|
|
*
|
|
* @since 1.2
|
|
*
|
|
* @param float $total Order total.
|
|
* @param int $order_id Order ID.
|
|
*/
|
|
return apply_filters( 'edd_payment_amount', floatval( $total ), $order->id );
|
|
}
|
|
|
|
/**
|
|
* Retrieves subtotal for an order (this is the amount before taxes) and then
|
|
* returns a full formatted amount. This function essentially calls
|
|
* edd_get_payment_subtotal().
|
|
*
|
|
* @since 1.3.3
|
|
* @since 3.0 Parameter renamed to $order_id.
|
|
* @since 3.1.1 Allows passing a full EDD\Orders\Order object in, instead of just the ID
|
|
*
|
|
* @param int $order_id Order ID.
|
|
*
|
|
* @return string Fully formatted order subtotal.
|
|
*/
|
|
function edd_payment_subtotal( $order_id = 0 ) {
|
|
$subtotal = edd_get_payment_subtotal( $order_id );
|
|
|
|
return edd_display_amount( $subtotal, edd_get_payment_currency_code( $order_id ) );
|
|
}
|
|
|
|
/**
|
|
* Retrieves subtotal for an order (this is the amount before taxes) and then
|
|
* returns a non formatted amount.
|
|
*
|
|
* @since 1.3.3
|
|
* @since 3.0 Refactored to use EDD\Orders\Order.
|
|
* @since 3.1.1 Allows passing a full EDD\Orders\Order object in, instead of just the ID
|
|
*
|
|
* @param int $order Order ID or the EDD\Orders\Order object
|
|
* @return float $subtotal Subtotal for the order (non formatted).
|
|
*/
|
|
function edd_get_payment_subtotal( $order = 0 ) {
|
|
|
|
// Bail if nothing was passed.
|
|
if ( empty( $order ) ) {
|
|
return 0.00;
|
|
}
|
|
|
|
if ( is_numeric( $order ) ) {
|
|
$order = edd_get_order( $order );
|
|
}
|
|
|
|
return $order
|
|
? $order->subtotal
|
|
: 0.00;
|
|
}
|
|
|
|
/**
|
|
* Retrieves taxed amount for payment and then returns a full formatted amount
|
|
* This function essentially calls edd_get_payment_tax()
|
|
*
|
|
* @since 1.3.3
|
|
* @since 3.0 Parameter renamed to $order_id.
|
|
*
|
|
* @param int $order_id Order ID.
|
|
* @param bool $payment_meta Parameter no longer used.
|
|
*
|
|
* @return string $tax Fully formatted tax amount.
|
|
*/
|
|
function edd_payment_tax( $order_id = 0, $payment_meta = null ) {
|
|
$tax = edd_get_payment_tax( $order_id, false );
|
|
|
|
return edd_display_amount( $tax, edd_get_payment_currency_code( $order_id ) );
|
|
}
|
|
|
|
/**
|
|
* Retrieves taxed amount for payment and then returns a non formatted amount
|
|
*
|
|
* @since 1.3.3
|
|
* @since 3.0 Refactored to use EDD\Orders\Order.
|
|
* @since 3.1.1 Allows passing a full EDD\Orders\Order object in, instead of just the ID
|
|
*
|
|
* @param int $order Order ID or the EDD\Orders\Order object
|
|
* @param bool $payment_meta Parameter no longer used.
|
|
*
|
|
* @return float $tax Tax for payment (non formatted)
|
|
*/
|
|
function edd_get_payment_tax( $order = 0, $payment_meta = null ) {
|
|
|
|
// Bail if nothing was passed.
|
|
if ( empty( $order ) ) {
|
|
return 0.00;
|
|
}
|
|
|
|
if ( is_numeric( $order ) ) {
|
|
$order = edd_get_order( $order );
|
|
}
|
|
|
|
return $order
|
|
? $order->tax
|
|
: 0.00;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the tax for a cart item by the cart key.
|
|
*
|
|
* @since 2.5
|
|
* @since 3.0 Refactored to use EDD\Orders\Order_Item.
|
|
*
|
|
* @param int $order_id Order ID.
|
|
* @param int $cart_index Cart index.
|
|
*
|
|
* @return float Cart item tax amount.
|
|
*/
|
|
function edd_get_payment_item_tax( $order_id = 0, $cart_index = 0 ) {
|
|
|
|
// Bail if nothing was passed.
|
|
if ( empty( $order_id ) ) {
|
|
return 0.00;
|
|
}
|
|
|
|
$order_item_tax = edd_get_order_items( array(
|
|
'number' => 1,
|
|
'order_id' => $order_id,
|
|
'cart_index' => $cart_index,
|
|
'fields' => 'tax',
|
|
) );
|
|
|
|
$order_item_tax = ( $order_item_tax && ! empty( $order_item_tax ) )
|
|
? $order_item_tax[0]
|
|
: 0.00;
|
|
|
|
return (float) $order_item_tax;
|
|
}
|
|
|
|
/**
|
|
* Retrieves arbitrary fees for the order.
|
|
*
|
|
* @since 1.5
|
|
* @since 3.0 Parameter renamed to $order_id.
|
|
*
|
|
* @param int $order_id Order ID.
|
|
* @param string $type Fee type. Default all.
|
|
*
|
|
* @return array Order fees.
|
|
*/
|
|
function edd_get_payment_fees( $order_id = 0, $type = 'all' ) {
|
|
|
|
// Bail if nothing was passed.
|
|
if ( empty( $order_id ) ) {
|
|
return array();
|
|
}
|
|
|
|
$payment = edd_get_payment( $order_id );
|
|
|
|
return $payment
|
|
? $payment->get_fees( $type )
|
|
: array();
|
|
}
|
|
|
|
/**
|
|
* Retrieves the transaction ID for an order.
|
|
*
|
|
* @since 2.1
|
|
* @since 3.0 Refactored to use EDD\Orders\Order.
|
|
*
|
|
* @param int $order_id Order ID.
|
|
* @return string Transaction ID.
|
|
*/
|
|
function edd_get_payment_transaction_id( $order_id = 0 ) {
|
|
|
|
// Bail if nothing was passed.
|
|
if ( empty( $order_id ) ) {
|
|
return '';
|
|
}
|
|
|
|
$order = edd_get_order( $order_id );
|
|
|
|
return $order
|
|
? $order->get_transaction_id()
|
|
: '';
|
|
}
|
|
|
|
/**
|
|
* Sets a transaction ID for a given order.
|
|
*
|
|
* @since 2.1
|
|
* @since 3.0 Updated to use new methods and store data in the new tables.
|
|
* Added $amount parameter.
|
|
*
|
|
* @param int $order_id Order ID.
|
|
* @param string $transaction_id Transaction ID from the gateway.
|
|
* @param mixed $amount Transaction amount.
|
|
*
|
|
* @return mixed Meta ID if successful, false if unsuccessful.
|
|
*/
|
|
function edd_set_payment_transaction_id( $order_id = 0, $transaction_id = '', $amount = false ) {
|
|
|
|
// Bail if nothing was passed.
|
|
if ( empty( $order_id ) || empty( $transaction_id ) ) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Filter the transaction ID before being stored in the database.
|
|
*
|
|
* @since 2.1
|
|
*
|
|
* @param string $transaction_id Transaction ID.
|
|
* @param int $order_id Order ID.
|
|
*/
|
|
$transaction_id = apply_filters( 'edd_set_payment_transaction_id', $transaction_id, $order_id );
|
|
|
|
$order = edd_get_order( $order_id );
|
|
|
|
if ( $order ) {
|
|
$amount = false === $amount
|
|
? $order->total
|
|
: floatval( $amount );
|
|
|
|
$transaction_ids = array_values( edd_get_order_transactions( array(
|
|
'fields' => 'ids',
|
|
'number' => 1,
|
|
'object_id' => $order_id,
|
|
'object_type' => 'order',
|
|
'orderby' => 'date_created',
|
|
'order' => 'ASC',
|
|
) ) );
|
|
|
|
if ( $transaction_ids && isset( $transaction_ids[0] ) ) {
|
|
return edd_update_order_transaction( $transaction_ids[0], array(
|
|
'transaction_id' => $transaction_id,
|
|
'gateway' => $order->gateway,
|
|
'total' => $amount,
|
|
) );
|
|
} else {
|
|
return edd_add_order_transaction( array(
|
|
'object_id' => $order_id,
|
|
'object_type' => 'order',
|
|
'transaction_id' => $transaction_id,
|
|
'gateway' => $order->gateway,
|
|
'status' => 'complete',
|
|
'total' => $amount,
|
|
) );
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the order ID based on the payment key.
|
|
*
|
|
* @since 1.3.2
|
|
* @since 3.0 Updated to use new query methods. Renamed parameter to $payment_key.
|
|
*
|
|
* @param string $payment_key Payment key to search for.
|
|
* @return int Order ID.
|
|
*/
|
|
function edd_get_purchase_id_by_key( $payment_key ) {
|
|
$global_key_string = 'edd_purchase_id_by_key' . $payment_key;
|
|
global $$global_key_string;
|
|
|
|
if ( null !== $$global_key_string ) {
|
|
return $$global_key_string;
|
|
}
|
|
|
|
/** @var EDD\Orders\Order $order */
|
|
$order = edd_get_order_by( 'payment_key', $payment_key );
|
|
|
|
if ( false !== $order ) {
|
|
$$global_key_string = $order->id;
|
|
return $$global_key_string;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the order ID based on the transaction ID.
|
|
*
|
|
* @since 2.4
|
|
* @since 3.0 Dispatch to edd_get_order_id_from_transaction_id().
|
|
*
|
|
* @see edd_get_order_id_from_transaction_id()
|
|
*
|
|
* @param string $transaction_id Transaction ID to search for.
|
|
* @return int Order ID.
|
|
*/
|
|
function edd_get_purchase_id_by_transaction_id( $transaction_id ) {
|
|
return edd_get_order_id_from_transaction_id( $transaction_id );
|
|
}
|
|
|
|
/**
|
|
* Retrieve all notes attached to an order.
|
|
*
|
|
* @since 1.4
|
|
* @since 3.0 Updated to use the edd_notes custom table to store notes.
|
|
*
|
|
* @param int $order_id The order ID to retrieve notes for.
|
|
* @param string $search Search for notes that contain a search term.
|
|
* @return array|bool $notes Order notes, false otherwise.
|
|
*/
|
|
function edd_get_payment_notes( $order_id = 0, $search = '' ) {
|
|
|
|
// Bail if nothing passed.
|
|
if ( empty( $order_id ) && empty( $search ) ) {
|
|
return false;
|
|
}
|
|
|
|
$args = array(
|
|
'object_type' => 'order',
|
|
'order' => 'ASC',
|
|
);
|
|
|
|
if ( ! empty( $order_id ) ) {
|
|
$args['object_id'] = $order_id;
|
|
}
|
|
|
|
if ( ! empty( $search ) ) {
|
|
$args['search'] = sanitize_text_field( $search );
|
|
}
|
|
|
|
return edd_get_notes( $args );
|
|
}
|
|
|
|
/**
|
|
* Add a note to an order.
|
|
*
|
|
* @since 1.4
|
|
* @since 3.0 Updated to use the edd_notes custom table to store notes.
|
|
*
|
|
* @param int $order_id The order ID to store a note for.
|
|
* @param string $note The content of the note.
|
|
* @return int|false The new note ID, false otherwise.
|
|
*/
|
|
function edd_insert_payment_note( $order_id = 0, $note = '' ) {
|
|
|
|
// Sanitize note contents
|
|
if ( ! empty( $note ) ) {
|
|
$note = trim( wp_kses( $note, edd_get_allowed_tags() ) );
|
|
}
|
|
|
|
// Bail if no order ID or note.
|
|
if ( empty( $order_id ) || empty( $note ) ) {
|
|
return false;
|
|
}
|
|
|
|
do_action( 'edd_pre_insert_payment_note', $order_id, $note );
|
|
|
|
/**
|
|
* For backwards compatibility purposes, we need to pass the data to
|
|
* wp_filter_comment in the event that the note data is filtered using the
|
|
* WordPress Core filters prior to be inserted into the database.
|
|
*/
|
|
$filtered_data = wp_filter_comment( array(
|
|
'comment_post_ID' => $order_id,
|
|
'comment_content' => $note,
|
|
'user_id' => is_admin() ? get_current_user_id() : 0,
|
|
'comment_date' => current_time( 'mysql' ),
|
|
'comment_date_gmt' => current_time( 'mysql', 1 ),
|
|
'comment_approved' => 1,
|
|
'comment_parent' => 0,
|
|
'comment_author' => '',
|
|
'comment_author_IP' => '',
|
|
'comment_author_url' => '',
|
|
'comment_author_email' => '',
|
|
'comment_type' => 'edd_payment_note'
|
|
) );
|
|
|
|
// Add the note
|
|
$note_id = edd_add_note( array(
|
|
'object_id' => $filtered_data['comment_post_ID'],
|
|
'content' => $filtered_data['comment_content'],
|
|
'user_id' => $filtered_data['user_id'],
|
|
'object_type' => 'order',
|
|
) );
|
|
|
|
do_action( 'edd_insert_payment_note', $note_id, $order_id, $note );
|
|
|
|
// Return the ID of the new note
|
|
return $note_id;
|
|
}
|
|
|
|
/**
|
|
* Deletes an order note.
|
|
*
|
|
* @since 1.6
|
|
* @since 3.0 Updated to use the edd_notes custom table to store notes.
|
|
*
|
|
* @param int $note_id Note ID.
|
|
* @param int $order_id Order ID.
|
|
* @return bool True on success, false otherwise.
|
|
*/
|
|
function edd_delete_payment_note( $note_id = 0, $order_id = 0 ) {
|
|
if ( empty( $note_id ) ) {
|
|
return false;
|
|
}
|
|
|
|
do_action( 'edd_pre_delete_payment_note', $note_id, $order_id );
|
|
|
|
$ret = edd_delete_note( $note_id );
|
|
|
|
do_action( 'edd_post_delete_payment_note', $note_id, $order_id );
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Gets the payment note HTML.
|
|
*
|
|
* @since 1.9
|
|
* @since 3.0 Deprecated & unused (use edd_admin_get_note_html())
|
|
*
|
|
* @param object|int $note The note object or ID.
|
|
* @param int $payment_id The payment ID the note is connected to.
|
|
*
|
|
* @return string Payment note HTML.
|
|
*/
|
|
function edd_get_payment_note_html( $note, $payment_id = 0 ) {
|
|
return edd_admin_get_note_html( $note );
|
|
}
|
|
|
|
/**
|
|
* Exclude notes (comments) on edd_payment post type from showing in Recent
|
|
* Comments widgets.
|
|
*
|
|
* @since 1.4.1
|
|
*
|
|
* @param object $query WordPress Comment Query Object
|
|
*/
|
|
function edd_hide_payment_notes( $query ) {
|
|
global $wp_version;
|
|
|
|
if ( version_compare( floatval( $wp_version ), '4.1', '>=' ) ) {
|
|
$types = isset( $query->query_vars['type__not_in'] ) ? $query->query_vars['type__not_in'] : array();
|
|
|
|
if ( ! is_array( $types ) ) {
|
|
$types = array( $types );
|
|
}
|
|
|
|
$types[] = 'edd_payment_note';
|
|
|
|
$query->query_vars['type__not_in'] = $types;
|
|
}
|
|
}
|
|
add_action( 'pre_get_comments', 'edd_hide_payment_notes', 10 );
|
|
|
|
/**
|
|
* Exclude notes (comments) on edd_payment post type from showing in Recent
|
|
* Comments widgets
|
|
*
|
|
* @since 2.2
|
|
*
|
|
* @param array $clauses Comment clauses for comment query.
|
|
* @param object $wp_comment_query WordPress Comment Query Object.
|
|
*
|
|
* @return array $clauses Updated comment clauses.
|
|
*/
|
|
function edd_hide_payment_notes_pre_41( $clauses, $wp_comment_query ) {
|
|
global $wp_version;
|
|
|
|
if ( version_compare( floatval( $wp_version ), '4.1', '<' ) ) {
|
|
$clauses['where'] .= ' AND comment_type != "edd_payment_note"';
|
|
}
|
|
|
|
return $clauses;
|
|
}
|
|
add_filter( 'comments_clauses', 'edd_hide_payment_notes_pre_41', 10, 2 );
|
|
|
|
/**
|
|
* Exclude notes (comments) on edd_payment post type from showing in comment feeds.
|
|
*
|
|
* @since 1.5.1
|
|
*
|
|
* @param string $where
|
|
* @param object $wp_comment_query WordPress Comment Query Object
|
|
*
|
|
* @return string $where Updated WHERE clause.
|
|
*/
|
|
function edd_hide_payment_notes_from_feeds( $where, $wp_comment_query ) {
|
|
global $wpdb;
|
|
|
|
$where .= $wpdb->prepare( ' AND comment_type != %s', 'edd_payment_note' );
|
|
|
|
return $where;
|
|
}
|
|
add_filter( 'comment_feed_where', 'edd_hide_payment_notes_from_feeds', 10, 2 );
|
|
|
|
/**
|
|
* Remove EDD Comments from the wp_count_comments function
|
|
*
|
|
* @since 1.5.2
|
|
*
|
|
* @param array $stats Empty from core filter.
|
|
* @param int $post_id Post ID.
|
|
*
|
|
* @return object Comment counts.
|
|
*/
|
|
function edd_remove_payment_notes_in_comment_counts( $stats, $post_id ) {
|
|
global $wpdb, $pagenow;
|
|
|
|
$array_excluded_pages = array( 'index.php', 'edit-comments.php' );
|
|
if ( ! in_array( $pagenow, $array_excluded_pages, true ) ) {
|
|
return $stats;
|
|
}
|
|
|
|
$post_id = (int) $post_id;
|
|
|
|
if ( apply_filters( 'edd_count_payment_notes_in_comments', false ) ) {
|
|
return $stats;
|
|
}
|
|
|
|
$stats = wp_cache_get( "comments-{$post_id}", 'counts' );
|
|
|
|
if ( false !== $stats ) {
|
|
return $stats;
|
|
}
|
|
|
|
$where = 'WHERE comment_type != "edd_payment_note"';
|
|
|
|
if ( $post_id > 0 ) {
|
|
$where .= $wpdb->prepare( " AND comment_post_ID = %d", $post_id );
|
|
}
|
|
|
|
$count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} {$where} GROUP BY comment_approved", ARRAY_A );
|
|
|
|
$total = 0;
|
|
|
|
$approved = array(
|
|
'0' => 'moderated',
|
|
'1' => 'approved',
|
|
'spam' => 'spam',
|
|
'trash' => 'trash',
|
|
'post-trashed' => 'post-trashed',
|
|
);
|
|
|
|
foreach ( (array) $count as $row ) {
|
|
|
|
// Don't count post-trashed toward totals.
|
|
if ( 'post-trashed' !== $row['comment_approved'] && 'trash' !== $row['comment_approved'] ) {
|
|
$total += $row['num_comments'];
|
|
}
|
|
|
|
if ( isset( $approved[ $row['comment_approved'] ] ) ) {
|
|
$stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments'];
|
|
|
|
}
|
|
}
|
|
|
|
$stats['total_comments'] = $total;
|
|
foreach ( $approved as $key ) {
|
|
if ( empty( $stats[ $key ] ) ) {
|
|
$stats[ $key ] = 0;
|
|
}
|
|
}
|
|
|
|
$stats = (object) $stats;
|
|
wp_cache_set( "comments-{$post_id}", $stats, 'counts' );
|
|
|
|
return $stats;
|
|
}
|
|
add_filter( 'wp_count_comments', 'edd_remove_payment_notes_in_comment_counts', 10, 2 );
|
|
|
|
/**
|
|
* Filter where older than one week.
|
|
*
|
|
* @since 1.6
|
|
*
|
|
* @param string $where Where clause.
|
|
* @return string $where Modified where clause.
|
|
*/
|
|
function edd_filter_where_older_than_week( $where = '' ) {
|
|
|
|
// Payments older than one week.
|
|
$start = date( 'Y-m-d', strtotime( '-7 days' ) );
|
|
|
|
$where .= " AND post_date <= '{$start}'";
|
|
|
|
return $where;
|
|
}
|
|
|
|
/**
|
|
* Gets the payment ID from the final edd_payment post.
|
|
* This was set as an option when the custom orders table was created.
|
|
* For internal use only.
|
|
*
|
|
* @todo deprecate in 3.1
|
|
*
|
|
* @since 3.0
|
|
* @return false|int
|
|
*/
|
|
function _edd_get_final_payment_id() {
|
|
return get_option( 'edd_v3_migration_pending', false );
|
|
}
|
|
|
|
/**
|
|
* Evaluates whether the EDD 3.0 migration should be run,
|
|
* based on _any_ data existing which will need to be migrated.
|
|
*
|
|
* This should only be run after `edd_v30_is_migration_complete` has returned false.
|
|
*
|
|
* @todo deprecate in 3.1
|
|
*
|
|
* @since 3.0.2
|
|
* @return bool
|
|
*/
|
|
function _edd_needs_v3_migration() {
|
|
// Return true if a final payment ID was recorded.
|
|
if ( _edd_get_final_payment_id() ) {
|
|
return true;
|
|
}
|
|
|
|
// Return true if any tax rates were saved.
|
|
$tax_rates = get_option( 'edd_tax_rates', array() );
|
|
if ( ! empty( $tax_rates ) ) {
|
|
return true;
|
|
}
|
|
|
|
// Return true if a fallback tax rate was saved.
|
|
if ( edd_get_option( 'tax_rate', false ) ) {
|
|
return true;
|
|
}
|
|
|
|
global $wpdb;
|
|
|
|
// Return true if any discounts were saved.
|
|
$discounts = $wpdb->get_results(
|
|
$wpdb->prepare(
|
|
"SELECT *
|
|
FROM {$wpdb->posts}
|
|
WHERE post_type = %s
|
|
LIMIT 1",
|
|
esc_sql( 'edd_discount' )
|
|
)
|
|
);
|
|
if ( ! empty( $discounts ) ) {
|
|
return true;
|
|
}
|
|
|
|
// Return true if there are any customers.
|
|
$customers = $wpdb->get_results(
|
|
"SELECT *
|
|
FROM {$wpdb->edd_customers}
|
|
LIMIT 1"
|
|
);
|
|
if ( ! empty( $customers ) ) {
|
|
return true;
|
|
}
|
|
|
|
// Return true if any customer email addresses were saved.
|
|
$customer_emails = $wpdb->get_results(
|
|
$wpdb->prepare(
|
|
"SELECT *
|
|
FROM {$wpdb->edd_customermeta}
|
|
WHERE meta_key = %s
|
|
LIMIT 1",
|
|
esc_sql( 'additional_email' )
|
|
)
|
|
);
|
|
if ( ! empty( $customer_emails ) ) {
|
|
return true;
|
|
}
|
|
|
|
// Return true if any customer addresses are in the user meta table.
|
|
$customer_addresses = $wpdb->get_results(
|
|
$wpdb->prepare(
|
|
"SELECT *
|
|
FROM {$wpdb->usermeta}
|
|
WHERE meta_key = %s
|
|
ORDER BY umeta_id ASC
|
|
LIMIT 1",
|
|
esc_sql( '_edd_user_address' )
|
|
)
|
|
);
|
|
if ( ! empty( $customer_addresses ) ) {
|
|
return true;
|
|
}
|
|
|
|
// Return true if there are any EDD logs (not sales) saved.
|
|
$logs = $wpdb->get_results(
|
|
$wpdb->prepare(
|
|
"SELECT p.*, t.slug
|
|
FROM {$wpdb->posts} AS p
|
|
LEFT JOIN {$wpdb->term_relationships} AS tr ON (p.ID = tr.object_id)
|
|
LEFT JOIN {$wpdb->term_taxonomy} AS tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id)
|
|
LEFT JOIN {$wpdb->terms} AS t ON (tt.term_id = t.term_id)
|
|
WHERE p.post_type = %s AND t.slug != %s
|
|
GROUP BY p.ID
|
|
LIMIT 1",
|
|
esc_sql( 'edd_log' ),
|
|
esc_sql( 'sale' )
|
|
)
|
|
);
|
|
if ( ! empty( $logs ) ) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Maybe adds a migration in progress notice to the order history.
|
|
*
|
|
* @todo remove in 3.1
|
|
* @since 3.0
|
|
* @return void
|
|
*/
|
|
add_action( 'edd_pre_order_history', function( $orders, $user_id ) {
|
|
if ( ! _edd_get_final_payment_id() ) {
|
|
return;
|
|
}
|
|
?>
|
|
<p class="edd-notice">
|
|
<?php esc_html_e( 'A store migration is in progress. Past orders will not appear in your purchase history until they have been updated.', 'easy-digital-downloads' ); ?>
|
|
</p>
|
|
<?php
|
|
}, 10, 2 );
|