updated plugin Easy Digital Downloads version 3.1.2

This commit is contained in:
2023-06-28 12:45:44 +00:00
committed by Gitium
parent 44df590080
commit f710fa7de2
120 changed files with 5556 additions and 3347 deletions

View File

@ -34,6 +34,31 @@ class DownloadURL {
* @return bool|string
*/
public function get_url() {
return false !== strpos( $this->plugin, 'https://downloads.wordpress.org/plugin' ) ? $this->plugin : false;
if ( ! $this->plugin ) {
return false;
}
if ( false === strpos( $this->plugin, 'https://downloads.wordpress.org/plugin' ) ) {
return false;
}
if ( ! in_array( $this->plugin, $this->get_allowed_urls(), true ) ) {
return false;
}
return $this->plugin;
}
/**
* Gets an array of allowed download URLs.
*
* @since 3.1.2
* @return array
*/
private function get_allowed_urls() {
return array(
'https://downloads.wordpress.org/plugin/edd-auto-register.zip',
'https://downloads.wordpress.org/plugin/wp-mail-smtp.zip',
'https://downloads.wordpress.org/plugin/google-analytics-for-wordpress.zip',
'https://downloads.wordpress.org/plugin/all-in-one-seo-pack.zip',
);
}
}

View File

@ -42,10 +42,7 @@ class Actions implements SubscriberInterface {
* @return void
*/
public function refresh() {
if ( ! current_user_can( 'manage_options' ) ) {
edd_redirect( $this->handler->get_extensions_url() );
}
if ( get_transient( 'edd_pass_refreshed' ) ) {
if ( ! $this->can_refresh() ) {
edd_redirect( $this->handler->get_extensions_url() );
}
@ -65,7 +62,6 @@ class Actions implements SubscriberInterface {
'edd_action' => 'check_license',
'license' => $pass_data->key,
'item_id' => $pass_data->pass_id,
'item_name' => $pass_data->item_name,
);
$license_data = $this->handler->remote_request( $api_params );
@ -80,4 +76,20 @@ class Actions implements SubscriberInterface {
edd_redirect( $this->handler->get_extensions_url() );
}
/**
* Check if the current user can refresh the pass status.
*
* @return bool
*/
private function can_refresh() {
if ( ! current_user_can( 'manage_options' ) ) {
return false;
}
if ( get_transient( 'edd_pass_refreshed' ) ) {
return false;
}
return true;
}
}

View File

@ -94,7 +94,7 @@ class Ajax implements SubscriberInterface {
'endpoint' => $endpoint,
'version' => EDD_VERSION,
'siteurl' => admin_url(),
'homeurl' => home_url(),
'homeurl' => network_home_url(),
'redirect' => rawurldecode( base64_encode( $redirect ) ), // phpcs:ignore
),
'https://upgrade.easydigitaldownloads.com'

View File

@ -156,7 +156,7 @@ class Handler {
$api_params = wp_parse_args(
$api_params,
array(
'url' => home_url(),
'url' => network_home_url(),
)
);
$api = new \EDD\Licensing\API();

View File

@ -103,7 +103,7 @@ class Pass_Manager {
*/
public function __construct() {
$this->pro_license = $this->get_pro_license();
if ( 'valid' === $this->pro_license ) {
if ( ! empty( $this->pro_license->license ) && 'valid' === $this->pro_license->license ) {
$this->highest_license_key = $this->pro_license->key;
$this->highest_pass_id = $this->pro_license->item_id;
$this->has_pass_data = true;

View File

@ -0,0 +1,323 @@
<?php
/**
* Defines the direct SiteHealth tests for EDD.
*/
namespace EDD\Admin\SiteHealth;
defined( 'ABSPATH' ) || exit;
class Direct extends Test {
public function get() {
$tests = array();
if ( current_user_can( 'manage_shop_settings' ) ) {
$tests['edd_purchase_page'] = array(
'label' => __( 'EDD Checkout Page', 'easy-digital-downloads' ),
'test' => array( $this, 'get_test_missing_purchase_page' ),
);
$tests['edd_uploads_url_protected'] = array(
'label' => __( 'Protected Download Files', 'easy-digital-downloads' ),
'test' => array( $this, 'get_test_uploads_url_protected' ),
'skip_cron' => true,
);
$tests['edd_gateways_enabled'] = array(
'label' => __( 'Enabled Gateways', 'easy-digital-downloads' ),
'test' => array( $this, 'get_test_gateways_enabled' ),
);
}
$tests['edd_cron_enabled'] = array(
'label' => __( 'Cron Events', 'easy-digital-downloads' ),
'test' => array( $this, 'get_test_cron_enabled' ),
);
$licenses = new Licenses();
$licenses_test = $licenses->get();
if ( ! empty( $licenses_test ) ) {
$tests['edd_licenses'] = $licenses_test;
}
return $tests;
}
/**
* Adds a test for the purchase/checkout page.
*
* @since 3.1.2
* @return array
*/
public function get_test_missing_purchase_page() {
$result = array(
'label' => __( 'You have a checkout page set', 'easy-digital-downloads' ),
'status' => 'good',
'badge' => $this->get_default_badge(),
'description' => sprintf(
'<p>%s</p>',
__( 'Your checkout page is set up and ready to process orders.', 'easy-digital-downloads' )
),
'actions' => '',
'test' => 'edd_missing_purchase_page',
);
$purchase_page = (int) edd_get_option( 'purchase_page', false );
if ( empty( $purchase_page ) ) {
$result['label'] = __( 'Your checkout page is missing', 'easy-digital-downloads' );
$result['status'] = 'critical';
$result['badge']['color'] = 'red';
$result['description'] = sprintf(
'<p>%s</p>',
__( 'Easy Digital Downloads requires a specific checkout page to be set to easily handle user interactions.', 'easy-digital-downloads' )
);
$result['actions'] = sprintf(
'<a class="button button-primary" href="%s">%s</a>',
edd_get_admin_url(
array(
'page' => 'edd-settings',
'tab' => 'general',
'section' => 'pages',
)
),
__( 'Fix the Checkout Page', 'easy-digital-downloads' )
);
} else {
if ( ! has_block( 'edd/checkout', $purchase_page ) ) {
$result['label'] = __( 'Your checkout page is using the legacy shortcode', 'easy-digital-downloads' );
$result['status'] = 'recommended';
$result['badge']['color'] = 'orange';
$result['description'] = wpautop(
sprintf(
__( 'Your checkout page is configured; however, it is currently using the legacy %1$s[download_checkout]%2$s shortcode. We recommend changing your checkout to use the EDD Checkout Block.', 'easy-digital-downloads' ),
'<code>',
'</code>'
)
);
// Link the action to edit the checkout page.
$result['actions'] = sprintf(
'<a class="button button-secondary" href="%s">%s</a>',
admin_url( 'post.php?post=' . $purchase_page . '&action=edit' ),
__( 'Edit Checkout Page', 'easy-digital-downloads' )
);
}
}
return $result;
}
/**
* Adds a test for whether the EDD uploads directory is protected.
*
* @return array
*/
public function get_test_uploads_url_protected() {
$result = array(
'label' => __( 'Your download files are protected', 'easy-digital-downloads' ),
'status' => 'good',
'badge' => $this->get_default_badge(),
'description' => sprintf(
'<p>%s</p>',
__( 'Your checkout page is a critical part of your store.', 'easy-digital-downloads' )
),
'actions' => '',
'test' => 'edd_uploads_url_protected',
);
if ( edd_is_uploads_url_protected() ) {
return $result;
}
// Attempt to get the main index.php file. If we get a 403, the downloads are protected after all.
$check = wp_safe_remote_get( trailingslashit( edd_get_upload_url() ) . 'index.php' );
if ( 403 === wp_remote_retrieve_response_code( $check ) ) {
return $result;
}
// Get the upload directory.
$upload_directory = edd_get_upload_dir();
// Running NGINX.
$show_nginx_notice = apply_filters( 'edd_show_nginx_redirect_notice', true );
if ( $show_nginx_notice && ! empty( $GLOBALS['is_nginx'] ) ) {
// The default NGINX recommendation for users.
$result['label'] = __( 'Your download files may not be protected', 'easy-digital-downloads' );
$result['status'] = 'recommended';
$result['badge']['color'] = 'orange';
$result['description'] = sprintf(
'<p>%s %s</p>',
sprintf(
/* translators: 1. opening link tag; 2. closing link tag */
__( 'To ensure the best protection, you should use this doc to add this %1$sNGINX redirect rule%2$s.', 'easy-digital-downloads' ),
'<a href="https://easydigitaldownloads.com/docs/download-files-not-protected-on-nginx/">',
'</a>'
),
__( 'If you have already done this, you can disregard this notice.', 'easy-digital-downloads' )
);
$download_method = edd_get_option( 'download_method', 'direct' );
$symlink = edd_get_option( 'symlink_file_downloads', false );
$additional_description = '';
if ( 'direct' === $download_method ) {
// If using the 'direct' download method, let the customer know that we are already obfuscating the URL, but for the best protection, make the recommended changes.
$additional_description .= sprintf(
'<p>%s</p>',
__( 'No need to worry, you are using the recommended \'Forced\' download method, and customers should never see the direct path to the files. The following action is still recommended, however.', 'easy-digital-downloads' )
);
} elseif ( 'redirect' === $download_method && false === $symlink ) {
// If using the 'redirect' download method but not the symlink, they need to make this change. Adjust to a critical notice with a link to make suggested changes.
$result['badge']['color'] = 'red';
$result['status'] = 'critical';
$additional_description = sprintf(
'<p>%s</p>',
__( 'You currently are using the \'Redirect\' download method, which may expose your downloadable products. Either switch to the \'Forced\' method or enable \'Symlinks\'.', 'easy-digital-downloads' )
);
$result['actions'] = sprintf(
'<a class="button button-primary" href="%s">%s</a>',
edd_get_admin_url(
array(
'page' => 'edd-settings',
'tab' => 'misc',
'section' => 'file-downloads',
)
),
__( 'Protect your files', 'easy-digital-downloads' )
);
} else {
// If using the 'redirect' download method and the symlink, they are already protected, but we can let them know that they can make the recommended changes.
$additional_description = sprintf(
'<p>%s</p>',
__( 'Your current download method creates a temporary copy of the file for the customer to download. After they successfully download it, it is removed, ensuring they never have direct access to your product files.', 'easy-digital-downloads' )
);
}
if ( ! empty( $additional_description ) ) {
$result['description'] = $additional_description . $result['description'];
}
return $result;
}
// Running Apache.
if ( ! empty( $GLOBALS['is_apache'] ) && ! edd_htaccess_exists() && ! get_user_meta( get_current_user_id(), '_edd_htaccess_missing_dismissed', true ) ) {
$result['label'] = __( 'Your download files are currently not protected', 'easy-digital-downloads' );
$result['status'] = 'critical';
$result['badge']['color'] = 'orange';
$result['description'] = sprintf(
'<p>%s %s</p>',
sprintf(
/* translators: the upload directory */
__( 'The .htaccess file is missing from: %s', 'easy-digital-downloads' ),
'<strong>' . $upload_directory . '</strong>'
),
sprintf(
/* translators: the upload directory */
__( 'First, please resave the Misc settings tab a few times. If this warning continues to appear, create a file called ".htaccess" in the %s directory, and copy the following into it:', 'easy-digital-downloads' ),
'<strong>' . $upload_directory . '</strong>'
)
);
$result['actions'] = sprintf(
'<a href="%s">%s</a>',
edd_get_admin_url(
array(
'page' => 'edd-settings',
'tab' => 'misc',
)
),
__( 'Miscellaneous Settings', 'easy-digital-downloads' )
);
return $result;
}
return $result;
}
/**
* Adds a test for enabled gateways.
*
* @since 3.1.2
* @return array
*/
public function get_test_gateways_enabled() {
$result = array(
'label' => __( 'You have at least one gateway enabled', 'easy-digital-downloads' ),
'status' => 'good',
'badge' => $this->get_default_badge(),
'description' => sprintf(
'<p>%s</p>',
__( 'Fantastic! You have enabled a gateway and can accept orders.', 'easy-digital-downloads' )
),
'actions' => '',
'test' => 'edd_gateways_enabled',
);
if ( edd_get_option( 'gateways' ) ) {
return $result;
}
$result['status'] = 'critical';
$result['badge']['color'] = 'red';
$result['actions'] = sprintf(
'<a href="%s">%s</a>',
edd_get_admin_url(
array(
'page' => 'edd-settings',
'tab' => 'gateways',
)
),
__( 'Please enable at least one gateway in order to allow customers to make purchases.', 'easy-digital-downloads' )
);
if ( edd_is_test_mode() ) {
$result['status'] = 'recommended';
$result['badge']['color'] = 'gray';
}
return $result;
}
/**
* Adds a test for checking whether cron events are disabled.
*
* @since 3.1.2
* @return array
*/
public function get_test_cron_enabled() {
$result = array(
'label' => __( 'Scheduled events are running', 'easy-digital-downloads' ),
'status' => 'good',
'badge' => $this->get_default_badge(),
'description' => sprintf(
'<p>%s</p>',
__( 'Easy Digital Downloads uses scheduled events in a number of ways to help maintain performance and stability.', 'easy-digital-downloads' )
),
'actions' => '',
'test' => 'edd_cron_enabled',
);
if ( ! defined( 'WP_DISABLE_CRON' ) || empty( WP_DISABLE_CRON ) ) {
return $result;
}
$result['label'] = __( 'Scheduled events are not running', 'easy-digital-downloads' );
$result['status'] = 'critical';
$result['badge']['color'] = 'red';
$result['description'] .= sprintf(
'<p>%s</p><p>%s</p>',
__( 'Your site has cron events disabled. WordPress cron events should run at least every ten minutes for your store to manage order related events.', 'easy-digital-downloads' ),
__( 'Some hosting providers disable cron events by default, in favor of their own solution to running WP_CRON. Please contact your hosting provider to confirm any necessary changes.', 'easy-digital-downloads' )
);
return $result;
}
}

View File

@ -0,0 +1,57 @@
<?php
/**
* Gets the gateways data for the Site Health report.
*
* @since 3.1.2
* @package EDD\Admin\SiteHealth
*/
namespace EDD\Admin\SiteHealth;
/**
* Loads gateways data into Site Health.
*
* @since 3.1.2
*/
class Gateways {
/**
* Gets the gateways data array.
*
* @since 3.1.2
*/
public function get() {
return array(
'label' => __( 'Easy Digital Downloads &mdash; Gateways', 'easy-digital-downloads' ),
'fields' => $this->get_gateways(),
);
}
/**
* Gets the gateways data.
*
* @since 3.1.2
*/
private function get_gateways() {
$all_gateways = edd_get_payment_gateways();
$gateways = array();
if ( ! empty( $all_gateways ) ) {
$default_gateway = edd_get_default_gateway();
foreach ( $all_gateways as $key => $gateway ) {
$gateways[ $key ] = array(
'label' => $gateway['admin_label'],
'value' => edd_is_gateway_active( $key ) ? 'Active' : 'Inactive',
);
if ( $default_gateway === $key ) {
$gateways[ $key ]['value'] .= ' (Default)';
}
}
}
return $gateways;
}
}

View File

@ -0,0 +1,147 @@
<?php
/**
* Gets the general EDD information.
*
* @since 3.1.2
* @package EDD\Admin\SiteHealth
*/
namespace EDD\Admin\SiteHealth;
use EDD\Admin\Pass_Manager;
/**
* Loads general EDD information into Site Health
*
* @since 3.1.2
*/
class General {
/**
* The pass manager.
*
* @since 3.1.2
* @var EDD\Admin\Pass_Manager
*/
private $pass_manager;
/**
* General constructor.
*/
public function __construct() {
$this->pass_manager = new Pass_Manager();
}
/**
* Gets the site health section.
*
* @since 3.1.2
* @return array
*/
public function get() {
return array(
'label' => __( 'Easy Digital Downloads &mdash; General', 'easy-digital-downloads' ),
'fields' => array(
'version' => array(
'label' => 'EDD Version',
'value' => EDD_VERSION,
),
'edd_timezone' => array(
'label' => 'EDD Timezone',
'value' => edd_get_timezone_abbr(),
),
'upgraded' => array(
'label' => 'Upgraded From',
'value' => get_option( 'edd_version_upgraded_from', 'None' ),
),
'edd_is_pro' => array(
'label' => 'EDD (Pro) Status',
'value' => $this->get_pro_status(),
),
'edd_activated' => array(
'label' => 'EDD Activation Date',
'value' => $this->get_date( 'edd_activation_date' ),
),
'edd_pro_activated' => array(
'label' => 'EDD (Pro) Activation Date',
'value' => $this->get_date( 'edd_pro_activation_date' ),
),
'edd_pass' => array(
'label' => 'EDD Pass Status',
'value' => $this->pass_manager->highest_pass_id ? 'Valid Pass' : 'Missing',
),
'edd_test_mode' => array(
'label' => 'Test Mode',
'value' => edd_is_test_mode() ? 'Enabled' : 'Disabled',
),
'edd_ajax' => array(
'label' => 'AJAX',
'value' => ! edd_is_ajax_disabled() ? 'Enabled' : 'Disabled',
),
'edd_guest_checkout' => array(
'label' => 'Guest Checkout',
'value' => edd_no_guest_checkout() ? 'Disabled' : 'Enabled',
),
'symlinks' => array(
'label' => 'Symlinks',
'value' => apply_filters( 'edd_symlink_file_downloads', edd_get_option( 'symlink_file_downloads', false ) ) && function_exists( 'symlink' ) ? 'Enabled' : 'Disabled',
),
'download_method' => array(
'label' => 'Download Method',
'value' => ucfirst( edd_get_file_download_method() ),
),
'currency_code' => array(
'label' => 'Currency Code',
'value' => edd_get_currency(),
),
'currency_code' => array(
'label' => 'Currency Position',
'value' => edd_get_option( 'currency_position', 'before' ),
),
'decimal_separator' => array(
'label' => 'Decimal Separator',
'value' => edd_get_option( 'decimal_separator', '.' ),
),
'thousands_separator' => array(
'label' => 'Thousands Separator',
'value' => edd_get_option( 'thousands_separator', '.' ),
),
'completed_upgrades' => array(
'label' => 'Upgrades Completed',
'value' => implode( ', ', edd_get_completed_upgrades() ),
),
'download_link_expiration' => array(
'label' => 'Download Link Expiration',
'value' => edd_get_option( 'download_link_expiration' ) . ' hour(s)',
),
),
);
}
/**
* Gets the date for an option.
*
* @since 3.1.2
* @param string $option The option name.
* @return string
*/
private function get_date( $option ) {
$date = get_option( $option );
return $date ? edd_date_i18n( $date, 'Y-m-d' ) : 'n/a';
}
/**
* Gets the pro license status for the site.
*
* @since 3.1.2
* @return string
*/
private function get_pro_status() {
if ( ! edd_is_pro() ) {
return 'Disabled';
}
return $this->pass_manager::isPro() ? 'Enabled' : 'Missing License';
}
}

View File

@ -0,0 +1,70 @@
<?php
/**
* Filters the WordPress debug_information array to add EDD's data.
*
* @since 3.1.2
* @package EDD\Admin\SiteHealth
*/
namespace EDD\Admin\SiteHealth;
/**
* Registers the EDD information for the Site Health.
*
* @since 3.1.2
*/
class Information implements \EDD\EventManagement\SubscriberInterface {
/**
* Returns an array of events that this subscriber wants to listen to.
*
* @since 3.1.2
* @return array
*/
public static function get_subscribed_events() {
return array(
'admin_head-site-health.php' => 'maybe_filter_debug',
);
}
/**
* Adds the EDD filters to the debug information.
* Additionally, removes other filters on the information if using the
* EDD system info link.
*
* @since 3.1.2
* @return void
*/
public function maybe_filter_debug() {
if ( ! empty( $_GET['edd'] ) && 'filter' === $_GET['edd'] ) {
remove_all_filters( 'debug_information' );
}
add_filter( 'debug_information', array( $this, 'get_data' ) );
}
/**
* Gets the array of EDD sections for the Site Health.
*
* @since 3.1.2
* @param array $information The debug information.
* @return array
*/
public function get_data( $information ) {
$collectors = array(
'edd_general' => new General(),
'edd_tables' => new Tables(),
'edd_pages' => new Pages(),
'edd_templates' => new Templates(),
'edd_gateways' => new Gateways(),
'edd_taxes' => new Taxes(),
'edd_sessions' => new Sessions(),
);
foreach ( $collectors as $key => $class ) {
$information[ $key ] = $class->get();
}
return $information;
}
}

View File

@ -0,0 +1,146 @@
<?php
/**
* Sets up the class for checking extension licenses.
*
* @since 3.1.2
*/
namespace EDD\Admin\SiteHealth;
defined( 'ABSPATH' ) || exit;
class Licenses extends Test {
/**
* Gets the test.
*
* @since 3.1.2
* @return false|array
*/
public function get() {
if ( empty( $this->get_licensed_products() ) ) {
return false;
}
return array(
'label' => __( 'Licensed Extensions', 'easy-digital-downloads' ),
'test' => array( $this, 'get_test_edd_licenses' ),
'skip_cron' => true,
);
}
/**
* Adds a test for whether EDD licenses are valid/missing/expired.
*
* @since 3.1.2
* @return array
*/
public function get_test_edd_licenses() {
$result = array(
'label' => __( 'Your extensions are receiving updates', 'easy-digital-downloads' ),
'status' => 'good',
'badge' => $this->get_default_badge(),
'description' => sprintf(
'<p>%s</p>',
__( 'Your EDD extensions are all licensed and receiving updates.', 'easy-digital-downloads' )
),
'actions' => '',
'test' => 'edd_licenses',
);
if ( ! $this->has_missing_licenses() ) {
return $result;
}
$result['label'] = __( 'You are not receiving updates for some extensions', 'easy-digital-downloads' );
$result['status'] = 'critical';
$result['badge']['color'] = 'red';
$result['description'] = sprintf(
'<p>%s</p>',
__( 'At least one of your extensions is missing a license key, or the license is expired. Your site may be missing critical software updates.', 'easy-digital-downloads' )
);
$result['actions'] = $this->get_licensing_action_links();
return $result;
}
/**
* Gets the licensed products global.
*
* @since 3.1.2
* @return array
*/
private function get_licensed_products() {
global $edd_licensed_products;
return $edd_licensed_products;
}
/**
* Checks the licensed products global for unlicensed extensions.
*
* @since 3.1.2
* @return bool
*/
private function has_missing_licenses() {
return in_array( 0, $this->get_licensed_products(), true );
}
/**
* Gets the licensing action links.
*
* @since 3.1.2
* @return string
*/
private function get_licensing_action_links() {
$actions = $this->get_licensing_actions();
$action_links = array();
foreach ( $actions as $action ) {
$action_links[] = sprintf(
'<a href="%s">%s</a>',
esc_url( $action['url'] ),
esc_html( $action['label'] )
);
}
return ! empty( $action_links ) ? implode( ' | ', $action_links ) : '';
}
/**
* Gets the licensing actions.
*
* @since 3.1.2
* @return array
*/
private function get_licensing_actions() {
return array(
array(
'label' => __( 'Upgrade to EDD (Pro)', 'easy-digital-downloads' ),
'url' => edd_link_helper(
'https://easydigitaldownloads.com/pricing/',
array(
'utm_medium' => 'site-health',
'utm_content' => 'upgrade-to-pro',
),
false
),
),
array(
'label' => __( 'Enter a license key for EDD (Pro)', 'easy-digital-downloads' ),
'url' => edd_get_admin_url(
array(
'page' => 'edd-settings',
'tab' => 'general',
)
),
),
array(
'label' => __( 'Enter a license key for an extension', 'easy-digital-downloads' ),
'url' => edd_get_admin_url(
array(
'page' => 'edd-settings',
'tab' => 'licenses',
)
),
),
);
}
}

View File

@ -0,0 +1,66 @@
<?php
/**
* Gets the information about the EDD registered pages.
*
* @since 3.1.2
* @package EDD\Admin\SiteHealth
*/
namespace EDD\Admin\SiteHealth;
/**
* Loads the EDD Page Settings into the Site Health.
*
* @since 3.1.2
*/
class Pages {
/**
* Gets the data for the section.
*
* @since 3.1.2
* @return array
*/
public function get() {
return array(
'label' => __( 'Easy Digital Downloads &mdash; Pages', 'easy-digital-downloads' ),
'fields' => $this->get_pages(),
);
}
/**
* Gets the page data.
*
* @since 3.1.2
* @return array
*/
private function get_pages() {
$purchase_page = edd_get_option( 'purchase_page', '' );
$success_page = edd_get_option( 'success_page', '' );
$failure_page = edd_get_option( 'failure_page', '' );
$pages = array(
'checkout' => array(
'label' => 'Checkout',
'value' => ! empty( $purchase_page ) ? 'Valid' : 'Invalid',
),
'checkout_uri' => array(
'label' => 'Checkout Page',
'value' => ! empty( $purchase_page ) ? get_permalink( $purchase_page ) : '',
),
'success_uri' => array(
'label' => 'Success Page',
'value' => ! empty( $success_page ) ? get_permalink( $success_page ) : '',
),
'failure_uri' => array(
'label' => 'Failure Page',
'value' => ! empty( $failure_page ) ? get_permalink( $failure_page ) : '',
),
'downloads_slug' => array(
'label' => 'Downloads Slug',
'value' => defined( 'EDD_SLUG' ) ? '/' . EDD_SLUG : '/downloads',
),
);
return $pages;
}
}

View File

@ -0,0 +1,88 @@
<?php
/**
* Gets the session data for the Site Health data.
*
* @since 3.1.2
* @package EDD\Admin\SiteHealth
*/
namespace EDD\Admin\SiteHealth;
/**
* Loads session data into Site Health.
*
* @since 3.1.2
*/
class Sessions {
/**
* Gets the session section data for Site Health.
*
* @since 3.1.2
* @return array
*/
public function get() {
return array(
'label' => __( 'Easy Digital Downloads &mdash; Sessions', 'easy-digital-downloads' ),
'fields' => $this->get_data(),
);
}
/**
* Gets the array of session data.
*
* @since 3.1.2
* @return array
*/
private function get_data() {
$data = array(
'edd_use_sessions' => array(
'label' => 'EDD Use Sessions',
'value' => defined( 'EDD_USE_PHP_SESSIONS' ) && EDD_USE_PHP_SESSIONS ? 'Enforced' : ( EDD()->session->use_php_sessions() ? 'Enabled' : 'Disabled' ),
),
'session_enabled' => array(
'label' => 'Session',
'value' => isset( $_SESSION ) ? 'Enabled' : 'Disabled',
),
);
$session_data = $this->get_session_data();
return $session_data ? array_merge( $data, $session_data ) : $data;
}
/**
* Gets the data from the $_SESSION global.
*
* @since 3.1.2
* @return false|array
*/
private function get_session_data() {
if ( ! isset( $_SESSION ) ) {
return false;
}
return array(
'name' => array(
'label' => 'Session Name',
'value' => ini_get( 'session.name' ),
),
'cookie_path' => array(
'label' => 'Cookie Path',
'value' => ini_get( 'session.cookie_path' ),
),
'save_path' => array(
'label' => 'Save Path',
'value' => ini_get( 'session.save_path' ),
),
'use_cookies' => array(
'label' => 'Use Cookies',
'value' => ini_get( 'session.use_cookies' ) ? 'On' : 'Off',
),
'use_only_cookies' => array(
'label' => 'Use Only Cookies',
'value' => ini_get( 'session.use_only_cookies' ) ? 'On' : 'Off',
),
);
}
}

View File

@ -0,0 +1,78 @@
<?php
/**
* Gets the custom table data for the Site Health data.
*
* @since 3.1.2
* @package EDD\Admin\SiteHealth
*/
namespace EDD\Admin\SiteHealth;
/**
* Loads custom table data into Site Health
*
* @since 3.1.2
*/
class Tables {
/**
* Gets the table data array.
*
* @since 3.1.2
* @return array
*/
public function get() {
return array(
'label' => __( 'Easy Digital Downloads &mdash; Custom Tables', 'easy-digital-downloads' ),
'fields' => $this->get_tables(),
);
}
/**
* Gets the name/version of each EDD table that's registered as a component.
*
* @since 3.1.2
* @return array
*/
private function get_tables() {
$tables = array(
'default' => array(
'label' => 'Table Name',
'value' => 'Version / Count',
),
);
foreach ( EDD()->components as $component ) {
// Object.
$thing = $component->get_interface( 'table' );
if ( ! empty( $thing ) ) {
$tables[ $thing->name ] = array(
'label' => $thing->name,
'value' => $this->get_value_string( $thing ),
);
}
// Meta.
$thing = $component->get_interface( 'meta' );
if ( ! empty( $thing ) ) {
$tables[ $thing->name ] = array(
'label' => $thing->name,
'value' => $this->get_value_string( $thing ),
);
}
}
return $tables;
}
/**
* Gets the value string for the table data.
*
* @since 3.1.2
* @param object $thing The table or meta object.
* @return string
*/
private function get_value_string( $thing ) {
return sprintf( '%s / %s', $thing->get_version(), $thing->count() );
}
}

View File

@ -0,0 +1,75 @@
<?php
/**
* Gets the tax information and rates for the site.
*
* @since 3.1.2
* @package EDD\Admin\SiteHealth
*/
namespace EDD\Admin\SiteHealth;
/**
* Loads tax information into Site Health.
*
* @since 3.1.2
*/
class Taxes {
/**
* Gets the data.
*
* @since 3.1.2
* @return array
*/
public function get() {
return array(
'label' => __( 'Easy Digital Downloads &mdash; Taxes', 'easy-digital-downloads' ),
'fields' => $this->get_taxes(),
);
}
/**
* Gets the tax information.
*
* @since 3.1.2
* @return array
*/
private function get_taxes() {
$taxes = array(
'taxes_enabled' => array(
'label' => 'Taxes',
'value' => edd_use_taxes() ? 'Enabled' : 'Disabled',
),
'default_rate' => array(
'label' => 'Default Tax Rate',
'value' => edd_get_formatted_tax_rate(),
),
'display_on_checkout' => array(
'label' => 'Display on Checkout',
'value' => edd_get_option( 'checkout_include_tax', false ) ? 'Displayed' : 'Not Displayed',
),
'prices_include_tax' => array(
'label' => 'Prices Include Tax',
'value' => edd_prices_include_tax() ? 'Yes' : 'No',
),
);
$rates = edd_get_tax_rates( array(), OBJECT );
if ( ! empty( $rates ) ) {
foreach ( $rates as $rate ) {
if ( 'global' === $rate->scope ) {
continue;
}
$tax_rate = $rate->name;
if ( ! empty( $rate->description ) ) {
$tax_rate .= ' / ' . $rate->description;
}
$taxes[ $rate->id ] = array(
'label' => $tax_rate,
'value' => edd_get_formatted_tax_rate( $rate->name, $rate->description ),
);
}
}
return $taxes;
}
}

View File

@ -0,0 +1,56 @@
<?php
/**
* Gets the customized template data.
*
* @since 3.1.2
* @package EDD\Admin\SiteHealth
*/
namespace EDD\Admin\SiteHealth;
/**
* Loads customized template data into Site Health.
*
* @since 3.1.2
*/
class Templates {
/**
* Gets the site health fields.
*
* @since 3.1.2
* @return array
*/
public function get() {
return array(
'label' => __( 'Easy Digital Downloads &mdash; Customized Templates', 'easy-digital-downloads' ),
'fields' => $this->get_templates(),
);
}
/**
* Gets the customized templates.
*
* @since 3.1.2
* @return array
*/
private function get_templates() {
$customized_template_files = edd_get_theme_edd_templates();
$templates = array();
if ( empty( $customized_template_files ) ) {
$templates['empty'] = array(
'label' => '',
'value' => 'No custom templates found.',
);
} else {
foreach ( $customized_template_files as $customized_template_file ) {
$templates[] = array(
'label' => '',
'value' => $customized_template_file,
);
}
}
return $templates;
}
}

View File

@ -0,0 +1,25 @@
<?php
/**
* Abstract class for getting SiteHealth tests.
*/
namespace EDD\Admin\SiteHealth;
defined( 'ABSPATH' ) || exit;
abstract class Test {
abstract public function get();
/**
* Gets the default EDD test badge.
*
* @since 3.1.2
* @return array
*/
protected function get_default_badge() {
return array(
'label' => __( 'Easy Digital Downloads', 'easy-digital-downloads' ),
'color' => 'blue',
);
}
}

View File

@ -0,0 +1,41 @@
<?php
/**
* Site Health integration for EDD.
*/
namespace EDD\Admin\SiteHealth;
defined( 'ABSPATH' ) || exit;
use EDD\EventManagement\SubscriberInterface;
class Tests implements SubscriberInterface {
/**
* Returns an array of events that this subscriber wants to listen to.
*
* @since 3.1.2
* @return array
*/
public static function get_subscribed_events() {
return array(
'site_status_tests' => 'add_tests',
);
}
/**
* Register custom tests for EDD.
*
* @since 3.1.2
* @param array $tests
* @return array
*/
public function add_tests( $tests ) {
$direct = new Direct();
$direct_tests = $direct->get();
if ( ! empty( $direct_tests ) ) {
$tests['direct'] = array_merge( $tests['direct'], $direct_tests );
}
return $tests;
}
}

View File

@ -48,6 +48,8 @@ class Core extends EventManagement\Subscribers {
new Admin\Onboarding\Wizard(),
new Admin\Onboarding\Ajax(),
new Licensing\Ajax(),
new Admin\SiteHealth\Tests(),
new Admin\SiteHealth\Information(),
);
}

View File

@ -34,6 +34,10 @@ class Recalculations implements SubscriberInterface {
*/
public function maybe_schedule_recalculation( $order_id, $data = array(), $previous_order = false ) {
if ( get_option( '_edd_v30_doing_order_migration', false ) ) {
return;
}
// 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;

View File

@ -100,15 +100,15 @@ class Handler {
$this->item_shortname = $this->get_shortname();
$this->version = $_version;
$this->edd_license = new License( $this->item_name, $_optname );
$this->pass_manager = new Pass_Manager();
if ( empty( $this->edd_license->key ) || empty( $this->edd_license->license ) ) {
$pro_license = new License( 'pro' );
if ( ! empty( $pro_license->key ) ) {
if ( ! empty( $pro_license->key ) && $this->is_included_in_pass() ) {
$this->is_pro_license = true;
$this->edd_license = $pro_license;
}
}
$this->license_key = $this->edd_license->key;
$this->pass_manager = new Pass_Manager();
$this->license_key = $this->edd_license->key;
$this->hooks();
$this->update_global();
@ -126,7 +126,7 @@ class Handler {
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() ) {
if ( ! $this->is_pro_license ) {
add_action( 'edd_weekly_scheduled_events', array( $this, 'weekly_license_check' ) );
}
@ -342,14 +342,11 @@ class Handler {
* @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;
$edd_licensed_products[ $this->item_shortname ] = (int) (bool) $this->is_license_valid();
}
/**

View File

@ -0,0 +1,278 @@
<?php
/**
* Class for getting/assigning order numbers.
*/
namespace EDD\Orders;
class Number {
/**
* Whether core sequential order numbers are enabled.
*
* @since 3.1.2
* @var bool
*/
private $sequential;
/**
* The order number prefix.
*
* @since 3.1.2
* @var string
*/
private $prefix = '';
/**
* The order number postfix.
*
* @since 3.1.2
* @var string
*/
private $postfix = '';
public function __construct() {
$this->sequential = edd_get_option( 'enable_sequential', false );
// If sequential order numbers are enabled, we need to make sure the prefix and suffix are loaded.
if ( $this->sequential ) {
$this->prefix = $this->get_prefix();
$this->postfix = $this->get_postfix();
}
}
/**
* Gets the formatted order number; if sequential order numbers are enabled,
* this function also updates the last payment number in the database.
*
* @since 3.1.2
* @return string|bool A formatted order number, or false if sequential order numbers are disabled.
*/
public function apply() {
if ( false === $this->sequential ) {
return '';
}
$next_order_number = $this->get_next_payment_number();
if ( ! $next_order_number ) {
return '';
}
return $this->format( $next_order_number );
}
/**
* Gets the unformatted next order number from the database.
*
* @since 3.1.2
* @return false|int False if sequential order numbers are disabled, otherwise the next order number to apply.
*/
public function get_next_payment_number() {
if ( false === $this->sequential ) {
return false;
}
return (int) apply_filters( 'edd_get_next_payment_number', $this->get_next() );
}
/**
* Formats the order number with the sequential pre/postfixes.
*
* @since 3.1.2
* @param int $number
* @return string|int
*/
public function format( $number ) {
if ( ! $this->sequential || ! is_numeric( $number ) ) {
return $number;
}
$prefix = $this->prefix;
$number = absint( $number );
$postfix = $this->postfix;
$formatted_number = $prefix . $number . $postfix;
return apply_filters( 'edd_format_payment_number', $formatted_number, $prefix, $number, $postfix );
}
/**
* Given an order number, unformat it by removing the pre/postfix.
*
* @since 3.1.2
* @param string $number
* @return int
*/
public function unformat( $number ) {
if ( ! $this->sequential ) {
return $number;
}
$prefix = $this->prefix;
$postfix = $this->postfix;
// Remove prefix
$number = preg_replace( '/' . $prefix . '/', '', $number, 1 );
// Remove the postfix
$length = strlen( $number );
$postfix_pos = strrpos( $number, strval( $postfix ) );
if ( false !== $postfix_pos ) {
$number = substr_replace( $number, '', $postfix_pos, $length );
}
return apply_filters( 'edd_remove_payment_prefix_postfix', intval( $number ), $prefix, $postfix );
}
/**
* Gets the next order number from the database. This also updates the "next"
* order number in the database with the number which is being returned.
*
* @since 3.1.2
* @return int
*/
private function get_next() {
global $wpdb;
$number = $wpdb->get_var( $wpdb->prepare( "SELECT option_value FROM {$wpdb->options} WHERE option_name=%s", 'edd_next_order_number' ) );
// The next order number exists, so increment it and update the database.
if ( ! is_null( $number ) ) {
$number = (int) $number;
// Update the option for the next order number now.
$this->update( $number + 1 );
return $number;
}
// If the option is not set for the next order number, we need to get the last order number from the database.
$order_number = (int) $this->get_last();
$next_number = $order_number + 1;
$this->insert( $next_number );
return $order_number;
}
/**
* Updates the last order number in the database.
*
* This doesn't use $wpdb->update() and instead opts for using $wpdb->query() because
* in our testing we're a consistent improvment in performance. While it's measured in microseconds
* it is in the effort to remove any race condition we are running into here.
*
* @since 3.1.2
* @param int $value
* @return bool
*/
private function update( $value ) {
global $wpdb;
// We should never hit this....but just in case, we need to unformat it.
if ( ! is_numeric( $value ) ) {
$value = $this->unformat( $value );
}
$value = $wpdb->prepare( '%d', $value );
return $wpdb->query(
"UPDATE {$wpdb->options} SET option_value = {$value} WHERE option_name = 'edd_next_order_number'"
);
}
/**
* Adds the last order number to the database.
*
* @since 3.1.2
* @param int $value
* @return bool
*/
private function insert( $value ) {
global $wpdb;
return $wpdb->insert(
$wpdb->options,
array(
'option_name' => 'edd_next_order_number',
'option_value' => $value,
),
array( '%s', '%d' )
);
}
/**
* Gets the last payment number from the database, or from the option.
*
* @return string
*/
private function get_last() {
// If this was the first order after switching to useing the 'next' order number option, we need to get the last order number from the database.
$last_payment_number = $this->get_last_payment_number();
if ( ! is_null( $last_payment_number ) ) {
return $last_payment_number + 1;
}
// If they enabled sequential order numbers after having orders, we need to get the last order number from the database.
$last_order = edd_get_orders(
array(
'number' => 1,
'orderby' => 'id',
'order' => 'DESC',
)
);
if ( ! empty( $last_order ) ) {
$last_order = reset( $last_order );
if ( $last_order instanceof EDD\Orders\Order && ! empty( $last_order->order_number ) ) {
return $this->unformat( $last_order->order_number );
}
}
// If all else fails, just get the starting number from the setting.
return $this->get_start();
}
/**
* Gets the EDD sequential starting number.
* Used when the last order number cannot otherwise be found.
*
* @return int
*/
private function get_start() {
return (int) edd_get_option( 'sequential_start', 1 );
}
/**
* Gets the sequential prefix.
*
* @since 3.1.2
* @return string
*/
private function get_prefix() {
return (string) edd_get_option( 'sequential_prefix' );
}
/**
* Gets the sequential postfix.
*
* @since 3.1.2
* @return string
*/
private function get_postfix() {
return (string) edd_get_option( 'sequential_postfix' );
}
/**
* Gets the last payment number from the database.
*
* @since 3.1.2
*
* @return int
*/
private function get_last_payment_number() {
global $wpdb;
return $wpdb->get_var( $wpdb->prepare( "SELECT option_value FROM {$wpdb->options} WHERE option_name=%s", 'edd_last_payment_number' ) );
}
}

View File

@ -43,7 +43,7 @@ class Licenses {
return array(
'extension' => 'edd_pro',
'status' => $pro_license->license,
'status' => $this->get_license_status( $pro_license ),
);
}
@ -59,14 +59,30 @@ class Licenses {
foreach ( $extensions as $slug ) {
$shortname = str_replace( 'edd_', '', $slug );
$license = new License( $shortname );
if ( ! empty( $license->license ) ) {
$data[] = array(
'extension' => $slug,
'status' => $license->license,
);
}
$data[] = array(
'extension' => $slug,
'status' => $this->get_license_status( $license ),
);
}
return $data;
}
/**
* Gets the license status.
*
* @since 3.1.2
* @param \EDD\Licensing\License $license
* @return string
*/
private function get_license_status( $license ) {
if ( ! empty( $license->license ) ) {
return $license->license;
}
if ( ! empty( $license->error ) ) {
return $license->error;
}
return 'missing';
}
}

View File

@ -0,0 +1,136 @@
<?php
/**
* Utility class to handle operations on an array of objects or arrays.
*
* @since 3.1.2
* @package EDD\Utils
*/
namespace EDD\Utils;
defined( 'ABSPATH' ) || exit;
class ListHandler {
/**
* The array to be handled.
*
* @var array
*/
private $array;
/**
* ListHandler constructor.
*
* @param array $array The array to be handled.
*/
public function __construct( $array ) {
$this->array = $array;
}
/**
* Gets the key of the array with the searched value.
*
* @since 3.1.2
* @param mixed $search The value to search for.
* @param string $type The type of search to perform. Currently supports 'min' or 'max'.
* @return int|string|false The key of the array with the searched value.
*/
public function search( $search, $type = 'min' ) {
if ( empty( $this->array ) || ! is_array( $this->array ) ) {
return false;
}
if ( $this->is_array_associative() ) {
return array_search( $search, $this->array ); // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
}
if ( in_array( $type, array( 'min', 'max' ), true ) ) {
$plucked = $this->pluck( $search );
if ( empty( $plucked ) ) {
return false;
}
$search = call_user_func( $type, $plucked );
}
foreach ( $this->array as $key => $value ) {
$result = array_search( $search, $value ); // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
if ( $result ) {
return $key;
}
}
return false;
}
/**
* Checks if the array is associative.
*
* @since 3.1.2
* @return bool
*/
private function is_array_associative() {
return count( $this->array ) === count( $this->array, COUNT_RECURSIVE );
}
/**
* Plucks a certain field out of each element in the input array.
*
* This has the same functionality and prototype of
* array_column() (PHP 5.5) but also supports objects.
*
* This is a near copy of the pluck() method from the WP_List_Util class, but
* that errors if a nonexistent field is passed. This version does not.
*
* @since 3.1.2
* @param int|string $field Field to fetch from the object or array.
* @param int|string $index_key Optional. Field from the element to use as keys for the new array.
* @return array Array of found values. If `$index_key` is set, an array of found values with keys
* corresponding to `$index_key`. If `$index_key` is null, array keys from the original
* `$list` will be preserved in the results.
*/
private function pluck( $field, $index_key = null ) {
$newlist = array();
if ( ! is_string( $field ) && ! is_int( $field ) ) {
return $newlist;
}
if ( ! $index_key ) {
/*
* This is simple. Could at some point wrap array_column()
* if we knew we had an array of arrays.
*/
foreach ( $this->array as $key => $value ) {
if ( is_object( $value ) ) {
$newlist[ $key ] = $value->$field;
} elseif ( is_array( $value ) && isset( $value[ $field ] ) ) {
$newlist[ $key ] = $value[ $field ];
}
}
return $newlist;
}
/*
* When index_key is not set for a particular item, push the value
* to the end of the stack. This is how array_column() behaves.
*/
foreach ( $this->array as $value ) {
if ( is_object( $value ) ) {
if ( isset( $value->$index_key ) ) {
$newlist[ $value->$index_key ] = $value->$field;
} else {
$newlist[] = $value->$field;
}
} elseif ( is_array( $value ) && isset( $value[ $field ] ) ) {
if ( isset( $value[ $index_key ] ) ) {
$newlist[ $value[ $index_key ] ] = $value[ $field ];
} else {
$newlist[] = $value[ $field ];
}
}
}
return $newlist;
}
}