updated plugin `Easy Digital Downloads` version 3.1.1.4.2

This commit is contained in:
KawaiiPunk 2023-06-05 11:21:17 +00:00 committed by Gitium
parent e5482aabb7
commit b7bbe6d733
105 changed files with 3161 additions and 1326 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
!function(e){var t={};function a(n){if(t[n])return t[n].exports;var i=t[n]={i:n,l:!1,exports:{}};return e[n].call(i.exports,i,i.exports,a),i.l=!0,i.exports}a.m=e,a.c=t,a.d=function(e,t,n){a.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,t){if(1&t&&(e=a(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(a.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)a.d(n,i,function(t){return e[t]}.bind(null,i));return n},a.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(t,"a",t),t},a.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},a.p="",a(a.s=229)}({1:function(e,t){e.exports=jQuery},229:function(e,t,a){(function(e){!function(e,t){"use strict";t("p.submit").remove(),t(".edd-license__control").on("click",".edd-license__action",(function(e){e.preventDefault();var a=t(this),n=a.attr("data-action"),i="",r=a.text(),d=t(this).closest(".edd-license__control"),s=d.find("input");if(!a.attr("disabled")){switch(n){case"activate":i="edd_activate_extension_license",a.text(EDDLicenseHandler.activating);break;case"deactivate":i="edd_deactivate_extension_license",a.text(EDDLicenseHandler.deactivating);break;default:return}a.removeClass("button-primary").attr("disabled",!0).addClass("updating-message");var o={action:i,token:a.attr("data-token"),timestamp:a.attr("data-timestamp"),nonce:a.attr("data-nonce"),license:s.val(),item_id:s.attr("data-item"),item_name:s.attr("data-name"),key:s.attr("data-key")};t.post(ajaxurl,o).done((function(e){console.log(e),a.text(r);var t=d.next(".edd-license-data");e.success?(e.data.actions&&d.find(".edd-licensing__actions").replaceWith(e.data.actions),e.data.message&&("deactivate"===n?t.find("p").replaceWith(e.data.message):t.replaceWith(e.data.message)),o.license.length&&"activate"===n?s.attr("readonly",!0):s.attr("readonly",!1)):t.find("p").replaceWith(e.data.message),a.attr("disabled",!1).removeClass("updating-message")}))}})),t(".edd-license__control").on("click",".edd-license__delete",(function(e){e.preventDefault();var a=t(this),n=t(this).closest(".edd-license__control"),i=n.find("input"),r={action:"edd_delete_extension_license",token:a.attr("data-token"),timestamp:a.attr("data-timestamp"),nonce:a.attr("data-nonce"),license:i.val(),item_name:i.attr("data-name")};a.attr("disabled",!0).addClass("updating-message"),i.val(""),t.post(ajaxurl,r).done((function(e){e.success&&a.hide(),n.next(".edd-license-data").find("p").replaceWith(e.data.message),a.attr("disabled",!1).removeClass("updating-message")}))}))}(document,e)}).call(this,a(1))}});
!function(e){var t={};function a(n){if(t[n])return t[n].exports;var i=t[n]={i:n,l:!1,exports:{}};return e[n].call(i.exports,i,i.exports,a),i.l=!0,i.exports}a.m=e,a.c=t,a.d=function(e,t,n){a.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,t){if(1&t&&(e=a(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(a.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)a.d(n,i,function(t){return e[t]}.bind(null,i));return n},a.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(t,"a",t),t},a.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},a.p="",a(a.s=229)}({1:function(e,t){e.exports=jQuery},229:function(e,t,a){(function(e){!function(e,t){"use strict";t("p.submit").remove(),t(".edd-license__control").on("click",".edd-license__action",(function(e){e.preventDefault();var a=t(this),n=a.attr("data-action"),i="",r=a.text(),d=t(this).closest(".edd-license__control"),s=d.find('input[type="password"]'),o=d.find('input[name="apiurl"]');if(!a.attr("disabled")){switch(n){case"activate":i="edd_activate_extension_license",a.text(EDDLicenseHandler.activating);break;case"deactivate":i="edd_deactivate_extension_license",a.text(EDDLicenseHandler.deactivating);break;default:return}a.removeClass("button-primary").attr("disabled",!0).addClass("updating-message");var c={action:i,token:a.attr("data-token"),timestamp:a.attr("data-timestamp"),nonce:a.attr("data-nonce"),license:s.val(),item_id:s.attr("data-item"),item_name:s.attr("data-name"),key:s.attr("data-key"),api:o.val()};t.post(ajaxurl,c).done((function(e){console.log(e),a.text(r);var t=d.next(".edd-license-data");e.success?(e.data.actions&&d.find(".edd-licensing__actions").replaceWith(e.data.actions),e.data.message&&("deactivate"===n?t.find("p").replaceWith(e.data.message):t.replaceWith(e.data.message)),c.license.length&&"activate"===n?s.attr("readonly",!0):s.attr("readonly",!1)):t.find("p").replaceWith(e.data.message),a.attr("disabled",!1).removeClass("updating-message")}))}})),t(".edd-license__control").on("click",".edd-license__delete",(function(e){e.preventDefault();var a=t(this),n=t(this).closest(".edd-license__control"),i=n.find("input"),r={action:"edd_delete_extension_license",token:a.attr("data-token"),timestamp:a.attr("data-timestamp"),nonce:a.attr("data-nonce"),license:i.val(),item_name:i.attr("data-name")};a.attr("disabled",!0).addClass("updating-message"),i.val(""),t.post(ajaxurl,r).done((function(e){e.success&&a.hide(),n.next(".edd-license-data").find("p").replaceWith(e.data.message),a.attr("disabled",!1).removeClass("updating-message")}))}))}(document,e)}).call(this,a(1))}});

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,7 @@
* Description: The easiest way to sell digital products with WordPress.
* Author: Easy Digital Downloads
* Author URI: https://easydigitaldownloads.com
* Version: 3.1.1.3
* Version: 3.1.1.4.2
* Text Domain: easy-digital-downloads
* Domain Path: /languages
* Requires at least: 5.4
@ -27,7 +27,7 @@
* @package EDD
* @category Core
* @author Easy Digital Downloads
* @version 3.1.1.3
* @version 3.1.1.4.2
*/
// Exit if accessed directly.

View File

@ -282,3 +282,35 @@ function edd_add_extentions_link() {
} );
}
}
/**
* Process bulk edit actions via AJAX
*
* @deprecated 3.1.1.4
* @since 1.4.4
* @return void
*/
function edd_save_bulk_edit() {
$post_ids = ! empty( $_POST['post_ids'] )
? wp_parse_id_list( $_POST['post_ids'] )
: array();
if ( ! empty( $post_ids ) && is_array( $post_ids ) ) {
$price = isset( $_POST['price'] )
? strip_tags( stripslashes( $_POST['price'] ) )
: 0;
foreach ( $post_ids as $post_id ) {
if ( ! current_user_can( 'edit_post', $post_id ) ) {
continue;
}
if ( ! empty( $price ) ) {
update_post_meta( $post_id, 'edd_price', edd_sanitize_amount( $price ) );
}
}
}
die();
}

View File

@ -51,6 +51,11 @@ class EDD_Notices {
*/
public function add_notice( $args = array() ) {
// Avoid malformed notices variable
if ( ! is_array( $this->notices ) ) {
$this->notices = array();
}
// Parse args
$r = wp_parse_args( $args, array(
'id' => '',
@ -59,6 +64,11 @@ class EDD_Notices {
'is_dismissible' => true,
) );
// Prevent a notice from being added more than once.
if ( ! empty( $r['id'] ) && array_key_exists( $r['id'], $this->notices ) ) {
return;
}
$default_class = 'updated';
// One message as string
@ -93,9 +103,10 @@ class EDD_Notices {
}
// CSS Classes
$classes = ! empty( $r['class'] )
? array( $r['class'] )
: array( $default_class );
$classes = array( $default_class );
if ( ! empty( $r['class'] ) ) {
$classes = explode( ' ', $r['class'] );
}
// Add dismissible class
if ( ! empty( $r['is_dismissible'] ) ) {
@ -106,13 +117,8 @@ class EDD_Notices {
$message = '<div class="notice ' . implode( ' ', array_map( 'sanitize_html_class', $classes ) ) . '">' . $message . '</div>';
$message = str_replace( "'", "\'", $message );
// Avoid malformed notices variable
if ( ! is_array( $this->notices ) ) {
$this->notices = array();
}
// Add notice to notices array
$this->notices[] = $message;
$this->notices[ $r['id'] ] = $message;
}
/**

View File

@ -48,7 +48,8 @@ function edd_admin_add_discount( $data = array() ) {
edd_redirect( add_query_arg( 'edd-message', 'discount_invalid_code' ) );
}
if ( ! is_numeric( $data['amount'] ) ) {
$sanitized_amount = (float) edd_sanitize_amount( $data['amount'] );
if ( empty( $data['amount'] ) || 0.00 === $sanitized_amount ) {
edd_redirect( add_query_arg( 'edd-message', 'discount_invalid_amount' ) );
}
@ -73,6 +74,10 @@ function edd_admin_add_discount( $data = array() ) {
$to_add[ $column ] = $value;
break;
case 'amount':
$to_add['amount'] = edd_sanitize_amount( $value );
break;
default:
$to_add[ $column ] = is_array( $value )
? array_map( 'sanitize_text_field', $value )
@ -180,7 +185,8 @@ function edd_admin_edit_discount( $data = array() ) {
wp_die( __( 'Invalid discount', 'easy-digital-downloads' ), __( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) );
}
if ( empty( $data['amount'] ) || ! is_numeric( $data['amount'] ) ) {
$sanitized_amount = (float) edd_sanitize_amount( $data['amount'] );
if ( empty( $data['amount'] ) || 0.00 === $sanitized_amount ) {
edd_redirect( add_query_arg( 'edd-message', 'discount_invalid_amount' ) );
}
@ -203,7 +209,11 @@ function edd_admin_edit_discount( $data = array() ) {
$to_update['id'] = $value;
break;
default :
case 'amount':
$to_update['amount'] = edd_sanitize_amount( $value );
break;
default:
$to_update[ $column ] = sanitize_text_field( $value );
break;
}

View File

@ -346,7 +346,11 @@ add_action( 'bulk_edit_custom_box', 'edd_price_field_quick_edit', 10, 2 );
* @return void
*/
function edd_price_save_quick_edit( $post_id ) {
if ( ! isset( $_POST['post_type']) || 'download' !== $_POST['post_type'] ) {
if ( ! isset( $_REQUEST['_edd_regprice'] ) ) {
return;
}
if ( ! isset( $_REQUEST['post_type'] ) || 'download' !== $_REQUEST['post_type'] ) {
return;
}
@ -358,40 +362,6 @@ function edd_price_save_quick_edit( $post_id ) {
return $post_id;
}
if ( isset( $_REQUEST['_edd_regprice'] ) ) {
update_post_meta( $post_id, 'edd_price', strip_tags( stripslashes( $_REQUEST['_edd_regprice'] ) ) );
}
update_post_meta( $post_id, 'edd_price', wp_strip_all_tags( stripslashes( $_REQUEST['_edd_regprice'] ) ) );
}
add_action( 'save_post', 'edd_price_save_quick_edit' );
/**
* Process bulk edit actions via AJAX
*
* @since 1.4.4
* @return void
*/
function edd_save_bulk_edit() {
$post_ids = ! empty( $_POST['post_ids'] )
? wp_parse_id_list( $_POST['post_ids'] )
: array();
if ( ! empty( $post_ids ) && is_array( $post_ids ) ) {
$price = isset( $_POST['price'] )
? strip_tags( stripslashes( $_POST['price'] ) )
: 0;
foreach ( $post_ids as $post_id ) {
if ( ! current_user_can( 'edit_post', $post_id ) ) {
continue;
}
if ( ! empty( $price ) ) {
update_post_meta( $post_id, 'edd_price', edd_sanitize_amount( $price ) );
}
}
}
die();
}
add_action( 'wp_ajax_edd_save_bulk_edit', 'edd_save_bulk_edit' );

View File

@ -162,15 +162,6 @@ function edd_update_payment_details( $data = array() ) {
$previous_customer->remove_payment( $order_id, false );
$customer->attach_payment( $order_id, false );
// If purchase was completed and not ever refunded, adjust stats of customers
if ( 'revoked' === $new_status || 'complete' === $new_status ) {
$previous_customer->recalculate_stats();
if ( ! empty( $customer ) ) {
$customer->recalculate_stats();
}
}
$order_update_args['customer_id'] = $customer->id;
}

View File

@ -978,6 +978,14 @@ class EDD_Payment_History_Table extends List_Table {
*/
private function parse_search( $search, $args ) {
// Order ID/number.
if ( is_numeric( $search ) ) {
$args['id'] = $search;
$args['order_number'] = $search;
return $args;
}
// Transaction ID
if ( is_string( $search ) && ( false !== strpos( $search, 'txn:' ) ) ) {
$args['txn'] = trim( str_replace( 'txn:', '', $search ) );
@ -999,13 +1007,6 @@ class EDD_Payment_History_Table extends List_Table {
return $args;
}
// Order ID
if ( is_numeric( $search ) ) {
$args['id'] = $search;
return $args;
}
// The customers name or ID prefixed by customer:
if ( ! is_array( $search ) && ( false !== strpos( $search, 'customer:' ) ) ) {
$search = trim( str_replace( 'customer:', '', $search ) );

View File

@ -92,13 +92,13 @@ function edd_payments_contextual_help() {
) );
$screen->add_help_tab( array(
'id' => 'edd-payments-search',
'title' => __( 'Search', 'easy-digital-downloads' ),
'content' =>
'id' => 'edd-payments-search',
'title' => __( 'Search', 'easy-digital-downloads' ),
'content' =>
'<p>' . __( 'The order history can be searched in several different ways.', 'easy-digital-downloads' ) . '</p>' .
'<p>' . __( 'You can enter:', 'easy-digital-downloads' ) . '</p>' .
'<ul>
<li>' . __( 'The order ID', 'easy-digital-downloads' ) . '</li>
<li>' . __( 'The specific order ID', 'easy-digital-downloads' ) . '</li>
<li>' . __( 'The 32-character order key', 'easy-digital-downloads' ) . '</li>
<li>' . __( 'The customer\'s email address', 'easy-digital-downloads' ) . '</li>
<li>' . sprintf(

View File

@ -28,6 +28,14 @@ class EDD_Batch_Sales_Export extends EDD_Batch_Export {
*/
public $export_type = 'sales';
/**
* The array of order IDs.
*
* @since 3.1.1.4
* @var array
*/
private $orders;
/**
* Set the CSV columns
*
@ -61,20 +69,15 @@ class EDD_Batch_Sales_Export extends EDD_Batch_Export {
public function get_data() {
$data = array();
$args = array(
'number' => 30,
'offset' => ( $this->step * 30 ) - 30,
'order' => 'ASC',
$args = array_merge(
$this->get_order_item_args(),
array(
'number' => 30,
'offset' => ( $this->step * 30 ) - 30,
'order' => 'ASC',
)
);
if ( ! empty( $this->start ) || ! empty( $this->end ) ) {
$args['date_query'] = $this->get_date_query();
}
if ( 0 !== $this->download_id ) {
$args['product_id'] = $this->download_id;
}
$items = edd_get_order_items( $args );
foreach ( $items as $item ) {
@ -112,16 +115,7 @@ class EDD_Batch_Sales_Export extends EDD_Batch_Export {
* @return int
*/
public function get_percentage_complete() {
$args = array();
if ( ! empty( $this->start ) || ! empty( $this->end ) ) {
$args['date_query'] = $this->get_date_query();
}
if ( 0 !== $this->download_id ) {
$args['product_id'] = $this->download_id;
}
$args = $this->get_order_item_args();
$total = edd_count_order_items( $args );
$percentage = 100;
@ -136,9 +130,52 @@ class EDD_Batch_Sales_Export extends EDD_Batch_Export {
return $percentage;
}
/**
* Gets the default order item parameters based on the class properties.
*
* @since 3.1.1.4
* @return array
*/
private function get_order_item_args() {
$args = array();
if ( ! empty( $this->start ) || ! empty( $this->end ) ) {
$args['date_query'] = $this->get_date_query();
}
if ( ! empty( $this->download_id ) ) {
$args['product_id'] = $this->download_id;
}
if ( ! empty( $this->orders ) ) {
$args['order_id__in'] = $this->orders;
}
return $args;
}
public function set_properties( $request ) {
$this->start = isset( $request['orders-export-start'] ) ? sanitize_text_field( $request['orders-export-start'] ) : '';
$this->end = isset( $request['orders-export-end'] ) ? sanitize_text_field( $request['orders-export-end'] ) . ' 23:59:59' : '';
$this->start = isset( $request['sales-export-start'] ) ? sanitize_text_field( $request['sales-export-start'] ) : '';
$this->end = isset( $request['sales-export-end'] ) ? sanitize_text_field( $request['sales-export-end'] ) . ' 23:59:59' : '';
$this->download_id = isset( $request['download_id'] ) ? absint( $request['download_id'] ) : 0;
$this->orders = $this->get_orders();
}
/**
* Gets the array of complete order IDs for the time period.
*
* @return array
*/
private function get_orders() {
$args = array(
'fields' => 'ids',
'type' => 'sale',
'number' => 999999999,
'status__in' => edd_get_complete_order_statuses(),
);
if ( ! empty( $this->start ) || ! empty( $this->end ) ) {
$args['date_query'] = $this->get_date_query();
}
return edd_get_orders( $args );
}
}

View File

@ -328,13 +328,23 @@ class EDD_Batch_Export extends EDD_Export {
* @return array
*/
protected function get_date_query() {
return array(
array(
'after' => $this->start ? date( 'Y-m-d 00:00:00', strtotime( $this->start ) ) : '',
'before' => $this->end ? date( 'Y-m-d 23:59:59', strtotime( $this->end ) ) : '',
'inclusive' => true,
),
$time_zone = edd_get_timezone_id();
$date_query = array(
'after' => '',
'before' => '',
'inclusive' => true,
);
}
if ( $this->start ) {
$date = edd_get_utc_equivalent_date( EDD()->utils->date( $this->start . '00:00:00', $time_zone, false ) );
$date_query['after'] = $date->format( 'Y-m-d H:i:s' );
}
if ( $this->end ) {
$date = edd_get_utc_equivalent_date( EDD()->utils->date( $this->end . '23:59:59', $time_zone, false ) );
$date_query['before'] = $date->format( 'Y-m-d H:i:s' );
}
return array( $date_query );
}
}

View File

@ -23,37 +23,17 @@ defined( 'ABSPATH' ) || exit;
function edd_overview_sales_earnings_chart() {
global $wpdb;
$dates = Reports\get_dates_filter( 'objects' );
$chart_dates = Reports\parse_dates_for_range( null, 'now', false );
$day_by_day = Reports\get_dates_filter_day_by_day();
$hour_by_hour = Reports\get_dates_filter_hour_by_hour();
$column = Reports\get_taxes_excluded_filter() ? '(total - tax)' : 'total';
$currency = Reports\get_filter_value( 'currencies' );
$dates = Reports\get_dates_filter( 'objects' );
$chart_dates = Reports\parse_dates_for_range( null, 'now', false );
$column = Reports\get_taxes_excluded_filter() ? '(total - tax)' : 'total';
$currency = Reports\get_filter_value( 'currencies' );
$period = Reports\get_graph_period();
if ( empty( $currency ) || 'convert' === $currency ) {
$column .= ' / rate';
}
$sql_clauses = array(
'select' => 'DATE_FORMAT(date_created, "%%Y-%%m") AS date',
'where' => '',
'groupby' => '',
);
// Default to 'monthly'.
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'MONTH', 'date_created' );
$sql_clauses['orderby'] = 'MONTH(date_created)';
// Now drill down to the smallest unit.
if ( $hour_by_hour ) {
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'HOUR', 'date_created' );
$sql_clauses['orderby'] = 'HOUR(date_created)';
$sql_clauses['select'] = 'DATE_FORMAT(date_created, "%%Y-%%m-%%d %%H:00:00") AS date';
} elseif ( $day_by_day ) {
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'DATE', 'date_created' );
$sql_clauses['orderby'] = 'DATE(date_created)';
$sql_clauses['select'] = 'DATE_FORMAT(date_created, "%%Y-%%m-%%d") AS date';
}
$sql_clauses = Reports\get_sql_clauses( $period );
if ( ! empty( $currency ) && array_key_exists( strtoupper( $currency ), edd_get_currencies() ) ) {
$sql_clauses['where'] = $wpdb->prepare( " AND currency = %s ", strtoupper( $currency ) );
@ -86,7 +66,7 @@ function edd_overview_sales_earnings_chart() {
$sales_results = $wpdb->get_results(
$wpdb->prepare(
"SELECT COUNT(id) AS sales, {$sql_clauses['select']}
"SELECT COUNT(*) AS sales, {$sql_clauses['select']}
FROM {$wpdb->edd_orders} edd_o
WHERE date_created >= %s AND date_created <= %s
AND status IN( {$statuses} )
@ -122,14 +102,13 @@ function edd_overview_sales_earnings_chart() {
$date_of_db_value = EDD()->utils->date( $earnings_result->date );
// Add any sales/earnings that happened during this hour.
if ( $hour_by_hour ) {
$date_of_db_value = edd_get_edd_timezone_equivalent_date_from_utc( $date_of_db_value );
if ( 'hour' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d H' ) === $date_on_chart->format( 'Y-m-d H' ) ) {
$earnings[ $timestamp ][1] += $earnings_result->earnings;
}
// Add any sales/earnings that happened during this day.
} elseif ( $day_by_day ) {
} elseif ( 'day' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d' ) === $date_on_chart->format( 'Y-m-d' ) ) {
$earnings[ $timestamp ][1] += $earnings_result->earnings;
@ -148,14 +127,13 @@ function edd_overview_sales_earnings_chart() {
$date_of_db_value = EDD()->utils->date( $sales_result->date );
// Add any sales/earnings that happened during this hour.
if ( $hour_by_hour ) {
$date_of_db_value = edd_get_edd_timezone_equivalent_date_from_utc( $date_of_db_value );
if ( 'hour' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d H' ) === $date_on_chart->format( 'Y-m-d H' ) ) {
$sales[ $timestamp ][1] += $sales_result->sales;
}
// Add any sales/earnings that happened during this day.
} elseif ( $day_by_day ) {
} elseif ( 'day' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d' ) === $date_on_chart->format( 'Y-m-d' ) ) {
$sales[ $timestamp ][1] += $sales_result->sales;
@ -170,9 +148,9 @@ function edd_overview_sales_earnings_chart() {
}
// Move the chart along to the next hour/day/month to get ready for the next loop.
if ( $hour_by_hour ) {
if ( 'hour' === $period ) {
$chart_dates['start']->addHour( 1 );
} elseif ( $day_by_day ) {
} elseif ( 'day' === $period ) {
$chart_dates['start']->addDays( 1 );
} else {
$chart_dates['start']->addMonth( 1 );
@ -194,30 +172,12 @@ function edd_overview_sales_earnings_chart() {
function edd_overview_refunds_chart() {
global $wpdb;
$dates = Reports\get_dates_filter( 'objects' );
$chart_dates = Reports\parse_dates_for_range( null, 'now', false );
$day_by_day = Reports\get_dates_filter_day_by_day();
$hour_by_hour = Reports\get_dates_filter_hour_by_hour();
$column = Reports\get_taxes_excluded_filter() ? 'total - tax' : 'total';
$currency = Reports\get_filter_value( 'currencies' );
$sql_clauses = array(
'select' => 'date_created AS date',
'where' => '',
);
// Default to 'monthly'.
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'MONTH', 'date_created' );
$sql_clauses['orderby'] = 'MONTH(date_created)';
// Now drill down to the smallest unit.
if ( $hour_by_hour ) {
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'HOUR', 'date_created' );
$sql_clauses['orderby'] = 'HOUR(date_created)';
} elseif ( $day_by_day ) {
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'DATE', 'date_created' );
$sql_clauses['orderby'] = 'DATE(date_created)';
}
$dates = Reports\get_dates_filter( 'objects' );
$chart_dates = Reports\parse_dates_for_range( null, 'now', false );
$column = Reports\get_taxes_excluded_filter() ? 'total - tax' : 'total';
$currency = Reports\get_filter_value( 'currencies' );
$period = Reports\get_graph_period();
$sql_clauses = Reports\get_sql_clauses( $period );
if ( empty( $currency ) || 'convert' === $currency ) {
$column = sprintf( '(%s) / rate', $column );
@ -227,7 +187,7 @@ function edd_overview_refunds_chart() {
$results = $wpdb->get_results(
$wpdb->prepare(
"SELECT COUNT(id) AS number, SUM({$column}) AS amount, {$sql_clauses['select']}
"SELECT COUNT(*) AS number, SUM({$column}) AS amount, {$sql_clauses['select']}
FROM {$wpdb->edd_orders} edd_o
WHERE status IN (%s, %s) AND date_created >= %s AND date_created <= %s AND type = 'refund'
{$sql_clauses['where']}
@ -240,7 +200,7 @@ function edd_overview_refunds_chart() {
)
);
$number = array();
$number = array();
$amount = array();
// Initialise all arrays with timestamps and set values to 0.
@ -259,15 +219,14 @@ function edd_overview_refunds_chart() {
$date_of_db_value = EDD()->utils->date( $result->date );
// Add any refunds that happened during this hour.
if ( $hour_by_hour ) {
$date_of_db_value = edd_get_edd_timezone_equivalent_date_from_utc( $date_of_db_value );
if ( 'hour' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d H' ) === $date_on_chart->format( 'Y-m-d H' ) ) {
$number[ $timestamp ][1] += $result->number;
$amount[ $timestamp ][1] += abs( $result->amount );
}
// Add any refunds that happened during this day.
} elseif ( $day_by_day ) {
} elseif ( 'day' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d' ) === $date_on_chart->format( 'Y-m-d' ) ) {
$number[ $timestamp ][1] += $result->number;
@ -284,9 +243,9 @@ function edd_overview_refunds_chart() {
}
// Move the chart along to the next hour/day/month to get ready for the next loop.
if ( $hour_by_hour ) {
if ( 'hour' === $period ) {
$chart_dates['start']->addHour( 1 );
} elseif ( $day_by_day ) {
} elseif ( 'day' === $period ) {
$chart_dates['start']->addDays( 1 );
} else {
$chart_dates['start']->addMonth( 1 );
@ -297,5 +256,4 @@ function edd_overview_refunds_chart() {
'number' => array_values( $number ),
'amount' => array_values( $amount ),
);
}

View File

@ -735,45 +735,17 @@ function edd_register_downloads_report( $reports ) {
'data_callback' => function () use ( $download_data, $currency ) {
global $wpdb;
$dates = Reports\get_dates_filter( 'objects' );
$day_by_day = Reports\get_dates_filter_day_by_day();
$hour_by_hour = Reports\get_dates_filter_hour_by_hour();
$chart_dates = Reports\parse_dates_for_range( null, 'now', false );
$sql_clauses = array(
'select' => 'edd_oi.date_created AS date',
'where' => '',
'groupby' => '',
);
$dates = Reports\get_dates_filter( 'objects' );
$chart_dates = Reports\parse_dates_for_range( null, 'now', false );
$period = Reports\get_graph_period();
$sql_clauses = Reports\get_sql_clauses( $period, 'edd_oi.date_created' );
$union_clauses = array(
'select' => 'date',
'where' => '',
'groupby' => '',
'groupby' => 'date',
'orderby' => 'date',
);
// 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'] ) )
: '';
@ -782,14 +754,12 @@ function edd_register_downloads_report( $reports ) {
$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
"SELECT SUM(edd_oi.total / edd_oi.rate) AS earnings, {$sql_clauses['select']}
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})
WHERE edd_oi.product_id = %d {$price_id} 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
@ -803,20 +773,18 @@ function edd_register_downloads_report( $reports ) {
$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
"SELECT SUM(edd_oa.total / edd_oa.rate) AS earnings, {$sql_clauses['select']}
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
{$price_id}
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
@ -865,16 +833,16 @@ function edd_register_downloads_report( $reports ) {
// Loop through each date there were sales/earnings, which we queried from the database.
foreach ( $earnings_results as $earnings_result ) {
$date_of_db_value = edd_get_edd_timezone_equivalent_date_from_utc( EDD()->utils->date( $earnings_result->date ) );
$date_of_db_value = EDD()->utils->date( $earnings_result->date );
// Add any sales/earnings that happened during this hour.
if ( $hour_by_hour ) {
if ( 'hour' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d H' ) === $date_on_chart->format( 'Y-m-d H' ) ) {
$earnings[ $timestamp ][1] += $earnings_result->earnings;
}
// Add any sales/earnings that happened during this day.
} elseif ( $day_by_day ) {
} elseif ( 'day' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d' ) === $date_on_chart->format( 'Y-m-d' ) ) {
$earnings[ $timestamp ][1] += $earnings_result->earnings;
@ -890,16 +858,16 @@ function edd_register_downloads_report( $reports ) {
// Loop through each date there were sales/earnings, which we queried from the database.
foreach ( $sales_results as $sales_result ) {
$date_of_db_value = edd_get_edd_timezone_equivalent_date_from_utc( EDD()->utils->date( $sales_result->date ) );
$date_of_db_value = EDD()->utils->date( $sales_result->date );
// Add any sales/earnings that happened during this hour.
if ( $hour_by_hour ) {
if ( 'hour' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d H' ) === $date_on_chart->format( 'Y-m-d H' ) ) {
$sales[ $timestamp ][1] += $sales_result->sales;
}
// Add any sales/earnings that happened during this day.
} elseif ( $day_by_day ) {
} elseif ( 'day' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d' ) === $date_on_chart->format( 'Y-m-d' ) ) {
$sales[ $timestamp ][1] += $sales_result->sales;
@ -914,9 +882,9 @@ function edd_register_downloads_report( $reports ) {
}
// Move the chart along to the next hour/day/month to get ready for the next loop.
if ( $hour_by_hour ) {
if ( 'hour' === $period ) {
$chart_dates['start']->addHour( 1 );
} elseif ( $day_by_day ) {
} elseif ( 'day' === $period ) {
$chart_dates['start']->addDays( 1 );
} else {
$chart_dates['start']->addMonth( 1 );
@ -1562,27 +1530,9 @@ function edd_register_payment_gateways_report( $reports ) {
global $wpdb;
$dates = Reports\get_dates_filter( 'objects' );
$day_by_day = Reports\get_dates_filter_day_by_day();
$hour_by_hour = Reports\get_dates_filter_hour_by_hour();
$chart_dates = Reports\parse_dates_for_range( null, 'now', false );
$sql_clauses = array(
'select' => 'date_created AS date',
'where' => '',
);
// Default to 'monthly'.
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'MONTH', 'date_created' );
$sql_clauses['orderby'] = 'MONTH(date_created)';
// Now drill down to the smallest unit.
if ( $hour_by_hour ) {
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'HOUR', 'date_created' );
$sql_clauses['orderby'] = 'HOUR(date_created)';
} elseif ( $day_by_day ) {
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'DATE', 'date_created' );
$sql_clauses['orderby'] = 'DATE(date_created)';
}
$period = Reports\get_graph_period();
$sql_clauses = Reports\get_sql_clauses( $period, 'date_created' );
$gateway = Reports\get_filter_value( 'gateways' );
$column = $exclude_taxes
@ -1605,7 +1555,7 @@ function edd_register_payment_gateways_report( $reports ) {
ORDER BY {$sql_clauses['orderby']} ASC",
esc_sql( $gateway ), $dates['start']->copy()->format( 'mysql' ), $dates['end']->copy()->format( 'mysql' ) ) );
$sales = array();
$sales = array();
$earnings = array();
/**
@ -1625,17 +1575,17 @@ function edd_register_payment_gateways_report( $reports ) {
// Loop through each date there were sales/earnings, which we queried from the database.
foreach ( $results as $result ) {
$date_of_db_value = edd_get_edd_timezone_equivalent_date_from_utc( EDD()->utils->date( $result->date ) );
$date_of_db_value = EDD()->utils->date( $result->date );
// Add any sales/earnings that happened during this hour.
if ( $hour_by_hour ) {
if ( 'hour' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d H' ) === $date_on_chart->format( 'Y-m-d H' ) ) {
$sales[ $timestamp ][1] += $result->sales;
$earnings[ $timestamp ][1] += $result->earnings;
}
// Add any sales/earnings that happened during this day.
} elseif ( $day_by_day ) {
} elseif ( 'day' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d' ) === $date_on_chart->format( 'Y-m-d' ) ) {
$sales[ $timestamp ][1] += $result->sales;
@ -1652,9 +1602,9 @@ function edd_register_payment_gateways_report( $reports ) {
}
// Move the chart along to the next hour/day/month to get ready for the next loop.
if ( $hour_by_hour ) {
if ( 'hour' === $period ) {
$chart_dates['start']->addHour( 1 );
} elseif ( $day_by_day ) {
} elseif ( 'day' === $period ) {
$chart_dates['start']->addDays( 1 );
} else {
$chart_dates['start']->addMonth( 1 );
@ -2060,29 +2010,10 @@ function edd_register_file_downloads_report( $reports ) {
'data_callback' => function () use ( $filter, $download_data ) {
global $wpdb;
$dates = Reports\get_dates_filter( 'objects' );
$chart_dates = Reports\parse_dates_for_range( null, 'now', false );
$day_by_day = Reports\get_dates_filter_day_by_day();
$hour_by_hour = Reports\get_dates_filter_hour_by_hour();
$sql_clauses = array(
'select' => 'date_created AS date',
'where' => '',
'groupby' => '',
);
// Default to 'monthly'.
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'MONTH', 'date_created' );
$sql_clauses['orderby'] = 'MONTH(date_created)';
// Now drill down to the smallest unit.
if ( $hour_by_hour ) {
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'HOUR', 'date_created' );
$sql_clauses['orderby'] = 'HOUR(date_created)';
} elseif ( $day_by_day ) {
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'DATE', 'date_created' );
$sql_clauses['orderby'] = 'DATE(date_created)';
}
$dates = Reports\get_dates_filter( 'objects' );
$chart_dates = Reports\parse_dates_for_range( null, 'now', false );
$period = Reports\get_graph_period();
$sql_clauses = Reports\get_sql_clauses( $period );
$product_id = '';
$price_id = '';
@ -2114,16 +2045,16 @@ function edd_register_file_downloads_report( $reports ) {
$file_downloads[ $timestamp ][1] = 0;
foreach ( $results as $result ) {
$date_of_db_value = edd_get_edd_timezone_equivalent_date_from_utc( EDD()->utils->date( $result->date ) );
$date_of_db_value = EDD()->utils->date( $result->date );
// Add any file downloads that happened during this hour.
if ( $hour_by_hour ) {
if ( 'hour' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d H' ) === $date_on_chart->format( 'Y-m-d H' ) ) {
$file_downloads[ $timestamp ][1] += absint( $result->total );
}
// Add any file downloads that happened during this day.
} elseif ( $day_by_day ) {
} elseif ( 'day' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d' ) === $date_on_chart->format( 'Y-m-d' ) ) {
$file_downloads[ $timestamp ][1] += absint( $result->total );
@ -2138,9 +2069,9 @@ function edd_register_file_downloads_report( $reports ) {
}
// Move the chart along to the next hour/day/month to get ready for the next loop.
if ( $hour_by_hour ) {
if ( 'hour' === $period ) {
$chart_dates['start']->addHour( 1 );
} elseif ( $day_by_day ) {
} elseif ( 'day' === $period ) {
$chart_dates['start']->addDays( 1 );
} else {
$chart_dates['start']->addMonth( 1 );
@ -2400,28 +2331,9 @@ function edd_register_discounts_report( $reports ) {
global $wpdb;
$dates = Reports\get_dates_filter( 'objects' );
$day_by_day = Reports\get_dates_filter_day_by_day();
$hour_by_hour = Reports\get_dates_filter_hour_by_hour();
$chart_dates = Reports\parse_dates_for_range( null, 'now', false );
$sql_clauses = array(
'select' => 'edd_oa.date_created AS date',
'where' => '',
);
// Default to 'monthly'.
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'MONTH', 'edd_oa.date_created' );
$sql_clauses['orderby'] = 'MONTH(edd_oa.date_created)';
// Now drill down to the smallest unit.
if ( $hour_by_hour ) {
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'HOUR', 'edd_oa.date_created' );
$sql_clauses['orderby'] = 'HOUR(edd_oa.date_created)';
} elseif ( $day_by_day ) {
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'DATE', 'edd_oa.date_created' );
$sql_clauses['orderby'] = 'DATE(edd_oa.date_created)';
}
$period = Reports\get_graph_period();
$sql_clauses = Reports\get_sql_clauses( $period, 'edd_oa.date_created' );
$discount_code = ! empty( $d->code )
? $wpdb->prepare( 'AND type = %s AND description = %s', 'discount', esc_sql( $d->code ) )
@ -2447,16 +2359,16 @@ function edd_register_discounts_report( $reports ) {
// Loop through each date in which there were discount codes used, which we queried from the database.
foreach ( $results as $result ) {
$date_of_db_value = edd_get_edd_timezone_equivalent_date_from_utc( EDD()->utils->date( $result->date ) );
$date_of_db_value = EDD()->utils->date( $result->date );
// Add any discount codes that were used during this hour.
if ( $hour_by_hour ) {
if ( 'hour' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d H' ) === $date_on_chart->format( 'Y-m-d H' ) ) {
$discount_usage[ $timestamp ][1] += abs( $result->total );
}
// Add any discount codes that were used during this day.
} elseif ( $day_by_day ) {
} elseif ( 'day' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d' ) === $date_on_chart->format( 'Y-m-d' ) ) {
$discount_usage[ $timestamp ][1] += abs( $result->total );
@ -2471,9 +2383,9 @@ function edd_register_discounts_report( $reports ) {
}
// Move the chart along to the next hour/day/month to get ready for the next loop.
if ( $hour_by_hour ) {
if ( 'hour' === $period ) {
$chart_dates['start']->addHour( 1 );
} elseif ( $day_by_day ) {
} elseif ( 'day' === $period ) {
$chart_dates['start']->addDays( 1 );
} else {
$chart_dates['start']->addMonth( 1 );
@ -2645,23 +2557,9 @@ function edd_register_customer_report( $reports ) {
global $wpdb;
$dates = Reports\get_dates_filter( 'objects' );
$day_by_day = Reports\get_dates_filter_day_by_day();
$hour_by_hour = Reports\get_dates_filter_hour_by_hour();
$chart_dates = Reports\parse_dates_for_range( null, 'now', false );
$sql_clauses = array(
'select' => 'date_created AS date',
'groupby' => Reports\get_groupby_date_string( 'MONTH', 'date_created' ),
'orderby' => 'MONTH(date_created)',
);
if ( $hour_by_hour ) {
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'HOUR', 'date_created' );
$sql_clauses['orderby'] = 'HOUR(date_created)';
} elseif ( $day_by_day ) {
$sql_clauses['groupby'] = Reports\get_groupby_date_string( 'DATE', 'date_created' );
$sql_clauses['orderby'] = 'DATE(date_created)';
}
$period = Reports\get_graph_period();
$sql_clauses = Reports\get_sql_clauses( $period );
$results = $wpdb->get_results( $wpdb->prepare(
"SELECT COUNT(c.id) AS total, {$sql_clauses['select']}
@ -2684,16 +2582,16 @@ function edd_register_customer_report( $reports ) {
$customers[ $timestamp ][1] = 0;
foreach ( $results as $result ) {
$date_of_db_value = edd_get_edd_timezone_equivalent_date_from_utc( EDD()->utils->date( $result->date ) );
$date_of_db_value = EDD()->utils->date( $result->date );
// Add any new customers that were created during this hour.
if ( $hour_by_hour ) {
if ( 'hour' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d H' ) === $date_on_chart->format( 'Y-m-d H' ) ) {
$customers[ $timestamp ][1] += $result->total;
}
// Add any new customers that were created during this day.
} elseif ( $day_by_day ) {
} elseif ( 'day' === $period ) {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value->format( 'Y-m-d' ) === $date_on_chart->format( 'Y-m-d' ) ) {
$customers[ $timestamp ][1] += $result->total;
@ -2708,9 +2606,9 @@ function edd_register_customer_report( $reports ) {
}
// Move the chart along to the next hour/day/month to get ready for the next loop.
if ( $hour_by_hour ) {
if ( 'hour' === $period ) {
$chart_dates['start']->addHour( 1 );
} elseif ( $day_by_day ) {
} elseif ( 'day' === $period ) {
$chart_dates['start']->addDays( 1 );
} else {
$chart_dates['start']->addMonth( 1 );

View File

@ -399,3 +399,43 @@ function edd_tax_settings_display_tax_disabled_notice() {
}
add_action( 'edd_settings_tab_top_taxes_rates', 'edd_tax_settings_display_tax_disabled_notice', 10 );
/**
* Display help text at the top of the Licenses tab.
*
* @since 3.1.1.4
* @return void
*/
function edd_license_settings_help_text() {
?>
<div class="edd-licenses__description">
<p>
<?php esc_html_e( 'Manage extensions for Easy Digital Downloads which are not included with a pass. Having an active license for your extensions gives you access to updates when they\'re available.', 'easy-digital-downloads' ); ?>
</p>
<?php
$pass_manager = new \EDD\Admin\Pass_Manager();
if ( ! $pass_manager->highest_license_key ) :
?>
<p>
<?php
$url = edd_get_admin_url(
array(
'page' => 'edd-settings',
'tab' => 'general',
)
);
printf(
wp_kses_post(
/* translators: 1. opening anchor tag; 2. closing anchor tag */
__( 'Have a pass? You\'re ready to set up EDD (Pro). %1$sActivate Your Pass%2$s' )
),
'<a href="' . esc_url( $url ) . '" class="button button-primary">',
'</a>'
);
?>
</p>
<?php endif; ?>
</div>
<?php
}
add_action( 'edd_settings_tab_top_licenses_main', 'edd_license_settings_help_text' );

View File

@ -35,6 +35,10 @@
"show_price": {
"type": "boolean",
"default": true
},
"direct": {
"type": "boolean",
"default": false
}
},
"example": {

View File

@ -1 +1 @@
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => 'd12364cb3d89217da0af');
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => '75153cfac5e884f38a28');

View File

@ -1 +1 @@
.edd-no-js{display:none!important}svg.edd-blocks__icon{fill:none!important}.editor-styles-wrapper .wp-block.wp-block-edd-buy-button .components-placeholder{align-items:center;background-color:#fefefe;border-radius:5px}.editor-styles-wrapper .wp-block.wp-block-edd-buy-button .components-placeholder__fieldset{justify-content:center}
.edd-no-js{display:none!important}svg.edd-blocks__icon{fill:none!important}.editor-styles-wrapper .components-placeholder a.components-button.edd-new-download{background-color:var(--wp-admin-theme-color)!important;color:#fff!important;line-height:1.5;margin:0 auto!important;padding:.5em 1em;text-decoration:none}.editor-styles-wrapper .wp-block.wp-block-edd-buy-button .components-placeholder{align-items:center;background-color:#fefefe;border-radius:5px}.editor-styles-wrapper .wp-block.wp-block-edd-buy-button .components-placeholder__fieldset{justify-content:center}

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => '44a7f6fcddb3d7a45761');
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => 'cf21706935ed810cf190');

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => 'f7eb0560b580188ab6f6');
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => 'a4b81968f6c606c084d6');

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => 'fbe222c67791f3db7f56');
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => '3ebd3d803f03e6d7cdb8');

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
.edd-blocks__row{align-items:center;display:grid;gap:1rem}.edd-blocks__row-label{font-weight:700}@media(min-width:480px){.edd-blocks__row{grid-template-columns:1fr 1fr}.edd-blocks__row>div:last-of-type:not(:first-of-type){text-align:right}.edd-blocks__row>div:only-child{grid-column:1/span 2}}.edd-blocks-receipt__items,.edd-blocks-receipt__totals{border:1px solid var(--edd-blocks-light-grey);display:grid;margin:0 auto 1.5rem;padding:1rem}.edd-blocks-receipt__row-item{border-bottom:1px solid var(--edd-blocks-light-grey);padding:.5rem 0}.edd-blocks-receipt__row-item:last-child{border-bottom:none!important}.edd-blocks-receipt__row-header{border-bottom:1px solid var(--edd-blocks-light-grey);font-size:1.1rem;font-weight:700;padding-bottom:.5rem}
.edd-blocks__row{align-items:center;display:grid;gap:1rem}.edd-blocks__row-label{font-weight:700}@media(min-width:480px){.edd-blocks__row{grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}.edd-blocks__row>div:last-of-type:not(:first-of-type){text-align:right}.edd-blocks__row>div:only-child{grid-column:1/span 2}}.edd-blocks-receipt__items,.edd-blocks-receipt__totals{border:1px solid var(--edd-blocks-light-grey);display:grid;margin:0 auto 1.5rem;padding:1rem}.edd-blocks-receipt__row-item{border-bottom:1px solid var(--edd-blocks-light-grey);padding:.5rem 0}.edd-blocks-receipt__row-item:last-child{border-bottom:none!important}.edd-blocks-receipt__row-header{border-bottom:1px solid var(--edd-blocks-light-grey);font-size:1.1rem;font-weight:700;padding-bottom:.5rem}

View File

@ -1 +1 @@
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => '4dc61207e0bc9900907a');
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => '2066313c4795ca117892');

View File

@ -1 +1 @@
.edd-no-js{display:none!important}svg.edd-blocks__icon{fill:none!important}.edd-blocks-term-selector select{min-height:60px!important}.edd-blocks-term-selector svg{display:none!important}
.edd-no-js{display:none!important}svg.edd-blocks__icon{fill:none!important}.editor-styles-wrapper .components-placeholder a.components-button.edd-new-download{background-color:var(--wp-admin-theme-color)!important;color:#fff!important;line-height:1.5;margin:0 auto!important;padding:.5em 1em;text-decoration:none}.edd-blocks-term-selector select{min-height:60px!important}.edd-blocks-term-selector svg{display:none!important}

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => '8022d11843870776cb71');
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => 'edc5631c889b13e0c385');

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => 'ba06ffbd66b5912e943d');
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => 'daec310e0801da6bedd7');

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => '5db7f26583a44b89219b');
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => '9c5caff2035d02a7827e');

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
.screen-reader-text{clip:rect(1px,1px,1px,1px);word-wrap:normal!important;border:0;-webkit-clip-path:inset(50%);clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.edd-blocks__row{align-items:center;display:grid;gap:1rem}.edd-blocks__row-label{font-weight:700}@media(min-width:480px){.edd-blocks__row{grid-template-columns:1fr 1fr}.edd-blocks__row>div:last-of-type:not(:first-of-type){text-align:right}.edd-blocks__row>div:only-child{grid-column:1/span 2}}.edd-blocks-form{border:1px solid var(--edd-blocks-light-grey);display:grid;gap:1.25rem;padding:2rem}.widget .edd-blocks-form{border:none;padding:0}.edd-blocks-form .edd-blocks-form__group,.edd-blocks-form legend{display:block;margin:0}.edd-blocks-form .edd-blocks-form__group>label{display:block;margin-bottom:.5rem!important}.edd-blocks-form input[type=email],.edd-blocks-form input[type=password],.edd-blocks-form input[type=text],.edd-blocks-form select{box-sizing:border-box;display:block;padding:4px 6px;width:100%}.edd-blocks-form .edd-blocks-form__halves{display:flex!important;gap:1rem;justify-content:space-between}@media(min-width:600px){.edd-blocks-form .edd-blocks-form__halves>*{flex-basis:50%}}p+.edd-blocks-form{margin-top:2rem}.edd-button-secondary,.edd-submit{transition:all .2s ease-in-out}.edd-button-secondary:active,.edd-button-secondary:hover,.edd-submit:active,.edd-submit:hover{transform:translateY(-1px)}.edd-button-secondary{background-color:var(--edd-blocks-light-grey);border:1px solid #ddd;border-radius:4px;color:unset;margin:0;padding:.5rem 1rem}.edd-button-secondary:disabled{opacity:.6}.edd-blocks-receipt__items,.edd-blocks-receipt__totals{border:1px solid var(--edd-blocks-light-grey);display:grid;margin:0 auto 1.5rem;padding:1rem}.edd-blocks-receipt__row-item{border-bottom:1px solid var(--edd-blocks-light-grey);padding:.5rem 0}.edd-blocks-receipt__row-item:last-child{border-bottom:none!important}.edd-blocks-receipt__row-header{border-bottom:1px solid var(--edd-blocks-light-grey);font-size:1.1rem;font-weight:700;padding-bottom:.5rem}.edd-blocks-receipt__items .edd-blocks__row{border-bottom:1px solid var(--edd-blocks-light-grey);padding:.5rem 0}
.screen-reader-text{clip:rect(1px,1px,1px,1px);word-wrap:normal!important;border:0;-webkit-clip-path:inset(50%);clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.edd-blocks__row{align-items:center;display:grid;gap:1rem}.edd-blocks__row-label{font-weight:700}@media(min-width:480px){.edd-blocks__row{grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}.edd-blocks__row>div:last-of-type:not(:first-of-type){text-align:right}.edd-blocks__row>div:only-child{grid-column:1/span 2}}.edd-blocks-form{border:1px solid var(--edd-blocks-light-grey);display:grid;gap:1.25rem;padding:2rem}.widget .edd-blocks-form{border:none;padding:0}.edd-blocks-form .edd-blocks-form__group,.edd-blocks-form legend{display:block;margin:0}.edd-blocks-form .edd-blocks-form__group>label{display:block;margin-bottom:.5rem!important}.edd-blocks-form input[type=email],.edd-blocks-form input[type=password],.edd-blocks-form input[type=text],.edd-blocks-form select{box-sizing:border-box;display:block;padding:4px 6px;width:100%}.edd-blocks-form .edd-blocks-form__halves{display:flex!important;gap:1rem;justify-content:space-between}@media(min-width:600px){.edd-blocks-form .edd-blocks-form__halves>*{flex-basis:50%}}p+.edd-blocks-form{margin-top:2rem}.edd-button-secondary,.edd-submit{transition:all .2s ease-in-out}.edd-button-secondary:active,.edd-button-secondary:hover,.edd-submit:active,.edd-submit:hover{transform:translateY(-1px)}.edd-button-secondary{background-color:var(--edd-blocks-light-grey);border:1px solid #ddd;border-radius:4px;color:unset;margin:0;padding:.5rem 1rem}.edd-button-secondary:disabled{opacity:.6}.edd-blocks-receipt__items,.edd-blocks-receipt__totals{border:1px solid var(--edd-blocks-light-grey);display:grid;margin:0 auto 1.5rem;padding:1rem}.edd-blocks-receipt__row-item{border-bottom:1px solid var(--edd-blocks-light-grey);padding:.5rem 0}.edd-blocks-receipt__row-item:last-child{border-bottom:none!important}.edd-blocks-receipt__row-header{border-bottom:1px solid var(--edd-blocks-light-grey);font-size:1.1rem;font-weight:700;padding-bottom:.5rem}.edd-blocks-receipt__items .edd-blocks__row{border-bottom:1px solid var(--edd-blocks-light-grey);padding:.5rem 0}

View File

@ -1 +1 @@
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => '0661e954af1bb187dd97');
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => '48f22fda332b4e2cd8f3');

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => '1028b825bf11c1432c23');
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => 'b5c8776e3d561d9f287e');

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => '535d394ba6d83f8c0b16');
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => '323ff8718132587855ee');

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
.screen-reader-text{clip:rect(1px,1px,1px,1px);word-wrap:normal!important;border:0;-webkit-clip-path:inset(50%);clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.edd-pro-search__control{display:flex;justify-content:flex-end;margin-bottom:2em}.edd-pro-search__control input{max-width:100%;width:300px}.edd-pro-search__hidden{display:none!important}.edd-blocks__row{align-items:center;display:grid;gap:1rem}.edd-blocks__row-label{font-weight:700}@media(min-width:480px){.edd-blocks__row{grid-template-columns:1fr 1fr}.edd-blocks__row>div:last-of-type:not(:first-of-type){text-align:right}.edd-blocks__row>div:only-child{grid-column:1/span 2}}div.edd-blocks__user-downloads{border:1px solid var(--edd-blocks-light-grey);padding:1rem}div.edd-blocks__user-downloads .edd-order-item__product .edd-order-item__files,div.edd-blocks__user-downloads .edd-order-items__header .edd-blocks__row-label{text-align:left}.edd-order-item__product,.edd-order-items__header{border-bottom:1px solid var(--edd-blocks-light-grey);gap:1em;padding:.5em 0}.edd-order-item__product:last-child,.edd-order-items__header:last-child{border-bottom:none;padding-bottom:0}.edd-order-items__header{padding-top:0}
.screen-reader-text{clip:rect(1px,1px,1px,1px);word-wrap:normal!important;border:0;-webkit-clip-path:inset(50%);clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.edd-pro-search__control{display:flex;justify-content:flex-end;margin-bottom:2em}.edd-pro-search__control input{max-width:100%;width:300px}.edd-pro-search__hidden{display:none!important}.edd-blocks__row{align-items:center;display:grid;gap:1rem}.edd-blocks__row-label{font-weight:700}@media(min-width:480px){.edd-blocks__row{grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}.edd-blocks__row>div:last-of-type:not(:first-of-type){text-align:right}.edd-blocks__row>div:only-child{grid-column:1/span 2}}div.edd-blocks__user-downloads{border:1px solid var(--edd-blocks-light-grey);padding:1rem}div.edd-blocks__user-downloads .edd-blocks__row-column{text-align:left}.edd-order-item__product,.edd-order-items__header{border-bottom:1px solid var(--edd-blocks-light-grey);gap:1em;padding:.5em 0}.edd-order-item__product:last-child,.edd-order-items__header:last-child{border-bottom:none;padding-bottom:0}.edd-order-items__header{padding-top:0}

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.5.1
* Version: 2.0.6
* Author: Easy Digital Downloads
* License: GPL-2.0-or-later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
@ -68,12 +68,9 @@ function init_core_blocks() {
}
if ( edd_is_pro() ) {
$pro_files = array(
'search',
);
foreach ( $pro_files as $file ) {
require_once trailingslashit( EDD_BLOCKS_DIR . 'pro' ) . $file . '.php';
if ( file_exists( EDD_BLOCKS_DIR . 'pro/pro.php' ) ) {
require_once EDD_BLOCKS_DIR . 'pro/pro.php';
Pro\init();
}
}
}

View File

@ -12,17 +12,28 @@ add_action( 'enqueue_block_editor_assets', __NAMESPACE__ . '\localize' );
*/
function localize() {
$user = wp_get_current_user();
$user = wp_get_current_user();
$downloads = new \WP_Query(
array(
'post_type' => 'download',
'posts_per_page' => 1,
'post_status' => 'any',
'no_found_rows' => true,
)
);
wp_localize_script(
'wp-block-editor',
'EDDBlocks',
array(
'current_user' => md5( $user->user_email ),
'all_access' => function_exists( 'edd_all_access' ),
'recurring' => function_exists( 'EDD_Recurring' ),
'is_pro' => edd_is_pro(),
'no_redownload' => edd_no_redownload(),
'current_user' => md5( $user->user_email ),
'all_access' => function_exists( 'edd_all_access' ),
'recurring' => function_exists( 'EDD_Recurring' ),
'is_pro' => edd_is_pro(),
'no_redownload' => edd_no_redownload(),
'supports_buy_now' => edd_shop_supports_buy_now(),
'has_downloads' => $downloads->have_posts(),
'new_download' => add_query_arg( 'post_type', 'download', admin_url( 'post-new.php' ) ),
)
);
}

View File

@ -43,7 +43,7 @@ function get_personal_info_forms( $block_attributes, $customer_info_complete = t
if ( ! edd_no_guest_checkout() || ( ! $customer_info_complete && is_user_logged_in() ) ) {
$forms['guest'] = $options['guest'];
}
if ( ! empty( $block_attributes['show_register_form'] ) ) {
if ( ! empty( $block_attributes['show_register_form'] ) && ! is_user_logged_in() ) {
$setting = $block_attributes['show_register_form'];
if ( 'both' === $setting ) {
$forms['login'] = $options['login'];
@ -76,7 +76,7 @@ function do_personal_info_forms( $block_attributes ) {
if ( is_user_logged_in() ) {
include EDD_BLOCKS_DIR . 'views/checkout/purchase-form/logged-in.php';
if ( ! empty( $customer['email'] ) && ! empty( $customer['first_name'] ) ) {
if ( ! empty( $customer['email'] ) && ! empty( $customer['first_name'] ) && ! has_action( 'edd_purchase_form_user_info_fields' ) ) {
return;
}
$customer_info_complete = false;

View File

@ -131,6 +131,8 @@ function buy_button( $block_attributes = array() ) {
'download_id' => get_the_ID(),
'show_price' => true,
'align' => '',
'direct' => false,
'text' => edd_get_option( 'add_to_cart_text', __( 'Purchase', 'easy-digital-downloads' ) ),
)
);
if ( empty( $block_attributes['download_id'] ) || 'download' !== get_post_type( $block_attributes['download_id'] ) ) {
@ -148,14 +150,19 @@ function buy_button( $block_attributes = array() ) {
wp_enqueue_style( 'edd-styles' );
}
$output = sprintf( '<div class="%s">', esc_attr( implode( ' ', $classes ) ) );
$output .= edd_get_purchase_link(
array(
'class' => implode( ' ', get_purchase_link_classes( $block_attributes ) ),
'download_id' => absint( $block_attributes['download_id'] ),
'price' => (bool) $block_attributes['show_price'],
)
$args = array(
'class' => implode( ' ', get_purchase_link_classes( $block_attributes ) ),
'download_id' => absint( $block_attributes['download_id'] ),
'price' => (bool) $block_attributes['show_price'],
'text' => $block_attributes['text'],
);
if ( $block_attributes['direct'] && edd_shop_supports_buy_now() ) {
$args['direct'] = true;
$args['text'] = edd_get_option( 'buy_now_text', __( 'Buy Now', 'easy-digital-downloads' ) );
}
$output = sprintf( '<div class="%s">', esc_attr( implode( ' ', $classes ) ) );
$output .= edd_get_purchase_link( $args );
$output .= '</div>';
add_filter( 'edd_purchase_link_args', __NAMESPACE__ . '\maybe_update_purchase_links', 100 );

View File

@ -58,7 +58,15 @@ function login( $block_attributes = array() ) {
)
);
$action = ! empty( $_GET['action'] ) ? sanitize_text_field( $_GET['action'] ) : false;
$action = ! empty( $_GET['action'] ) ? sanitize_text_field( $_GET['action'] ) : false;
if ( 'rp' === $action ) {
list( $rp_login, $rp_key ) = explode( ':', wp_unslash( $_COOKIE[ 'wp-resetpass-' . COOKIEHASH ] ), 2 );
$user = check_password_reset_key( $rp_key, $rp_login );
if ( ! $user || is_wp_error( $user ) ) {
$action = 'lostpassword';
edd_set_error( 'invalidkey', __( 'Your password reset link appears to be invalid. Please request a new link below.', 'easy-digital-downloads' ) );
}
}
$block_classes = array( 'wp-block-edd-login' );
if ( $action ) {
$block_classes[] = "wp-block-edd-login__{$action}";
@ -75,7 +83,6 @@ function login( $block_attributes = array() ) {
if ( 'lostpassword' === $action ) {
include EDD_BLOCKS_DIR . 'views/forms/lost-password.php';
} elseif ( 'rp' === $action ) {
list( $rp_login, $rp_key ) = explode( ':', wp_unslash( $_COOKIE[ 'wp-resetpass-' . COOKIEHASH ] ), 2 );
include EDD_BLOCKS_DIR . 'views/forms/reset-password.php';
} else {
$redirect_url = get_redirect_url( $block_attributes, true );

View File

@ -347,10 +347,25 @@ function downloads( $block_attributes = array() ) {
}
?>
<div class="edd-blocks__row edd-blocks__row-header edd-order-items__header">
<div class="edd-blocks__row-label"><?php esc_html_e( 'Products', 'easy-digital-downloads' ); ?></div>
<?php if ( ! edd_no_redownload() ) : ?>
<div class="edd-blocks__row-label"><?php esc_html_e( 'Files', 'easy-digital-downloads' ); ?></div>
<?php endif; ?>
<?php
foreach ( get_user_downloads_block_columns() as $column_id => $column ) {
$header = $column['header'];
$header_classes = array(
'edd-blocks__row-label',
'edd-blocks__row-label--' . $column_id,
);
if ( ! empty( $header['classes'] ) ) {
$header_classes = array_merge( $header_classes, $header['classes'] );
}
?>
<div class="<?php echo esc_attr( implode( ' ', array_filter( $header_classes ) ) ); ?>">
<?php do_action( 'edd_blocks_user_downloads_block_header_' . $column_id, $block_attributes ); ?>
</div>
<?php
}
?>
</div>
<?php
ksort( $downloads );
@ -455,3 +470,127 @@ function get_purchased_products( $block_attributes ) {
return ! empty( $downloads ) ? $downloads : false;
}
/**
* Get the registered User Downloads block columns.
*
* @since 2.0.6
* @return array
*/
function get_user_downloads_block_columns() {
$columns = array(
'product' => array(
'header' => array(),
'row' => array(
'classes' => array( 'edd-blocks__row-label' ),
),
),
);
if ( ! edd_no_redownload() ) {
$columns['files'] = array(
'header' => array(),
'row' => array(
'classes' => array( 'edd-order-item__files' ),
),
);
}
/**
* Filters the registered User Downloads block columns.
*
* @since 2.0.6
*
* @param array $columns The registered columns.
* A column should have a unique array key and be an array with two keys 'header' and 'row'.
* Each of these can contain an array key 'classes' which should be an array of classes to add to the header or row.
*
* By default we add base classes as well as the columns array key to the header and row, so developers should only add additional
* classes they want.
*
* Developers will need to hook into the following actions to output the content for the header and column:
* - edd_blocks_user_downloads_block_header_{your_column_key}
* - edd_blocks_user_downloads_block_column_{your_column_key}
*
* @return array
*/
$columns = apply_filters( 'edd_blocks_user_downloads_block_columns', $columns );
// Ensure that all registered columns have the required keys.
foreach ( $columns as $column_id => $column ) {
$default_keys = array(
'header' => array(),
'row' => array(),
);
$columns[ $column_id ] = array_merge( $default_keys, $columns[ $column_id ] );
}
return $columns;
}
/**
* Render the User Downloads block product header
*
* @since 2.0.6
*
* @param array $block_attributes The block attributes.
*/
function render_user_downloads_product_header( $block_attributes = array() ) {
esc_html_e( 'Product', 'easy-digital-downloads' );
}
add_action( 'edd_blocks_user_downloads_block_header_product', __NAMESPACE__ . '\render_user_downloads_product_header', 10, 1 );
/**
* Render the User Downloads block product column.
*
* @since 2.0.6
*
* @param array $action_args The action arguments.
*/
function render_user_downloads_product_column( $action_args = array() ) {
echo esc_html( $action_args['name'] );
}
add_action( 'edd_blocks_user_downloads_block_column_product', __NAMESPACE__ . '\render_user_downloads_product_column', 10, 1 );
/**
* Render the User Downloads block files header
* This is only used if the 'Disable Redownload' option is not enabled.
*
* @since 2.0.6
*
* @param array $block_attributes The block attributes.
*/
function render_user_downloads_files_header( $block_attributes = array() ) {
echo esc_html( __( 'Files', 'easy-digital-downloads' ) );
}
add_action( 'edd_blocks_user_downloads_block_header_files', __NAMESPACE__ . '\render_user_downloads_files_header', 10, 1 );
/**
* Render the User Downloads block files column.
* This is only used if the 'Disable Redownload' option is not enabled.
*
* @since 2.0.6
*
* @param array $action_args The action arguments.
*/
function render_user_downloads_files_column( $action_args = array() ) {
// If there are no files, return early.
if ( empty( $action_args['download_files'] ) ) {
echo esc_html( $action_args['block_attributes']['nofiles'] );
}
foreach ( $action_args['download_files'] as $filekey => $file ) :
$order = $action_args['order'];
$item = $action_args['order_item'];
$download_url = edd_get_download_file_url( $order, $order->email, $filekey, $item->product_id, $item->price_id );
?>
<div class="edd-order-item__file">
<a href="<?php echo esc_url( $download_url ); ?>" class="edd-order-item__file-link">
<?php echo esc_html( edd_get_file_name( $file ) ); ?>
</a>
</div>
<?php
endforeach;
}
add_action( 'edd_blocks_user_downloads_block_column_files', __NAMESPACE__ . '\render_user_downloads_files_column', 10, 1 );

View File

@ -7,7 +7,7 @@
$is_checkout_block = empty( $is_cart_widget ) && ( edd_is_checkout() || edd_doing_ajax() );
?>
<div id="edd_checkout_cart" class="<?php echo esc_attr( implode( ' ', $cart_classes ) ); ?>">
<?php if ( edd_is_checkout() ) : ?>
<?php if ( $is_checkout_block ) : ?>
<div class="edd-blocks-cart__row edd-blocks-cart__row-header edd_cart_header_row">
<div class="edd_cart_item_name"><?php esc_html_e( 'Item Name', 'easy-digital-downloads' ); ?></div>
<div class="edd_cart_item_price"><?php esc_html_e( 'Item Price', 'easy-digital-downloads' ); ?></div>

View File

@ -44,5 +44,13 @@ if ( function_exists( 'EDD_CFM' ) ) {
<input class="edd-input" type="text" name="edd_last" id="edd-last" placeholder="<?php esc_html_e( 'Last name', 'easy-digital-downloads' ); ?>" value="<?php echo esc_attr( $customer['last_name'] ); ?>" aria-describedby="edd-last-description" <?php EDD\Blocks\Functions\mark_field_required( 'edd_last' ); ?>/>
<p class="edd-description" id="edd-last-description"><?php esc_html_e( 'We will use this as well to personalize your account experience.', 'easy-digital-downloads' ); ?></p>
</div>
<?php endif; ?>
<?php
endif;
/**
* Allow users to add additional fields to the checkout form.
*
* @param array $customer Customer information. Note that this parameter is not in the original shortcode hook.
*/
do_action( 'edd_purchase_form_user_info_fields', $customer );
?>
</fieldset>

View File

@ -4,7 +4,8 @@
'download_id' => get_the_ID(),
'align' => $block_attributes['purchase_link_align'],
'show_price' => (bool) $block_attributes['show_price'],
'direct' => 'direct' === edd_get_download_button_behavior( get_the_ID() ),
);
echo EDD\Blocks\Downloads\buy_button( $args );
echo EDD\Blocks\Downloads\buy_button( $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
?>
</footer>

View File

@ -1,5 +1,4 @@
<?php
$price_id = $item->price_id;
$download_files = edd_get_download_files( $item->product_id, $item->price_id );
if ( $block_attributes['hide_empty'] && empty( $download_files ) ) {
return;
@ -12,28 +11,49 @@ $classes = array(
if ( $block_attributes['search'] && edd_is_pro() ) {
$classes[] = 'edd-pro-search__product';
}
$registered_columns = EDD\Blocks\Orders\get_user_downloads_block_columns();
?>
<div class="<?php echo esc_attr( implode( ' ', $classes ) ); ?>">
<div class="edd-blocks__row-label"><?php echo esc_html( $name ); ?></div>
<?php
foreach ( $registered_columns as $column_id => $column ) {
$row = $column['row'];
<?php if ( ! edd_no_redownload() ) : ?>
<div class="edd-order-item__files">
$classes = array(
'edd-blocks__row-column',
'edd-blocks__row-column--' . $column_id,
);
if ( ! empty( $row['classes'] ) ) {
$classes = array_merge( $classes, $row['classes'] );
}
?>
<div class="<?php echo esc_attr( implode( ' ', array_filter( $classes ) ) ); ?>">
<?php
if ( $download_files ) :
foreach ( $download_files as $filekey => $file ) :
$download_url = edd_get_download_file_url( $order, $order->email, $filekey, $item->product_id, $price_id );
?>
<div class="edd-order-item__file">
<a href="<?php echo esc_url( $download_url ); ?>" class="edd-order-item__file-link">
<?php echo esc_html( edd_get_file_name( $file ) ); ?>
</a>
</div>
<?php
endforeach;
else :
echo esc_html( $block_attributes['nofiles'] );
endif; // End $download_files
$action_args = array(
'name' => $name,
'order_item' => $item,
'order' => $order,
'block_attributes' => $block_attributes,
'download_files' => $download_files,
);
/**
* Renders a column in the user downloads block.
*
* To add a new column, use the `edd_blocks_user_download_columns` filter.
*
* @since 2.0.6
* @param array $action_args The arguments to pass to the hook.
* @param string $name The name of the product.
* @param EDD\Orders\Order_Item $item The order item.
* @param EDD\Orders\Order $order The order object.
* @param array $block_attributes The block attributes.
* @param array $download_files The download files.
*/
do_action( 'edd_blocks_user_downloads_block_column_' . $column_id, $action_args );
?>
</div>
<?php endif; ?>
<?php } ?>
</div>

View File

@ -355,7 +355,7 @@ final class Easy_Digital_Downloads {
// Plugin version.
if ( ! defined( 'EDD_VERSION' ) ) {
define( 'EDD_VERSION', '3.1.1.3' );
define( 'EDD_VERSION', '3.1.1.4.2' );
}
// Make sure CAL_GREGORIAN is defined.
@ -759,7 +759,6 @@ final class Easy_Digital_Downloads {
require_once EDD_PLUGIN_DIR . 'includes/template-actions.php';
require_once EDD_PLUGIN_DIR . 'includes/country-functions.php';
require_once EDD_PLUGIN_DIR . 'includes/extensions/licensing-functions.php';
require_once EDD_PLUGIN_DIR . 'includes/extensions/ExtensionRegistry.php';
require_once EDD_PLUGIN_DIR . 'includes/date-functions.php';
require_once EDD_PLUGIN_DIR . 'includes/misc-functions.php';
require_once EDD_PLUGIN_DIR . 'includes/discount-functions.php';

View File

@ -75,20 +75,20 @@ class EDD_License {
$this->item_shortname = 'edd_' . preg_replace( '/[^a-zA-Z0-9_\s]/', '', str_replace( ' ', '_', strtolower( $this->item_name ) ) );
$this->version = $_version;
$this->edd_license = new License( $this->item_name, $_optname );
if ( empty( $this->edd_license->key ) ) {
$this->edd_license = new License( 'pro' );
if ( ! empty( $this->edd_license->key ) ) {
if ( empty( $_api_url ) && ( empty( $this->edd_license->key ) || empty( $this->edd_license->license ) ) ) {
$pro_license = new License( 'pro' );
if ( ! empty( $pro_license->key ) ) {
$this->is_pro_license = true;
$this->edd_license = $pro_license;
}
}
$this->license = $this->edd_license->key;
$this->author = $_author;
$this->api_handler = new API();
$this->api_url = is_null( $_api_url ) ? $this->api_handler->get_url() : $_api_url;
$this->api_handler = new API( $_api_url );
$this->api_url = $_api_url;
$this->pass_manager = new \EDD\Admin\Pass_Manager();
// Setup hooks
$this->includes();
$this->hooks();
/**
@ -100,7 +100,7 @@ class EDD_License {
*
* @see \EDD\Admin\Promos\Notices\License_Upgrade_Notice::__construct()
*/
if ( ! empty( $this->license ) ) {
if ( ! empty( $this->license ) && is_null( $this->api_url ) ) {
global $edd_licensed_products;
if ( ! is_array( $edd_licensed_products ) ) {
$edd_licensed_products = array();
@ -115,11 +115,7 @@ class EDD_License {
* @access private
* @return void
*/
private function includes() {
if ( ! class_exists( 'EDD_SL_Plugin_Updater' ) ) {
require_once 'EDD_SL_Plugin_Updater.php';
}
}
private function includes() {}
/**
* Setup hooks
@ -130,15 +126,10 @@ class EDD_License {
private function hooks() {
// Register settings
add_filter( 'edd_settings_licenses', array( $this, 'settings' ), 1 );
// Display help text at the top of the Licenses tab
add_action( 'edd_settings_tab_top', array( $this, 'license_help_text' ) );
add_filter( 'edd_settings_licenses', array( $this, 'settings' ) );
// Check that license is valid once per week
if ( edd_doing_cron() ) {
add_action( 'edd_weekly_scheduled_events', array( $this, 'weekly_license_check' ) );
}
add_action( 'edd_weekly_scheduled_events', array( $this, 'weekly_license_check' ) );
// For testing license notices, uncomment this line to force checks on every page load
//add_action( 'admin_init', array( $this, 'weekly_license_check' ) );
@ -176,7 +167,7 @@ class EDD_License {
$license = $this->license;
// Fall back to the highest license key if one is not saved for this extension or there isn't a pro license.
if ( empty( $license ) ) {
if ( empty( $license ) && empty( $this->api_url ) ) {
if ( $this->pass_manager->highest_license_key ) {
$license = $this->pass_manager->highest_license_key;
}
@ -200,9 +191,13 @@ class EDD_License {
$args['item_name'] = $this->item_name;
}
if ( ! class_exists( 'EDD_SL_Plugin_Updater' ) ) {
require_once 'EDD_SL_Plugin_Updater.php';
}
// Setup the updater
new EDD_SL_Plugin_Updater(
$this->api_url,
is_null( $this->api_url ) ? $this->api_handler->get_url() : $this->api_url,
$this->file,
$args
);
@ -224,66 +219,13 @@ class EDD_License {
'options' => array(
'is_valid_license_option' => $this->item_shortname . '_license_active',
'item_id' => $this->item_id,
'api_url' => $this->api_url,
),
'size' => 'regular',
)
) );
}
/**
* Display help text at the top of the Licenses tag
*
* @since 2.5
* @param string $active_tab
* @return void
*/
public function license_help_text( $active_tab = '' ) {
static $has_ran = false;
if ( 'licenses' !== $active_tab ) {
return;
}
if ( ! empty( $has_ran ) ) {
return;
}
?>
<div class="edd-licenses__description">
<p>
<?php
printf(
__( 'Enter your extension license keys here to receive updates for purchased extensions. If your license key has expired, please %srenew your license%s.', 'easy-digital-downloads' ),
'<a href="https://easydigitaldownloads.com/docs/license-renewal/" target="_blank">',
'</a>'
);
?>
</p>
<?php if ( ! $this->pass_manager->highest_license_key ) : ?>
<p>
<?php
$url = edd_get_admin_url(
array(
'page' => 'edd-settings',
'tab' => 'general',
)
);
printf(
__( 'Have a pass? You\'re ready to set up EDD (Pro). %1$sActivate Your Pass%2$s' ),
'<a href="' . esc_url( $url ) . '" class="button button-primary">',
'</a>'
);
?>
</p>
<?php
endif;
?>
</div>
<?php
$has_ran = true;
}
/**
* Check if license key is valid once per week
*
@ -293,7 +235,7 @@ class EDD_License {
public function weekly_license_check() {
// If a pro license is active, that license check is handled separately.
if ( $this->is_pro_license ) {
if ( $this->is_pro_license && empty( $this->api_url ) ) {
return;
}
@ -322,7 +264,9 @@ class EDD_License {
return false;
}
$this->pass_manager->maybe_set_pass_flag( $this->license, $license_data );
if ( empty( $this->api_url ) ) {
$this->pass_manager->maybe_set_pass_flag( $this->license, $license_data );
}
$this->edd_license->save( $license_data );
}
@ -332,8 +276,6 @@ class EDD_License {
* @return void
*/
public function notices() {
static $showed_invalid_message = false;
if ( empty( $this->license ) ) {
return;
}
@ -342,28 +284,25 @@ class EDD_License {
return;
}
$messages = array();
$license = $this->edd_license;
if ( ( empty( $license->license ) || 'valid' !== $license->license ) && empty( $showed_invalid_message ) ) {
if ( empty( $_GET['tab'] ) || 'licenses' !== $_GET['tab'] ) {
$messages[] = sprintf(
__( 'You have invalid or expired license keys for Easy Digital Downloads. <a href="%s">Fix this</a>', 'easy-digital-downloads' ),
esc_url( edd_get_admin_url( array( 'page' => 'edd-settings', 'tab' => 'licenses' ) ) )
);
$showed_invalid_message = true;
}
if ( ! empty( $_GET['tab'] ) && 'licenses' === $_GET['tab'] ) {
return;
}
if ( ! empty( $messages ) ) {
foreach( $messages as $message ) {
echo '<div class="edd-notice error">';
echo '<p>' . $message . '</p>';
echo '</div>';
}
if ( ( empty( $this->edd_license->license ) || 'valid' !== $this->edd_license->license ) ) {
EDD()->notices->add_notice(
array(
'id' => 'edd-missing-license',
'class' => "error {$this->item_shortname}-license-error",
'message' => sprintf(
/* translators: 1. opening anchor tag; 2. closing anchor tag */
__( 'You have invalid or expired license keys for Easy Digital Downloads. %1$sActivate License(s)%2$s', 'easy-digital-downloads' ),
'<a href="' . esc_url( edd_get_admin_url( array( 'page' => 'edd-settings', 'tab' => 'licenses' ) ) ) . '" class="button button-secondary">',
'</a>'
),
'is_dismissible' => false,
)
);
}
}
@ -568,6 +507,16 @@ class EDD_License {
delete_option( $this->item_shortname . '_license_active' );
}
}
/**
* Display help text at the top of the Licenses tag
*
* @since 2.5
* @deprecated 3.1.1.4
* @param string $active_tab
* @return void
*/
public function license_help_text( $active_tab = '' ) {}
}
endif; // end class_exists check

View File

@ -52,21 +52,8 @@ function edd_add_customer( $data = array() ) {
}
$customers = new EDD\Database\Queries\Customer();
$customer_id = $customers->add_item( $data );
if ( ! empty( $customer_id ) ) {
/**
* Action that runs when a customer is added with the edd_add_customer function.
*
* @since 3.0.4
*
* @param int $customer_id Customer ID added.
* @param array $data Array of arguments sent to create the customer with.
*/
do_action( 'edd_customer_added', $customer_id, $data );
}
return $customer_id;
return $customers->add_item( $data );
}
/**
@ -80,20 +67,7 @@ function edd_add_customer( $data = array() ) {
function edd_delete_customer( $customer_id = 0 ) {
$customers = new EDD\Database\Queries\Customer();
$customer_deleted = $customers->delete_item( $customer_id );
if ( ! empty( $customer_deleted ) ) {
/**
* Action that runs when a customer is deleted with the edd_delete_customer function.
*
* @since 3.0.4
*
* @param int $customer_id Customer ID being deleted.
*/
do_action( 'edd_customer_deleted', $customer_id );
}
return $customer_deleted;
return $customers->delete_item( $customer_id );
}
/**
@ -189,23 +163,7 @@ function edd_destroy_customer( $customer_id = 0 ) {
function edd_update_customer( $customer_id = 0, $data = array() ) {
$customers = new EDD\Database\Queries\Customer();
$previous_customer_data = edd_get_customer( $customer_id );
$customer_updated = $customers->update_item( $customer_id, $data );
if ( ! empty( $customer_updated ) ) {
/**
* Action that runs when a customer is updated with the edd_update_customer function.
*
* @since 3.0.4
*
* @param int $customer_id Customer ID updated.
* @param array $data Array of arguments sent to create the customer with.
* @param EDD_Customer $previous_customer_data The customer row before it was updated.
*/
do_action( 'edd_customer_updated', $customer_id, $data, $previous_customer_data );
}
return $customer_updated;
return $customers->update_item( $customer_id, $data );
}
/**

View File

@ -1794,6 +1794,16 @@ class Query extends Base {
// Transition item data
$this->transition_item( $save, $item_id );
/**
* Adds a hook for a successfully added item.
* Custom for EDD.
*
* @since 3.1.1.4
* @param int $item_id The item id.
* @param array $data The array of data for the update.
*/
do_action( $this->apply_prefix( "{$this->item_name}_added" ), $item_id, $data );
// Return result
return $item_id;
}
@ -1819,15 +1829,15 @@ class Query extends Base {
$primary = $this->get_primary_column_name();
// Get item to update (from database, not cache)
$item = $this->get_item_raw( $primary, $item_id );
$item_raw = $this->get_item_raw( $primary, $item_id );
// Bail if item does not exist to update
if ( empty( $item ) ) {
if ( empty( $item_raw ) ) {
return false;
}
// Cast as an array for easier manipulation
$item = (array) $item;
$item = (array) $item_raw;
// Unset the primary key from data to parse
unset( $data[ $primary ] );
@ -1877,6 +1887,17 @@ class Query extends Base {
// Transition item data
$this->transition_item( $save, $item );
/**
* Adds a hook for a successfully updated item.
* Custom for EDD.
*
* @since 3.1.1.4
* @param int $item_id The item id.
* @param array $data The array of data for the update.
* @param object $item_raw The original item.
*/
do_action( $this->apply_prefix( "{$this->item_name}_updated" ), $item_id, $data, $item_raw );
// Return result
return $result;
}
@ -1930,6 +1951,15 @@ class Query extends Base {
$this->delete_all_item_meta( $item_id );
$this->clean_item_cache( $item );
/**
* Adds a hook for a successfully deleted item.
* Custom for EDD.
*
* @since 3.1.1.4
* @param int $item_id The item id.
*/
do_action( $this->apply_prefix( "{$this->item_name}_deleted" ), $item_id );
// Return result
return $result;
}

View File

@ -373,6 +373,25 @@ class Order extends Query {
return $clauses;
}
/**
* When searching by a numeric order number, we need to override the default where clause
* to return orders matching either the ID or order number.
*
* @since 3.1.1.4
* @param array $clauses
* @return array
*/
public function query_by_order_search( $clauses ) {
global $wpdb;
$clauses['where'] = $wpdb->prepare(
"{$this->table_alias}.id = %d OR {$this->table_alias}.order_number = %d",
absint( $this->query_vars['id'] ),
absint( $this->query_vars['order_number'] )
);
return $clauses;
}
/**
* Set the query var defaults for country and region.
*
@ -441,6 +460,10 @@ class Order extends Query {
'condition' => ! empty( $query['discount_id'] ),
'callback' => 'query_by_discount_id',
),
array(
'condition' => ! empty( $query['id'] ) && ! empty( $query['order_number'] ) && $query['id'] === $query['order_number'],
'callback' => 'query_by_order_search',
),
);
}
}

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,117 +31,117 @@ class Orders 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',
'length' => '20',
'unsigned' => true,
'default' => '0',
'sortable' => true
'name' => 'parent',
'type' => 'bigint',
'length' => '20',
'unsigned' => true,
'default' => '0',
'sortable' => true,
),
// order_number
// order_number.
array(
'name' => 'order_number',
'type' => 'varchar',
'length' => '255',
'searchable' => true,
'sortable' => true
'sortable' => true,
),
// status
// status.
array(
'name' => 'status',
'type' => 'varchar',
'length' => '20',
'default' => 'pending',
'sortable' => true,
'transition' => true
'transition' => true,
),
// type
// type.
array(
'name' => 'type',
'type' => 'varchar',
'length' => '20',
'default' => 'sale',
'sortable' => true
'name' => 'type',
'type' => 'varchar',
'length' => '20',
'default' => 'sale',
'sortable' => true,
),
// user_id
// user_id.
array(
'name' => 'user_id',
'type' => 'bigint',
'length' => '20',
'unsigned' => true,
'default' => '0',
'sortable' => true
'name' => 'user_id',
'type' => 'bigint',
'length' => '20',
'unsigned' => true,
'default' => '0',
'sortable' => true,
),
// customer_id
// customer_id.
array(
'name' => 'customer_id',
'type' => 'bigint',
'length' => '20',
'unsigned' => true,
'default' => '0',
'sortable' => true
'name' => 'customer_id',
'type' => 'bigint',
'length' => '20',
'unsigned' => true,
'default' => '0',
'sortable' => true,
),
// email
// email.
array(
'name' => 'email',
'type' => 'varchar',
'length' => '100',
'searchable' => true,
'sortable' => true
),
// ip
array(
'name' => 'ip',
'type' => 'varchar',
'length' => '60',
'sortable' => true
),
// gateway
array(
'name' => 'gateway',
'type' => 'varchar',
'length' => '100',
'sortable' => true,
'default' => 'manual',
),
// mode
// ip.
array(
'name' => 'mode',
'type' => 'varchar',
'length' => '20'
'name' => 'ip',
'type' => 'varchar',
'length' => '60',
'sortable' => true,
),
// currency
// gateway.
array(
'name' => 'currency',
'type' => 'varchar',
'length' => '20',
'validate' => 'strtoupper',
'name' => 'gateway',
'type' => 'varchar',
'length' => '100',
'sortable' => true,
'default' => 'manual',
),
// payment_key
// mode.
array(
'name' => 'mode',
'type' => 'varchar',
'length' => '20',
),
// currency.
array(
'name' => 'currency',
'type' => 'varchar',
'length' => '20',
'validate' => 'strtoupper',
),
// payment_key.
array(
'name' => 'payment_key',
'type' => 'varchar',
@ -148,7 +149,7 @@ class Orders extends Schema {
'searchable' => true,
),
// tax_rate_id
// tax_rate_id.
array(
'name' => 'tax_rate_id',
'type' => 'bigint',
@ -156,100 +157,100 @@ class Orders extends Schema {
'unsigned' => true,
'default' => null,
'allow_null' => true,
'sortable' => true
),
// subtotal
array(
'name' => 'subtotal',
'type' => 'decimal',
'length' => '18,9',
'default' => '0',
'sortable' => true,
'validate' => 'edd_sanitize_amount'
),
// discount
// subtotal.
array(
'name' => 'discount',
'type' => 'decimal',
'length' => '18,9',
'default' => '0',
'sortable' => true,
'validate' => 'edd_sanitize_amount'
'name' => 'subtotal',
'type' => 'decimal',
'length' => '18,9',
'default' => '0',
'sortable' => true,
'validate' => 'edd_sanitize_amount',
),
// tax
// discount.
array(
'name' => 'tax',
'type' => 'decimal',
'length' => '18,9',
'default' => '0',
'sortable' => true,
'validate' => 'edd_sanitize_amount'
'name' => 'discount',
'type' => 'decimal',
'length' => '18,9',
'default' => '0',
'sortable' => true,
'validate' => 'edd_sanitize_amount',
),
// total
// tax.
array(
'name' => 'total',
'type' => 'decimal',
'length' => '18,9',
'default' => '0',
'sortable' => true,
'validate' => 'edd_sanitize_amount'
'name' => 'tax',
'type' => 'decimal',
'length' => '18,9',
'default' => '0',
'sortable' => true,
'validate' => 'edd_sanitize_amount',
),
// rate
// total.
array(
'name' => 'rate',
'type' => 'decimal',
'length' => '10,5',
'default' => '1.00000',
'name' => 'total',
'type' => 'decimal',
'length' => '18,9',
'default' => '0',
'sortable' => true,
'validate' => 'edd_sanitize_amount',
),
// date_created
// rate.
array(
'name' => 'rate',
'type' => 'decimal',
'length' => '10,5',
'default' => '1.00000',
),
// 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,
),
// date_completed
// date_completed.
array(
'name' => 'date_completed',
'type' => 'datetime',
'default' => null,
'allow_null' => true,
'date_query' => true,
'sortable' => true
'sortable' => true,
),
// date_refundable
// date_refundable.
array(
'name' => 'date_refundable',
'type' => 'datetime',
'default' => null,
'allow_null' => true,
'date_query' => true,
'sortable' => true
'sortable' => true,
),
// uuid
// uuid.
array(
'uuid' => true,
)
'uuid' => true,
),
);
}

View File

@ -33,7 +33,7 @@ function edd_maybe_schedule_download_recalculation( $download_id ) {
// Check if the recalculation has already been scheduled.
if ( $is_scheduled && ! $bypass_cron ) {
edd_debug_log( 'Recalculation is already scheduled for ' . $download_id . ' at ' . edd_date_i18n( $is_scheduled, 'datetime' ) );
edd_debug_log( 'Recalculation is already scheduled for product ' . $download_id . ' at ' . edd_date_i18n( $is_scheduled, 'datetime' ) );
return;
}
@ -43,7 +43,7 @@ function edd_maybe_schedule_download_recalculation( $download_id ) {
return;
}
edd_debug_log( 'Scheduling recalculation for ' . $download_id );
edd_debug_log( 'Scheduling recalculation for product ' . $download_id );
wp_schedule_single_event(
time() + ( 5 * MINUTE_IN_SECONDS ),
'edd_recalculate_download_sales_earnings_deferred',

View File

@ -57,8 +57,7 @@ class EDD_Email_Summary {
public function __construct( $test_mode = false ) {
$this->test_mode = $test_mode;
$this->email_options = array(
'email_summary_frequency' => edd_get_option( 'email_summary_frequency', 'weekly' ),
'email_summary_start_of_week' => jddayofweek( (int) get_option( 'start_of_week' ) - 1, 1 ),
'email_summary_frequency' => edd_get_option( 'email_summary_frequency', 'weekly' ),
);
}
@ -416,5 +415,4 @@ class EDD_Email_Summary {
return $email_sent;
}
}

View File

@ -109,6 +109,11 @@ add_action( 'edd_checkout_user_error_checks', __NAMESPACE__ . '\send_ajax_errors
* @return void
*/
function create_order( $purchase_data ) {
if ( ! wp_verify_nonce( $purchase_data['gateway_nonce'], 'edd-gateway' ) ) {
wp_die( __( 'Nonce verification has failed', 'easy-digital-downloads' ), __( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) );
}
edd_debug_log( 'PayPal - create_order()' );
if ( ! ready_to_accept_payments() ) {

View File

@ -1,3 +1,3 @@
#edd-stripe-card-errors:not(:empty){margin:20px 0 0}:root{--edds-modal-grid-unit: 1rem;--edds-modal-overlay: rgba(0, 0, 0, 0.60)}.edds-modal__overlay{z-index:9999;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0, 0, 0, 0.60);background:var(--edds-modal-overlay);display:flex;justify-content:center;align-items:center}.edds-modal__container{background-color:#fff;min-width:350px;max-width:90vw;max-height:90vh;box-sizing:border-box;overflow-y:auto}.admin-bar .edds-modal__container{margin-top:32px}.edds-modal__header{padding:calc(1rem*1.5);padding:calc(var(--edds-modal-grid-unit)*1.5);display:flex;justify-content:space-between;align-items:center;position:sticky;top:0;z-index:2;background:#fff;border-bottom:1px solid #eee}.edds-modal__title{text-align:left;font-size:150%;margin:0}.edds-modal__close{line-height:1;padding:1rem}.edds-modal__close:before{content:"✕"}.edds-modal__content{margin:calc(1rem*1.5);margin:calc(var(--edds-modal-grid-unit)*1.5)}@keyframes eddsSlideIn{from{transform:translateY(15%)}to{transform:translateY(0)}}@keyframes eddsSlideOut{from{transform:translateY(0)}to{transform:translateY(15%)}}.edds-modal.has-slide{display:none}.edds-modal.has-slide.is-open{display:block}.edds-modal.has-slide[aria-hidden=false] .edds-modal__container{animation:eddsSlideIn .3s cubic-bezier(0, 0, 0.2, 1)}.edds-modal.has-slide[aria-hidden=true] .edds-modal__container{animation:eddsSlideOut .3s cubic-bezier(0, 0, 0.2, 1)}.edds-modal.has-slide .edds-modal__container,.edds-modal.has-slide .edds-modal__overlay{will-change:transform}.edds-buy-now-modal{width:500px}.edds-buy-now-modal .edds-modal__close{padding:.5rem}.edds-buy-now-modal #edd_checkout_form_wrap input.edd-input,.edds-buy-now-modal #edd_checkout_form_wrap textarea.edd-input{width:100%}.edds-buy-now-modal #edd_checkout_form_wrap #edd_purchase_submit{margin-top:1.5rem;margin-bottom:0}.edds-buy-now-modal .edds-field-spacer-shim{margin-bottom:1rem}.edds-buy-now-modal .edd-alert-error{margin:20px 0}.edds-buy-now-modal #edd-stripe-card-errors:not(:empty){margin-bottom:20px}.edds-buy-now-modal #edd-stripe-card-errors:not(:empty) .edd-alert-error{margin:0}#edd_purchase_submit #edd-purchase-button[data-edd-button-state=disabled]{opacity:.5;cursor:not-allowed}#edd_purchase_submit #edd-purchase-button[data-edd-button-state=updating],#edd_purchase_submit #edd-purchase-button [data-edd-button-state=processing]{opacity:.5;cursor:wait}
#edd-stripe-card-errors:not(:empty){margin:20px 0 0}:root{--edds-modal-grid-unit: 1rem;--edds-modal-overlay: rgba(0, 0, 0, 0.60)}.edds-modal__overlay{z-index:9999;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0, 0, 0, 0.60);background:var(--edds-modal-overlay);display:flex;justify-content:center;align-items:center}.edds-modal__container{background-color:#fff;min-width:350px;max-width:90vw;max-height:90vh;box-sizing:border-box;overflow-y:auto}.admin-bar .edds-modal__container{margin-top:32px}.edds-modal__header{padding:calc(1rem*1.5);padding:calc(var(--edds-modal-grid-unit)*1.5);display:flex;justify-content:space-between;align-items:center;position:sticky;top:0;z-index:2;background:#fff;border-bottom:1px solid #eee}.edds-modal__title{text-align:left;font-size:150%;margin:0}.edds-modal__close{line-height:1;padding:1rem}.edds-modal__close:before{content:"✕"}.edds-modal__content{margin:calc(1rem*1.5);margin:calc(var(--edds-modal-grid-unit)*1.5)}@keyframes eddsSlideIn{from{transform:translateY(15%)}to{transform:translateY(0)}}@keyframes eddsSlideOut{from{transform:translateY(0)}to{transform:translateY(15%)}}.edds-modal.has-slide{display:none}.edds-modal.has-slide.is-open{display:block}.edds-modal.has-slide[aria-hidden=false] .edds-modal__container{animation:eddsSlideIn .3s cubic-bezier(0, 0, 0.2, 1)}.edds-modal.has-slide[aria-hidden=true] .edds-modal__container{animation:eddsSlideOut .3s cubic-bezier(0, 0, 0.2, 1)}.edds-modal.has-slide .edds-modal__container,.edds-modal.has-slide .edds-modal__overlay{will-change:transform}.edds-buy-now-modal{width:500px}.edds-buy-now-modal .edds-modal__close{padding:.5rem}.edds-buy-now-modal #edd_checkout_form_wrap input.edd-input,.edds-buy-now-modal #edd_checkout_form_wrap textarea.edd-input{width:100%}.edds-buy-now-modal #edd_checkout_form_wrap #edd_purchase_submit{margin-top:1.5rem;margin-bottom:0}.edds-buy-now-modal .edds-field-spacer-shim{margin-bottom:1rem}.edds-buy-now-modal .edd-alert-error{margin:20px 0}.edds-buy-now-modal #edd-stripe-card-errors:not(:empty){margin-bottom:20px}.edds-buy-now-modal #edd-stripe-card-errors:not(:empty) .edd-alert-error{margin:0}#edd_purchase_submit #edd-purchase-button[data-edd-button-state=disabled]{opacity:.5;cursor:not-allowed}#edd_purchase_submit #edd-purchase-button[data-edd-button-state=updating],#edd_purchase_submit #edd-purchase-button [data-edd-button-state=processing]{opacity:.5;cursor:wait}#card_name,.card-name{padding:8px !important;width:100% !important;box-sizing:border-box}
/*# sourceMappingURL=paymentelements.min.css.map*/

View File

@ -1 +1 @@
{"version":3,"sources":["webpack:///./assets/css/src/payment-elements.scss"],"names":[],"mappings":"AAAA,oCAAoC,gBAAgB,MAAM,6BAA6B,0CAA0C,qBAAqB,aAAa,eAAe,MAAM,OAAO,QAAQ,SAAS,+BAA+B,qCAAqC,aAAa,uBAAuB,mBAAmB,uBAAuB,sBAAsB,gBAAgB,eAAe,gBAAgB,sBAAsB,gBAAgB,kCAAkC,gBAAgB,oBAAoB,uBAAuB,8CAA8C,aAAa,8BAA8B,mBAAmB,gBAAgB,MAAM,UAAU,gBAAgB,6BAA6B,mBAAmB,gBAAgB,eAAe,SAAS,mBAAmB,cAAc,aAAa,0BAA0B,YAAY,qBAAqB,sBAAsB,6CAA6C,uBAAuB,KAAK,0BAA0B,GAAG,yBAAyB,wBAAwB,KAAK,wBAAwB,GAAG,2BAA2B,sBAAsB,aAAa,8BAA8B,cAAc,gEAAgE,qDAAqD,+DAA+D,sDAAsD,wFAAwF,sBAAsB,oBAAoB,YAAY,uCAAuC,cAAc,2HAA2H,WAAW,iEAAiE,kBAAkB,gBAAgB,4CAA4C,mBAAmB,qCAAqC,cAAc,wDAAwD,mBAAmB,yEAAyE,SAAS,0EAA0E,WAAW,mBAAmB,uJAAuJ,WAAW,Y","file":"assets/css/build/paymentelements.min.css","sourcesContent":["#edd-stripe-card-errors:not(:empty){margin:20px 0 0}:root{--edds-modal-grid-unit: 1rem;--edds-modal-overlay: rgba(0, 0, 0, 0.60)}.edds-modal__overlay{z-index:9999;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0, 0, 0, 0.60);background:var(--edds-modal-overlay);display:flex;justify-content:center;align-items:center}.edds-modal__container{background-color:#fff;min-width:350px;max-width:90vw;max-height:90vh;box-sizing:border-box;overflow-y:auto}.admin-bar .edds-modal__container{margin-top:32px}.edds-modal__header{padding:calc(1rem*1.5);padding:calc(var(--edds-modal-grid-unit)*1.5);display:flex;justify-content:space-between;align-items:center;position:sticky;top:0;z-index:2;background:#fff;border-bottom:1px solid #eee}.edds-modal__title{text-align:left;font-size:150%;margin:0}.edds-modal__close{line-height:1;padding:1rem}.edds-modal__close:before{content:\"✕\"}.edds-modal__content{margin:calc(1rem*1.5);margin:calc(var(--edds-modal-grid-unit)*1.5)}@keyframes eddsSlideIn{from{transform:translateY(15%)}to{transform:translateY(0)}}@keyframes eddsSlideOut{from{transform:translateY(0)}to{transform:translateY(15%)}}.edds-modal.has-slide{display:none}.edds-modal.has-slide.is-open{display:block}.edds-modal.has-slide[aria-hidden=false] .edds-modal__container{animation:eddsSlideIn .3s cubic-bezier(0, 0, 0.2, 1)}.edds-modal.has-slide[aria-hidden=true] .edds-modal__container{animation:eddsSlideOut .3s cubic-bezier(0, 0, 0.2, 1)}.edds-modal.has-slide .edds-modal__container,.edds-modal.has-slide .edds-modal__overlay{will-change:transform}.edds-buy-now-modal{width:500px}.edds-buy-now-modal .edds-modal__close{padding:.5rem}.edds-buy-now-modal #edd_checkout_form_wrap input.edd-input,.edds-buy-now-modal #edd_checkout_form_wrap textarea.edd-input{width:100%}.edds-buy-now-modal #edd_checkout_form_wrap #edd_purchase_submit{margin-top:1.5rem;margin-bottom:0}.edds-buy-now-modal .edds-field-spacer-shim{margin-bottom:1rem}.edds-buy-now-modal .edd-alert-error{margin:20px 0}.edds-buy-now-modal #edd-stripe-card-errors:not(:empty){margin-bottom:20px}.edds-buy-now-modal #edd-stripe-card-errors:not(:empty) .edd-alert-error{margin:0}#edd_purchase_submit #edd-purchase-button[data-edd-button-state=disabled]{opacity:.5;cursor:not-allowed}#edd_purchase_submit #edd-purchase-button[data-edd-button-state=updating],#edd_purchase_submit #edd-purchase-button [data-edd-button-state=processing]{opacity:.5;cursor:wait}"],"sourceRoot":""}
{"version":3,"sources":["webpack:///./assets/css/src/payment-elements.scss"],"names":[],"mappings":"AAAA,oCAAoC,gBAAgB,MAAM,6BAA6B,0CAA0C,qBAAqB,aAAa,eAAe,MAAM,OAAO,QAAQ,SAAS,+BAA+B,qCAAqC,aAAa,uBAAuB,mBAAmB,uBAAuB,sBAAsB,gBAAgB,eAAe,gBAAgB,sBAAsB,gBAAgB,kCAAkC,gBAAgB,oBAAoB,uBAAuB,8CAA8C,aAAa,8BAA8B,mBAAmB,gBAAgB,MAAM,UAAU,gBAAgB,6BAA6B,mBAAmB,gBAAgB,eAAe,SAAS,mBAAmB,cAAc,aAAa,0BAA0B,YAAY,qBAAqB,sBAAsB,6CAA6C,uBAAuB,KAAK,0BAA0B,GAAG,yBAAyB,wBAAwB,KAAK,wBAAwB,GAAG,2BAA2B,sBAAsB,aAAa,8BAA8B,cAAc,gEAAgE,qDAAqD,+DAA+D,sDAAsD,wFAAwF,sBAAsB,oBAAoB,YAAY,uCAAuC,cAAc,2HAA2H,WAAW,iEAAiE,kBAAkB,gBAAgB,4CAA4C,mBAAmB,qCAAqC,cAAc,wDAAwD,mBAAmB,yEAAyE,SAAS,0EAA0E,WAAW,mBAAmB,uJAAuJ,WAAW,YAAY,sBAAsB,uBAAuB,sBAAsB,sB","file":"assets/css/build/paymentelements.min.css","sourcesContent":["#edd-stripe-card-errors:not(:empty){margin:20px 0 0}:root{--edds-modal-grid-unit: 1rem;--edds-modal-overlay: rgba(0, 0, 0, 0.60)}.edds-modal__overlay{z-index:9999;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0, 0, 0, 0.60);background:var(--edds-modal-overlay);display:flex;justify-content:center;align-items:center}.edds-modal__container{background-color:#fff;min-width:350px;max-width:90vw;max-height:90vh;box-sizing:border-box;overflow-y:auto}.admin-bar .edds-modal__container{margin-top:32px}.edds-modal__header{padding:calc(1rem*1.5);padding:calc(var(--edds-modal-grid-unit)*1.5);display:flex;justify-content:space-between;align-items:center;position:sticky;top:0;z-index:2;background:#fff;border-bottom:1px solid #eee}.edds-modal__title{text-align:left;font-size:150%;margin:0}.edds-modal__close{line-height:1;padding:1rem}.edds-modal__close:before{content:\"✕\"}.edds-modal__content{margin:calc(1rem*1.5);margin:calc(var(--edds-modal-grid-unit)*1.5)}@keyframes eddsSlideIn{from{transform:translateY(15%)}to{transform:translateY(0)}}@keyframes eddsSlideOut{from{transform:translateY(0)}to{transform:translateY(15%)}}.edds-modal.has-slide{display:none}.edds-modal.has-slide.is-open{display:block}.edds-modal.has-slide[aria-hidden=false] .edds-modal__container{animation:eddsSlideIn .3s cubic-bezier(0, 0, 0.2, 1)}.edds-modal.has-slide[aria-hidden=true] .edds-modal__container{animation:eddsSlideOut .3s cubic-bezier(0, 0, 0.2, 1)}.edds-modal.has-slide .edds-modal__container,.edds-modal.has-slide .edds-modal__overlay{will-change:transform}.edds-buy-now-modal{width:500px}.edds-buy-now-modal .edds-modal__close{padding:.5rem}.edds-buy-now-modal #edd_checkout_form_wrap input.edd-input,.edds-buy-now-modal #edd_checkout_form_wrap textarea.edd-input{width:100%}.edds-buy-now-modal #edd_checkout_form_wrap #edd_purchase_submit{margin-top:1.5rem;margin-bottom:0}.edds-buy-now-modal .edds-field-spacer-shim{margin-bottom:1rem}.edds-buy-now-modal .edd-alert-error{margin:20px 0}.edds-buy-now-modal #edd-stripe-card-errors:not(:empty){margin-bottom:20px}.edds-buy-now-modal #edd-stripe-card-errors:not(:empty) .edd-alert-error{margin:0}#edd_purchase_submit #edd-purchase-button[data-edd-button-state=disabled]{opacity:.5;cursor:not-allowed}#edd_purchase_submit #edd-purchase-button[data-edd-button-state=updating],#edd_purchase_submit #edd-purchase-button [data-edd-button-state=processing]{opacity:.5;cursor:wait}#card_name,.card-name{padding:8px !important;width:100% !important;box-sizing:border-box}"],"sourceRoot":""}

View File

@ -2,8 +2,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.9.2.1
* Description: Adds support for pre-authorized credit card payments and removes additional transaction fees.
* Version: 2.9.2.2
* Requires at least: 5.4
* Requires PHP: 7.1
* Author: Easy Digital Downloads
@ -44,7 +44,7 @@ function edd_stripe_core_bootstrap() {
}
if ( ! defined( 'EDD_STRIPE_VERSION' ) ) {
define( 'EDD_STRIPE_VERSION', '2.9.2.1' );
define( 'EDD_STRIPE_VERSION', '2.9.2.2' );
}
if ( ! defined( 'EDD_STRIPE_API_VERSION' ) ) {

View File

@ -26,14 +26,14 @@ add_filter( 'edd_settings_sections_gateways', 'edds_settings_section' );
*/
function edds_add_settings( $settings ) {
$stripe_settings = array(
'stripe_connect_button' => array(
'stripe_connect_button' => array(
'id' => 'stripe_connect_button',
'name' => __( 'Connection Status', 'easy-digital-downloads' ),
'desc' => edds_stripe_connect_setting_field(),
'type' => 'descriptive_text',
'class' => 'edd-stripe-connect-row',
),
'test_publishable_key' => array(
'test_publishable_key' => array(
'id' => 'test_publishable_key',
'name' => __( 'Test Publishable Key', 'easy-digital-downloads' ),
'desc' => __( 'Enter your test publishable key, found in your Stripe Account Settings', 'easy-digital-downloads' ),
@ -49,7 +49,7 @@ function edds_add_settings( $settings ) {
'size' => 'regular',
'class' => 'edd-hidden edds-api-key-row',
),
'live_publishable_key' => array(
'live_publishable_key' => array(
'id' => 'live_publishable_key',
'name' => __( 'Live Publishable Key', 'easy-digital-downloads' ),
'desc' => __( 'Enter your live publishable key, found in your Stripe Account Settings', 'easy-digital-downloads' ),
@ -57,7 +57,7 @@ function edds_add_settings( $settings ) {
'size' => 'regular',
'class' => 'edd-hidden edds-api-key-row',
),
'live_secret_key' => array(
'live_secret_key' => array(
'id' => 'live_secret_key',
'name' => __( 'Live Secret Key', 'easy-digital-downloads' ),
'desc' => __( 'Enter your live secret key, found in your Stripe Account Settings', 'easy-digital-downloads' ),
@ -65,7 +65,7 @@ function edds_add_settings( $settings ) {
'size' => 'regular',
'class' => 'edd-hidden edds-api-key-row',
),
'stripe_webhook_description' => array(
'stripe_webhook_description' => array(
'id' => 'stripe_webhook_description',
'type' => 'descriptive_text',
'name' => __( 'Webhooks', 'easy-digital-downloads' ),
@ -93,7 +93,7 @@ function edds_add_settings( $settings ) {
) .
'</p>',
),
'stripe_billing_fields' => array(
'stripe_billing_fields' => array(
'id' => 'stripe_billing_fields',
'name' => __( 'Billing Address Display', 'easy-digital-downloads' ),
'desc' => __( 'Select how you would like to display the billing address fields on the checkout form. <p><strong>Notes</strong>:</p><p>If taxes are enabled, this option cannot be changed from "Full address".</p><p>If set to "No address fields", you <strong>must</strong> disable "zip code verification" in your Stripe account.</p>', 'easy-digital-downloads' ),
@ -105,13 +105,13 @@ function edds_add_settings( $settings ) {
'none' => __( 'No address fields', 'easy-digital-downloads' ),
),
),
'stripe_statement_descriptor' => array(
'stripe_statement_descriptor' => array(
'id' => 'stripe_statement_descriptor',
'name' => __( 'Statement Descriptor', 'easy-digital-downloads' ),
'desc' => __( 'Choose how charges will appear on customer\'s credit card statements. <em>Max 22 characters</em>', 'easy-digital-downloads' ),
'type' => 'text',
),
'stripe_restrict_assets' => array(
'stripe_restrict_assets' => array(
'id' => 'stripe_restrict_assets',
'name' => ( __( 'Restrict Stripe Assets', 'easy-digital-downloads' ) ),
'check' => ( __( 'Only load Stripe.com hosted assets on pages that specifically utilize Stripe functionality.', 'easy-digital-downloads' ) ),

View File

@ -420,4 +420,17 @@ class EDD_Stripe_Rate_Limiting {
}
}
/**
* Get the error message to display when the card error limit has been hit.
*
* @since 2.9.2.2
* @return string The error message.
*/
public function get_rate_limit_error_message() {
return esc_html__(
'We are unable to process your payment at this time, please try again later or contact support.',
'easy-digital-downloads'
);
}
}

View File

@ -36,6 +36,22 @@ class EDD_Stripe {
*/
public $rate_limiting;
/**
* Has Regional Support.
*
* @since 2.9.2.2
* @var bool
*/
public $has_regional_support = false;
/**
* Regional Support class.
*
* @since 2.9.2.2
* @var EDD_Stripe_Country_Base
*/
public $regional_support;
/**
* Instantiates or returns the singleton instance.
*
@ -52,27 +68,15 @@ class EDD_Stripe {
self::$instance->filters();
if ( true === edds_is_pro() ) {
if ( class_exists( '\\EDD\\Extensions\\ExtensionRegistry' ) ) {
add_action( 'edd_extension_license_init', function( \EDD\Extensions\ExtensionRegistry $registry ) {
$registry->addExtension(
EDD_STRIPE_PLUGIN_FILE,
'Stripe Pro Payment Gateway',
167,
EDD_STRIPE_VERSION,
'stripe_license_key'
);
} );
} elseif ( class_exists( 'EDD_License' ) ) {
new EDD_License(
add_action( 'edd_extension_license_init', function( \EDD\Extensions\ExtensionRegistry $registry ) {
$registry->addExtension(
EDD_STRIPE_PLUGIN_FILE,
'Stripe Pro Payment Gateway',
167,
EDD_STRIPE_VERSION,
'Easy Digital Downloads',
'stripe_license_key',
null,
167
'stripe_license_key'
);
}
} );
}
}
@ -173,6 +177,9 @@ class EDD_Stripe {
require_once EDDS_PLUGIN_DIR . '/includes/integrations/edd-auto-register.php';
}
// Load Regional Support.
$this->load_regional_support();
// Pro.
$pro = EDDS_PLUGIN_DIR . '/includes/pro/index.php';
@ -293,4 +300,33 @@ class EDD_Stripe {
return $gateways;
}
/**
* Loads regional support.
*
* @since 2.9.2.2
*/
private function load_regional_support() {
$base_country = edd_get_option( 'base_country', 'US' );
$regions_needing_support = array( 'IN' );
if ( ! in_array( $base_country, $regions_needing_support, true ) ) {
return;
}
$possible_region_file = 'class-edd-stripe-region-' . strtolower( $base_country ) . '.php';
$possible_region_path = EDDS_PLUGIN_DIR . 'includes/utils/regional-support/' . $possible_region_file;
if ( ! file_exists( $possible_region_path ) ) {
return;
}
// Regional Support is needed.
require_once EDDS_PLUGIN_DIR . 'includes/utils/regional-support/class-edd-stripe-region-base.php';
require_once $possible_region_path;
$possible_region_class = 'EDD_Stripe_Region_' . strtoupper( $base_country );
if ( class_exists( $possible_region_class ) ) {
$this->has_regional_support = true;
require_once EDDS_PLUGIN_DIR . 'includes/utils/regional-support/' . $possible_region_file;
$this->regional_support = new $possible_region_class();
}
}
}

View File

@ -20,7 +20,7 @@ function edds_get_stripe_payment_elements_theme() {
*
* @link https://stripe.com/docs/elements/appearance-api#theme
*
* @see assets/js/src/frontend/payment-elements/index.php::generateElementStyles
* @see assets/js/src/frontend/payment-elements/index.js::generateElementStyles
*
* @param array $payment_elements_theme The theme to use for the Payment Element object.
*/
@ -42,7 +42,7 @@ function edds_get_stripe_payment_elements_variables() {
*
* @link https://stripe.com/docs/elements/appearance-api?platform=web#variables
*
* @see assets/js/src/frontend/payment-elements/index.php::generateElementStyles
* @see assets/js/src/frontend/payment-elements/index.js::generateElementStyles
*
* @param array $payment_elements_variables Variables used for the Payment Elements.
*/
@ -95,7 +95,7 @@ function edds_get_stripe_payment_elements_layout() {
*
* @link https://stripe.com/docs/js/elements_object/create_payment_element#payment_element_create-options-layout
*
* @see assets/js/src/frontend/payment-elements/index.php::generateElementStyles
* @see assets/js/src/frontend/payment-elements/index.js::generateElementStyles
*
* @param array $payment_elements_layout Layout values used to create Stripe Elements object.
*/
@ -121,7 +121,7 @@ function edds_get_stripe_payment_elements_wallets() {
*
* @link https://stripe.com/docs/js/elements_object/create_payment_element#payment_element_create-options-wallets
*
* @see assets/js/src/frontend/payment-elements/index.php::generateElementStyles
* @see assets/js/src/frontend/payment-elements/index.js::generateElementStyles
*
* @param bool If wallets should be disabled.
*/
@ -151,7 +151,7 @@ function edds_get_stripe_payment_elements_wallets() {
*
* @link https://stripe.com/docs/js/elements_object/create_payment_element#payment_element_create-options-wallets
*
* @see assets/js/src/frontend/payment-elements/index.php::generateElementStyles
* @see assets/js/src/frontend/payment-elements/index.js::generateElementStyles
*
* @param array $enabled_wallets Allowed wallets payment methods ot use on the Payment Element.
*/
@ -177,7 +177,7 @@ function edds_get_stripe_payment_elements_label_style() {
*
* @link https://stripe.com/docs/elements/appearance-api?platform=web#others
*
* @see assets/js/src/frontend/payment-elements/index.php::generateElementStyles
* @see assets/js/src/frontend/payment-elements/index.js::generateElementStyles
*
* @param array $label_style The style to use for the Payment Elements labels.
*/
@ -204,7 +204,7 @@ function edds_get_stripe_payment_elements_fonts() {
* @link https://stripe.com/docs/js/appendix/css_font_source_object
* @link https://stripe.com/docs/js/appendix/custom_font_source_object
*
* @see assets/js/src/frontend/payment-elements/index.php::generateElementStyles
* @see assets/js/src/frontend/payment-elements/index.js::generateElementStyles
*
* @param array $fonts The style to use for the Payment Elements labels.
*/
@ -212,6 +212,44 @@ function edds_get_stripe_payment_elements_fonts() {
}
/**
* Allows passing custom fields into the Stripe Elements.
*
* @since 2.9.2.2
*/
function edds_get_stripe_payment_elements_fields() {
$default_fields = array(
'billingDetails' => array(
'name' => 'auto',
'email' => 'never', // It is not advised to change this to auto, as it will create duplicate email fields on checkout.
'phone' => 'never',
'address' => 'never',
),
);
// By default, if the store has the address fields required, don't include them in the Payment Element.
if ( 'none' !== edd_get_option( 'stripe_billing_fields', 'none' ) ) {
$default_fields['billingDetails']['address'] = 'never';
}
/**
* Allows passing custom fields into the Stripe Elements.
*
* This needs to be an array. The default fields hold our values for the billingDetails fields. Fields can have a value of
* either 'auto' or 'never'. If you want to disable a field, set it to 'never'. When set to 'auto', Stripe will attempt to
* determine if the field is necessary based on a combination of currency, country, and account.
*
* @since 2.9.2.2
*
* @link https://stripe.com/docs/js/elements_object/create_payment_element#payment_element_create-options-fields
*
* @see assets/js/src/frontend/payment-elements/index.js::createAndMountElement
*
* @param array $default_fields The default fields and their values.
*/
return apply_filters( 'edds_stripe_payment_elements_fields', $default_fields );
}
/**
* Gathers all the possible customizations for the Stripe Payment Elements.
*
@ -234,6 +272,7 @@ function edds_gather_payment_element_customizations() {
'labels' => edds_get_stripe_payment_elements_label_style(),
'fonts' => edds_get_stripe_payment_elements_fonts(),
'paymentMethodTypes' => edds_payment_element_payment_method_types(),
'fields' => edds_get_stripe_payment_elements_fields(),
'i18n' => array(
'errorMessages' => edds_get_localized_error_messages(),
),

View File

@ -6,13 +6,21 @@
* @since 2.7.0
*/
/**
* If regional support is enabled, check if the card name field is required.
*/
function edds_maybe_disable_card_name() {
// We no longer need a card name field.
add_filter( 'edd_purchase_form_required_fields', function( $required_fields ) {
unset( $required_fields['card_name'] );
return $required_fields;
} );
remove_action( 'edd_checkout_error_checks', 'edds_process_post_data' );
// We no longer need a card name field for some regions, so remove the requirement if it's not needed.
if ( false === edd_stripe()->has_regional_support || false === edd_stripe()->regional_support->requires_card_name ) {
add_filter(
'edd_purchase_form_required_fields',
function( $required_fields ) {
unset( $required_fields['card_name'] );
return $required_fields;
}
);
remove_action( 'edd_checkout_error_checks', 'edds_process_post_data' );
}
}
add_action( 'edd_pre_process_purchase', 'edds_maybe_disable_card_name' );
@ -48,12 +56,7 @@ function edds_process_purchase_form( $purchase_data ) {
try {
if ( edd_stripe()->rate_limiting->has_hit_card_error_limit() ) {
throw new \EDD_Stripe_Gateway_Exception(
esc_html__(
'We are unable to process your payment at this time, please try again later or contact support.',
'easy-digital-downloads'
)
);
throw new \EDD_Stripe_Gateway_Exception( edd_stripe()->rate_limiting->get_rate_limit_error_message() );
}
/**
@ -70,8 +73,12 @@ function edds_process_purchase_form( $purchase_data ) {
*
* We're also going to attempt to restrict this to a single subscription and no mixed carts, for the time being.
*/
$cart_contains_subscription = false;
if ( function_exists( 'edd_recurring' ) ) {
if ( ( count( edd_get_cart_contents() ) > 1 && edd_recurring()->cart_contains_recurring() ) || edd_recurring()->cart_is_mixed() ) {
$cart_contains_subscription = edd_recurring()->cart_contains_recurring();
if ( ( count( edd_get_cart_contents() ) > 1 && $cart_contains_subscription ) || edd_recurring()->cart_is_mixed() ) {
throw new \EDD_Stripe_Gateway_Exception( edds_get_single_subscription_cart_error() );
}
@ -146,23 +153,23 @@ function edds_process_purchase_form( $purchase_data ) {
'edd_payment_fees' => esc_html( edd_get_cart_fee_total() ),
'edd_payment_total' => esc_html( $purchase_data['price'] ),
'edd_payment_items' => esc_html( implode( ', ', $payment_items ) ),
'zero_decimal_amount' => $amount,
),
);
if ( ! empty( $_REQUEST['payment_method_id'] ) ) {
$intent_args['payment_method'] = sanitize_text_field( $_REQUEST['payment_method_id'] );
} else {
$payment_method_types = edds_payment_element_payment_method_types();
$payment_method = $_REQUEST['payment_method'];
if ( ! empty( $payment_method_types ) ) {
$intent_args['payment_method_types'] = $payment_method_types;
} else {
$intent_args['automatic_payment_methods'] = array( 'enabled' => true );
}
}
// Attach the payment method.
$intent_args['payment_method'] = sanitize_text_field( $payment_method['id'] );
// Set to automatic payment methods so any of the supported methods can be used here.
$intent_args['automatic_payment_methods'] = array( 'enabled' => true );
// We need the intent type later, so we'll set it here.
$intent_type = ( edds_is_preapprove_enabled() || 0 === $amount ) ? 'SetupIntent' : 'PaymentIntent';
// Create a SetupIntent for a non-payment carts.
if ( edds_is_preapprove_enabled() || 0 === $amount ) {
if ( 'SetupIntent' === $intent_type ) {
$intent_args = array_merge(
array(
'description' => edds_get_payment_description( $purchase_data['cart_details'] ),
@ -171,8 +178,6 @@ function edds_process_purchase_form( $purchase_data ) {
$intent_args
);
$intent_type = 'SetupIntent';
/**
* BETA Functionality.
*
@ -229,8 +234,6 @@ function edds_process_purchase_form( $purchase_data ) {
$intent_args
);
$intent_type = 'PaymentIntent';
$stripe_connect_account_id = edd_get_option( 'stripe_connect_account_id' );
if (
@ -270,7 +273,29 @@ function edds_process_purchase_form( $purchase_data ) {
}
}
/**
* If purchasing a subscription with a card, we need to add the subscription mandate data.
*
* This will ensure that any cards that require mandates like INR payments or India based cards will correctly add
* the mandates necessary for recurring payments.
*
* We do this after we check for an existing intent ID, because the mandate data will change depending on the 'timestamp'.
*/
if ( 'card' === $payment_method['type'] && true === $cart_contains_subscription ) {
require_once EDDS_PLUGIN_DIR . 'includes/utils/class-edd-stripe-mandates.php';
$mandates = new EDD_Stripe_Mandates( $purchase_data, $intent_type );
$mandate_options = $mandates->mandate_options;
// Add the mandate options to the intent arguments.
$intent_args['payment_method_options']['card']['mandate_options'] = $mandate_options;
}
if ( ! empty( $existing_intent ) ) {
// Existing intents need to not have the automatic_payment_methods flag set.
if ( ! empty( $intent_args['automatic_payment_methods'] ) ) {
unset( $intent_args['automatic_payment_methods'] );
}
edds_api_request( $intent_type, 'update', $intent->id, $intent_args );
$intent = edds_api_request( $intent_type, 'retrieve', $intent->id );
} else {
@ -520,6 +545,27 @@ function edds_create_and_complete_order() {
)
);
// The returned Intent charges might contain a mandate ID, so let's save that and make a note.
if ( ! empty( $intent->charges->data ) ) {
foreach ( $intent->charges->data as $charge ) {
if ( empty( $charge->payment_method_details->card->mandate ) ) {
continue;
}
$mandate_id = $charge->payment_method_details->card->mandate;
edd_update_order_meta( $order->id, '_edds_stripe_mandate', $mandate_id );
edd_add_note(
array(
'object_id' => $order->id,
'content' => 'Stripe Mandate ID: ' . $mandate_id,
'user_id' => is_admin() ? get_current_user_id() : 0,
'object_type' => 'order',
)
);
}
}
// Attach the \Stripe\Customer ID to the \EDD_Customer meta if one exists.
$edd_customer = new EDD_Customer( $purchase_data['user_email'] );
@ -682,7 +728,13 @@ add_action( 'wp_ajax_nopriv_edds_create_and_complete_order', 'edds_create_and_co
function edds_payment_elements_rate_limit_tick() {
// Increase the card error count.
edd_stripe()->rate_limiting->increment_card_error_count();
exit();
wp_send_json_success(
array(
'is_at_limit' => edd_stripe()->rate_limiting->has_hit_card_error_limit(),
'message' => edd_stripe()->rate_limiting->get_rate_limit_error_message(),
)
);
}
add_action( 'wp_ajax_edds_payment_elements_rate_limit_tick', 'edds_payment_elements_rate_limit_tick' );
add_action( 'wp_ajax_nopriv_edds_payment_elements_rate_limit_tick', 'edds_payment_elements_rate_limit_tick' );
@ -698,7 +750,7 @@ add_action( 'wp_ajax_nopriv_edds_payment_elements_rate_limit_tick', 'edds_paymen
function edds_get_payment_description( $cart_details ) {
$purchase_summary = '';
if( is_array( $cart_details ) && ! empty( $cart_details ) ) {
if ( is_array( $cart_details ) && ! empty( $cart_details ) ) {
foreach( $cart_details as $item ) {
$purchase_summary .= $item['name'];
$price_id = isset( $item['item_number']['options']['price_id'] )
@ -715,7 +767,7 @@ function edds_get_payment_description( $cart_details ) {
$purchase_summary = rtrim( $purchase_summary, ', ' );
}
// Stripe has a maximum of 999 characters in the charge description
// Stripe has a maximum of 999 characters in the charge description.
$purchase_summary = substr( $purchase_summary, 0, 1000 );
return html_entity_decode( $purchase_summary, ENT_COMPAT, 'UTF-8' );

View File

@ -135,6 +135,15 @@ function edds_output_payment_elements_form() {
?>
<div id="edd-card-wrap">
<?php if ( edd_stripe()->has_regional_support && edd_stripe()->regional_support->requires_card_name ) : ?>
<p id="edd-card-name-wrap">
<label for="card_name" class="edd-label">
<?php esc_html_e( 'Name on the Card', 'easy-digital-downloads' ); ?>
<span class="edd-required-indicator">*</span>
</label>
<input type="text" name="card_name" id="card_name" class="card-name edd-input required" placeholder="<?php esc_attr_e( 'Card name', 'easy-digital-downloads' ); ?>" autocomplete="cc-name" required/>
</p>
<?php endif; ?>
<div id="edd-stripe-payment-element"></div>
<p class="edds-field-spacer-shim"></p><!-- Extra spacing -->
</div>

View File

@ -0,0 +1,225 @@
<?php
/**
* Adds support for Stripe Mandates.
*
* Mandates are added to the Payment and Setup Intents whenever a subscription is being purchased
* to accommodate for banking regulations to assist in renewal payments.
*
* @since 2.9.2.2
*/
class EDD_Stripe_Mandates {
/**
* The purchase data.
*
* @since 2.9.2.2
* @var array
*/
protected $purchase_data = array();
/**
* The intent type.
*
* @since 2.9.2.2
* @var string
*/
protected $intent_type = '';
/**
* The amount to charge.
*
* @since 2.9.2.2
* @var int
*/
protected $amount = 0;
/**
* The currency to charge.
*
* @since 2.9.2.2
* @var string
*/
protected $currency = '';
/**
* The amount type.
*
* @since 2.9.2.2
* @var string
*/
protected $amount_type = 'maximum';
/**
* The interval.
*
* @since 2.9.2.2
* @var string
*/
protected $interval = '';
/**
* The interval count.
*
* @since 2.9.2.2
* @var int
*/
protected $interval_count = 0;
/**
* The reference.
*
* @since 2.9.2.2
* @var string
*/
protected $reference = '';
/**
* The mandate options.
*
* @since 2.9.2.2
* @var array
*/
public $mandate_options = array();
/**
* Instaniate the class to generate mandates.
*
* @since 2.9.2.2
*
* @param array $purchase_data The purchase data.
* @param string $intent_type The intent type.
*/
public function __construct( $purchase_data = array(), $intent_type = 'PaymentIntent' ) {
// Save the purchase data locally, for use later.
$this->purchase_data = $purchase_data;
$this->intent_type = $intent_type;
$this->amount = $this->format_amount();
$this->currency = edd_get_currency();
$this->reference = $purchase_data['purchase_key'];
// Generate the interval and interval count.
$this->get_interval_and_count( $purchase_data );
// Now that all the data has been determined, generate the mandate options.
$this->generate_mandate_arguments();
}
/**
* Formats the amount into a Stripe-friendly format.
*
* @since 2.9.2.2
*
* @return int The formatted amount.
*/
private function format_amount() {
$amount = $this->purchase_data['price'];
if ( edds_is_zero_decimal_currency() ) {
return $amount;
}
return round( $amount * 100, 0 );
}
/**
* Gets the interval and interval count for the mandate.
*
* @since 2.9.2.2
*/
private function get_interval_and_count() {
/**
* Setup intervals based on the Recurring Payment periods.
*
* We use a foreach here, but with Payment Elements, it's only a single subscription, we just
* want to properly itterate on them.
*/
$period = false;
foreach ( $this->purchase_data['downloads'] as $download ) {
// This is a non-recurring download. Move along.
if ( ! isset( $download['options']['recurring'] ) ) {
continue;
}
$period = $download['options']['recurring']['period'];
break;
}
// Setup intervals for the mandate based on the Recurring Payment periods.
switch ( $period ) {
case 'day':
$interval = 'day';
$interval_count = 1;
break;
case 'week':
$interval = 'week';
$interval_count = 1;
break;
case 'month':
$interval = 'month';
$interval_count = 1;
break;
case 'quarter':
$interval = 'month';
$interval_count = 3;
break;
case 'semi-year':
$interval = 'month';
$interval_count = 6;
break;
case 'year':
$interval = 'year';
$interval_count = 1;
break;
default:
$interval = 'sporadic';
$interval_count = false;
break;
}
$this->interval = $interval;
if ( false !== $interval_count ) {
$this->interval_count = $interval_count;
}
}
/**
* Generates the mandate options for use with an intent.
*
* @since 2.9.2.2
*/
private function generate_mandate_arguments() {
$mandate_options = array(
'reference' => $this->reference,
'amount' => $this->amount,
'start_date' => current_time( 'timestamp' ),
'amount_type' => 'maximum',
'supported_types' => array( 'india' ),
'interval' => $this->interval,
);
if ( false !== $this->interval_count ) {
$mandate_options['interval_count'] = $this->interval_count;
}
// SetupIntent types require the currency to be passed with the mandate_options.
if ( 'SetupIntent' === $this->intent_type ) {
$mandate_options['currency'] = edd_get_currency();
}
/**
* Alllows further customization of the mandate options sent with the intent.
*
* @since 2.9.2.2
*
* @param array $mandate_options The set of mandate options we've generated.
* @param array $purchase_data The purchase data being processed.
* @param string $intent_type The intent type (either SetupIntent or PaymentIntent).
*/
$mandate_options = apply_filters( 'edds_mandate_options', $mandate_options, $this->purchase_data, $this->intent_type );
$this->mandate_options = $mandate_options;
}
}

View File

@ -0,0 +1,123 @@
<?php
/**
* Generic Regionality functionality class for EDD Stripe.
*
* @package EDD_Stripe
* @since 2.9.2.2
*/
abstract class EDD_Stripe_Region_Base {
/**
* Country code.
*
* @since 2.9.2.2
* @var string
*/
public $country_code;
/**
* If the country requires a card name.
*
* @since 2.9.2.2
* @var bool
*/
public $requires_card_name;
/**
* If the country requires a card address.
*
* @since 2.9.2.2
* @var bool
*/
public $requires_card_address;
/**
* Constructor.
*
* @since 2.9.2.2
*/
public function __construct() {
$this->setup_filters();
}
/**
* Applies various filters.
*/
protected function setup_filters() {
// Possibly add a message above the address fields if they are required.
add_filter( 'edd_settings_gateways', array( $this, 'add_billing_address_message' ), 30 );
}
/**
* Inserts a descriptive text setting prior to the address fields setting if a region requires card address.
*
* @since 2.9.2.2
*
* @param array $settings The current registered settings.
*
* @return array The settings with the new descriptive text, if necessary.
*/
public function add_billing_address_message( $settings ) {
// The current region does not require card address.
if ( ! $this->requires_card_address ) {
return $settings;
}
$current_billing_fields_option = edd_get_option( 'stripe_billing_fields' );
// The current region requires card address, but the billing fields option is set to "full" already.
if ( 'full' === $current_billing_fields_option ) {
return $settings;
}
$setting = array(
'id' => 'stripe_billing_address_message',
'name' => '',
'desc' => $this->get_billing_fields_message_output(),
'type' => 'descriptive_text',
'class' => 'edd-stripe-connect-row',
);
$position = array_search(
'stripe_billing_fields',
array_keys(
$settings['edd-stripe']
),
true
);
array_splice(
$settings['edd-stripe'],
$position,
0,
array(
'stripe_billing_address_message' => $setting,
)
);
return $settings;
}
/**
* Output a message concerning regions that should collect 'full address' information.
*
* @since 2.9.2.2
*/
protected function get_billing_fields_message_output() {
ob_start();
?>
<div id="edds-stripe-billing-fields-message" class="notice inline notice-warning">
<p>
<?php
printf(
esc_html__( 'Based on your store\'s base country of %s, it is recommended to set your Billing Address Display to use the "Full Address" option to ensure payments are completed successfully.', 'easy-digital-downloads' ),
edd_get_country_name( edd_get_option( 'base_country', 'US' ) )
);
?>
</p>
</div>
<?php
return ob_get_clean();
}
}

View File

@ -0,0 +1,18 @@
<?php
/**
* India Regionality functionality class for EDD Stripe.
*/
class EDD_Stripe_Region_IN extends EDD_Stripe_Region_Base {
/**
* Constructor.
*/
public function __construct() {
$this->country_code = 'IN';
$this->requires_card_name = true;
$this->requires_card_address = true;
parent::__construct();
}
}

View File

@ -429,7 +429,8 @@ class ClassLoader
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
(self::$includeFile)($file);
$includeFile = self::$includeFile;
$includeFile($file);
return true;
}
@ -560,7 +561,10 @@ class ClassLoader
return false;
}
private static function initializeIncludeClosure(): void
/**
* @return void
*/
private static function initializeIncludeClosure()
{
if (self::$includeFile !== null) {
return;
@ -574,8 +578,8 @@ class ClassLoader
* @param string $file
* @return void
*/
self::$includeFile = static function($file) {
self::$includeFile = \Closure::bind(static function($file) {
include $file;
};
}, null, null);
}
}

View File

@ -98,7 +98,7 @@ class InstalledVersions
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
}
}
@ -119,7 +119,7 @@ class InstalledVersions
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints($constraint);
$constraint = $parser->parseConstraints((string) $constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
@ -328,7 +328,9 @@ class InstalledVersions
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
$installed[] = self::$installedByVendor[$vendorDir] = $required;
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
}
@ -340,12 +342,17 @@ class InstalledVersions
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = require __DIR__ . '/installed.php';
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require __DIR__ . '/installed.php';
self::$installed = $required;
} else {
self::$installed = array();
}
}
$installed[] = self::$installed;
if (self::$installed !== array()) {
$installed[] = self::$installed;
}
return $installed;
}

View File

@ -1,9 +1,9 @@
<?php return array(
'root' => array(
'name' => 'easy-digital-downloads/edd-stripe',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '47178f1567076390fc6f41a5c5ebdf986b915165',
'pretty_version' => '2.9.2.2',
'version' => '2.9.2.2',
'reference' => '7e59ac4f4357cb3b388182e0601056f60f0b2407',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@ -11,9 +11,9 @@
),
'versions' => array(
'easy-digital-downloads/edd-stripe' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '47178f1567076390fc6f41a5c5ebdf986b915165',
'pretty_version' => '2.9.2.2',
'version' => '2.9.2.2',
'reference' => '7e59ac4f4357cb3b388182e0601056f60f0b2407',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),

View File

@ -63,20 +63,7 @@ function edd_add_order_adjustment( $data ) {
// Instantiate a query object
$order_adjustments = new EDD\Database\Queries\Order_Adjustment();
$order_adjustment_id = $order_adjustments->add_item( $data );
if ( ! empty( $order_adjustment_id ) ) {
/**
* Action that runs when an order item is successfully added.
*
* @since 3.1
* @param int Order adjustment ID.
* @param array Array of order adjustment data.
*/
do_action( 'edd_order_adjustment_added', $order_adjustment_id, $data );
}
return $order_adjustment_id;
return $order_adjustments->add_item( $data );
}
/**
@ -132,22 +119,7 @@ function edd_delete_order_adjustment( $order_adjustment_id = 0 ) {
function edd_update_order_adjustment( $order_adjustment_id = 0, $data = array() ) {
$order_adjustments = new EDD\Database\Queries\Order_Adjustment();
$previous_adjustment = edd_get_order_adjustment( $order_adjustment_id );
$order_adjustment_updated = $order_adjustments->update_item( $order_adjustment_id, $data );
if ( ! empty( $order_adjustment_updated ) ) {
/**
* Action that runs when an order item is updated.
*
* @since 3.1
* @param int The order adjustment ID.
* @param array The array of data to update.
* @param EDD\Orders\Order_Adjustment The original order adjustment object.
*/
do_action( 'edd_order_adjustment_updated', $order_adjustment_id, $data, $previous_adjustment );
}
return $order_adjustment_updated;
return $order_adjustments->update_item( $order_adjustment_id, $data );
}
/**

View File

@ -62,20 +62,7 @@ function edd_add_order_item( $data = array() ) {
// Instantiate a query object
$order_items = new EDD\Database\Queries\Order_Item();
$order_item_id = $order_items->add_item( $data );
if ( ! empty( $order_item_id ) ) {
/**
* Action that runs when an order item is successfully added.
*
* @since 3.1
* @param int Order item ID.
* @param array Array of order item data.
*/
do_action( 'edd_order_item_added', $order_item_id, $data );
}
return $order_item_id;
return $order_items->add_item( $data );
}
/**
@ -89,20 +76,7 @@ function edd_add_order_item( $data = array() ) {
function edd_delete_order_item( $order_item_id = 0 ) {
$order_items = new EDD\Database\Queries\Order_Item();
$order_item_deleted = $order_items->delete_item( $order_item_id );
if ( ! empty( $order_item_deleted ) ) {
/**
* Action that runs when an order item is deleted.
*
* @since 3.0.5
*
* @param int $order_item_id Order item ID being deleted.
*/
do_action( 'edd_order_item_deleted', $order_item_id );
}
return $order_item_deleted;
return $order_items->delete_item( $order_item_id );
}
/**
@ -143,22 +117,7 @@ function edd_delete_order_item( $order_item_id = 0 ) {
function edd_update_order_item( $order_item_id = 0, $data = array() ) {
$order_items = new EDD\Database\Queries\Order_Item();
$previous_order_item_data = edd_get_order_item( $order_item_id );
$order_item_updated = $order_items->update_item( $order_item_id, $data );
if ( ! empty( $order_item_updated ) ) {
/**
* Action that runs when an order item is updated.
*
* @since 3.1
* @param int The order item ID.
* @param array The array of data to update.
* @param EDD\Orders\Order_Item The original order item object.
*/
do_action( 'edd_order_item_updated', $order_item_id, $data, $previous_order_item_data );
}
return $order_item_updated;
return $order_items->update_item( $order_item_id, $data );
}
/**

View File

@ -127,12 +127,6 @@ function edd_trash_order( $order_id ) {
}
}
// Update the customer records when an order is trashed.
if ( ! empty( $order->customer_id ) ) {
$customer = new EDD_Customer( $order->customer_id );
$customer->recalculate_stats();
}
}
return filter_var( $trashed, FILTER_VALIDATE_BOOLEAN );
@ -362,14 +356,8 @@ function edd_destroy_order( $order_id = 0 ) {
*/
function edd_update_order( $order_id = 0, $data = array() ) {
$orders = new EDD\Database\Queries\Order();
$update = $orders->update_item( $order_id, $data );
if ( ! empty( $data['customer_id'] ) ) {
$customer = new EDD_Customer( $data['customer_id'] );
$customer->recalculate_stats();
}
return $update;
return $orders->update_item( $order_id, $data );
}
/**

View File

@ -144,10 +144,6 @@ function edd_complete_purchase( $order_id, $new_status, $old_status ) {
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
@ -174,7 +170,8 @@ function edd_complete_purchase( $order_id, $new_status, $old_status ) {
) );
// Required for backwards compatibility.
$payment = edd_get_payment( $order_id );
$payment = edd_get_payment( $order_id );
$customer = edd_get_customer( $customer_id );
/**
* Runs **when** a purchase is marked as "complete".

View File

@ -989,9 +989,6 @@ class EDD_Payment {
do_action( 'edd_payment_saved', $this->ID, $this );
}
$customer = new EDD_Customer( $this->customer_id );
$customer->recalculate_stats();
/**
* Update the payment in the object cache
*/
@ -2655,15 +2652,6 @@ class EDD_Payment {
if ( true === $alter_store_earnings ) {
edd_decrease_total_earnings( $this->total );
}
// Decrement the stats for the customer
if ( ! empty( $this->customer_id ) ) {
$customer = new EDD_Customer( $this->customer_id );
if ( ! empty( $alter_customer_value || $alter_customer_purchase_count ) ) {
$customer->recalculate_stats();
}
}
}
/**

View File

@ -215,10 +215,6 @@ function edd_delete_purchase( $payment_id = 0, $update_customer = true, $delete_
}
}
if ( $customer && $customer->id && $update_customer ) {
$customer->recalculate_stats();
}
do_action( 'edd_payment_deleted', $payment_id );
}

View File

@ -966,12 +966,64 @@ function get_dates_filter_day_by_day() {
return $day_by_day;
}
/**
* Gets the period for a graph.
*
* @since 3.1.1.4
* @return string
*/
function get_graph_period() {
if ( get_dates_filter_hour_by_hour() ) {
return 'hour';
}
if ( get_dates_filter_day_by_day() ) {
return 'day';
}
return 'month';
}
/**
* Gets the SQL clauses.
* The result of this function should be run through $wpdb->prepare().
*
* @since 3.1.1.4
* @param string $period The period for the query.
* @param string $column The column to query.
* @return array
*/
function get_sql_clauses( $period, $column = 'date_created' ) {
// Get the date for the query.
$converted_date = get_column_conversion( $column );
switch ( $period ) {
case 'hour':
$date_format = '%%Y-%%m-%%d %%H:00:00';
break;
case 'day':
$date_format = '%%Y-%%m-%%d';
break;
default:
$date_format = '%%Y-%%m';
break;
}
return array(
'select' => "DATE_FORMAT({$converted_date}, \"{$date_format}\") AS date",
'where' => '',
'groupby' => 'date',
'orderby' => 'date',
);
}
/**
* Given a function and column, make a timezone converted groupby query.
*
* @since 3.0
* @since 3.0.4 If MONTH is passed as the function, always add YEAR and MONTH
* to avoid issues with spanning multiple years.
* @since 3.1.1.4 This function isn't needed anymore due to using DATE_FORMAT in the select clause.
*
* @param string $function The function to run the value through, like DATE, HOUR, MONTH.
* @param string $column The column to group by.
@ -979,25 +1031,40 @@ function get_dates_filter_day_by_day() {
* @return string
*/
function get_groupby_date_string( $function = 'DATE', $column = 'date_created' ) {
$function = strtoupper( $function );
/**
* If there is no offset, the default column will be returned.
* Otherwise, the column will be converted to the timezone offset.
*/
$column_conversion = get_column_conversion( $column );
$function = strtoupper( $function );
switch ( $function ) {
case 'HOUR':
$group_by_string = "DAY({$column_conversion}), HOUR({$column_conversion})";
break;
case 'MONTH':
$group_by_string = "YEAR({$column_conversion}), MONTH({$column_conversion})";
break;
default:
$group_by_string = "{$function}({$column_conversion})";
break;
}
return $group_by_string;
}
/**
* Get the time zone converted dates for the query.
*
* @since 3.1.1.4
* @param string $column
* @return string
*/
function get_column_conversion( $column = 'date_created' ) {
$date = EDD()->utils->date( 'now', edd_get_timezone_id(), false );
$gmt_offset = $date->getOffset();
if ( empty( $gmt_offset ) ) {
switch ( $function ) {
case 'HOUR':
$group_by_string = "DAY({$column}), HOUR({$column})";
break;
case 'MONTH':
$group_by_string = "YEAR({$column}), MONTH({$column})";
break;
default:
$group_by_string = "{$function}({$column})";
break;
}
return $group_by_string;
return $column;
}
// Output the offset in the proper format.
@ -1017,20 +1084,7 @@ function get_groupby_date_string( $function = 'DATE', $column = 'date_created' )
*
* @see https://github.com/awesomemotive/easy-digital-downloads/pull/9449
*/
$column_conversion = "CONVERT_TZ({$column}, '+0:00', '{$math}{$formatted_offset}')";
switch ( $function ) {
case 'HOUR':
$group_by_string = "DAY({$column_conversion}), HOUR({$column_conversion})";
break;
case 'MONTH':
$group_by_string = "YEAR({$column_conversion}), MONTH({$column_conversion})";
break;
default:
$group_by_string = "{$function}({$column_conversion})";
break;
}
return $group_by_string;
return "CONVERT_TZ({$column}, '+00:00', '{$math}{$formatted_offset}')";
}
/**

View File

@ -34,8 +34,19 @@ function edd_get_users_purchases( $user = 0, $number = 20, $pagination = false,
$user = get_current_user_id();
}
if ( is_email( $user ) ) {
$customers = edd_get_customers(
array(
'email' => $user,
)
);
if ( $customers ) {
$user = $customers[0]->user_id;
}
}
// Bail if no user found.
if ( 0 === $user ) {
if ( empty( $user ) ) {
return false;
}

View File

@ -247,6 +247,22 @@ add_action( 'edd_user_reset_password', 'edd_validate_password_reset' );
* @return void
*/
function edd_validate_password_reset( $data ) {
// We don't need or use AJAX requests for this, so die if one is received.
if ( edd_doing_ajax() ) {
wp_die( __( 'Invalid password reset request.', 'easy-digital-downloads' ), __( 'Error', 'easy-digital-downloads' ), array( 'response' => 400 ) );
}
if ( empty( $data['rp_key'] ) ) {
edd_set_error( 'password_reset_failed', __( 'Invalid password reset request.', 'easy-digital-downloads' ) );
}
$user = check_password_reset_key( $data['rp_key'], $data['user_login'] );
if ( ! $user || is_wp_error( $user ) ) {
edd_set_error( 'password_reset_failed', __( 'Invalid password reset request.', 'easy-digital-downloads' ) );
}
// Check if password is one or all empty spaces.
if ( ! empty( $data['pass1'] ) ) {
$_POST['pass1'] = trim( $data['pass1'] );
@ -262,13 +278,15 @@ function edd_validate_password_reset( $data ) {
}
$user = get_user_by( 'login', $data['user_login'] );
if ( ! $user || is_wp_error( $user ) ) {
if ( false === $user ) {
edd_set_error( 'password_reset_unsuccessful', __( 'Your password could not be reset.', 'easy-digital-downloads' ) );
}
$redirect = remove_query_arg( 'action', $data['edd_redirect'] );
// If no errors were registered then reset the password.
if ( ! edd_get_errors() ) {
$errors = edd_get_errors();
if ( empty( $errors ) ) {
reset_password( $user, $data['pass1'] );
edd_set_success( 'password_reset_successful', __( 'Your password was successfully reset.', 'easy-digital-downloads' ) );
// todo: check if this is correct

View File

@ -6,7 +6,7 @@ Tags: ecommerce, payments, sell, digital store, stripe
Requires at least: 5.4
Tested up to: 6.2
Requires PHP: 7.1
Stable Tag: 3.1.1.3
Stable Tag: 3.1.1.4.2
License: GNU Version 2 or Any Later Version
Sell your digital products with the #1 eCommerce plugin written for digital creators by digital creators.
@ -225,6 +225,34 @@ Yes, with an Extended Pass you get access to [Recurring Payments](https://easydi
8. Checkout - Default Theme
== Changelog ==
= 3.1.1.4.2, May 1, 2023 =
* Security: Improved validation for edd hooks.
= 3.1.1.4.1, April 21, 2023 =
* Fix - Blocks: Harden blocks loader to verify files exist before requiring them.
= 3.1.1.4, April 20, 2023 =
* Improvement: Removed a possible unsupported PHP configuration from the email summaries.
* Improvement: The edd_get_users_purchases function has been updated to account for customer email address changes.
* Improvement: Reports have been updated to more accurately account for timezones and date ranges.
* Improvement: The onboarding wizard loading was not allowing a close and exit after the first step.
* Improvement: License key handling for 3rd party extensions has been accounted for.
* Improvement: When using sequential order numbers, searching has been updated to account for order number.
* Improvement - Stripe: The Payment Element has been improved to handle failed 3DS challenges.
* Improvement - Stripe: Failed payment attempts are now more reliably accounted for.
* Improvement - Stripe: The Payment Element billing fields can now be filtered.
* Improvement - Stripe: The Payment Element now supports mandates, improving multi-regional payments.
* Improvement - Stripe: The 'Card Name' field is re-introduced for regions that require it.
* Improvement - Blocks: Better support for custom fields with the Checkout Block.
* Improvement - Blocks: Developers can now register custom columns for the User Downloads block.
* Improvement - Blocks: The Buy Now button can now have its behavior defined as Add to Cart or Buy Now.
* Fix: Discounts with high value amounts were not saving correctly.
* Fix: Bulk Editing prices was not working with WordPress 6.1+.
* Fix: Exporting product sales was not always respecting the date range filters.
* Fix: Exports with date queries were not always accounting for timezones accurately.
* Fix - Blocks: Cart section headings were not always displayed when reloading the section via AJAX.
* Dev: New custom hooks in database row transitions have been added.
= 3.1.1.3, March 23, 2023 =
* Improvement: The orders list table in the admin now sorts orders by date as the default.

View File

@ -19,6 +19,7 @@ class Core extends EventManagement\Subscribers {
return array(
new Admin\PassHandler\Ajax( $this->pass_handler ),
new Admin\Extensions\Extension_Manager(),
new Customers\Recalculations(),
);
}

View File

@ -0,0 +1,123 @@
<?php
/**
* Handles scheduling recalculations for a customer.
*/
namespace EDD\Customers;
defined( 'ABSPATH' ) || exit;
use EDD\EventManagement\SubscriberInterface;
class Recalculations implements SubscriberInterface {
/**
* Returns an array of events that this subscriber wants to listen to.
*
* @return array
*/
public static function get_subscribed_events() {
return array(
'edd_order_added' => array( 'maybe_schedule_recalculation', 10, 2 ),
'edd_order_updated' => array( 'maybe_schedule_recalculation', 10, 3 ),
'edd_order_deleted' => 'maybe_schedule_recalculation',
'edd_recalculate_customer_deferred' => 'recalculate',
);
}
/**
* When an order is added, updated, or changed, the customer stats may need to be recalculated.
*
* @param int $order_id The order ID.
* @param array $data The array of order data.
* @param bool|EDD\Orders|Order $previous_order The previous order object (when updating).
* @return void
*/
public function maybe_schedule_recalculation( $order_id, $data = array(), $previous_order = false ) {
// Recalculations do not need to run when the order item is first being added to the database if it's pending.
if ( 'edd_order_added' === current_action() && ( empty( $data['status'] ) || 'pending' === $data['status'] ) ) {
return;
}
// If the order item data being updated doesn't affect sales/earnings, recalculations do not need to be run.
if ( $previous_order instanceof EDD\Orders\Order ) {
$columns_affecting_stats = array( 'status', 'total', 'subtotal', 'discount', 'tax', 'rate', 'customer_id' );
// If the data being updated isn't one of these columns then we don't need to recalculate.
if ( empty( array_intersect( array_keys( $data ), $columns_affecting_stats ) ) ) {
return;
}
// If the data exists but matches, we don't need to recalculate.
if (
( empty( $data['status'] ) || $previous_order->status === $data['status'] ) &&
( ! isset( $data['total'] ) || $previous_order->total == $data['total'] ) &&
( ! isset( $data['subtotal'] ) || $previous_order->subtotal == $data['subtotal'] ) &&
( ! isset( $data['discount'] ) || $previous_order->discount == $data['discount'] ) &&
( ! isset( $data['tax'] ) || $previous_order->tax == $data['tax'] ) &&
( ! isset( $data['rate'] ) || $previous_order->rate == $data['rate'] ) &&
( empty( $data['customer_id'] ) || $previous_order->customer_id == $data['customer_id'] )
) {
return;
}
// Recalculate the previous product values if the product ID has changed.
if ( ! empty( $data['customer_id'] ) && $previous_order->customer_id != $data['customer_id'] ) {
$this->schedule_recalculation( $previous_order->customer_id );
}
}
$order = edd_get_order( $order_id );
if ( empty( $order->customer_id ) ) {
return;
}
$this->schedule_recalculation( $order->customer_id );
}
/**
* Recalculate the value of a customer.
*
* @since 3.1.1.4
* @param int $customer_id
* @return void
*/
public function recalculate( $customer_id ) {
$customer = edd_get_customer( $customer_id );
if ( ! $customer instanceof \EDD_Customer ) {
return;
}
$customer->recalculate_stats();
}
/**
* Maybe schedule the customer recalculation--it will be skipped if already scheduled.
*
* @since 3.1.1.4
* @param int $customer_id
* @return void
*/
private function schedule_recalculation( $customer_id ) {
$is_scheduled = wp_next_scheduled( 'edd_recalculate_customer_deferred', array( $customer_id ) );
$bypass_cron = apply_filters( 'edd_recalculate_bypass_cron', false );
// Check if the recalculation has already been scheduled.
if ( $is_scheduled && ! $bypass_cron ) {
edd_debug_log( 'Recalculation is already scheduled for customer ' . $customer_id . ' at ' . edd_date_i18n( $is_scheduled, 'datetime' ) );
return;
}
// If we are intentionally bypassing cron somehow, recalculate now and return.
if ( $bypass_cron || ( defined( 'EDD_DOING_TESTS' ) && EDD_DOING_TESTS ) || ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) ) {
$this->recalculate( $customer_id );
return;
}
edd_debug_log( 'Scheduling recalculation for customer ' . $customer_id );
wp_schedule_single_event(
time() + ( 5 * MINUTE_IN_SECONDS ),
'edd_recalculate_customer_deferred',
array( $customer_id )
);
}
}

View File

@ -35,7 +35,7 @@ class ExtensionRegistry extends \ArrayObject {
$this->offsetSet(
$pluginId,
new \EDD_License( $pluginFile, $pluginName, $currentVersion, 'Easy Digital Downloads', $optionName, null, $pluginId )
new Handler( $pluginFile, $pluginId, $pluginName, $currentVersion, $optionName )
);
}
@ -46,8 +46,7 @@ class ExtensionRegistry extends \ArrayObject {
* flexibility to change exactly what it returns in the future.
*
* @since 2.11.4
*
* @return \EDD_License[]
* @return Handler[]
*/
private function getExtensions() {
return $this->getArrayCopy();
@ -64,8 +63,8 @@ class ExtensionRegistry extends \ArrayObject {
* @return int
*/
public function countLicensedExtensions() {
$licensedExtensions = array_filter( $this->getExtensions(), function ( \EDD_License $license ) {
return ! empty( $license->license );
$licensedExtensions = array_filter( $this->getExtensions(), function ( Handler $license ) {
return ! empty( $license->license_key );
} );
return count( $licensedExtensions );

View File

@ -0,0 +1,407 @@
<?php
/**
* License handler for extensions using the ExtensionRegistry.
*
* @since 3.1.1.4
*/
namespace EDD\Extensions;
use EDD\Licensing\API;
use EDD\Licensing\License;
use EDD\Admin\Pass_Manager;
// Exit if accessed directly
defined( 'ABSPATH' ) || exit;
/**
* Handler Class
*/
class Handler {
/**
* The license key.
*
* @var string
*/
private $license_key;
/**
* The plugin file.
*
* @var string
*/
private $file;
/**
* The extension name.
*
* @var string
*/
private $item_name;
/**
* The extension item ID.
*
* @var int
*/
private $item_id;
/**
* The extension shortname.
*
* @var string
*/
private $item_shortname;
/**
* The extension version.
*
* @var string
*/
private $version;
/**
* The pass manager.
*
* @var \EDD\Admin\Pass_Manager
*/
private $pass_manager;
/**
* The EDD license object.
* This contains standard license data (from the API response) and the license key.
*
* @var \EDD\Licensing\License
*/
private $edd_license;
/**
* Whether the license being checked is a pro license.
*
* @since 3.1.1
* @var bool
*/
private $is_pro_license = false;
/**
* Class constructor
*
* @param string $_file
* @param int $_item_id
* @param string $_item_name
* @param string $_version
* @param string $_optname
*/
public function __construct( $_file, $_item_id, $_item_name, $_version, $_optname = null ) {
$this->file = $_file;
$this->item_id = absint( $_item_id );
$this->item_name = $_item_name;
$this->item_shortname = $this->get_shortname();
$this->version = $_version;
$this->edd_license = new License( $this->item_name, $_optname );
if ( empty( $this->edd_license->key ) || empty( $this->edd_license->license ) ) {
$pro_license = new License( 'pro' );
if ( ! empty( $pro_license->key ) ) {
$this->is_pro_license = true;
$this->edd_license = $pro_license;
}
}
$this->license_key = $this->edd_license->key;
$this->pass_manager = new Pass_Manager();
$this->hooks();
$this->update_global();
}
/**
* Set up hooks.
*
* @access private
* @return void
*/
private function hooks() {
// Register settings.
add_filter( 'edd_settings_licenses', array( $this, 'settings' ), 1 );
// Check that license is valid once per week.
if ( ! $this->is_pro_license || ! $this->is_included_in_pass() ) {
add_action( 'edd_weekly_scheduled_events', array( $this, 'weekly_license_check' ) );
}
// Updater.
add_action( 'init', array( $this, 'auto_updater' ) );
// Display notices to admins.
add_action( 'admin_notices', array( $this, 'notices' ) );
add_action( 'in_plugin_update_message-' . plugin_basename( $this->file ), array( $this, 'plugin_row_license_missing' ), 10, 2 );
// Register plugins for beta support.
add_filter( 'edd_beta_enabled_extensions', array( $this, 'register_beta_support' ) );
}
/**
* Auto updater
*
* @return void
*/
public function auto_updater() {
if ( ! current_user_can( 'manage_options' ) && ! edd_doing_cron() ) {
return;
}
// Fall back to the highest license key if one is not saved for this extension or there isn't a pro license.
if ( empty( $this->license_key ) ) {
if ( $this->pass_manager->highest_license_key ) {
$this->license_key = $this->pass_manager->highest_license_key;
}
}
// Don't check for updates if there isn't a license key.
if ( empty( $this->license_key ) ) {
return;
}
$args = array(
'version' => $this->version,
'license' => $this->license_key,
'item_id' => $this->item_id,
'beta' => function_exists( 'edd_extension_has_beta_support' ) && edd_extension_has_beta_support( $this->item_shortname ),
);
// Set up the updater.
new Updater(
$this->file,
$args
);
}
/**
* Add license field to settings, unless the extension is included in the user's pass.
*
* @param array $settings
* @return array
*/
public function settings( $settings ) {
if ( $this->is_pro_license && $this->is_included_in_pass() ) {
return $settings;
}
return array_merge(
$settings,
array(
array(
'id' => "{$this->item_shortname}_license_key",
'name' => $this->item_name,
'type' => 'license_key',
'options' => array(
'is_valid_license_option' => "{$this->item_shortname}_license_active",
'item_id' => $this->item_id,
),
),
)
);
}
/**
* Check if license key is valid once per week
*
* @since 2.5
* @return void
*/
public function weekly_license_check() {
// Don't fire when saving settings.
if ( ! empty( $_POST['edd_settings'] ) ) {
return;
}
if ( empty( $this->license_key ) ) {
return;
}
if ( ! edd_doing_cron() ) {
return;
}
// data to send in our API request
$api_params = array(
'edd_action' => 'check_license',
'license' => $this->license_key,
'item_name' => urlencode( $this->item_name ),
'item_id' => $this->item_id,
);
$api_handler = new API();
$license_data = $api_handler->make_request( $api_params );
if ( ! $license_data ) {
return false;
}
$this->pass_manager->maybe_set_pass_flag( $this->license_key, $license_data );
$this->edd_license->save( $license_data );
}
/**
* Admin notices for errors.
*
* @return void
*/
public function notices() {
if ( ! $this->should_show_error_notice() ) {
return;
}
EDD()->notices->add_notice(
array(
'id' => 'edd-missing-license',
'class' => "error {$this->item_shortname}-license-error",
'message' => sprintf(
/* translators: 1. opening anchor tag; 2. closing anchor tag */
__( 'You have invalid or expired license keys for Easy Digital Downloads. %1$sActivate License(s)%2$s', 'easy-digital-downloads' ),
'<a href="' . esc_url( $this->get_license_tab_url() ) . '" class="button button-secondary">',
'</a>'
),
'is_dismissible' => false,
)
);
}
/**
* Displays message inline on plugin row that the license key is missing
*
* @since 2.5
* @return void
*/
public function plugin_row_license_missing( $plugin_data, $version_info ) {
static $showed_imissing_key_message = array();
if ( ! $this->is_license_valid() && empty( $showed_imissing_key_message[ $this->item_shortname ] ) ) {
echo '&nbsp;<strong><a href="' . esc_url( $this->get_license_tab_url() ) . '">' . esc_html__( 'Enter valid license key for automatic updates.', 'easy-digital-downloads' ) . '</a></strong>';
$showed_imissing_key_message[ $this->item_shortname ] = true;
}
}
/**
* Adds this plugin to the beta page
*
* @param array $products
* @since 2.6.11
* @return array
*/
public function register_beta_support( $products ) {
$products[ $this->item_shortname ] = $this->item_name;
return $products;
}
/**
* Gets the URL for the licensing tab.
*
* @since 3.1.1.4
* @return string
*/
private function get_license_tab_url() {
return edd_get_admin_url(
array(
'page' => 'edd-settings',
'tab' => 'licenses',
)
);
}
/**
* Whether the license is valid.
*
* @since 3.1.1.4
* @return bool
*/
private function is_license_valid() {
return ! empty( $this->license_key ) && 'valid' === $this->edd_license->license;
}
/**
* Gets the extension shortname.
*
* @since 3.1.1.4
* @return string
*/
private function get_shortname() {
return 'edd_' . preg_replace( '/[^a-zA-Z0-9_\s]/', '', str_replace( ' ', '_', strtolower( $this->item_name ) ) );
}
/**
* Maintain an array of active, licensed plugins that have a license key entered.
* This is to help us more easily determine if the site has a license key entered
* at all. Initializing it this way helps us limit the data to activated plugins only.
* If we relied on the options table (`edd_%_license_active`) then we could accidentally
* be picking up plugins that have since been deactivated.
*
* @see \EDD\Admin\Promos\Notices\License_Upgrade_Notice::__construct()
*/
private function update_global() {
if ( empty( $this->license_key ) ) {
return;
}
global $edd_licensed_products;
if ( ! is_array( $edd_licensed_products ) ) {
$edd_licensed_products = array();
}
$edd_licensed_products[] = $this->item_shortname;
}
/**
* Whether a given product is included in the customer's active pass.
* Note this is nearly a copy of what's in EDD\Licensing\Traits\Controls\is_included_in_pass().
*
* @since 3.1.1.4
* @return bool
*/
private function is_included_in_pass() {
// All Access and lifetime passes can access everything.
if ( $this->pass_manager->hasAllAccessPass() ) {
return true;
}
$api = new \EDD\Admin\Extensions\ExtensionsAPI();
$product_data = $api->get_product_data( array(), $this->item_id );
if ( ! $product_data || empty( $product_data->categories ) ) {
return false;
}
return (bool) $this->pass_manager->can_access_categories( $product_data->categories );
}
/**
* Helper method to determine if we should show the error notice.
*
* @since 3.1.1.4
* @return bool
*/
private function should_show_error_notice() {
// Included in pass.
if ( $this->is_included_in_pass() ) {
return false;
}
// Not a pro license, but valid.
if ( ! $this->is_pro_license && $this->is_license_valid() ) {
return false;
}
// Current user lacks permissions.
if ( ! current_user_can( 'manage_shop_settings' ) ) {
return false;
}
// It's the licenses tab.
if ( ! empty( $_GET['tab'] ) && 'licenses' === $_GET['tab'] ) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,605 @@
<?php
/**
* Custom update handler for EDD extensions.
* Forked from the EDD_SL_Updater class, but customized for EDD.
*
* @since 3.1.1.4
*/
namespace EDD\Extensions;
// Exit if accessed directly
defined( 'ABSPATH' ) || exit;
class Updater {
private $api_handler;
private $api_url = '';
private $api_data = array();
private $plugin_file = '';
private $name = '';
private $slug = '';
private $version = '';
private $wp_override = false;
private $beta = false;
private $failed_request_cache_key;
/**
* Class constructor.
*
* @uses plugin_basename()
* @uses hook()
*
* @param string $_plugin_file Path to the plugin file.
* @param array $_api_data Optional data to send with API calls.
*/
public function __construct( $_plugin_file, $_api_data = null ) {
global $edd_plugin_data;
$this->api_handler = new \EDD\Licensing\API();
$this->api_url = trailingslashit( $this->api_handler->get_url() );
$this->api_data = $_api_data;
$this->plugin_file = $_plugin_file;
$this->name = plugin_basename( $_plugin_file );
$this->slug = basename( $_plugin_file, '.php' );
$this->version = $_api_data['version'];
$this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false;
$this->beta = ! empty( $this->api_data['beta'] ) ? true : false;
$this->failed_request_cache_key = 'edd_sl_failed_http_' . md5( $this->api_url );
$edd_plugin_data[ $this->slug ] = $this->api_data;
// Set up hooks.
$this->init();
}
/**
* Set up WordPress filters to hook into WP's update process.
*
* @uses add_filter()
*
* @return void
*/
public function init() {
add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
add_action( 'after_plugin_row', array( $this, 'show_update_notification' ), 10, 2 );
add_action( 'admin_init', array( $this, 'show_changelog' ) );
}
/**
* Check for Updates at the defined API endpoint and modify the update array.
*
* This function dives into the update API just when WordPress creates its update array,
* then adds a custom API call and injects the custom plugin data retrieved from the API.
* It is reassembled from parts of the native WordPress plugin update code.
* See wp-includes/update.php line 121 for the original wp_update_plugins() function.
*
* @uses api_request()
*
* @param array $_transient_data Update array build by WordPress.
* @return array Modified update array with custom plugin data.
*/
public function check_update( $_transient_data ) {
if ( ! is_object( $_transient_data ) ) {
$_transient_data = new \stdClass();
}
if ( ! empty( $_transient_data->response ) && ! empty( $_transient_data->response[ $this->name ] ) && false === $this->wp_override ) {
return $_transient_data;
}
$current = $this->get_repo_api_data();
if ( false !== $current && is_object( $current ) && isset( $current->new_version ) ) {
if ( version_compare( $this->version, $current->new_version, '<' ) ) {
$_transient_data->response[ $this->name ] = $current;
} else {
// Populating the no_update information is required to support auto-updates in WordPress 5.5.
$_transient_data->no_update[ $this->name ] = $current;
}
}
$_transient_data->last_checked = time();
$_transient_data->checked[ $this->name ] = $this->version;
return $_transient_data;
}
/**
* Get repo API data from store.
* Save to cache.
*
* @return \stdClass
*/
public function get_repo_api_data() {
$version_info = $this->get_cached_version_info();
if ( false === $version_info ) {
$version_info = $this->api_request(
'plugin_latest_version',
array(
'slug' => $this->slug,
'beta' => $this->beta,
)
);
if ( ! $version_info ) {
return false;
}
// This is required for your plugin to support auto-updates in WordPress 5.5.
$version_info->plugin = $this->name;
$version_info->id = $this->name;
$version_info->tested = $this->get_tested_version( $version_info );
$this->set_version_info_cache( $version_info );
}
return $version_info;
}
/**
* Gets the plugin's tested version.
*
* @since 1.9.2
* @param object $version_info
* @return null|string
*/
private function get_tested_version( $version_info ) {
// There is no tested version.
if ( empty( $version_info->tested ) ) {
return null;
}
// Strip off extra version data so the result is x.y or x.y.z.
list( $current_wp_version ) = explode( '-', get_bloginfo( 'version' ) );
// The tested version is greater than or equal to the current WP version, no need to do anything.
if ( version_compare( $version_info->tested, $current_wp_version, '>=' ) ) {
return $version_info->tested;
}
$current_version_parts = explode( '.', $current_wp_version );
$tested_parts = explode( '.', $version_info->tested );
// The current WordPress version is x.y.z, so update the tested version to match it.
if ( isset( $current_version_parts[2] ) && $current_version_parts[0] === $tested_parts[0] && $current_version_parts[1] === $tested_parts[1] ) {
$tested_parts[2] = $current_version_parts[2];
}
return implode( '.', $tested_parts );
}
/**
* Show the update notification on multisite subsites.
*
* @param string $file
* @param array $plugin
*/
public function show_update_notification( $file, $plugin ) {
// Return early if in the network admin, or if this is not a multisite install.
if ( is_network_admin() || ! is_multisite() ) {
return;
}
// Allow single site admins to see that an update is available.
if ( ! current_user_can( 'activate_plugins' ) ) {
return;
}
if ( $this->name !== $file ) {
return;
}
// Do not print any message if update does not exist.
$update_cache = get_site_transient( 'update_plugins' );
if ( ! isset( $update_cache->response[ $this->name ] ) ) {
if ( ! is_object( $update_cache ) ) {
$update_cache = new \stdClass();
}
$update_cache->response[ $this->name ] = $this->get_repo_api_data();
}
// Return early if this plugin isn't in the transient->response or if the site is running the current or newer version of the plugin.
if ( empty( $update_cache->response[ $this->name ] ) || version_compare( $this->version, $update_cache->response[ $this->name ]->new_version, '>=' ) ) {
return;
}
printf(
'<tr class="plugin-update-tr %3$s" id="%1$s-update" data-slug="%1$s" data-plugin="%2$s">',
$this->slug,
$file,
in_array( $this->name, $this->get_active_plugins(), true ) ? 'active' : 'inactive'
);
echo '<td colspan="3" class="plugin-update colspanchange">';
echo '<div class="update-message notice inline notice-warning notice-alt"><p>';
$changelog_link = '';
if ( ! empty( $update_cache->response[ $this->name ]->sections->changelog ) ) {
$changelog_link = add_query_arg(
array(
'edd_sl_action' => 'view_plugin_changelog',
'plugin' => urlencode( $this->name ),
'slug' => urlencode( $this->slug ),
'TB_iframe' => 'true',
'width' => 77,
'height' => 911,
),
self_admin_url( 'index.php' )
);
}
$update_link = add_query_arg(
array(
'action' => 'upgrade-plugin',
'plugin' => urlencode( $this->name ),
),
self_admin_url( 'update.php' )
);
printf(
/* translators: the plugin name. */
esc_html__( 'There is a new version of %1$s available.', 'easy-digital-downloads' ),
esc_html( $plugin['Name'] )
);
if ( ! current_user_can( 'update_plugins' ) ) {
echo ' ';
esc_html_e( 'Contact your network administrator to install the update.', 'easy-digital-downloads' );
} elseif ( empty( $update_cache->response[ $this->name ]->package ) && ! empty( $changelog_link ) ) {
echo ' ';
printf(
/* translators: 1. opening anchor tag, do not translate 2. the new plugin version 3. closing anchor tag, do not translate. */
__( '%1$sView version %2$s details%3$s.', 'easy-digital-downloads' ),
'<a target="_blank" class="thickbox open-plugin-details-modal" href="' . esc_url( $changelog_link ) . '">',
esc_html( $update_cache->response[ $this->name ]->new_version ),
'</a>'
);
} elseif ( ! empty( $changelog_link ) ) {
echo ' ';
printf(
__( '%1$sView version %2$s details%3$s or %4$supdate now%5$s.', 'easy-digital-downloads' ),
'<a target="_blank" class="thickbox open-plugin-details-modal" href="' . esc_url( $changelog_link ) . '">',
esc_html( $update_cache->response[ $this->name ]->new_version ),
'</a>',
'<a target="_blank" class="update-link" href="' . esc_url( wp_nonce_url( $update_link, 'upgrade-plugin_' . $file ) ) . '">',
'</a>'
);
} else {
printf(
' %1$s%2$s%3$s',
'<a target="_blank" class="update-link" href="' . esc_url( wp_nonce_url( $update_link, 'upgrade-plugin_' . $file ) ) . '">',
esc_html__( 'Update now.', 'easy-digital-downloads' ),
'</a>'
);
}
do_action( "in_plugin_update_message-{$file}", $plugin, $plugin );
echo '</p></div></td></tr>';
}
/**
* Gets the plugins active in a multisite network.
*
* @return array
*/
private function get_active_plugins() {
$active_plugins = (array) get_option( 'active_plugins' );
$active_network_plugins = (array) get_site_option( 'active_sitewide_plugins' );
return array_merge( $active_plugins, array_keys( $active_network_plugins ) );
}
/**
* Updates information on the "View version x.x details" page with custom data.
*
* @uses api_request()
*
* @param mixed $_data
* @param string $_action
* @param object $_args
* @return object $_data
*/
public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
if ( 'plugin_information' !== $_action ) {
return $_data;
}
if ( ! isset( $_args->slug ) || ( $_args->slug !== $this->slug ) ) {
return $_data;
}
$to_send = array(
'slug' => $this->slug,
'is_ssl' => is_ssl(),
'fields' => array(
'banners' => array(),
'reviews' => false,
'icons' => array(),
),
);
// Get the transient where we store the api request for this plugin for 24 hours
$edd_api_request_transient = $this->get_cached_version_info();
//If we have no transient-saved value, run the API, set a fresh transient with the API value, and return that value too right now.
if ( empty( $edd_api_request_transient ) ) {
$api_response = $this->api_request( 'plugin_information', $to_send );
// Expires in 3 hours
$this->set_version_info_cache( $api_response );
if ( false !== $api_response ) {
$_data = $api_response;
}
} else {
$_data = $edd_api_request_transient;
}
// Convert sections into an associative array, since we're getting an object, but Core expects an array.
if ( isset( $_data->sections ) && ! is_array( $_data->sections ) ) {
$_data->sections = $this->convert_object_to_array( $_data->sections );
}
// Convert banners into an associative array, since we're getting an object, but Core expects an array.
if ( isset( $_data->banners ) && ! is_array( $_data->banners ) ) {
$_data->banners = $this->convert_object_to_array( $_data->banners );
}
// Convert icons into an associative array, since we're getting an object, but Core expects an array.
if ( isset( $_data->icons ) && ! is_array( $_data->icons ) ) {
$_data->icons = $this->convert_object_to_array( $_data->icons );
}
// Convert contributors into an associative array, since we're getting an object, but Core expects an array.
if ( isset( $_data->contributors ) && ! is_array( $_data->contributors ) ) {
$_data->contributors = $this->convert_object_to_array( $_data->contributors );
}
if ( ! isset( $_data->plugin ) ) {
$_data->plugin = $this->name;
}
return $_data;
}
/**
* Convert some objects to arrays when injecting data into the update API
*
* Some data like sections, banners, and icons are expected to be an associative array, however due to the JSON
* decoding, they are objects. This method allows us to pass in the object and return an associative array.
*
* @since 3.6.5
*
* @param stdClass $data
*
* @return array
*/
private function convert_object_to_array( $data ) {
if ( ! is_array( $data ) && ! is_object( $data ) ) {
return array();
}
$new_data = array();
foreach ( $data as $key => $value ) {
$new_data[ $key ] = is_object( $value ) ? $this->convert_object_to_array( $value ) : $value;
}
return $new_data;
}
/**
* Calls the API and, if successfull, returns the object delivered by the API.
*
* @uses get_bloginfo()
* @uses wp_remote_get()
* @uses is_wp_error()
*
* @param string $_action The requested action.
* @param array $_data Parameters for the API action.
* @return false|object
*/
private function api_request( $_action, $_data ) {
$data = array_merge( $this->api_data, $_data );
if ( $data['slug'] !== $this->slug ) {
return false;
}
if ( $this->request_recently_failed() ) {
return false;
}
return $this->get_version_from_remote();
}
/**
* Determines if a request has recently failed.
*
* @since 1.9.1
*
* @return bool
*/
private function request_recently_failed() {
$failed_request_details = get_option( $this->failed_request_cache_key );
// Request has never failed.
if ( empty( $failed_request_details ) || ! is_numeric( $failed_request_details ) ) {
return false;
}
/*
* Request previously failed, but the timeout has expired.
* This means we're allowed to try again.
*/
if ( time() > $failed_request_details ) {
delete_option( $this->failed_request_cache_key );
return false;
}
return true;
}
/**
* Logs a failed HTTP request for this API URL.
* We set a timestamp for 1 hour from now. This prevents future API requests from being
* made to this domain for 1 hour. Once the timestamp is in the past, API requests
* will be allowed again. This way if the site is down for some reason we don't bombard
* it with failed API requests.
*
* @see EDD_SL_Plugin_Updater::request_recently_failed
*
* @since 1.9.1
*/
private function log_failed_request() {
update_option( $this->failed_request_cache_key, strtotime( '+1 hour' ), false );
}
/**
* If available, show the changelog for sites in a multisite install.
*/
public function show_changelog() {
if ( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' !== $_REQUEST['edd_sl_action'] ) {
return;
}
if ( empty( $_REQUEST['plugin'] ) ) {
return;
}
if ( empty( $_REQUEST['slug'] ) || $this->slug !== $_REQUEST['slug'] ) {
return;
}
if ( ! current_user_can( 'update_plugins' ) ) {
wp_die( esc_html__( 'You do not have permission to install plugin updates', 'easy-digital-downloads' ), esc_html__( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) );
}
$version_info = $this->get_repo_api_data();
if ( isset( $version_info->sections ) ) {
$sections = $this->convert_object_to_array( $version_info->sections );
if ( ! empty( $sections['changelog'] ) ) {
echo '<div style="background:#fff;padding:10px;">' . wp_kses_post( $sections['changelog'] ) . '</div>';
}
}
exit;
}
/**
* Gets the current version information from the remote site.
*
* @return array|false
*/
private function get_version_from_remote() {
$request = $this->api_handler->make_request( $this->get_api_params() );
if ( $request && isset( $request->sections ) ) {
$request->sections = maybe_unserialize( $request->sections );
} else {
return false;
}
if ( isset( $request->banners ) ) {
$request->banners = maybe_unserialize( $request->banners );
}
if ( isset( $request->icons ) ) {
$request->icons = maybe_unserialize( $request->icons );
}
if ( ! empty( $request->sections ) ) {
foreach ( $request->sections as $key => $section ) {
$request->$key = (array) $section;
}
}
return $request;
}
/**
* Get the version info from the cache, if it exists.
*
* @param string $cache_key
* @return object
*/
public function get_cached_version_info( $cache_key = '' ) {
if ( empty( $cache_key ) ) {
$cache_key = $this->get_cache_key();
}
$cache = get_option( $cache_key );
// Cache is expired
if ( empty( $cache['timeout'] ) || time() > $cache['timeout'] ) {
return false;
}
// We need to turn the icons into an array, thanks to WP Core forcing these into an object at some point.
$cache['value'] = json_decode( $cache['value'] );
if ( ! empty( $cache['value']->icons ) ) {
$cache['value']->icons = (array) $cache['value']->icons;
}
return $cache['value'];
}
/**
* Adds the plugin version information to the database.
*
* @param string $value
* @param string $cache_key
*/
public function set_version_info_cache( $value = '', $cache_key = '' ) {
if ( empty( $cache_key ) ) {
$cache_key = $this->get_cache_key();
}
$data = array(
'timeout' => strtotime( '+3 hours', time() ),
'value' => wp_json_encode( $value ),
);
update_option( $cache_key, $data, false );
}
/**
* Gets the parameters for the API request.
*
* @since 3.1.1.4
* @return array
*/
private function get_api_params() {
return array(
'edd_action' => 'get_version',
'license' => ! empty( $this->api_data['license'] ) ? $this->api_data['license'] : '',
'item_id' => isset( $this->api_data['item_id'] ) ? $this->api_data['item_id'] : false,
'version' => isset( $this->api_data['version'] ) ? $this->api_data['version'] : false,
'slug' => $this->slug,
'beta' => $this->beta,
'php_version' => phpversion(),
'wp_version' => get_bloginfo( 'version' ),
'easy-digital-downloads_version' => EDD_VERSION,
);
}
/**
* Gets the unique key (option name) for a plugin.
*
* @since 1.9.0
* @return string
*/
private function get_cache_key() {
$string = $this->slug . $this->api_data['license'] . $this->beta;
return 'edd_sl_' . md5( serialize( $string ) );
}
}

View File

@ -22,6 +22,18 @@ class API {
*/
private $api_url = 'https://easydigitaldownloads.com/edd-sl-api';
/**
* The class constructor.
*
* @since 3.1.1.4
* @param null|string $url Optional; used only for requests to non-EDD sites.
*/
public function __construct( $url = null ) {
if ( ! empty( $url ) ) {
$this->api_url = $url;
}
}
/**
* Gets the API URL.
*

View File

@ -63,15 +63,16 @@ class Ajax implements SubscriberInterface {
);
}
$this->name = filter_input( INPUT_POST, 'item_name', FILTER_SANITIZE_SPECIAL_CHARS );
$api_params = array(
'edd_action' => 'activate_license',
'license' => $this->license_key,
'item_name' => $this->name,
'item_id' => filter_input( INPUT_POST, 'item_id', FILTER_SANITIZE_NUMBER_INT ),
$this->name = filter_input( INPUT_POST, 'item_name', FILTER_SANITIZE_SPECIAL_CHARS );
$api_params = array(
'edd_action' => 'activate_license',
'license' => $this->license_key,
'item_name' => $this->name,
'item_id' => filter_input( INPUT_POST, 'item_id', FILTER_SANITIZE_NUMBER_INT ),
'environment' => function_exists( 'wp_get_environment_type' ) ? wp_get_environment_type() : 'production',
);
$api = new API();
$custom_api = filter_input( INPUT_POST, 'api', FILTER_SANITIZE_URL );
$api = new API( $custom_api );
$license_data = $api->make_request( $api_params );
if ( empty( $license_data->success ) ) {
@ -141,11 +142,13 @@ class Ajax implements SubscriberInterface {
$this->license = new License( $this->name );
$this->license_key = $this->license->key;
$api_params = array(
'edd_action' => 'deactivate_license',
'license' => $this->license_key,
'item_id' => urlencode( $item_id ),
'edd_action' => 'deactivate_license',
'license' => $this->license_key,
'item_id' => urlencode( $item_id ),
'environment' => function_exists( 'wp_get_environment_type' ) ? wp_get_environment_type() : 'production',
);
$api = new API();
$custom_api = filter_input( INPUT_POST, 'api', FILTER_SANITIZE_URL );
$api = new API( $custom_api );
$license_data = $api->make_request( $api_params );
$this->license->save( $license_data );

View File

@ -186,21 +186,7 @@ class Messages {
break;
default:
if ( ! empty( $this->license_data['license_key'] ) ) {
$error = ! empty( $this->license->error ) ? $this->license->error : __( 'unknown_error', 'easy-digital-downloads' );
$message = sprintf(
/* translators: 1. the error code; 2. opening link tag; 3. closing link tag. */
__( 'There was an error with this license key: %1$s. Please %2$scontact our support team%3$s.', 'easy-digital-downloads' ),
'<code>' . $error . '</code>',
'<a href="https://easydigitaldownloads.com/support">',
'</a>'
);
} else {
$message = sprintf(
/* translators: the extension name. */
__( 'Unlicensed: currently not receiving updates.', 'easy-digital-downloads' )
);
}
$message = __( 'Unlicensed: currently not receiving updates.', 'easy-digital-downloads' );
break;
}

Some files were not shown because too many files have changed in this diff Show More