updated plugin Easy Digital Downloads version 3.1.0.4

This commit is contained in:
2023-01-18 16:39:57 +00:00
committed by Gitium
parent ae8dabbd21
commit 6f8f73e860
77 changed files with 2262 additions and 681 deletions

View File

@ -450,4 +450,33 @@ class EDD_Customer_Addresses_Table extends List_Table {
'per_page' => $this->per_page
) );
}
/**
* Generate the table navigation above or below the table.
* We're overriding this to turn off the referer param in `wp_nonce_field()`.
*
* @param string $which
* @since 3.1.0.4
*/
protected function display_tablenav( $which ) {
if ( 'top' === $which ) {
wp_nonce_field( 'bulk-' . $this->_args['plural'], '_wpnonce', false );
}
?>
<div class="tablenav <?php echo esc_attr( $which ); ?>">
<?php if ( $this->has_items() ) : ?>
<div class="alignleft actions bulkactions">
<?php $this->bulk_actions( $which ); ?>
</div>
<?php
endif;
$this->extra_tablenav( $which );
$this->pagination( $which );
?>
<br class="clear"/>
</div>
<?php
}
}

View File

@ -437,4 +437,33 @@ class EDD_Customer_Email_Addresses_Table extends List_Table {
'per_page' => $this->per_page
) );
}
/**
* Generate the table navigation above or below the table.
* We're overriding this to turn off the referer param in `wp_nonce_field()`.
*
* @param string $which
* @since 3.1.0.4
*/
protected function display_tablenav( $which ) {
if ( 'top' === $which ) {
wp_nonce_field( 'bulk-' . $this->_args['plural'], '_wpnonce', false );
}
?>
<div class="tablenav <?php echo esc_attr( $which ); ?>">
<?php if ( $this->has_items() ) : ?>
<div class="alignleft actions bulkactions">
<?php $this->bulk_actions( $which ); ?>
</div>
<?php
endif;
$this->extra_tablenav( $which );
$this->pagination( $which );
?>
<br class="clear"/>
</div>
<?php
}
}

View File

@ -430,4 +430,33 @@ class EDD_Customer_Reports_Table extends List_Table {
'per_page' => $this->per_page,
) );
}
/**
* Generate the table navigation above or below the table.
* We're overriding this to turn off the referer param in `wp_nonce_field()`.
*
* @param string $which
* @since 3.1.0.4
*/
protected function display_tablenav( $which ) {
if ( 'top' === $which ) {
wp_nonce_field( 'bulk-' . $this->_args['plural'], '_wpnonce', false );
}
?>
<div class="tablenav <?php echo esc_attr( $which ); ?>">
<?php if ( $this->has_items() ) : ?>
<div class="alignleft actions bulkactions">
<?php $this->bulk_actions( $which ); ?>
</div>
<?php
endif;
$this->extra_tablenav( $which );
$this->pagination( $which );
?>
<br class="clear"/>
</div>
<?php
}
}

View File

@ -427,4 +427,33 @@ class EDD_Discount_Codes_Table extends List_Table {
'per_page' => $this->per_page,
) );
}
/**
* Generate the table navigation above or below the table.
* We're overriding this to turn off the referer param in `wp_nonce_field()`.
*
* @param string $which
* @since 3.1.0.4
*/
protected function display_tablenav( $which ) {
if ( 'top' === $which ) {
wp_nonce_field( 'bulk-' . $this->_args['plural'], '_wpnonce', false );
}
?>
<div class="tablenav <?php echo esc_attr( $which ); ?>">
<?php if ( $this->has_items() ) : ?>
<div class="alignleft actions bulkactions">
<?php $this->bulk_actions( $which ); ?>
</div>
<?php
endif;
$this->extra_tablenav( $which );
$this->pagination( $which );
?>
<br class="clear"/>
</div>
<?php
}
}

View File

@ -226,33 +226,52 @@ add_action( 'load-edit.php', 'edd_download_load', 9999 );
function edd_add_download_filters() {
global $typenow;
// Checks if the current post type is 'download'
if ( $typenow !== 'download') {
// Checks if the current post type is 'download'.
if ( 'download' !== $typenow ) {
return;
}
$terms = get_terms( 'download_category' );
if ( count( $terms ) > 0 ) {
echo "<select name='download_category' id='download_category' class='postform'>";
$category_labels = edd_get_taxonomy_labels( 'download_category' );
echo "<option value=''>" . sprintf( __( 'All %s', 'easy-digital-downloads' ), strtolower( $category_labels['name'] ) ) . "</option>";
foreach ( $terms as $term ) {
$selected = isset( $_GET['download_category'] ) && $_GET['download_category'] === $term->slug ? ' selected="selected"' : '';
echo '<option value="' . esc_attr( $term->slug ) . '"' . $selected . '>' . esc_html( $term->name ) .' (' . $term->count .')</option>';
}
echo "</select>";
}
$category_args = array(
'taxonomy' => 'download_category',
'number' => 30,
);
$terms = get_terms( 'download_tag' );
if ( count( $terms ) > 0 ) {
echo "<select name='download_tag' id='download_tag' class='postform'>";
$tag_labels = edd_get_taxonomy_labels( 'download_tag' );
echo "<option value=''>" . sprintf( __( 'All %s', 'easy-digital-downloads' ), strtolower( $tag_labels['name'] ) ) . "</option>";
foreach ( $terms as $term ) {
$selected = isset( $_GET['download_tag']) && $_GET['download_tag'] === $term->slug ? ' selected="selected"' : '';
echo '<option value="' . esc_attr( $term->slug ) . '"' . $selected . '>' . esc_html( $term->name ) .' (' . $term->count .')</option>';
}
echo "</select>";
$categories = get_terms( $category_args );
if ( ! empty( $categories ) ) {
$category_labels = edd_get_taxonomy_labels( 'download_category' );
$options = array();
$options[''] = sprintf( _x( 'All %s', 'plural: Example: "All Categories"', 'easy-digital-downloads' ), $category_labels['name'] );
// Ensure we include the selected value in the pre-populated list.
$selected = ! empty( $_GET['download_category'] ) ? $_GET['download_category'] : '';
if ( ! empty( $selected ) ) {
$selected_term = get_term_by( 'slug', $selected, 'download_category' );
$options[ $selected_term->slug ] = $selected_term->name . ' (' . $selected_term->count . ')';
}
foreach ( $categories as $category ) {
$options[ $category->slug ] = $category->name . ' (' . $category->count . ')';
}
echo EDD()->html->select(
array(
'name' => 'download_category',
'id' => 'download_category',
'class' => 'postform',
'chosen' => true,
'show_option_all' => false,
'show_option_none' => false,
'options' => $options,
'selected' => $selected,
'data' => array(
'placeholder' => sprintf( _x( 'Search %s', 'plural: Example: "Search Download Categories"', 'easy-digital-downloads' ), $category_labels['name'] ),
'search-type' => 'download_category',
'search-placeholder' => sprintf( _x( 'Search %s', 'plural: Example: "Search Download Categories"', 'easy-digital-downloads' ), $category_labels['name'] ),
),
)
);
}
if ( isset( $_REQUEST['all_posts'] ) && '1' === $_REQUEST['all_posts'] ) {

View File

@ -1057,4 +1057,33 @@ class EDD_Payment_History_Table extends List_Table {
'per_page' => $this->per_page,
) );
}
/**
* Generate the table navigation above or below the table.
* We're overriding this to turn off the referer param in `wp_nonce_field()`.
*
* @param string $which
* @since 3.1.0.4
*/
protected function display_tablenav( $which ) {
if ( 'top' === $which ) {
wp_nonce_field( 'bulk-' . $this->_args['plural'], '_wpnonce', false );
}
?>
<div class="tablenav <?php echo esc_attr( $which ); ?>">
<?php if ( $this->has_items() ) : ?>
<div class="alignleft actions bulkactions">
<?php $this->bulk_actions( $which ); ?>
</div>
<?php
endif;
$this->extra_tablenav( $which );
$this->pagination( $which );
?>
<br class="clear"/>
</div>
<?php
}
}

View File

@ -745,39 +745,85 @@ function edd_register_downloads_report( $reports ) {
'groupby' => '',
);
$union_clauses = array(
'select' => 'date',
'where' => '',
'groupby' => '',
);
// Default to 'monthly'.
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'MONTH', 'edd_oi.date_created' );
$sql_clauses['orderby'] = 'MONTH(edd_oi.date_created)';
$union_clauses['groupby'] = Reports\get_groupby_date_string( 'MONTH', 'date' );
$union_clauses['orderby'] = 'MONTH(date)';
// Now drill down to the smallest unit.
if ( $hour_by_hour ) {
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'HOUR', 'edd_oi.date_created' );
$sql_clauses['orderby'] = 'HOUR(edd_oi.date_created)';
$union_clauses['groupby'] = Reports\get_groupby_date_string( 'HOUR', 'date' );
$union_clauses['orderby'] = 'HOUR(date)';
} elseif ( $day_by_day ) {
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'DATE', 'edd_oi.date_created' );
$sql_clauses['orderby'] = 'DATE(edd_oi.date_created)';
}
$union_clauses['groupby'] = Reports\get_groupby_date_string( 'DATE', 'date' );
$union_clauses['orderby'] = 'DATE(date)';
}
$price_id = isset( $download_data['price_id'] ) && is_numeric( $download_data['price_id'] )
? sprintf( 'AND price_id = %d', absint( $download_data['price_id'] ) )
: '';
$earnings_results = $wpdb->get_results(
$wpdb->prepare(
"SELECT SUM(edd_oi.total / edd_oi.rate) AS earnings, %1s
FROM {$wpdb->edd_order_items} edd_oi
WHERE edd_oi.product_id = %d %1s AND edd_oi.date_created >= %s AND edd_oi.date_created <= %s AND edd_oi.status IN ( 'complete', 'refunded', 'partially_refunded' )
GROUP BY {$sql_clauses['groupby']}
ORDER BY {$sql_clauses['orderby']} ASC",
$sql_clauses['select'],
$download_data['download_id'],
$price_id,
$dates['start']->copy()->format( 'mysql' ),
$dates['end']->copy()->format( 'mysql' )
)
$earnings_statuses = edd_get_gross_order_statuses();
$earnings_status_string = implode( ', ', array_fill( 0, count( $earnings_statuses ), '%s' ) );
$order_item_earnings = $wpdb->prepare(
"SELECT SUM(edd_oi.total / edd_oi.rate) AS earnings, %1s
FROM {$wpdb->edd_order_items} edd_oi
INNER JOIN {$wpdb->edd_orders} edd_o ON edd_oi.order_id = edd_o.id
WHERE edd_oi.product_id = %d %1s AND edd_oi.date_created >= %s AND edd_oi.date_created <= %s AND edd_o.status IN ({$earnings_status_string})
GROUP BY {$sql_clauses['groupby']}",
$sql_clauses['select'],
$download_data['download_id'],
$price_id,
$dates['start']->copy()->format( 'mysql' ),
$dates['end']->copy()->format( 'mysql' ),
...$earnings_statuses
);
/**
* The adjustments query needs a different order status check than the order items. This is due to the fact that
* adjustments refunded would end up being double counted, and therefore create an inaccurate revenue report.
*/
$adjustments_statuses = edd_get_net_order_statuses();
$adjustments_status_string = implode( ', ', array_fill( 0, count( $adjustments_statuses ), '%s' ) );
$order_adjustments = $wpdb->prepare(
"SELECT SUM(edd_oa.total / edd_oa.rate) AS earnings, %1s
FROM {$wpdb->edd_order_adjustments} edd_oa
INNER JOIN {$wpdb->edd_order_items} edd_oi ON
edd_oi.id = edd_oa.object_id
AND edd_oi.product_id = %d
%1s
AND edd_oi.date_created >= %s AND edd_oi.date_created <= %s
INNER JOIN {$wpdb->edd_orders} edd_o ON edd_oi.order_id = edd_o.id AND edd_o.type = 'sale' AND edd_o.status IN ({$adjustments_status_string})
WHERE edd_oa.object_type = 'order_item'
AND edd_oa.type != 'discount'
GROUP BY {$sql_clauses['groupby']}",
$sql_clauses['select'],
$download_data['download_id'],
$price_id,
$dates['start']->copy()->format( 'mysql' ),
$dates['end']->copy()->format( 'mysql' ),
...$adjustments_statuses
);
$earnings_sql = "SELECT SUM(earnings) as earnings, {$union_clauses['select']} FROM ({$order_item_earnings} UNION {$order_adjustments})a GROUP BY {$union_clauses['groupby']} ORDER BY {$union_clauses['orderby']}";
$earnings_results = $wpdb->get_results( $earnings_sql );
$statuses = edd_get_net_order_statuses();
$status_string = implode( ', ', array_fill( 0, count( $statuses ), '%s' ) );
@ -786,22 +832,22 @@ function edd_register_downloads_report( $reports ) {
...$statuses
);
$sales_results = $wpdb->get_results(
$wpdb->prepare(
"SELECT COUNT(edd_oi.total) AS sales, %1s
FROM {$wpdb->edd_order_items} edd_oi
{$join}
WHERE edd_oi.product_id = %d %1s AND edd_oi.date_created >= %s AND edd_oi.date_created <= %s AND edd_oi.status IN ( 'complete', 'refunded', 'partially_refunded' )
GROUP BY {$sql_clauses['groupby']}
ORDER BY {$sql_clauses['orderby']} ASC",
$sql_clauses['select'],
$download_data['download_id'],
$price_id,
$dates['start']->copy()->format( 'mysql' ),
$dates['end']->copy()->format( 'mysql' )
)
$sales_sql = $wpdb->prepare(
"SELECT COUNT(edd_oi.total) AS sales, {$sql_clauses['select']}
FROM {$wpdb->edd_order_items} edd_oi
{$join}
WHERE edd_oi.product_id = %d %1s AND edd_oi.date_created >= %s AND edd_oi.date_created <= %s AND edd_oi.status IN ({$status_string})
GROUP BY {$sql_clauses['groupby']}
ORDER BY {$sql_clauses['orderby']} ASC",
$download_data['download_id'],
$price_id,
$dates['start']->copy()->format( 'mysql' ),
$dates['end']->copy()->format( 'mysql' ),
...$statuses
);
$sales_results = $wpdb->get_results( $sales_sql );
$sales = array();
$earnings = array();

View File

@ -598,24 +598,30 @@ function edd_ajax_download_search() {
// but we'll worry about that later if that situation ever happens.
$args = get_transient( 'edd_download_search' );
// Parse args
$search = wp_parse_args( (array) $args, array(
'text' => '',
'results' => array()
) );
// Parse args.
$search = wp_parse_args(
(array) $args,
array(
'text' => '',
'results' => array(),
)
);
// Get the search string
// Get the search string.
$new_search = isset( $_GET['s'] )
? sanitize_text_field( $_GET['s'] )
: '';
// Bail early if the search text has not changed
// Limit to only alphanumeric characters, including unicode and spaces.
$new_search = preg_replace( '/[^\pL^\pN\pZ]/', ' ', $new_search );
// Bail early if the search text has not changed.
if ( $search['text'] === $new_search ) {
echo json_encode( $search['results'] );
echo wp_json_encode( $search['results'] );
edd_die();
}
// Set the local static search variable
// Set the local static search variable.
$search['text'] = $new_search;
// Are we excluding the current ID?
@ -640,17 +646,17 @@ function edd_ajax_download_search() {
// Are we including all statuses, or only public ones?
$status = ! current_user_can( 'edit_products' )
? apply_filters( 'edd_product_dropdown_status_nopriv', array( 'publish' ) )
: apply_filters( 'edd_product_dropdown_status', array( 'publish', 'draft', 'private', 'future' ) );
: apply_filters( 'edd_product_dropdown_status', array( 'publish', 'draft', 'private', 'future' ) );
// Default query arguments
// Default query arguments.
$args = array(
'orderby' => 'title',
'order' => 'ASC',
'post_type' => 'download',
'posts_per_page' => 50,
'post_status' => implode( ',', $status ), // String
'post__not_in' => $excludes, // Array
'edd_search' => $new_search, // String
'post_status' => implode( ',', $status ), // String.
'post__not_in' => $excludes, // Array.
'edd_search' => $new_search, // String.
'suppress_filters' => false,
);
@ -672,11 +678,11 @@ function edd_ajax_download_search() {
}
add_filter( 'posts_where', 'edd_ajax_filter_download_where', 10, 2 );
// Get downloads
// Get downloads.
$items = get_posts( $args );
remove_filter( 'posts_where', 'edd_ajax_filter_download_where', 10, 2 );
// Pluck title & ID
// Pluck title & ID.
if ( ! empty( $items ) ) {
$items = wp_list_pluck( $items, 'post_title', 'ID' );
@ -684,25 +690,25 @@ function edd_ajax_download_search() {
foreach ( $items as $post_id => $title ) {
$product_title = $title;
// Look for variable pricing
// Look for variable pricing.
$prices = edd_get_variable_prices( $post_id );
if ( ! empty( $prices ) && ( false === $variations|| ! $variations_only ) ) {
if ( ! empty( $prices ) && ( false === $variations || ! $variations_only ) ) {
$title .= ' (' . __( 'All Price Options', 'easy-digital-downloads' ) . ')';
}
if ( empty( $prices ) || ! $variations_only ) {
// Add item to results array
// Add item to results array.
$search['results'][] = array(
'id' => $post_id,
'name' => $title,
);
}
// Maybe include variable pricing
// Maybe include variable pricing.
if ( ! empty( $variations ) && ! empty( $prices ) ) {
foreach ( $prices as $key => $value ) {
$name = ! empty( $value['name'] ) ? $value['name'] : '';
$name = ! empty( $value['name'] ) ? $value['name'] : '';
if ( ! empty( $name ) ) {
$search['results'][] = array(
@ -713,17 +719,16 @@ function edd_ajax_download_search() {
}
}
}
// Empty the results array
} else {
// Empty the results array.
$search['results'] = array();
}
// Update the transient
// Update the transient.
set_transient( 'edd_download_search', $search, 30 );
// Output the results
echo json_encode( $search['results'] );
// Output the results.
echo wp_json_encode( $search['results'] );
// Done!
edd_die();
@ -802,6 +807,45 @@ function edd_ajax_customer_search() {
}
add_action( 'wp_ajax_edd_customer_search', 'edd_ajax_customer_search' );
/**
* Search the download categories via AJAX
*
* @since 3.1.0.4
* @return void
*/
function edd_ajax_download_category_search() {
$search = esc_sql( sanitize_text_field( $_GET['s'] ) );
$results = array();
$category_args = array(
'taxonomy' => array( 'download_category' ),
'orderby' => 'id',
'order' => 'ASC',
'hide_empty' => true,
'fields' => 'all',
'name__like' => $search,
);
$categories_found = get_terms( $category_args );
if ( ! empty( $categories_found ) ) {
foreach ( $categories_found as $category ) {
$results[] = array(
'id' => $category->slug,
'name' => $category->name . ' (' . $category->count . ')',
);
}
} else {
$results[] = array(
'id' => 0,
'name' => __( 'No categories found', 'easy-digital-downloads' ),
);
}
echo wp_send_json( $results );
}
add_action( 'wp_ajax_edd_download_category_search', 'edd_ajax_download_category_search' );
/**
* Search the users database via AJAX
*

View File

@ -370,102 +370,118 @@ class EDD_API_V2 extends EDD_API_V1 {
$sales = array();
if( ! user_can( $this->user_id, 'view_shop_reports' ) && ! $this->override ) {
if ( ! user_can( $this->user_id, 'view_shop_reports' ) && ! $this->override ) {
return $sales;
}
if( isset( $wp_query->query_vars['id'] ) ) {
if ( isset( $wp_query->query_vars['id'] ) ) {
$query = array();
$query[] = new EDD_Payment( $wp_query->query_vars['id'] );
} elseif( isset( $wp_query->query_vars['purchasekey'] ) ) {
$query[] = edd_get_order( $wp_query->query_vars['id'] );
} elseif ( isset( $wp_query->query_vars['purchasekey'] ) ) {
$query = array();
$query[] = edd_get_payment_by( 'key', $wp_query->query_vars['purchasekey'] );
} elseif( isset( $wp_query->query_vars['email'] ) ) {
$query = edd_get_payments( array( 'fields' => 'ids', 'meta_key' => '_edd_payment_user_email', 'meta_value' => $wp_query->query_vars['email'], 'number' => $this->per_page(), 'page' => $this->get_paged(), 'status' => 'complete' ) );
$query[] = edd_get_order_by( 'payment_key', $wp_query->query_vars['purchasekey'] );
} elseif ( isset( $wp_query->query_vars['email'] ) ) {
$query = edd_get_orders(
array(
'type' => 'sale',
'email' => $wp_query->query_vars['email'],
'number' => $this->per_page(),
'offset' => ( $this->get_paged() - 1 ) * $this->per_page(),
'status__in' => edd_get_net_order_statuses(),
)
);
} else {
$query = edd_get_payments( array( 'fields' => 'ids', 'number' => $this->per_page(), 'page' => $this->get_paged(), 'status' => 'complete' ) );
$query = edd_get_orders(
array(
'type' => 'sale',
'number' => $this->per_page(),
'offset' => ( $this->get_paged() - 1 ) * $this->per_page(),
'status__in' => edd_get_net_order_statuses(),
)
);
}
if ( $query ) {
$i = 0;
foreach ( $query as $payment ) {
if ( is_numeric( $payment ) ) {
$payment = new EDD_Payment( $payment );
foreach ( $query as $order ) {
/** @var EDD\Orders\Order $order An Order object. */
$localized_time = edd_get_edd_timezone_equivalent_date_from_utc( EDD()->utils->date( $order->date_created ) );
$sales['sales'][ $i ]['ID'] = $order->get_number();
$sales['sales'][ $i ]['mode'] = $order->mode;
$sales['sales'][ $i ]['status'] = $order->status;
$sales['sales'][ $i ]['transaction_id'] = $order->get_transaction_id();
$sales['sales'][ $i ]['key'] = $order->payment_key;
$sales['sales'][ $i ]['subtotal'] = $order->subtotal;
$sales['sales'][ $i ]['tax'] = $order->tax;
$sales['sales'][ $i ]['total'] = $order->total;
$sales['sales'][ $i ]['gateway'] = $order->gateway;
$sales['sales'][ $i ]['customer_id'] = $order->customer_id;
$sales['sales'][ $i ]['user_id'] = $order->user_id;
$sales['sales'][ $i ]['email'] = $order->email;
$sales['sales'][ $i ]['date'] = $localized_time->copy()->format( 'Y-m-d H:i:s' );
$sales['sales'][ $i ]['date_utc'] = $order->date_created;
$fees = array();
$discounts = array();
foreach ( $order->adjustments as $adjustment ) {
switch ( $adjustment->type ) {
case 'fee':
$fees[] = array(
'amount' => $adjustment->total,
'label' => $adjustment->description,
'no_tax' => empty( $adjustment->tax ),
'type' => $adjustment->type,
'price_id' => null,
'download_id' => null,
'id' => $adjustment->type_key,
);
break;
case 'discount':
$discounts[ $adjustment->description ] = $adjustment->total;
break;
}
}
$payment_meta = $payment->get_meta();
$user_info = $payment->user_info;
$sales['sales'][ $i ]['ID'] = $payment->number;
$sales['sales'][ $i ]['mode'] = $payment->mode;
$sales['sales'][ $i ]['status'] = $payment->status;
$sales['sales'][ $i ]['transaction_id'] = ( ! empty( $payment->transaction_id ) ) ? $payment->transaction_id : null;
$sales['sales'][ $i ]['key'] = $payment->key;
$sales['sales'][ $i ]['subtotal'] = $payment->subtotal;
$sales['sales'][ $i ]['tax'] = $payment->tax;
$sales['sales'][ $i ]['fees'] = ( ! empty( $payment->fees ) ? $payment->fees : null );
$sales['sales'][ $i ]['total'] = $payment->total;
$sales['sales'][ $i ]['gateway'] = $payment->gateway;
$sales['sales'][ $i ]['customer_id'] = $payment->customer_id;
$sales['sales'][ $i ]['user_id'] = $payment->user_id;
$sales['sales'][ $i ]['email'] = $payment->email;
$sales['sales'][ $i ]['date'] = $payment->date;
$c = 0;
$discounts = ! empty( $payment->discounts ) ? explode( ',', $payment->discounts ) : array();
$discounts = array_map( 'trim', $discounts );
$discount_values = array();
foreach ( $discounts as $discount ) {
if ( 'none' === $discount ) { continue; }
$discount_values[ $discount ] = 0;
}
$cart_items = array();
foreach ( $payment->cart_details as $key => $item ) {
foreach ( $order->items as $item ) {
$cart_items[ $c ]['object_id'] = $item->id;
$cart_items[ $c ]['id'] = $item->product_id;
$cart_items[ $c ]['quantity'] = $item->quantity;
$cart_items[ $c ]['name'] = $item->product_name;
$cart_items[ $c ]['price'] = $item->total;
$item_id = isset( $item['id'] ) ? $item['id'] : $item;
$price = isset( $item['price'] ) ? $item['price'] : false; // The final price for the item
$item_price = isset( $item['item_price'] ) ? $item['item_price'] : false; // The price before discounts
// Keeping this here for backwards compatibility.
$cart_items[ $c ]['price_name'] = null === $item->price_id
? ''
: edd_get_price_name( $item->product_id, array( 'price_id' => $item->price_id ) );
$price_id = isset( $item['item_number']['options']['price_id'] ) ? $item['item_number']['options']['price_id'] : null;
$quantity = isset( $item['quantity'] ) && $item['quantity'] > 0 ? $item['quantity'] : 1;
if( ! $price ) {
// This function is only used on payments with near 1.0 cart data structure
$price = edd_get_download_final_price( $item_id, $user_info, null );
}
$price_name = '';
if ( isset( $item['item_number'] ) && isset( $item['item_number']['options'] ) ) {
$price_options = $item['item_number']['options'];
if ( isset( $price_options['price_id'] ) ) {
$price_name = edd_get_price_option_name( $item_id, $price_options['price_id'], $payment->ID );
// Check for any item level fees to include in the fees array.
foreach ( $item->adjustments as $adjustment ) {
if ( 'fee' === $adjustment->type ) {
$fees[] = array(
'amount' => $adjustment->total,
'label' => $adjustment->description,
'no_tax' => empty( $adjustment->tax ),
'type' => $adjustment->type,
'price_id' => $item->price_id,
'download_id' => $item->product_id,
'id' => $adjustment->type_key,
);
}
}
$cart_items[ $c ]['id'] = $item_id;
$cart_items[ $c ]['quantity'] = $quantity;
$cart_items[ $c ]['name'] = get_the_title( $item_id );
$cart_items[ $c ]['price'] = $price;
$cart_items[ $c ]['price_name'] = $price_name;
// Determine the discount amount for the item, if there is one
foreach ( $discount_values as $discount => $amount ) {
$item_discount = edd_get_cart_item_discount_amount( $item, $discount );
$discount_values[ $discount ] += $item_discount;
}
$c++;
}
$sales['sales'][ $i ]['discounts'] = ( ! empty( $discount_values ) ? $discount_values : null );
$sales['sales'][ $i ]['products'] = $cart_items;
$sales['sales'][ $i ]['fees'] = ! empty( $fees ) ? $fees : null;
$sales['sales'][ $i ]['discounts'] = ! empty( $discounts ) ? $discounts : null;
$i++;
}

View File

@ -6,7 +6,7 @@
"title": "EDD Checkout",
"category": "easy-digital-downloads",
"icon": "products",
"description": "Beta: Full checkout block for Easy Digital Downloads.",
"description": "Full checkout block for Easy Digital Downloads.",
"keywords": [
"easy digital downloads",
"edd",

View File

@ -4,7 +4,7 @@
* Description: Core blocks for Easy Digital Downloads.
* Requires at least: 5.8
* Requires PHP: 7.0
* Version: 2.0.2
* Version: 2.0.3
* Author: Easy Digital Downloads
* License: GPL-2.0-or-later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html

View File

@ -181,6 +181,7 @@ function checkout( $block_attributes = array() ) {
}
do_action( 'edd_before_checkout_cart' );
include EDD_BLOCKS_DIR . 'views/checkout/cart/cart.php';
do_action( 'edd_after_checkout_cart' );
Forms\do_purchase_form( $block_attributes );
?>
</div>

View File

@ -160,7 +160,7 @@ class EDD_Cart {
*/
private function get_tax_rate() {
if ( null === $this->tax_rate ) {
$this->tax_rate = edd_get_tax_rate();
$this->tax_rate = edd_use_taxes() ? edd_get_tax_rate() : 0;
}
return $this->tax_rate;

View File

@ -325,7 +325,7 @@ final class Easy_Digital_Downloads {
// Plugin version.
if ( ! defined( 'EDD_VERSION' ) ) {
define( 'EDD_VERSION', '3.1.0.3' );
define( 'EDD_VERSION', '3.1.0.4' );
}
// Plugin Root File.

View File

@ -147,7 +147,8 @@ class Stats {
$args = wp_parse_args( $args, array(
'column_prefix' => '',
'accepted_functions' => array(),
'rate' => true
'requested_function' => false,
'rate' => true,
) );
$column = $this->query_vars['column'];
@ -165,11 +166,16 @@ class Stats {
$default_function = is_array( $args['accepted_functions'] ) && isset( $args['accepted_functions'][0] ) ? $args['accepted_functions'][0] : false;
$function = ! empty( $this->query_vars['function'] ) ? $this->query_vars['function'] : $default_function;
if ( ! empty( $args['requested_function'] ) ) {
$function = $args['requested_function'];
}
if ( empty( $function ) ) {
throw new \InvalidArgumentException( 'Missing select function.' );
}
if ( ! empty( $args['accepted_functions'] ) && ! in_array( strtoupper( $this->query_vars['function'] ), $args['accepted_functions'], true ) ) {
if ( ! empty( $args['accepted_functions'] ) && ! in_array( strtoupper( $function ), $args['accepted_functions'], true ) ) {
if ( ! empty( $default_function ) ) {
$function = $default_function;
} else {
@ -177,7 +183,7 @@ class Stats {
}
}
$function = $this->query_vars['function'] = strtoupper( $function );
$function = strtoupper( $function );
// Multiply by rate if currency conversion is enabled.
if (
@ -930,18 +936,13 @@ class Stats {
$this->query_vars['table'] = $this->get_db()->edd_order_items;
$this->query_vars['column'] = true === $this->query_vars['exclude_taxes'] ? 'total - tax' : 'total';
$this->query_vars['date_query_column'] = 'date_created';
$this->query_vars['status'] = array( 'complete', 'refunded', 'partially_refunded' );
$this->query_vars['status'] = edd_get_gross_order_statuses();
// Run pre-query checks and maybe generate SQL.
$this->pre_query( $query );
$function = $this->get_amount_column_and_function( array(
'column_prefix' => $this->query_vars['table'],
'accepted_functions' => array( 'SUM', 'AVG' )
) );
$product_id = ! empty( $this->query_vars['product_id'] )
? $this->get_db()->prepare( 'AND product_id = %d', absint( $this->query_vars['product_id'] ) )
? $this->get_db()->prepare( "AND {$this->query_vars['table']}.product_id = %d", absint( $this->query_vars['product_id'] ) )
: '';
$price_id = $this->generate_price_id_query_sql();
@ -954,28 +955,119 @@ class Stats {
? $this->get_db()->prepare( 'AND edd_oa.country = %s', esc_sql( $this->query_vars['country'] ) )
: '';
$status = ! empty( $this->query_vars['status'] )
? " AND {$this->query_vars['table']}.status IN ('" . implode( "', '", $this->query_vars['status'] ) . "')"
: '';
$join = $currency = '';
if ( ! empty( $country ) || ! empty( $region ) ) {
$join .= " INNER JOIN {$this->get_db()->edd_order_addresses} edd_oa ON {$this->query_vars['table']}.order_id = edd_oa.order_id ";
}
$join .= " INNER JOIN {$this->get_db()->edd_orders} edd_o ON ({$this->query_vars['table']}.order_id = edd_o.id) AND edd_o.status IN ('" . implode( "', '", $this->query_vars['status'] ) . "') ";
if ( ! empty( $this->query_vars['currency'] ) && array_key_exists( strtoupper( $this->query_vars['currency'] ), edd_get_currencies() ) ) {
$join .= " INNER JOIN {$this->get_db()->edd_orders} edd_o ON ({$this->query_vars['table']}.order_id = edd_o.id) ";
$currency = $this->get_db()->prepare( "AND edd_o.currency = %s", strtoupper( $this->query_vars['currency'] ) );
}
/**
* The adjustments query needs a different order status check than the order items. This is due to the fact that
* adjustments refunded would end up being double counted, and therefore create an inaccurate revenue report.
*/
$adjustments_join = " INNER JOIN {$this->get_db()->edd_orders} edd_o ON ({$this->query_vars['table']}.order_id = edd_o.id) AND edd_o.type = 'sale' AND edd_o.status IN ('" . implode( "', '", edd_get_net_order_statuses() ) . "') ";
/**
* With the addition of including fees into the calcualtion, the order_items
* and order_adjustments for the order items needs to be a SUM and then the final function
* (SUM or AVG) needs to be run on the final UNION Query.
*/
$order_item_function = $this->get_amount_column_and_function( array(
'column_prefix' => $this->query_vars['table'],
'accepted_functions' => array( 'SUM', 'AVG' ),
'requested_function' => 'SUM',
) );
$order_adjustment_function = $this->get_amount_column_and_function( array(
'column_prefix' => 'oadj',
'accepted_functions' => array( 'SUM', 'AVG' ),
'requested_function' => 'SUM',
) );
$union_function = $this->get_amount_column_and_function( array(
'column_prefix' => '',
'accepted_functions' => array( 'SUM', 'AVG' ),
'rate' => false,
) );
if ( true === $this->query_vars['grouped'] ) {
$sql = "SELECT product_id, price_id, {$function} AS total
FROM {$this->query_vars['table']}
{$join}
WHERE 1=1 {$product_id} {$price_id} {$region} {$country} {$currency} {$this->query_vars['where_sql']} {$this->query_vars['date_query_sql']}
GROUP BY product_id, price_id
ORDER BY total DESC";
$order_items = "SELECT
{$this->query_vars['table']}.product_id,
{$this->query_vars['table']}.price_id,
{$order_item_function} AS total
FROM {$this->query_vars['table']}
{$join}
WHERE 1=1
{$product_id}
{$price_id}
{$region}
{$country}
{$currency}
{$this->query_vars['where_sql']}
{$this->query_vars['date_query_sql']}
GROUP BY {$this->query_vars['table']}.product_id, {$this->query_vars['table']}.price_id";
$order_adjustments = "SELECT
{$this->query_vars['table']}.product_id as product_id,
{$this->query_vars['table']}.price_id as price_id,
{$order_adjustment_function} as total
FROM {$this->get_db()->edd_order_adjustments} oadj
INNER JOIN {$this->query_vars['table']} ON
({$this->query_vars['table']}.id = oadj.object_id)
{$product_id}
{$price_id}
{$region}
{$country}
{$currency}
{$adjustments_join}
WHERE oadj.object_type = 'order_item'
AND oadj.type != 'discount'
{$this->query_vars['date_query_sql']}
GROUP BY {$this->query_vars['table']}.product_id, {$this->query_vars['table']}.price_id";
$sql = "SELECT product_id, price_id, {$union_function} AS total
FROM ({$order_items} UNION {$order_adjustments})a
GROUP BY product_id, price_id
ORDER BY total DESC";
} else {
$sql = "SELECT {$function} AS total
FROM {$this->query_vars['table']}
{$join}
WHERE 1=1 {$product_id} {$price_id} {$region} {$country} {$currency} {$this->query_vars['where_sql']} {$this->query_vars['date_query_sql']}";
$order_items = "SELECT
{$order_item_function} AS total
FROM {$this->query_vars['table']}
{$join}
WHERE 1=1
{$product_id}
{$price_id}
{$region}
{$country}
{$currency}
{$this->query_vars['where_sql']}
{$this->query_vars['date_query_sql']}";
$order_adjustments = "SELECT
{$order_adjustment_function} as total
FROM {$this->get_db()->edd_order_adjustments} oadj
INNER JOIN {$this->query_vars['table']} ON
({$this->query_vars['table']}.id = oadj.object_id)
{$product_id}
{$price_id}
{$region}
{$country}
{$currency}
{$adjustments_join}
WHERE oadj.object_type = 'order_item'
AND oadj.type != 'discount'
{$this->query_vars['date_query_sql']}";
$sql = "SELECT {$union_function} AS total FROM ({$order_items} UNION {$order_adjustments})a";
}
$result = $this->get_db()->get_results( $sql );
@ -2788,8 +2880,9 @@ class Stats {
$date_query_sql = ' AND ';
if ( ! empty( $this->query_vars['start'] ) ) {
$start_date = EDD()->utils->date( $this->query_vars['start'], edd_get_timezone_id(), false )->format( 'mysql' );
$date_query_sql .= "{$this->query_vars['table']}.{$this->query_vars['date_query_column']} ";
$date_query_sql .= $this->get_db()->prepare( '>= %s', $this->query_vars['start'] );
$date_query_sql .= $this->get_db()->prepare( '>= %s', $start_date );
}
// Join dates with `AND` if start and end date set.
@ -2798,7 +2891,8 @@ class Stats {
}
if ( ! empty( $this->query_vars['end'] ) ) {
$date_query_sql .= $this->get_db()->prepare( "{$this->query_vars['table']}.{$this->query_vars['date_query_column']} <= %s", $this->query_vars['end'] );
$end_date = EDD()->utils->date( $this->query_vars['end'], edd_get_timezone_id(), false )->format( 'mysql' );
$date_query_sql .= $this->get_db()->prepare( "{$this->query_vars['table']}.{$this->query_vars['date_query_column']} <= %s", $end_date );
}
$this->query_vars['date_query_sql'] = $date_query_sql;
@ -2957,7 +3051,7 @@ class Stats {
*/
private function generate_price_id_query_sql() {
return ! is_null( $this->query_vars['price_id'] ) && is_numeric( $this->query_vars['price_id'] )
? $this->get_db()->prepare( 'AND price_id = %d', absint( $this->query_vars['price_id'] ) )
? $this->get_db()->prepare( "AND {$this->query_vars['table']}.price_id = %d", absint( $this->query_vars['price_id'] ) )
: '';
}

View File

@ -8,9 +8,10 @@
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
* @since 3.0
*/
namespace EDD\Database\Schemas;
// Exit if accessed directly
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;
use EDD\Database\Schema;
@ -30,18 +31,18 @@ final class Adjustments extends Schema {
*/
public $columns = array(
// id
// id.
array(
'name' => 'id',
'type' => 'bigint',
'length' => '20',
'unsigned' => true,
'extra' => 'auto_increment',
'primary' => true,
'sortable' => true
'name' => 'id',
'type' => 'bigint',
'length' => '20',
'unsigned' => true,
'extra' => 'auto_increment',
'primary' => true,
'sortable' => true,
),
// parent
// parent.
array(
'name' => 'parent',
'type' => 'bigint',
@ -49,35 +50,36 @@ final class Adjustments extends Schema {
'unsigned' => true,
'default' => '0',
'sortable' => true,
'transition' => true
'transition' => true,
),
// name
// name.
array(
'name' => 'name',
'type' => 'varchar',
'length' => '200',
'searchable' => true,
'sortable' => true
'sortable' => true,
),
// code
// code.
array(
'name' => 'code',
'type' => 'varchar',
'length' => '50',
'searchable' => true,
'sortable' => true
'sortable' => true,
'cache_key' => true,
),
// status
// status.
array(
'name' => 'status',
'type' => 'varchar',
'length' => '20',
'default' => 'draft',
'sortable' => true,
'transition' => true
'transition' => true,
),
// type
@ -87,124 +89,124 @@ final class Adjustments extends Schema {
'length' => '20',
'default' => '',
'sortable' => true,
'transition' => true
'transition' => true,
),
// scope
// scope.
array(
'name' => 'scope',
'type' => 'varchar',
'length' => '20',
'default' => '',
'sortable' => true,
'transition' => true
'transition' => true,
),
// amount_type
// amount_type.
array(
'name' => 'amount_type',
'type' => 'varchar',
'length' => '20',
'default' => '',
'sortable' => true,
'transition' => true
'transition' => true,
),
// amount
// amount.
array(
'name' => 'amount',
'type' => 'decimal',
'length' => '18,9',
'default' => '0',
'sortable' => true
'name' => 'amount',
'type' => 'decimal',
'length' => '18,9',
'default' => '0',
'sortable' => true,
),
// description
// description.
array(
'name' => 'description',
'type' => 'longtext',
'default' => '',
'searchable' => true
'searchable' => true,
),
// max_uses
// max_uses.
array(
'name' => 'max_uses',
'type' => 'bigint',
'length' => '20',
'unsigned' => true,
'default' => '0'
),
// use_count
array(
'name' => 'use_count',
'type' => 'bigint',
'length' => '20',
'unsigned' => true,
'default' => '0',
'sortable' => true,
),
// once_per_customer
// use_count.
array(
'name' => 'once_per_customer',
'type' => 'int',
'length' => '1',
'default' => '0'
'name' => 'use_count',
'type' => 'bigint',
'length' => '20',
'unsigned' => true,
'default' => '0',
'sortable' => true,
),
// min_charge_amount
// once_per_customer.
array(
'name' => 'min_charge_amount',
'type' => 'decimal',
'length' => '18,9',
'default' => '0'
'name' => 'once_per_customer',
'type' => 'int',
'length' => '1',
'default' => '0',
),
// start_date
// min_charge_amount.
array(
'name' => 'min_charge_amount',
'type' => 'decimal',
'length' => '18,9',
'default' => '0',
),
// start_date.
array(
'name' => 'start_date',
'type' => 'datetime',
'default' => null,
'allow_null' => true,
'date_query' => true,
'sortable' => true
'sortable' => true,
),
// end_date
// end_date.
array(
'name' => 'end_date',
'type' => 'datetime',
'default' => null,
'allow_null' => true,
'date_query' => true,
'sortable' => true
'sortable' => true,
),
// date_created
// date_created.
array(
'name' => 'date_created',
'type' => 'datetime',
'default' => '', // Defaults to current time in query class
'default' => '', // Defaults to current time in query class.
'created' => true,
'date_query' => true,
'sortable' => true
'sortable' => true,
),
// date_modified
// date_modified.
array(
'name' => 'date_modified',
'type' => 'datetime',
'default' => '', // Defaults to current time in query class
'default' => '', // Defaults to current time in query class.
'modified' => true,
'date_query' => true,
'sortable' => true
'sortable' => true,
),
// uuid
// uuid.
array(
'uuid' => true,
)
'uuid' => true,
),
);
}

View File

@ -280,8 +280,12 @@ function get_order_items( $purchase_data ) {
if ( $item_amount <= 0 ) {
$item_amount = 0;
}
$substr_func = function_exists( 'mb_substr' ) ? 'mb_substr' : 'substr';
$name = $substr_func( edd_get_cart_item_name( $item ), 0, 127 );
$items[ $i ] = array(
'name' => stripslashes_deep( html_entity_decode( substr( edd_get_cart_item_name( $item ), 0, 127 ), ENT_COMPAT, 'UTF-8' ) ),
'name' => stripslashes_deep( html_entity_decode( $name, ENT_COMPAT, 'UTF-8' ) ),
'quantity' => $item['quantity'],
'unit_amount' => array(
'currency_code' => edd_get_currency(),

View File

@ -13,6 +13,7 @@
namespace EDD\Gateways\PayPal\IPN;
use EDD\Gateways\PayPal;
/**
* Listens for an IPN call from PayPal
*
@ -25,6 +26,11 @@ function listen_for_ipn() {
return;
}
// If PayPal is not connected, we don't need to run here.
if ( ! PayPal\has_rest_api_connection() ) {
return;
}
ipn_debug_log( 'IPN Backup Loaded' );
// Moving this up in the load order so we can check some things before even getting to verification.
@ -174,7 +180,7 @@ function listen_for_ipn() {
// Bail if this is the very first payment.
if ( date( 'Y-n-d', strtotime( $subscription->created ) ) == date( 'Y-n-d', strtotime( $posted['payment_date'] ) ) ) {
if ( ! empty( $posted['payment_date'] ) && date( 'Y-n-d', strtotime( $subscription->created ) ) == date( 'Y-n-d', strtotime( $posted['payment_date'] ) ) ) {
ipn_debug_log( 'IPN for subscription ' . $subscription->id . ': processing stopped because this is the initial payment.' );
return;
}

File diff suppressed because one or more lines are too long

View File

@ -8,10 +8,19 @@ domReady( () => {
const containerEl = document.getElementById( 'edds-stripe-connect-account' );
const actionsEl = document.getElementById( 'edds-stripe-disconnect-reconnect' );
if ( ! containerEl ) {
return;
}
/*
* Do not make a request, if we are inside Onboarding Wizard.
* Onboarding Wizard will make it's own call.
*/
if ( containerEl.hasAttribute('data-onboarding-wizard') ) {
return;
}
return apiRequest( 'edds_stripe_connect_account_info', {
...containerEl.dataset,
} )

View File

@ -3,8 +3,8 @@
* Plugin Name: Easy Digital Downloads - Stripe Pro Payment Gateway
* Plugin URI: https://easydigitaldownloads.com/downloads/stripe-gateway/
* Description: Adds a payment gateway for Stripe.com
* Version: 2.8.13
* Requires at least: 4.4
* Version: 2.8.13.1
* Requires at least: 4.9
* Requires PHP: 5.6
* Author: Easy Digital Downloads
* Author URI: https://easydigitaldownloads.com
@ -44,7 +44,7 @@ function edd_stripe_core_bootstrap() {
}
if ( ! defined( 'EDD_STRIPE_VERSION' ) ) {
define( 'EDD_STRIPE_VERSION', '2.8.13' );
define( 'EDD_STRIPE_VERSION', '2.8.13.1' );
}
if ( ! defined( 'EDD_STRIPE_API_VERSION' ) ) {

View File

@ -83,27 +83,57 @@ function edds_stripe_connect_url() {
*/
function edds_process_gateway_connect_completion() {
if( ! isset( $_GET['edd_gateway_connect_completion'] ) || 'stripe_connect' !== $_GET['edd_gateway_connect_completion'] || ! isset( $_GET['state'] ) ) {
$redirect_screen = ! empty( $_GET['redirect_screen'] ) ? sanitize_text_field( $_GET['redirect_screen'] ) : '';
// A cancelled connection doesn't contain the completion or state values, but we do need to listen for the redirect_screen for the wizard.
if (
isset( $_GET['edd_gateway_connect_error'] ) &&
filter_var( $_GET['edd_gateway_connect_error'], FILTER_VALIDATE_BOOLEAN ) &&
! empty( $redirect_screen )
) {
$error_redirect = '';
switch ( $redirect_screen ) {
case 'onboarding-wizard':
$error_redirect = admin_url( 'edit.php?post_type=download&page=edd-onboarding-wizard&current_step=payment_methods' );
break;
}
if ( ! empty( $error_redirect ) ) {
wp_safe_redirect( esc_url_raw( $error_redirect ) );
exit;
}
}
if ( ! isset( $_GET['edd_gateway_connect_completion'] ) || 'stripe_connect' !== $_GET['edd_gateway_connect_completion'] || ! isset( $_GET['state'] ) ) {
return;
}
if( ! current_user_can( 'manage_shop_settings' ) ) {
if ( ! current_user_can( 'manage_shop_settings' ) ) {
return;
}
if( headers_sent() ) {
if ( headers_sent() ) {
return;
}
$edd_credentials_url = add_query_arg( array(
'live_mode' => (int) ! edd_is_test_mode(),
'state' => sanitize_text_field( $_GET['state'] ),
'customer_site_url' => admin_url( 'edit.php?post_type=download' ),
), 'https://easydigitaldownloads.com/?edd_gateway_connect_credentials=stripe_connect' );
$customer_site_url = admin_url( 'edit.php?post_type=download' );
if ( ! empty( $redirect_screen ) ) {
$customer_site_url = add_query_arg( 'redirect_screen', $redirect_screen, $customer_site_url );
}
$edd_credentials_url = add_query_arg(
array(
'live_mode' => (int) ! edd_is_test_mode(),
'state' => sanitize_text_field( $_GET['state'] ),
'customer_site_url' => urlencode( $customer_site_url ),
),
'https://easydigitaldownloads.com/?edd_gateway_connect_credentials=stripe_connect'
);
$response = wp_remote_get( esc_url_raw( $edd_credentials_url ) );
if( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
$message = '<p>' . sprintf(
/* translators: %1$s Opening anchor tag, do not translate. %2$s Closing anchor tag, do not translate. */
__( 'There was an error getting your Stripe credentials. Please %1$stry again%2$s. If you continue to have this problem, please contact support.', 'easy-digital-downloads' ),
@ -116,7 +146,7 @@ function edds_process_gateway_connect_completion() {
$data = json_decode( $response['body'], true );
$data = $data['data'];
if( edd_is_test_mode() ) {
if ( edd_is_test_mode() ) {
edd_update_option( 'test_publishable_key', sanitize_text_field( $data['publishable_key'] ) );
edd_update_option( 'test_secret_key', sanitize_text_field( $data['secret_key'] ) );
} else {
@ -125,7 +155,18 @@ function edds_process_gateway_connect_completion() {
}
edd_update_option( 'stripe_connect_account_id', sanitize_text_field( $data['stripe_user_id'] ) );
wp_redirect( esc_url_raw( admin_url( 'edit.php?post_type=download&page=edd-settings&tab=gateways&section=edd-stripe' ) ) );
$redirect_url = admin_url( 'edit.php?post_type=download&page=edd-settings&tab=gateways&section=edd-stripe' );
if ( ! empty( $redirect_screen ) ) {
switch ( $redirect_screen ) {
case 'onboarding-wizard':
$redirect_url = admin_url( 'edit.php?post_type=download&page=edd-onboarding-wizard&current_step=payment_methods' );
break;
}
}
wp_safe_redirect( esc_url_raw( $redirect_url ) );
exit;
}
@ -178,7 +219,7 @@ function edds_stripe_connect_disconnect_url() {
function edds_stripe_connect_process_disconnect() {
// Do not need to handle this request, bail.
if (
! ( isset( $_GET['page'] ) && 'edd-settings' === $_GET['page'] ) ||
! ( isset( $_GET['page'] ) && ( 'edd-settings' === $_GET['page'] || 'edd-onboarding-wizard' === $_GET['page'] ) ) ||
! isset( $_GET['edds-stripe-disconnect'] )
) {
return;
@ -337,7 +378,7 @@ function edds_stripe_connect_setting_field() {
class="edds-stripe-connect-acount-info notice inline"
data-account-id="<?php echo esc_attr( $stripe_connect_account_id ); ?>"
data-nonce="<?php echo wp_create_nonce( 'edds-stripe-connect-account-information' ); ?>"
>
<?php echo ( ! empty( $_GET['page'] ) && 'edd-onboarding-wizard' === $_GET['page'] ) ? ' data-onboarding-wizard="true"' : ''; ?>>
<p><span class="spinner is-active"></span>
<em><?php esc_html_e( 'Retrieving account information...', 'easy-digital-downloads' ); ?></em>
</div>

View File

@ -357,13 +357,21 @@ function edds_add_payment_method() {
}
$stripe_customer_id = edds_get_stripe_customer_id( get_current_user_id() );
$stripe_customer = edds_get_stripe_customer(
$customer_name = '';
if ( ! empty( $edd_customer->name ) ) {
$customer_name = $edd_customer->name;
}
$stripe_customer = edds_get_stripe_customer(
$stripe_customer_id,
array(
'email' => $edd_customer->email,
'description' => $edd_customer->email,
'name' => $customer_name,
)
);
if ( false === $stripe_customer ) {
wp_send_json_error(
array(

View File

@ -88,7 +88,7 @@ function edds_has_met_requirements( $requirement = false ) {
: true
),
'wp' => (
version_compare( get_bloginfo( 'version' ), '4.4', '>=' )
version_compare( get_bloginfo( 'version' ), '4.9', '>=' )
),
);

View File

@ -1175,10 +1175,22 @@ function edds_checkout_setup_customer( $purchase_data ) {
// No customer ID found, let's look one up based on the email.
$stripe_customer_id = edds_get_stripe_customer_id( $purchase_data['user_email'], false );
}
$customer_name = '';
if ( ! empty( $purchase_data['user_info']['first_name'] ) ) {
$customer_name .= sanitize_text_field( $purchase_data['user_info']['first_name'] );
}
if ( ! empty( $purchase_data['user_info']['last_name'] ) ) {
$customer_name .= ' ' . sanitize_text_field( $purchase_data['user_info']['last_name'] );
}
$customer_args = array(
'email' => $purchase_data['user_email'],
'description' => $purchase_data['user_email'],
'name' => $customer_name,
);
/**
* Filters the arguments used to create a Customer in Stripe.
*

View File

@ -32,10 +32,9 @@ function edds_buy_now_modal() {
edd_localize_scripts();
} else {
edd_load_scripts();
edd_agree_to_terms_js();
}
edd_agree_to_terms_js();
remove_filter( 'edd_is_checkout', '__return_true' );
// Enqueue scripts.

View File

@ -42,6 +42,9 @@ namespace Composer\Autoload;
*/
class ClassLoader
{
/** @var \Closure(string):void */
private static $includeFile;
/** @var ?string */
private $vendorDir;
@ -106,6 +109,7 @@ class ClassLoader
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
}
/**
@ -425,7 +429,7 @@ class ClassLoader
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
(self::$includeFile)($file);
return true;
}
@ -555,18 +559,23 @@ class ClassLoader
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
* @private
*/
function includeFile($file)
{
include $file;
private static function initializeIncludeClosure(): void
{
if (self::$includeFile !== null) {
return;
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
*/
self::$includeFile = static function($file) {
include $file;
};
}
}

View File

@ -3,7 +3,7 @@
'name' => 'easy-digital-downloads/edd-stripe',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '829e436e3e0b91ab69528aebcee3344aa2e91eca',
'reference' => '24964d034941e0d3d07390ecc39570bfc64e7369',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@ -13,7 +13,7 @@
'easy-digital-downloads/edd-stripe' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '829e436e3e0b91ab69528aebcee3344aa2e91eca',
'reference' => '24964d034941e0d3d07390ecc39570bfc64e7369',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),

View File

@ -187,6 +187,7 @@ class Download {
"SELECT SUM((oa.total - oa.tax)/ oa.rate) as revenue
FROM {$wpdb->edd_order_adjustments} oa
INNER JOIN {$wpdb->edd_order_items} oi ON(oi.id = oa.object_id)
INNER JOIN {$wpdb->edd_orders} o ON oi.order_id = o.id AND o.type = 'sale' {$order_status_sql}
WHERE {$product_id_sql}
{$price_id_sql}
AND oa.object_type = 'order_item'
@ -194,7 +195,9 @@ class Download {
AND oi.status IN('complete','partially_refunded')
{$date_query_sql}";
$results = $wpdb->get_row( "SELECT SUM(revenue) AS revenue FROM ({$order_items} UNION {$order_adjustments})a" );
$sql = "SELECT SUM(revenue) AS revenue FROM ({$order_items} UNION {$order_adjustments})a";
$results = $wpdb->get_row( $sql );
return ! empty( $results->revenue ) ? $results->revenue : 0.00;
}

View File

@ -164,4 +164,13 @@ class Order_Adjustment extends \EDD\Database\Rows\Order_Adjustment {
'parent' => $this->id
) );
}
/**
* Backwards compatibility for the `amount` property, which is now the `total`.
*
* @since 3.1.0.4
*/
public function get_amount() {
return $this->total;
}
}

View File

@ -234,6 +234,7 @@ 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
* @since 3.1.0.4 This also verifies that all order items have the synced status as the order.
* @param $payment_id
* @param $force
*/
@ -248,6 +249,31 @@ function edd_process_after_payment_actions( $payment_id = 0, $force = false ) {
return;
}
/**
* In the event that during the order completion process, a timeout happens,
* ensure that all the order items have the correct status, to match the order itself.
*
* @see https://github.com/awesomemotive/easy-digital-downloads-pro/issues/77
*/
$order_items = edd_get_order_items(
array(
'order_id' => $payment_id,
'status__not_in' => edd_get_deliverable_order_item_statuses(),
'number' => 200,
)
);
if ( ! empty( $order_items ) ) {
foreach ( $order_items as $order_item ) {
edd_update_order_item(
$order_item->id,
array(
'status' => $payment->status,
)
);
}
}
$payment->add_note( __( 'After payment actions processed.', 'easy-digital-downloads' ) );
$payment->update_meta( '_edd_complete_actions_run', time() ); // This is in GMT

View File

@ -3098,7 +3098,7 @@ class EDD_Payment {
}
$item_fees[ $id ] = array(
'amount' => $item_fee->amount,
'amount' => $item_fee->total,
'label' => $item_fee->description,
'no_tax' => $no_tax ? $no_tax : false,
'type' => 'fee',

View File

@ -527,22 +527,22 @@ class EDD_Payments_Query extends EDD_Stats {
$order_ids = array();
if ( is_array( $this->args['download'] ) ) {
$orders = edd_get_order_items( array(
$order_items = 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;
foreach ( $order_items as $order_item ) {
/** @var $order_item EDD\Orders\Order_Item */
$order_ids[] = $order_item->order_id;
}
} else {
$orders = edd_get_order_items( array(
$order_items = edd_get_order_items( array(
'product_id' => $this->args['download'],
) );
foreach ( $orders as $order ) {
/** @var $order EDD\Orders\Order_Item */
$order_ids[] = $order->id;
foreach ( $order_items as $order_item ) {
/** @var $order_item EDD\Orders\Order_Item */
$order_ids[] = $order_item->order_id;
}
}

View File

@ -1249,7 +1249,7 @@ function edd_get_payment_amount( $order_id = 0 ) {
// Bail if nothing was passed.
if ( empty( $order_id ) ) {
return '';
return 0.00;
}
$order = edd_get_order( $order_id );

View File

@ -15,6 +15,7 @@ defined( 'ABSPATH' ) || exit;
use EDD\Reports as Reports;
use EDD\Admin\List_Table;
use EDD\Stats as Stats;
/**
* Earnings_By_Taxonomy_List_Table class.
@ -34,27 +35,8 @@ class Earnings_By_Taxonomy_List_Table extends List_Table {
global $wpdb;
$dates = Reports\get_filter_value( 'dates' );
$date_range = Reports\parse_dates_for_range( $dates['range'] );
$currency = Reports\get_filter_value( 'currencies' );
// Generate date query SQL if dates have been set.
$date_query_sql = '';
if ( ! empty( $date_range['start'] ) || ! empty( $date_range['end'] ) ) {
if ( ! empty( $date_range['start'] ) ) {
$date_query_sql .= $wpdb->prepare( 'AND oi.date_created >= %s', $date_range['start']->format( 'mysql' ) );
}
// Join dates with `AND` if start and end date set.
if ( ! empty( $date_range['start'] ) && ! empty( $date_range['end'] ) ) {
$date_query_sql .= ' AND ';
}
if ( ! empty( $date_range['end'] ) ) {
$date_query_sql .= $wpdb->prepare( 'oi.date_created <= %s', $date_range['end']->format( 'mysql' ) );
}
}
$taxonomies = edd_get_download_taxonomies();
$taxonomies = array_map( 'sanitize_text_field', $taxonomies );
@ -78,64 +60,56 @@ class Earnings_By_Taxonomy_List_Table extends List_Table {
$taxonomies[ absint( $r->term_id ) ]['parent'] = absint( $r->parent );
}
$data = array();
$parent_ids = array();
// Setup an empty array for the final returned data.
$data = array();
$column = Reports\get_taxes_excluded_filter() ? 'oi.total - oi.tax' : 'oi.total';
$join = " INNER JOIN {$wpdb->edd_orders} o ON o.id = oi.order_id ";
$currency_clause = '';
if ( empty( $currency ) || 'convert' === $currency ) {
$column = sprintf( '(%s) / oi.rate', $column );
} elseif ( array_key_exists( strtoupper( $currency ), edd_get_currencies() ) ) {
$currency_clause = $wpdb->prepare(
" AND o.currency = %s ",
strtoupper( $currency )
);
}
$statuses = edd_get_net_order_statuses();
$status_string = implode( ', ', array_fill( 0, count( $statuses ), '%s' ) );
$status_sql = $wpdb->prepare(
" AND oi.status IN('complete','partially_refunded')
AND o.status IN({$status_string})",
...$statuses
);
// Store each download's stats during the loop to avoid double queries.
$download_stats = array();
foreach ( $taxonomies as $k => $t ) {
$c = new \stdClass();
$c->id = $k;
$c->name = $taxonomies[ $k ]['name'];
$placeholders = implode( ', ', array_fill( 0, count( $taxonomies[ $k ]['object_ids'] ), '%d' ) );
$product_id__in = $wpdb->prepare( "oi.product_id IN({$placeholders})", $taxonomies[ $k ]['object_ids'] );
$earnings = 0.00;
$sales = 0;
$sql = "SELECT SUM({$column}) as total
FROM {$wpdb->edd_order_items} oi
{$join}
WHERE {$product_id__in} {$currency_clause} {$date_query_sql} {$status_sql}";
$average_earnings = 0.00;
$average_sales = 0;
$result = $wpdb->get_row( $sql ); // WPCS: unprepared SQL ok.
foreach ( $taxonomies[ $k ]['object_ids'] as $download_id ) {
if ( ! isset( $download_stats[ $download_id ] ) ) {
$stats = new Stats(
array(
'product_id' => absint( $download_id ),
'currency' => $currency,
'range' => $dates['range'],
'output' => 'typed',
)
);
$earnings = null === $result && null === $result->total
? 0.00
: floatval( $result->total );
$download_stats[ $download_id ]['earnings'] = $stats->get_order_item_earnings(
array(
'function' => 'SUM',
)
);
$complete_orders = "SELECT SUM(oi.quantity) as sales
FROM {$wpdb->edd_order_items} oi
{$join}
WHERE {$product_id__in} {$currency_clause} {$date_query_sql} {$status_sql}";
$partial_orders = "SELECT SUM(oi.quantity) as sales
FROM {$wpdb->edd_order_items} oi
LEFT JOIN {$wpdb->edd_order_items} ri
ON ri.parent = oi.id
{$join}
WHERE {$product_id__in} {$currency_clause} {$date_query_sql}
AND oi.status ='partially_refunded'
AND oi.quantity = - ri.quantity";
$sql_sales = $wpdb->get_row( "SELECT SUM(sales) AS sales FROM ({$complete_orders} UNION {$partial_orders})a" );
$download_stats[ $download_id ]['sales'] = $stats->get_order_item_count(
array(
'function' => 'COUNT',
)
);
$sales = ! empty( $sql_sales->sales ) ? $sql_sales->sales : 0;
$download_stats[ $download_id ]['average_earnings'] = edd_get_average_monthly_download_earnings( $download_id );
$download_stats[ $download_id ]['average_sales'] = edd_get_average_monthly_download_sales( $download_id );
}
$earnings += $download_stats[ $download_id ]['earnings'];
$sales += $download_stats[ $download_id ]['sales'];
$average_earnings += $download_stats[ $download_id ]['average_earnings'];
$average_sales += $download_stats[ $download_id ]['average_sales'];
}
$c->sales = $sales;
$c->earnings = $earnings;
@ -143,14 +117,6 @@ class Earnings_By_Taxonomy_List_Table extends List_Table {
? null
: $t['parent'];
$average_sales = 0;
$average_earnings = 0.00;
foreach ( $taxonomies[ $k ]['object_ids'] as $download ) {
$average_sales += edd_get_average_monthly_download_sales( $download );
$average_earnings += edd_get_average_monthly_download_earnings( $download );
}
$c->average_sales = $average_sales;
$c->average_earnings = $average_earnings;
@ -161,7 +127,7 @@ class Earnings_By_Taxonomy_List_Table extends List_Table {
foreach ( $data as $d ) {
// Get parent level elements
// Get parent level elements.
if ( null === $d->parent ) {
$sorted_data[] = $d;
@ -173,7 +139,7 @@ class Earnings_By_Taxonomy_List_Table extends List_Table {
}
}
// Sort by total earnings
// Sort by total earnings.
usort( $sorted_data, function( $a, $b ) {
return ( $a->earnings < $b->earnings ) ? -1 : 1;
} );

View File

@ -229,7 +229,7 @@ function edd_get_purchase_link( $args = array() ) {
<?php } ?>
<?php if( apply_filters( 'edd_download_redirect_to_checkout', edd_straight_to_checkout(), $download->ID, $args ) ) : ?>
<input type="hidden" name="edd_redirect_to_checkout" id="edd_redirect_to_checkout" value="1">
<input type="hidden" name="edd_redirect_to_checkout" value="1">
<?php endif; ?>
<?php do_action( 'edd_purchase_link_end', $download->ID, $args ); ?>

View File

@ -30,13 +30,24 @@ class NotificationImporter {
* @since 2.11.4
*/
public function run() {
$request_timeout = get_option( 'edd_notification_req_timeout', false );
if ( false !== $request_timeout && current_time( 'timestamp' ) < $request_timeout ) {
edd_debug_log( 'Skipping notifications API request, timeout not reached' );
return;
}
edd_debug_log( 'Fetching notifications via ' . $this->getApiEndpoint() );
try {
$notifications = $this->fetchNotifications();
// If successful, make it so we don't request for another 23 hours.
update_option( 'edd_notification_req_timeout', current_time( 'timestamp' ) + ( HOUR_IN_SECONDS * 23 ), false );
} catch ( \Exception $e ) {
edd_debug_log( sprintf( 'Notification fetch exception: %s', $e->getMessage() ) );
// If for some reason our request failed, delay for 4 hours.
update_option( 'edd_notification_req_timeout', current_time( 'timestamp' ) + ( HOUR_IN_SECONDS * 4 ), false );
return;
}