installed plugin Easy Digital Downloads version 3.1.0.3

This commit is contained in:
2022-11-27 15:03:07 +00:00
committed by Gitium
parent 555673545b
commit c5dce2cec6
1200 changed files with 238970 additions and 0 deletions

View File

@ -0,0 +1,447 @@
<?php
/**
* Payment Actions
*
* @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
if ( !defined( 'ABSPATH' ) ) exit;
/**
* Complete a purchase
*
* Performs all necessary actions to complete a purchase.
* Triggered by the edd_update_payment_status() function.
*
* @since 1.0.8.3
* @since 3.0 Updated to use new order methods.
*
* @param int $order_id Order ID.
* @param string $new_status New order status.
* @param string $old_status Old order status.
*/
function edd_complete_purchase( $order_id, $new_status, $old_status ) {
// This specifically does not use edd_get_complete_order_statuses().
$completed_statuses = array( 'publish', 'complete', 'completed' );
// Make sure that payments are only completed once.
if ( in_array( $old_status, $completed_statuses, true ) ) {
return;
}
// Make sure the payment completion is only processed when new status is complete.
if ( ! in_array( $new_status, $completed_statuses, true ) ) {
return;
}
$order = edd_get_order( $order_id );
if ( ! $order || 'sale' !== $order->type ) {
return;
}
$completed_date = empty( $order->date_completed )
? null
: $order->date_completed;
$customer_id = $order->customer_id;
$amount = $order->total;
$order_items = $order->items;
do_action( 'edd_pre_complete_purchase', $order_id );
if ( is_array( $order_items ) ) {
// Increase purchase count and earnings.
foreach ( $order_items as $item ) {
// "bundle" or "default"
$download_type = edd_get_download_type( $item->product_id );
// Increase earnings and fire actions once per quantity number.
for ( $i = 0; $i < $item->quantity; $i++ ) {
// Ensure these actions only run once, ever.
if ( empty( $completed_date ) ) {
// For backwards compatibility purposes, we need to construct an array and pass it
// to edd_complete_download_purchase.
$item_fees = array();
foreach ( $item->get_fees() as $key => $item_fee ) {
/** @var EDD\Orders\Order_Adjustment $item_fee */
$download_id = $item->product_id;
$price_id = $item->price_id;
$no_tax = (bool) 0.00 === $item_fee->tax;
$id = is_null( $item_fee->type_key ) ? $item_fee->id : $item_fee->type_key;
if ( array_key_exists( $id, $item_fees ) ) {
$id .= '_2';
}
$item_fees[ $id ] = array(
'amount' => $item_fee->amount,
'label' => $item_fee->description,
'no_tax' => $no_tax ? $no_tax : false,
'type' => 'fee',
'download_id' => $download_id,
'price_id' => $price_id ? $price_id : null,
);
}
$item_options = array(
'quantity' => $item->quantity,
'price_id' => $item->price_id,
);
/*
* For backwards compatibility from pre-3.0: add in order item meta prefixed with `_option_`.
* While saving, we've migrated these values to order item meta, but people may still be looking
* for them in this cart details array, so we need to fill them back in.
*/
$order_item_meta = edd_get_order_item_meta( $item->id );
if ( ! empty( $order_item_meta ) ) {
foreach ( $order_item_meta as $item_meta_key => $item_meta_value ) {
if ( '_option_' === substr( $item_meta_key, 0, 8 ) && isset( $item_meta_value[0] ) ) {
$item_options[ str_replace( '_option_', '', $item_meta_key ) ] = $item_meta_value[0];
}
}
}
$cart_details = array(
'name' => $item->product_name,
'id' => $item->product_id,
'item_number' => array(
'id' => $item->product_id,
'quantity' => $item->quantity,
'options' => $item_options,
),
'item_price' => $item->amount,
'quantity' => $item->quantity,
'discount' => $item->discount,
'subtotal' => $item->subtotal,
'tax' => $item->tax,
'fees' => $item_fees,
'price' => $item->amount,
);
do_action( 'edd_complete_download_purchase', $item->product_id, $order_id, $download_type, $cart_details, $item->cart_index );
}
}
}
// Clear the total earnings cache
delete_transient( 'edd_earnings_total' );
delete_transient( 'edd_earnings_total_without_tax' );
// Clear the This Month earnings (this_monththis_month is NOT a typo)
delete_transient( md5( 'edd_earnings_this_monththis_month' ) );
delete_transient( md5( 'edd_earnings_todaytoday' ) );
}
// Increase the customer's purchase stats
$customer = new EDD_Customer( $customer_id );
$customer->recalculate_stats();
edd_increase_total_earnings( $amount );
// Check for discount codes and increment their use counts
$discounts = $order->get_discounts();
foreach ( $discounts as $adjustment ) {
/** @var EDD\Orders\Order_Adjustment $adjustment */
edd_increase_discount_usage( $adjustment->description );
}
// Ensure this action only runs once ever
if ( empty( $completed_date ) ) {
$date = EDD()->utils->date()->format( 'mysql' );
$date_refundable = edd_get_refund_date( $date );
$date_refundable = false === $date_refundable
? ''
: $date_refundable;
// Save the completed date
edd_update_order( $order_id, array(
'date_completed' => $date,
'date_refundable' => $date_refundable,
) );
// Required for backwards compatibility.
$payment = edd_get_payment( $order_id );
/**
* Runs **when** a purchase is marked as "complete".
*
* @since 2.8 Added EDD_Payment and EDD_Customer object to action.
*
* @param int $order_id Payment ID.
* @param EDD_Payment $payment EDD_Payment object containing all payment data.
* @param EDD_Customer $customer EDD_Customer object containing all customer data.
*/
do_action( 'edd_complete_purchase', $order_id, $payment, $customer );
// If cron doesn't work on a site, allow the filter to use __return_false and run the events immediately.
$use_cron = apply_filters( 'edd_use_after_payment_actions', true, $order_id );
if ( false === $use_cron ) {
/**
* Runs **after** a purchase is marked as "complete".
*
* @see edd_process_after_payment_actions()
*
* @since 2.8 - Added EDD_Payment and EDD_Customer object to action.
*
* @param int $order_id Payment ID.
* @param EDD_Payment $payment EDD_Payment object containing all payment data.
* @param EDD_Customer $customer EDD_Customer object containing all customer data.
*/
do_action( 'edd_after_payment_actions', $order_id, $payment, $customer );
}
}
// Empty the shopping cart
edd_empty_cart();
}
add_action( 'edd_update_payment_status', 'edd_complete_purchase', 100, 3 );
/**
* Schedules the one time event via WP_Cron to fire after purchase actions.
*
* Is run on the edd_complete_purchase action.
*
* @since 2.8
* @param $payment_id
*/
function edd_schedule_after_payment_action( $payment_id ) {
$use_cron = apply_filters( 'edd_use_after_payment_actions', true, $payment_id );
if ( $use_cron ) {
$after_payment_delay = apply_filters( 'edd_after_payment_actions_delay', 30, $payment_id );
// Use time() instead of current_time( 'timestamp' ) to avoid scheduling the event in the past when server time
// and WordPress timezone are different.
wp_schedule_single_event( time() + $after_payment_delay, 'edd_after_payment_scheduled_actions', array( $payment_id, false ) );
}
}
add_action( 'edd_complete_purchase', 'edd_schedule_after_payment_action', 10, 1 );
/**
* Executes the one time event used for after purchase actions.
*
* @since 2.8
* @param $payment_id
* @param $force
*/
function edd_process_after_payment_actions( $payment_id = 0, $force = false ) {
if ( empty( $payment_id ) ) {
return;
}
$payment = new EDD_Payment( $payment_id );
$has_fired = $payment->get_meta( '_edd_complete_actions_run' );
if ( ! empty( $has_fired ) && false === $force ) {
return;
}
$payment->add_note( __( 'After payment actions processed.', 'easy-digital-downloads' ) );
$payment->update_meta( '_edd_complete_actions_run', time() ); // This is in GMT
do_action( 'edd_after_payment_actions', $payment_id, $payment, new EDD_Customer( $payment->customer_id ) );
}
add_action( 'edd_after_payment_scheduled_actions', 'edd_process_after_payment_actions', 10, 1 );
/**
* Updates week-old+ 'pending' orders to 'abandoned'
*
* This function is only intended to be used by WordPress cron.
*
* @since 1.6
* @return void
*/
function edd_mark_abandoned_orders() {
// Bail if not in WordPress cron
if ( ! edd_doing_cron() ) {
return;
}
$args = array(
'status' => 'pending',
'number' => 9999999,
'output' => 'edd_payments',
);
add_filter( 'posts_where', 'edd_filter_where_older_than_week' );
$payments = edd_get_payments( $args );
remove_filter( 'posts_where', 'edd_filter_where_older_than_week' );
if( $payments ) {
foreach( $payments as $payment ) {
if( 'pending' === $payment->post_status ) {
$payment->status = 'abandoned';
$payment->save();
}
}
}
}
add_action( 'edd_weekly_scheduled_events', 'edd_mark_abandoned_orders' );
/**
* Process an attempt to complete a recoverable payment.
*
* @since 2.7
* @return void
*/
function edd_recover_payment() {
if ( empty( $_GET['payment_id'] ) ) {
return;
}
$payment = new EDD_Payment( $_GET['payment_id'] );
if ( $payment->ID !== (int) $_GET['payment_id'] ) {
return;
}
if ( ! $payment->is_recoverable() ) {
return;
}
if (
// Logged in, but wrong user ID
( is_user_logged_in() && $payment->user_id != get_current_user_id() )
// ...OR...
||
// Logged out, but payment is for a user
( ! is_user_logged_in() && ! empty( $payment->user_id ) )
) {
$redirect = get_permalink( edd_get_option( 'purchase_history_page' ) );
edd_set_error( 'edd-payment-recovery-user-mismatch', __( 'Error resuming payment.', 'easy-digital-downloads' ) );
edd_redirect( $redirect );
}
$payment->add_note( __( 'Payment recovery triggered URL', 'easy-digital-downloads' ) );
// Empty out the cart.
EDD()->cart->empty_cart();
// Recover any downloads.
foreach ( $payment->cart_details as $download ) {
edd_add_to_cart( $download['id'], $download['item_number']['options'] );
// Recover any item specific fees.
if ( ! empty( $download['fees'] ) ) {
foreach ( $download['fees'] as $key => $fee ) {
$fee['id'] = ! empty( $fee['id'] ) ? $fee['id'] : $key;
EDD()->fees->add_fee( $fee );
}
}
}
// Recover any global fees.
foreach ( $payment->fees as $key => $fee ) {
$fee['id'] = ! empty( $fee['id'] ) ? $fee['id'] : $key;
EDD()->fees->add_fee( $fee );
}
// Recover any discounts.
if ( 'none' !== $payment->discounts && ! empty( $payment->discounts ) ){
$discounts = ! is_array( $payment->discounts ) ? explode( ',', $payment->discounts ) : $payment->discounts;
foreach ( $discounts as $discount ) {
edd_set_cart_discount( $discount );
}
}
EDD()->session->set( 'edd_resume_payment', $payment->ID );
$redirect_args = array( 'payment-mode' => urlencode( $payment->gateway ) );
$redirect = add_query_arg( $redirect_args, edd_get_checkout_uri() );
edd_redirect( $redirect );
}
add_action( 'edd_recover_payment', 'edd_recover_payment' );
/**
* If the payment trying to be recovered has a User ID associated with it, be sure it's the same user.
*
* @since 2.7
* @return void
*/
function edd_recovery_user_mismatch() {
if ( ! edd_is_checkout() ) {
return;
}
$resuming_payment = EDD()->session->get( 'edd_resume_payment' );
if ( $resuming_payment ) {
$payment = new EDD_Payment( $resuming_payment );
if ( is_user_logged_in() && $payment->user_id != get_current_user_id() ) {
edd_empty_cart();
edd_set_error( 'edd-payment-recovery-user-mismatch', __( 'Error resuming payment.', 'easy-digital-downloads' ) );
edd_redirect( get_permalink( edd_get_option( 'purchase_page' ) ) );
}
}
}
add_action( 'template_redirect', 'edd_recovery_user_mismatch' );
/**
* If the payment trying to be recovered has a User ID associated with it, we need them to log in.
*
* @since 2.7
* @return void
*/
function edd_recovery_force_login_fields() {
$resuming_payment = EDD()->session->get( 'edd_resume_payment' );
if ( $resuming_payment ) {
$payment = new EDD_Payment( $resuming_payment );
$requires_login = edd_no_guest_checkout();
if ( ( $requires_login && ! is_user_logged_in() ) && ( $payment->user_id > 0 && ( ! is_user_logged_in() ) ) ) {
?>
<div class="edd-alert edd-alert-info">
<p><?php _e( 'To complete this payment, please login to your account.', 'easy-digital-downloads' ); ?></p>
<p>
<a href="<?php echo esc_url( edd_get_lostpassword_url() ); ?>" title="<?php esc_attr_e( 'Lost Password', 'easy-digital-downloads' ); ?>">
<?php _e( 'Lost Password?', 'easy-digital-downloads' ); ?>
</a>
</p>
</div>
<?php
$show_register_form = edd_get_option( 'show_register_form', 'none' );
if ( 'both' === $show_register_form || 'login' === $show_register_form ) {
return;
}
do_action( 'edd_purchase_form_login_fields' );
}
}
}
add_action( 'edd_purchase_form_before_register_login', 'edd_recovery_force_login_fields' );
/**
* When processing the payment, check if the resuming payment has a user id and that it matches the logged in user.
*
* @since 2.7
* @param $verified_data
* @param $post_data
*/
function edd_recovery_verify_logged_in( $verified_data, $post_data ) {
$resuming_payment = EDD()->session->get( 'edd_resume_payment' );
if ( $resuming_payment ) {
$payment = new EDD_Payment( $resuming_payment );
$same_user = ! empty( $payment->user_id ) && ( is_user_logged_in() && $payment->user_id == get_current_user_id() );
$same_email = strtolower( $payment->email ) === strtolower( $post_data['edd_email'] );
if ( ( is_user_logged_in() && ! $same_user ) || ( ! is_user_logged_in() && (int) $payment->user_id > 0 && ! $same_email ) ) {
edd_set_error( 'recovery_requires_login', __( 'To complete this payment, please login to your account.', 'easy-digital-downloads' ) );
}
}
}
add_action( 'edd_checkout_error_checks', 'edd_recovery_verify_logged_in', 10, 2 );

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,541 @@
<?php
/**
* Earnings / Sales Stats
*
* @package EDD
* @subpackage Classes/Stats
* @copyright Copyright (c) 2018, Easy Digital Downloads, LLC
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
* @since 1.8
*/
// Exit if accessed directly
defined( 'ABSPATH' ) || exit;
/**
* EDD_Payment_Stats Class.
*
* This class is for retrieving stats for earnings and sales.
*
* Stats can be retrieved for date ranges and pre-defined periods.
*
* This class remains here for backwards compatibility purposes. The EDD\Stats class should be used instead.
*
* @since 1.8
* @since 3.0 Refactored to work with custom tables.
*/
class EDD_Payment_Stats extends EDD_Stats {
/**
* Retrieve sale stats.
*
* @since 1.8
* @since 3.0 Refactored to work with custom tables.
*
* @param int $download_id The download product to retrieve stats for. If false, gets stats for all products
* @param string|bool $start_date The starting date for which we'd like to filter our sale stats. If false, we'll use the default start date of `this_month`
* @param string|bool $end_date The end date for which we'd like to filter our sale stats. If false, we'll use the default end date of `this_month`
* @param string|array $status The sale status(es) to count. Only valid when retrieving global stats
*
* @return float|int Total amount of sales based on the passed arguments.
*/
public function get_sales( $download_id = 0, $start_date = false, $end_date = false, $status = 'complete' ) {
global $wpdb;
$this->setup_dates( $start_date, $end_date );
// Make sure start date is valid
if ( is_wp_error( $this->start_date ) ) {
return $this->start_date;
}
// Make sure end date is valid
if ( is_wp_error( $this->end_date ) ) {
return $this->end_date;
}
if ( empty( $download_id ) ) {
// Global sale stats
add_filter( 'edd_count_payments_where', array( $this, 'count_where' ) );
$count = 0;
$total_counts = edd_count_payments();
foreach ( (array) $status as $payment_status ) {
if ( isset( $total_counts->$payment_status ) ) {
$count += absint( $total_counts->$payment_status );
}
}
remove_filter( 'edd_count_payments_where', array( $this, 'count_where' ) );
} else {
$this->timestamp = false;
$date_created_query = array(
array(
'after' => array(
'year' => date( 'Y', $this->start_date ),
'month' => date( 'm', $this->start_date ),
'day' => date( 'd', $this->start_date ),
),
'before' => array(
'year' => date( 'Y', $this->end_date ),
'month' => date( 'm', $this->end_date ),
'day' => date( 'd', $this->end_date ),
),
'inclusive' => true,
),
);
add_filter( 'date_query_valid_columns', array( $this, '__filter_valid_date_columns' ), 2 );
$date_query = new \WP_Date_Query( $date_created_query, 'edd_o.date_created' );
$date_query->column = 'edd_o.date_created';
$date_query_sql = $date_query->get_sql();
remove_filter( 'date_query_valid_columns', array( $this, '__filter_valid_date_columns' ), 2 );
$statuses = edd_get_net_order_statuses();
/**
* Filters Order statuses that should be included when calculating stats.
*
* @since 2.7
*
* @param array $statuses Order statuses to include when generating stats.
*/
$statuses = apply_filters( 'edd_payment_stats_post_statuses', $statuses );
$statuses = "'" . implode( "', '", $statuses ) . "'";
$result = $wpdb->get_row( $wpdb->prepare(
"SELECT COUNT(edd_oi.id) AS sales
FROM {$wpdb->edd_order_items} edd_oi
INNER JOIN {$wpdb->edd_orders} edd_o ON edd_oi.order_id = edd_o.id
WHERE edd_o.status IN ($statuses) AND edd_oi.product_id = %d {$date_query_sql}",
$download_id ) );
$count = null === $result
? 0
: absint( $result->sales );
}
return $count;
}
/**
* Retrieve earning stats.
*
* @since 1.8
* @since 3.0 Refactored to work with custom tables.
*
* @param int $download_id The download product to retrieve stats for. If false, gets stats for all products
* @param string|bool $start_date The starting date for which we'd like to filter our sale stats. If false, we'll use the default start date of `this_month`
* @param string|bool $end_date The end date for which we'd like to filter our sale stats. If false, we'll use the default end date of `this_month`
* @param bool $include_taxes If taxes should be included in the earnings graphs
*
* @return float|int Total amount of sales based on the passed arguments.
*/
public function get_earnings( $download_id = 0, $start_date = false, $end_date = false, $include_taxes = true ) {
global $wpdb;
$this->setup_dates( $start_date, $end_date );
// Make sure start date is valid
if ( is_wp_error( $this->start_date ) ) {
return $this->start_date;
}
// Make sure end date is valid
if ( is_wp_error( $this->end_date ) ) {
return $this->end_date;
}
if ( empty( $download_id ) ) {
/**
* Filters Order statuses that should be included when calculating stats.
*
* @since 2.7
*
* @param array $statuses Order statuses to include when generating stats.
*/
$statuses = apply_filters( 'edd_payment_stats_post_statuses', edd_get_net_order_statuses() );
// Global earning stats
$args = array(
'post_type' => 'edd_payment',
'nopaging' => true,
'post_status' => $statuses,
'fields' => 'ids',
'update_post_term_cache' => false,
'suppress_filters' => false,
'start_date' => $this->start_date, // These dates are not valid query args, but they are used for cache keys
'end_date' => $this->end_date,
'edd_transient_type' => 'edd_earnings', // This is not a valid query arg, but is used for cache keying
'include_taxes' => $include_taxes,
);
$args = apply_filters( 'edd_stats_earnings_args', $args );
$cached = get_transient( 'edd_stats_earnings' );
$key = md5( wp_json_encode( $args ) );
if ( ! isset( $cached[ $key ] ) ) {
$orders = edd_get_orders( array(
'type' => 'sale',
'status__in' => $args['post_status'],
'date_query' => array(
array(
'after' => array(
'year' => date( 'Y', $this->start_date ),
'month' => date( 'm', $this->start_date ),
'day' => date( 'd', $this->start_date ),
),
'before' => array(
'year' => date( 'Y', $this->end_date ),
'month' => date( 'm', $this->end_date ),
'day' => date( 'd', $this->end_date ),
),
'inclusive' => true,
),
),
'no_found_rows' => true,
) );
$earnings = 0;
if ( $orders ) {
$total_earnings = 0.00;
$total_tax = 0.00;
foreach ( $orders as $order ) {
$total_earnings += $order->total;
$total_tax += $order->tax;
}
$earnings = apply_filters( 'edd_payment_stats_earnings_total', $total_earnings, $orders, $args );
if ( false === $include_taxes ) {
$earnings -= $total_tax;
}
}
// Cache the results for one hour
$cached[ $key ] = $earnings;
set_transient( 'edd_stats_earnings', $cached, HOUR_IN_SECONDS );
}
// Download specific earning stats
} else {
$args = array(
'object_id' => $download_id,
'object_type' => 'download',
'type' => 'sale',
'log_type' => false,
'date_created_query' => array(
'after' => array(
'year' => date( 'Y', $this->start_date ),
'month' => date( 'm', $this->start_date ),
'day' => date( 'd', $this->start_date ),
),
'before' => array(
'year' => date( 'Y', $this->end_date ),
'month' => date( 'm', $this->end_date ),
'day' => date( 'd', $this->end_date ),
),
'inclusive' => true,
),
'start_date' => $this->start_date,
'end_date' => $this->end_date,
'include_taxes' => $include_taxes,
);
$args = apply_filters( 'edd_stats_earnings_args', $args );
$cached = get_transient( 'edd_stats_earnings' );
$key = md5( wp_json_encode( $args ) );
if ( ! isset( $cached[ $key ] ) ) {
$this->timestamp = false;
add_filter( 'date_query_valid_columns', array( $this, '__filter_valid_date_columns' ), 2 );
$date_query = new \WP_Date_Query( $args['date_created_query'], 'edd_o.date_created' );
$date_query->column = 'edd_o.date_created';
$date_query_sql = $date_query->get_sql();
remove_filter( 'date_query_valid_columns', array( $this, '__filter_valid_date_columns' ), 2 );
$statuses = edd_get_net_order_statuses();
/**
* Filters Order statuses that should be included when calculating stats.
*
* @since 2.7
*
* @param array $statuses Order statuses to include when generating stats.
*/
$statuses = apply_filters( 'edd_payment_stats_post_statuses', $statuses );
$statuses = "'" . implode( "', '", $statuses ) . "'";
$result = $wpdb->get_row( $wpdb->prepare(
"SELECT SUM(edd_oi.tax) as tax, SUM(edd_oi.total) as total
FROM {$wpdb->edd_order_items} edd_oi
INNER JOIN {$wpdb->edd_orders} edd_o ON edd_oi.order_id = edd_o.id
WHERE edd_o.status IN ($statuses) AND edd_oi.product_id = %d {$date_query_sql}",
$download_id ) );
$earnings = 0;
if ( $result ) {
$earnings += floatval( $result->total );
if ( ! $include_taxes ) {
$earnings -= floatval( $result->tax );
}
$earnings = apply_filters_deprecated( 'edd_payment_stats_item_earnings', array( $earnings ), 'EDD 3.0' );
}
// Cache the results for one hour
$cached[ $key ] = $earnings;
set_transient( 'edd_stats_earnings', $cached, HOUR_IN_SECONDS );
}
}
$result = $cached[ $key ];
return round( $result, edd_currency_decimal_filter() );
}
/**
* Get the best selling products
*
* @since 1.8
*
* @param int $number The number of results to retrieve with the default set to 10.
*
* @return array List of download IDs that are best selling
*/
public function get_best_selling( $number = 10 ) {
global $wpdb;
$downloads = $wpdb->get_results( $wpdb->prepare(
"SELECT post_id as download_id, max(meta_value) as sales
FROM $wpdb->postmeta
WHERE meta_key='_edd_download_sales' AND meta_value > 0
GROUP BY meta_value+0
DESC LIMIT %d;", $number
) );
return $downloads;
}
/**
* Retrieve sales stats based on range provided.
*
* @since 2.6.11
* @since 3.0 Refactored to work with custom tables.
*
* @param string $range Date range.
* @param string|bool $start_date The starting date for which we'd like to filter our sale stats.
* If false, we'll use the default start date of `this_month`.
* @param string|bool $end_date The end date for which we'd like to filter our sale stats.
* If false, we'll use the default end date of `this_month`.
* @param string|array $status The sale status(es) to count. Only valid when retrieving global stats.
*
* @return array|false Total amount of sales based on the passed arguments.
*/
public function get_sales_by_range( $range = 'today', $day_by_day = false, $start_date = false, $end_date = false, $status = 'complete' ) {
global $wpdb;
$this->setup_dates( $start_date, $end_date );
$this->end_date = strtotime( 'midnight', $this->end_date );
// Make sure start date is valid
if ( is_wp_error( $this->start_date ) ) {
return $this->start_date;
}
// Make sure end date is valid
if ( is_wp_error( $this->end_date ) ) {
return $this->end_date;
}
$cached = get_transient( 'edd_stats_sales' );
$key = md5( $range . '_' . date( 'Y-m-d', $this->start_date ) . '_' . date( 'Y-m-d', strtotime( '+1 DAY', $this->end_date ) ) );
$sales = isset( $cached[ $key ] ) ? $cached[ $key ] : false;
if ( false === $sales || ! $this->is_cacheable( $range ) ) {
if ( ! $day_by_day ) {
$select = "DATE_FORMAT(edd_o.date_created, '%%m') AS m, YEAR(edd_o.date_created) AS y, COUNT(DISTINCT edd_o.id) as count";
$grouping = "YEAR(edd_o.date_created), MONTH(edd_o.date_created)";
} else {
if ( 'today' === $range || 'yesterday' === $range ) {
$select = "DATE_FORMAT(edd_o.date_created, '%%d') AS d, DATE_FORMAT(edd_o.date_created, '%%m') AS m, YEAR(edd_o.date_created) AS y, HOUR(edd_o.date_created) AS h, COUNT(DISTINCT edd_o.id) as count";
$grouping = "YEAR(edd_o.date_created), MONTH(edd_o.date_created), DAY(edd_o.date_created), HOUR(edd_o.date_created)";
} else {
$select = "DATE_FORMAT(edd_o.date_created, '%%d') AS d, DATE_FORMAT(edd_o.date_created, '%%m') AS m, YEAR(edd_o.date_created) AS y, COUNT(DISTINCT edd_o.id) as count";
$grouping = "YEAR(edd_o.date_created), MONTH(edd_o.date_created), DAY(edd_o.date_created)";
}
}
if ( 'today' === $range || 'yesterday' === $range ) {
$grouping = 'YEAR(edd_o.date_created), MONTH(edd_o.date_created), DAY(edd_o.date_created), HOUR(edd_o.date_created)';
}
$statuses = edd_get_net_order_statuses();
/**
* Filters Order statuses that should be included when calculating stats.
*
* @since 2.7
*
* @param array $statuses Order statuses to include when generating stats.
*/
$statuses = apply_filters( 'edd_payment_stats_post_statuses', $statuses );
$statuses = "'" . implode( "', '", $statuses ) . "'";
$sales = $wpdb->get_results( $wpdb->prepare(
"SELECT {$select}
FROM {$wpdb->edd_orders} edd_o
WHERE edd_o.status IN ({$statuses}) AND edd_o.date_created >= %s AND edd_o.date_created < %s
GROUP BY {$grouping}
ORDER by edd_o.date_created ASC",
date( 'Y-m-d', $this->start_date ), date( 'Y-m-d', strtotime( '+1 day', $this->end_date ) ) ), ARRAY_A );
if ( $this->is_cacheable( $range ) ) {
$cached[ $key ] = $sales;
set_transient( 'edd_stats_sales', $cached, HOUR_IN_SECONDS );
}
}
return $sales;
}
/**
* Retrieve sales stats based on range provided (used for Reporting)
*
* @since 2.7
*
* @param string|bool $start_date The starting date for which we'd like to filter our earnings stats. If false, we'll use the default start date of `this_month`
* @param string|bool $end_date The end date for which we'd like to filter our earnings stats. If false, we'll use the default end date of `this_month`
* @param bool $include_taxes If taxes should be included in the earnings graphs
*
* @return array Total amount of earnings based on the passed arguments.
*/
public function get_earnings_by_range( $range = 'today', $day_by_day = false, $start_date = false, $end_date = false, $include_taxes = true ) {
global $wpdb;
$this->setup_dates( $start_date, $end_date );
$this->end_date = strtotime( 'midnight', $this->end_date );
// Make sure start date is valid
if ( is_wp_error( $this->start_date ) ) {
return $this->start_date;
}
// Make sure end date is valid
if ( is_wp_error( $this->end_date ) ) {
return $this->end_date;
}
$earnings = array();
$cached = get_transient( 'edd_stats_earnings' );
$key = md5( $range . '_' . date( 'Y-m-d', $this->start_date ) . '_' . date( 'Y-m-d', strtotime( '+1 DAY', $this->end_date ) ) );
$sales = isset( $cached[ $key ] ) ? $cached[ $key ] : false;
if ( false === $sales || ! $this->is_cacheable( $range ) ) {
if ( ! $day_by_day ) {
$select = "DATE_FORMAT(edd_o.date_created, '%%m') AS m, YEAR(edd_o.date_created) AS y, COUNT(DISTINCT edd_o.id) as count";
$grouping = "YEAR(edd_o.date_created), MONTH(edd_o.date_created)";
} else {
if ( 'today' === $range || 'yesterday' === $range ) {
$select = "DATE_FORMAT(edd_o.date_created, '%%d') AS d, DATE_FORMAT(edd_o.date_created, '%%m') AS m, YEAR(edd_o.date_created) AS y, HOUR(edd_o.date_created) AS h, COUNT(DISTINCT edd_o.id) as count";
$grouping = "YEAR(edd_o.date_created), MONTH(edd_o.date_created), DAY(edd_o.date_created), HOUR(edd_o.date_created)";
} else {
$select = "DATE_FORMAT(edd_o.date_created, '%%d') AS d, DATE_FORMAT(edd_o.date_created, '%%m') AS m, YEAR(edd_o.date_created) AS y, COUNT(DISTINCT edd_o.id) as count";
$grouping = "YEAR(edd_o.date_created), MONTH(edd_o.date_created), DAY(edd_o.date_created)";
}
}
if ( 'today' === $range || 'yesterday' === $range ) {
$grouping = 'YEAR(edd_o.date_created), MONTH(edd_o.date_created), DAY(edd_o.date_created), HOUR(edd_o.date_created)';
}
$statuses = edd_get_net_order_statuses();
/**
* Filters Order statuses that should be included when calculating stats.
*
* @since 2.7
*
* @param array $statuses Order statuses to include when generating stats.
*/
$statuses = apply_filters( 'edd_payment_stats_post_statuses', $statuses );
$statuses = "'" . implode( "', '", $statuses ) . "'";
$earnings = $wpdb->get_results( $wpdb->prepare(
"SELECT SUM(total) AS total, SUM(tax) AS tax, $select
FROM {$wpdb->edd_orders} edd_o
WHERE edd_o.status IN ({$statuses}) AND edd_o.date_created >= %s AND edd_o.date_created < %s
GROUP BY {$grouping}
ORDER by edd_o.date_created ASC",
date( 'Y-m-d', $this->start_date ), date( 'Y-m-d', strtotime( '+1 day', $this->end_date ) ) ), ARRAY_A );
if ( ! $include_taxes ) {
foreach ( $earnings as $key => $value ) {
$earnings[ $key ]['total'] -= $earnings[ $key ]['tax'];
unset( $earnings[ $key ]['tax'] );
}
}
}
return $earnings;
}
/**
* Is the date range cachable.
*
* @since 2.6.11
*
* @param string $date_range Date range of the report.
* @return bool Whether the date range is allowed to be cached or not.
*/
public function is_cacheable( $date_range = '' ) {
if ( empty( $date_range ) ) {
return false;
}
$cacheable_ranges = array(
'today',
'yesterday',
'this_week',
'last_week',
'this_month',
'last_month',
'this_quarter',
'last_quarter',
);
return in_array( $date_range, $cacheable_ranges, true );
}
/**
* This public method should not be called directly ever.
*
* It only exists to hack around a WordPress core issue with WP_Date_Query
* column stubbornness.
*
* @since 3.0
*
* @access private
* @param array $columns
* @return array
*/
public function __filter_valid_date_columns( $columns = array() ) {
$columns = array_merge( array( 'date_created' ), $columns );
return $columns;
}
}

View File

@ -0,0 +1,869 @@
<?php
/**
* Payments Query
*
* @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.8
*/
// Exit if accessed directly
defined( 'ABSPATH' ) || exit;
/**
* EDD_Payments_Query Class.
*
* This class is for retrieving payments data.
*
* Payments can be retrieved for date ranges and pre-defined periods.
*
* @since 1.8
* @since 3.0 Updated to use the new query classes and custom tables.
*/
class EDD_Payments_Query extends EDD_Stats {
/**
* The args to pass to the edd_get_payments() query
*
* @var array
* @since 1.8
*/
public $args = array();
/**
* The args as they came into the class.
*
* @var array
* @since 2.7.2
*/
public $initial_args = array();
/**
* The payments found based on the criteria set
*
* @var array
* @since 1.8
*/
public $payments = array();
/**
* Items returned from query.
*
* @since 3.0
* @var array|null
*/
private $items = array();
/**
* Default query arguments.
*
* Not all of these are valid arguments that can be passed to WP_Query. The ones that are not, are modified before
* the query is run to convert them to the proper syntax.
*
* @since 1.8
* @since 3.0 Updated to use the new query classes and custom tables.
*
* @param array $args The array of arguments that can be passed in and used for setting up this payment query.
*/
public function __construct( $args = array() ) {
$defaults = array(
'output' => 'payments', // Use 'posts' to get standard post objects
'post_type' => array( 'edd_payment' ),
'post_parent' => null,
'start_date' => false,
'end_date' => false,
'number' => 20,
'page' => null,
'orderby' => 'ID',
'order' => 'DESC',
'user' => null,
'customer' => null,
'status' => edd_get_payment_status_keys(),
'mode' => null,
'type' => 'sale',
'meta_key' => null,
'year' => null,
'month' => null,
'day' => null,
's' => null,
'search_in_notes' => false,
'children' => false,
'fields' => null,
'download' => null,
'gateway' => null,
'post__in' => null,
'post__not_in' => null,
'compare' => null,
'country' => null,
'region' => null,
);
$this->initial_args = $args;
// We need to store an array of the args used to instantiate the class, so that we can use it in later hooks.
$this->args = wp_parse_args( $args, $defaults );
// In EDD 3.0 we switched from 'publish' to 'complete' for the final state of a completed payment, this accounts for that change.
if ( is_array( $this->args['status'] ) && in_array( 'publish', $this->args['status'] ) ) {
foreach ( $this->args['status'] as $key => $status ) {
if ( $status === 'publish' ) {
unset( $this->args['status'][ $key ] );
}
}
$this->args['status'][] = 'complete';
} else if ( 'publish' === $this->args['status'] ) {
$this->args['status'] = 'complete';
}
}
/**
* Set a query variable.
*
* @since 1.8
*/
public function __set( $query_var, $value ) {
if ( in_array( $query_var, array( 'meta_query', 'tax_query' ), true ) ) {
$this->args[ $query_var ][] = $value;
} else {
$this->args[ $query_var ] = $value;
}
}
/**
* Unset a query variable.
*
* @since 1.8
*/
public function __unset( $query_var ) {
unset( $this->args[ $query_var ] );
}
/**
* Retrieve payments.
*
* The query can be modified in two ways; either the action before the
* query is run, or the filter on the arguments (existing mainly for backwards
* compatibility).
*
* @since 1.8
* @since 3.0 Updated to use the new query classes and custom tables.
*
* @return EDD_Payment[]|EDD\Orders\Order[]|int
*/
public function get_payments() {
// Modify the query/query arguments before we retrieve payments.
$this->date_filter_pre();
$this->orderby();
$this->status();
$this->month();
$this->per_page();
$this->page();
$this->user();
$this->customer();
$this->search();
$this->gateway();
$this->mode();
$this->children();
$this->download();
$this->post__in();
do_action( 'edd_pre_get_payments', $this );
$should_output_wp_post_objects = false;
$should_output_order_objects = false;
if ( 'posts' === $this->args['output'] ) {
$should_output_wp_post_objects = true;
} elseif ( 'orders' === $this->args['output'] ) {
$should_output_order_objects = true;
}
$this->remap_args();
// Check if $items is null after parsing the query.
if ( null === $this->items ) {
return array();
}
$this->items = edd_get_orders( $this->args );
if ( ! empty( $this->args['count'] ) && is_numeric( $this->items ) ) {
return intval( $this->items );
}
if ( $should_output_order_objects || ! empty( $this->args['fields'] ) ) {
return $this->items;
}
if ( $should_output_wp_post_objects ) {
$posts = array();
foreach ( $this->items as $order ) {
$p = new WP_Post( new stdClass() );
$p->ID = $order->id;
$p->post_date = EDD()->utils->date( $order->date_created, null, true )->toDateTimeString();
$p->post_date_gmt = $order->date_created;
$p->post_status = $order->status;
$p->post_modified = EDD()->utils->date( $order->date_modified, null, true )->toDateTimeString();
$p->post_modified_gmt = $order->date_modified;
$p->post_type = 'edd_payment';
$posts[] = $p;
}
return $posts;
}
foreach ( $this->items as $order ) {
$payment = edd_get_payment( $order->id );
if ( edd_get_option( 'enable_sequential' ) ) {
// Backwards compatibility, needs to set `payment_number` attribute
$payment->payment_number = $payment->number;
}
$this->payments[] = apply_filters( 'edd_payment', $payment, $order->id, $this );
}
do_action( 'edd_post_get_payments', $this );
return $this->payments;
}
/**
* If querying a specific date, add the proper filters.
*
* @since 1.8
*/
public function date_filter_pre() {
if ( ! ( $this->args['start_date'] || $this->args['end_date'] ) ) {
return;
}
$this->setup_dates( $this->args['start_date'], $this->args['end_date'] );
}
/**
* Post Status
*
* @since 1.8
*/
public function status() {
if ( ! isset( $this->args['status'] ) ) {
return;
}
$this->__set( 'post_status', $this->args['status'] );
$this->__unset( 'status' );
}
/**
* Current Page
*
* @since 1.8
*/
public function page() {
if ( ! isset( $this->args['page'] ) ) {
return;
}
$this->__set( 'paged', $this->args['page'] );
$this->__unset( 'page' );
}
/**
* Posts Per Page
*
* @since 1.8
*/
public function per_page() {
if ( ! isset( $this->args['number'] ) ) {
return;
}
if ( - 1 === $this->args['number'] ) {
$this->__set( 'nopaging', true );
} else {
$this->__set( 'posts_per_page', $this->args['number'] );
}
$this->__unset( 'number' );
}
/**
* Current Month
*
* @since 1.8
*/
public function month() {
if ( ! isset( $this->args['month'] ) ) {
return;
}
$this->__set( 'monthnum', $this->args['month'] );
$this->__unset( 'month' );
}
/**
* Order by
*
* @since 1.8
*/
public function orderby() {
switch ( $this->args['orderby'] ) {
case 'amount':
$this->__set( 'orderby', 'meta_value_num' );
$this->__set( 'meta_key', '_edd_payment_total' );
break;
default:
$this->__set( 'orderby', $this->args['orderby'] );
break;
}
}
/**
* Specific User
*
* @since 1.8
*/
public function user() {
if ( is_null( $this->args['user'] ) ) {
return;
}
if ( is_numeric( $this->args['user'] ) ) {
$user_key = '_edd_payment_user_id';
} else {
$user_key = '_edd_payment_user_email';
}
$this->__set( 'meta_query', array(
'key' => $user_key,
'value' => $this->args['user'],
) );
}
/**
* Specific customer id
*
* @since 2.6
*/
public function customer() {
if ( is_null( $this->args['customer'] ) || ! is_numeric( $this->args['customer'] ) ) {
return;
}
$this->__set( 'meta_query', array(
'key' => '_edd_payment_customer_id',
'value' => (int) $this->args['customer'],
) );
}
/**
* Specific gateway
*
* @since 2.8
*/
public function gateway() {
if ( is_null( $this->args['gateway'] ) ) {
return;
}
$this->__set( 'meta_query', array(
'key' => '_edd_payment_gateway',
'value' => $this->args['gateway'],
) );
}
/**
* Specific payments
*
* @since 2.8.7
*/
public function post__in() {
if ( is_null( $this->args['post__in'] ) ) {
return;
}
$this->__set( 'post__in', $this->args['post__in'] );
}
/**
* Search
*
* @since 1.8
*/
public function search() {
if ( ! isset( $this->args['s'] ) ) {
return;
}
$search = trim( $this->args['s'] );
if ( empty( $search ) ) {
return;
}
$is_email = is_email( $search ) || strpos( $search, '@' ) !== false;
$is_user = strpos( $search, strtolower( 'user:' ) ) !== false;
if ( ! empty( $this->args['search_in_notes'] ) ) {
$notes = edd_get_payment_notes( 0, $search );
if ( ! empty( $notes ) ) {
$payment_ids = wp_list_pluck( (array) $notes, 'object_id' );
// Set post__in for backwards compatibility purposes.
$this->__set( 'post__in', $payment_ids );
}
$this->__unset( 's' );
} elseif ( $is_email || 32 === strlen( $search ) ) {
$key = $is_email
? 'email'
: 'payment_key';
if ( 'email' === $key ) {
$this->__set( 'user', $search );
} else {
$this->__set( 'payment_key', $search );
}
$this->__unset( 's' );
} elseif ( $is_user ) {
$this->__set( 'user', trim( str_replace( 'user:', '', strtolower( $search ) ) ) );
$this->__unset( 's' );
} elseif ( edd_get_option( 'enable_sequential' ) && ( false !== strpos( $search, edd_get_option( 'sequential_prefix' ) ) || false !== strpos( $search, edd_get_option( 'sequential_postfix' ) ) ) ) {
$this->__set( 'order_number', $search );
$this->__unset( 's' );
} elseif ( is_numeric( $search ) ) {
$this->__set( 'post__in', array( $search ) );
if ( edd_get_option( 'enable_sequential' ) ) {
$this->__set( 'order_number', $search );
}
$this->__unset( 's' );
} elseif ( '#' === substr( $search, 0, 1 ) ) {
$search = str_replace( '#:', '', $search );
$search = str_replace( '#', '', $search );
$ids = edd_get_order_items( array(
'fields' => 'order_id',
'product_id' => $search,
) );
$this->__set( 'post__in', array_values( $ids ) );
$this->__unset( 's' );
} elseif ( 0 === strpos( $search, 'discount:' ) ) {
$search = trim( str_replace( 'discount:', '', $search ) );
$ids = edd_get_order_adjustments( array(
'fields' => 'object_id',
'type' => 'discount',
'description' => $search,
) );
$this->__set( 'post__in', array_values( $ids ) );
$this->__unset( 's' );
} else {
$this->__set( 's', $search );
}
}
/**
* Payment Mode
*
* @since 1.8
*/
public function mode() {
if ( empty( $this->args['mode'] ) || 'all' === $this->args['mode'] ) {
$this->__unset( 'mode' );
return;
}
$this->__set( 'meta_query', array(
'key' => '_edd_payment_mode',
'value' => $this->args['mode'],
) );
}
/**
* Children
*
* @since 1.8
*/
public function children() {
if ( empty( $this->args['children'] ) ) {
$this->__set( 'post_parent', 0 );
}
$this->__unset( 'children' );
}
/**
* Specific Download
*
* @since 1.8
*/
public function download() {
if ( empty( $this->args['download'] ) ) {
return;
}
$order_ids = array();
if ( is_array( $this->args['download'] ) ) {
$orders = edd_get_order_items( array(
'product_id__in' => (array) $this->args['download'],
) );
foreach ( $orders as $order ) {
/** @var $order EDD\Orders\Order_Item */
$order_ids[] = $order->order_id;
}
} else {
$orders = edd_get_order_items( array(
'product_id' => $this->args['download'],
) );
foreach ( $orders as $order ) {
/** @var $order EDD\Orders\Order_Item */
$order_ids[] = $order->id;
}
}
$this->args['id__in'] = $order_ids;
$this->__unset( 'download' );
}
/**
* As of EDD 3.0, we have introduced new query classes and custom tables so we need to remap the arguments so we can
* pass them to the new query classes.
*
* @since 3.0
* @access private
*/
private function remap_args() {
global $wpdb;
$arguments = array();
// Check for post_parent
if ( isset( $this->initial_args['post_parent'] ) ) {
$arguments['parent'] = absint( $this->initial_args['post_parent'] );
}
// Meta key and value
if ( isset( $this->initial_args['meta_query'] ) ) {
$arguments['meta_query'] = $this->initial_args['meta_query'];
} elseif ( isset( $this->initial_args['meta_key'] ) ) {
$meta_query = array(
'key' => $this->initial_args['meta_key']
);
if ( isset( $this->initial_args['meta_value'] ) ) {
$meta_query['value'] = $this->initial_args['meta_value'];
}
$arguments['meta_query'] = array( $meta_query );
}
foreach ( array( 'year', 'month', 'week', 'day', 'hour', 'minute', 'second' ) as $date_interval ) {
if ( isset( $this->initial_args[ $date_interval ] ) ) {
$arguments['date_created_query'][ $date_interval ] = $this->initial_args[ $date_interval ];
}
}
if ( $this->args['start_date'] ) {
if ( is_numeric( $this->start_date ) ) {
$this->start_date = \Carbon\Carbon::createFromTimestamp( $this->start_date )->toDateTimeString();
}
$this->start_date = \Carbon\Carbon::parse( $this->start_date, edd_get_timezone_id() )->setTimezone( 'UTC' )->timestamp;
$arguments['date_created_query']['after'] = array(
'year' => date( 'Y', $this->start_date ),
'month' => date( 'm', $this->start_date ),
'day' => date( 'd', $this->start_date ),
);
$arguments['date_created_query']['inclusive'] = true;
}
if ( $this->args['end_date'] ) {
if ( is_numeric( $this->end_date ) ) {
$this->end_date = \Carbon\Carbon::createFromTimestamp( $this->end_date )->toDateTimeString();
}
$this->end_date = \Carbon\Carbon::parse( $this->end_date, edd_get_timezone_id() )->setTimezone( 'UTC' )->timestamp;
$arguments['date_created_query']['before'] = array(
'year' => date( 'Y', $this->end_date ),
'month' => date( 'm', $this->end_date ),
'day' => date( 'd', $this->end_date ),
);
$arguments['date_created_query']['inclusive'] = true;
}
if ( isset( $this->initial_args['number'] ) ) {
if ( -1 == $this->initial_args['number'] ) {
_doing_it_wrong( __FUNCTION__, esc_html__( 'Do not use -1 to retrieve all results.', 'easy-digital-downloads' ), '3.0' );
$this->args['nopaging'] = true;
} else {
$arguments['number'] = $this->initial_args['number'];
}
}
$arguments['number'] = isset( $this->args['posts_per_page'] )
? $this->args['posts_per_page']
: 20;
if ( isset( $this->args['nopaging'] ) && true === $this->args['nopaging'] ) {
// Setting to a really large number because we don't actually have a way to get all results.
$arguments['number'] = 9999999;
}
switch ( $this->args['orderby'] ) {
case 'amount':
$arguments['orderby'] = 'total';
break;
case 'ID':
case 'title':
case 'post_title':
case 'author':
case 'post_author':
case 'type':
case 'post_type':
$arguments['orderby'] = 'id';
break;
case 'date':
case 'post_date':
$arguments['orderby'] = 'date_created';
break;
case 'modified':
case 'post_modified':
$arguments['orderby'] = 'date_modified';
break;
case 'parent':
case 'post_parent':
$arguments['orderby'] = 'parent';
break;
case 'post__in':
$arguments['orderby'] = 'id__in';
break;
case 'post_parent__in':
$arguments['orderby'] = 'parent__in';
break;
default:
$arguments['orderby'] = $this->args['orderby'];
break;
}
if ( ! is_null( $this->args['user'] ) ) {
$argument_key = is_numeric( $this->args['user'] )
? 'user_id'
: 'email';
$arguments[ $argument_key ] = $this->args['user'];
}
if ( ! is_null( $this->args['customer'] ) && is_numeric( $this->args['customer'] ) ) {
$arguments['customer_id'] = (int) $this->args['customer'];
}
if ( ! is_null( $this->args['gateway'] ) ) {
$arguments['gateway'] = $this->args['gateway'];
}
if ( ! is_null( $this->args['post__in'] ) ) {
$arguments['id__in'] = $this->args['post__in'];
}
if ( ! is_null( $this->args['post__not_in'] ) ) {
$arguments['id__in'] = $this->args['post__not_in'];
}
if ( ! empty( $this->args['mode'] ) && 'all' !== $this->args['mode'] ) {
$arguments['mode'] = $this->args['mode'];
}
if ( ! empty( $this->args['type'] ) ) {
$arguments['type'] = $this->args['type'];
}
if ( ! empty( $this->args['s'] ) ) {
$arguments['search'] = $this->args['s'];
}
if ( ! empty( $this->args['post_parent'] ) ) {
$this->args['parent'] = $this->args['post_parent'];
}
if ( ! empty( $this->args['offset'] ) ) {
$arguments['offset'] = $this->args['offset'];
} elseif ( isset( $this->args['paged'] ) && isset( $this->args['posts_per_page'] ) ) {
$arguments['offset'] = ( $this->args['paged'] * $this->args['posts_per_page'] ) - $this->args['posts_per_page'];
}
if ( isset( $this->args['count'] ) ) {
$arguments['count'] = (bool) $this->args['count'];
unset( $arguments['number'] );
}
if ( isset( $this->args['groupby'] ) ) {
$arguments['groupby'] = $this->args['groupby'];
}
if ( isset( $this->args['order'] ) ) {
$arguments['order'] = $this->args['order'];
}
if ( isset( $this->args['compare'] ) && is_array( $this->args['compare'] ) ) {
$arguments['compare'] = $this->args['compare'];
}
// Re-map post_status to status.
if ( isset( $this->args['post_status'] ) ) {
$arguments['status'] = $this->args['post_status'];
}
// If the status includes `any`, we should set the status to our whitelisted keys.
if ( isset( $arguments['status'] ) && ( 'any' === $arguments['status'] || ( is_array( $arguments['status'] ) && in_array( 'any', $arguments['status'], true ) ) ) ) {
$arguments['status'] = edd_get_payment_status_keys();
}
if ( isset( $arguments['meta_query'] ) && is_array( $arguments['meta_query'] ) ) {
foreach ( $arguments['meta_query'] as $meta_index => $meta ) {
if ( ! empty( $meta['key'] ) ) {
switch ( $meta['key'] ) {
case '_edd_payment_customer_id':
$arguments['customer_id'] = absint( $meta['value'] );
unset( $arguments['meta_query'][ $meta_index ] );
break;
case '_edd_payment_user_id':
$arguments['user_id'] = absint( $meta['value'] );
unset( $arguments['meta_query'][ $meta_index ] );
break;
case '_edd_payment_user_email':
$arguments['email'] = sanitize_email( $meta['value'] );
unset( $arguments['meta_query'][ $meta_index ] );
break;
case '_edd_payment_gateway':
$arguments['gateway'] = sanitize_text_field( $meta['value'] );
unset( $arguments['meta_query'][ $meta_index ] );
break;
case '_edd_payment_purchase_key' :
$arguments['payment_key'] = sanitize_text_field( $meta['value'] );
unset( $arguments['meta_query'][ $meta_index ] );
break;
}
}
}
}
if ( isset( $this->args['id__in'] ) ) {
$arguments['id__in'] = $this->args['id__in'];
}
if ( isset( $arguments['status'] ) && is_array( $arguments['status'] ) ) {
$arguments['status__in'] = $arguments['status'];
unset( $arguments['status'] );
}
if ( isset( $this->args['country'] ) && ! empty( $this->args['country'] ) && 'all' !== $this->args['country'] ) {
$country = $wpdb->prepare( 'AND edd_oa.country = %s', esc_sql( $this->args['country'] ) );
$region = ! empty( $this->args['region'] ) && 'all' !== $this->args['region']
? $wpdb->prepare( 'AND edd_oa.region = %s', esc_sql( $this->args['region'] ) )
: '';
$join = "INNER JOIN {$wpdb->edd_order_addresses} edd_oa ON edd_o.id = edd_oa.order_id";
$date_query = '';
if ( ! empty( $this->start_date ) || ! empty( $this->end_date ) ) {
$date_query = ' AND ';
if ( ! empty( $this->start_date ) ) {
$date_query .= $wpdb->prepare( 'edd_o.date_created >= %s', $this->start_date );
}
// Join dates with `AND` if start and end date set.
if ( ! empty( $this->start_date ) && ! empty( $this->end_date ) ) {
$date_query .= ' AND ';
}
if ( ! empty( $this->end_date ) ) {
$date_query .= $wpdb->prepare( 'edd_o.date_created <= %s', $this->end_date );
}
}
$gateway = ! empty( $arguments['gateway'] )
? $wpdb->prepare( 'AND edd_o.gateway = %s', esc_sql( $arguments['gateway'] ) )
: '';
$mode = ! empty( $arguments['mode'] )
? $wpdb->prepare( 'AND edd_o.mode = %s', esc_sql( $arguments['mode'] ) )
: '';
$sql = "
SELECT edd_o.id
FROM {$wpdb->edd_orders} edd_o
{$join}
WHERE 1=1 {$country} {$region} {$mode} {$gateway} {$date_query}
";
$ids = $wpdb->get_col( $sql, 0 ); // WPCS: unprepared SQL ok.
if ( ! empty( $ids ) ) {
$ids = wp_parse_id_list( $ids );
$arguments['id__in'] = isset( $arguments['id__in'] )
? array_merge( $ids, $arguments['id__in'] )
: $ids;
} else {
$this->items = null;
}
}
if ( isset( $this->args['date_query'] ) ) {
$arguments['date_query'] = $this->args['date_query'];
}
if ( isset( $this->args['date_created_query'] ) ) {
$arguments['date_created_query'] = $this->args['date_created_query'];
}
if ( isset( $this->args['date_modified_query'] ) ) {
$arguments['date_modified_query'] = $this->args['date_modified_query'];
}
if ( isset( $this->args['date_refundable_query'] ) ) {
$arguments['date_refundable_query'] = $this->args['date_refundable_query'];
}
// Make sure `fields` is honored if set (eg. 'ids').
if ( ! empty( $this->args['fields'] ) ) {
$arguments['fields'] = $this->args['fields'];
}
$this->args = $arguments;
}
}

File diff suppressed because it is too large Load Diff