updated plugin Easy Digital Downloads version 3.1.1.2

This commit is contained in:
2023-03-17 22:34:04 +00:00
committed by Gitium
parent e8a66564bd
commit 19e086d1c4
647 changed files with 20986 additions and 27305 deletions

View File

@ -1,258 +0,0 @@
<?php
/**
* Notifications Database
*
* @package easy-digital-downloads
* @copyright Copyright (c) 2021, Easy Digital Downloads
* @license GPL2+
* @since 2.11.4
*/
namespace EDD\Database;
use EDD\Models\Notification;
use EDD\Utils\EnvironmentChecker;
use EDD\Utils\NotificationImporter;
class NotificationsDB extends \EDD_DB {
/**
* Constructor
*/
public function __construct() {
global $wpdb;
$this->table_name = $wpdb->prefix . 'edd_notifications';
$this->primary_key = 'id';
$this->version = '1.0';
add_action( 'edd_daily_scheduled_events', array( $this, 'schedule_daily_notification_checks' ) );
$db_version = get_option( "{$this->table_name}_db_version" );
if ( version_compare( $db_version, $this->version, '>=' ) ) {
return;
}
$this->create_table();
}
/**
* Add a cron event to check for new notifications.
*
* @since 2.11.4
*/
public static function schedule_daily_notification_checks() {
$importer = new NotificationImporter();
$importer->run();
}
/**
* Columns and their formats.
*
* @since 2.11.4
*
* @return string[]
*/
public function get_columns() {
return array(
'id' => '%d',
'remote_id' => '%d',
'title' => '%s',
'content' => '%s',
'buttons' => '%s',
'type' => '%s',
'conditions' => '%s',
'start' => '%s',
'end' => '%s',
'dismissed' => '%d',
'date_created' => '%s',
'date_updated' => '%s',
);
}
/**
* Let MySQL handle most of the defaults.
* We just set the dates here to ensure they get saved in UTC.
*
* @since 2.11.4
*
* @return array
*/
public function get_column_defaults() {
return array(
'date_created' => gmdate( 'Y-m-d H:i:s' ),
'date_updated' => gmdate( 'Y-m-d H:i:s' ),
);
}
/**
* JSON-encodes any relevant columns.
*
* @since 2.11.4
*
* @param array $data
*
* @return array
*/
protected function maybeJsonEncode( $data ) {
$jsonColumns = array( 'buttons', 'conditions' );
foreach ( $jsonColumns as $column ) {
if ( ! empty( $data[ $column ] ) && is_array( $data[ $column ] ) ) {
$data[ $column ] = json_encode( $data[ $column ] );
}
}
return $data;
}
/**
* Inserts a new notification.
*
* @since 2.11.4
*
* @param array $data
* @param string $type
*
* @return int
*/
public function insert( $data, $type = 'notification' ) {
$result = parent::insert( $this->maybeJsonEncode( $data ), $type );
wp_cache_delete( 'edd_active_notification_count', 'edd_notifications' );
return $result;
}
/**
* Updates an existing notification.
*
* @since 2.11.4
*
* @param int $row_id
* @param array $data
* @param string $where
*
* @return bool
*/
public function update( $row_id, $data = array(), $where = '' ) {
return parent::update( $row_id, $this->maybeJsonEncode( $data ), $where );
}
/**
* Returns all notifications that have not been dismissed and should be
* displayed on this site.
*
* @since 2.11.4
*
* @param bool $conditionsOnly If set to true, then only the `conditions` column is retrieved
* for each notification.
*
* @return Notification[]
*/
public function getActiveNotifications( $conditionsOnly = false ) {
global $wpdb;
$environmentChecker = new EnvironmentChecker();
$notifications = $wpdb->get_results( $this->getActiveQuery( $conditionsOnly ) );
$models = array();
if ( is_array( $notifications ) ) {
foreach ( $notifications as $notification ) {
$model = new Notification( (array) $notification );
try {
// Only add to the array if all conditions are met or if the notification has no conditions.
if (
! $model->conditions ||
( is_array( $model->conditions ) && $environmentChecker->meetsConditions( $model->conditions ) )
) {
$models[] = $model;
}
} catch ( \Exception $e ) {
}
}
}
unset( $notifications );
return $models;
}
/**
* Builds the query for selecting or counting active notifications.
*
* @since 2.11.4
*
* @param bool $conditionsOnly
*
* @return string
*/
private function getActiveQuery( $conditionsOnly = false ) {
global $wpdb;
$select = $conditionsOnly ? 'conditions' : '*';
return $wpdb->prepare(
"SELECT {$select} FROM {$this->table_name}
WHERE dismissed = 0
AND (start <= %s OR start IS NULL)
AND (end >= %s OR end IS NULL)
ORDER BY start DESC, id DESC",
gmdate( 'Y-m-d H:i:s' ),
gmdate( 'Y-m-d H:i:s' )
);
}
/**
* Counts the number of active notifications.
* Note: We can't actually do a real `COUNT(*)` on the database, because we want
* to double-check the conditions are met before displaying. That's why we use
* `getActiveNotifications()` which runs the conditions through the EnvironmentChecker.
*
* @since 2.11.4
*
* @return int
*/
public function countActiveNotifications() {
$numberActive = wp_cache_get( 'edd_active_notification_count', 'edd_notifications' );
if ( false === $numberActive ) {
$numberActive = count( $this->getActiveNotifications( true ) );
wp_cache_set( 'edd_active_notification_count', $numberActive, 'edd_notifications' );
}
return $numberActive;
}
/**
* Creates the table.
*
* @since 2.11.4
*/
public function create_table() {
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
global $wpdb;
dbDelta( "CREATE TABLE {$this->table_name} (
id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
remote_id bigint(20) UNSIGNED DEFAULT NULL,
title text NOT NULL,
content longtext NOT NULL,
buttons longtext DEFAULT NULL,
type varchar(64) NOT NULL,
conditions longtext DEFAULT NULL,
start datetime DEFAULT NULL,
end datetime DEFAULT NULL,
dismissed tinyint(1) UNSIGNED NOT NULL DEFAULT 0,
date_created datetime NOT NULL DEFAULT CURRENT_TIMESTAMP(),
date_updated datetime NOT NULL DEFAULT CURRENT_TIMESTAMP(),
PRIMARY KEY (id),
KEY dismissed_start_end (dismissed, start, end)
) DEFAULT CHARACTER SET {$wpdb->charset} COLLATE {$wpdb->collate};" );
update_option( $this->table_name . '_db_version', $this->version );
}
}

View File

@ -143,4 +143,62 @@ class Customer extends Query {
public function __construct( $query = array() ) {
parent::__construct( $query );
}
/**
* Allow the customers query to be modified.
*
* @since 3.1.1
* @access public
*
* @param string|array $query See Customers::__construct() for accepted arguments.
*
* @see Customers::__construct()
*/
public function query( $query = array() ) {
$query = $this->parse_query_for_emails( $query );
return parent::query( $query );
}
/**
* If we are querying for an email, this queries the email addresses table first,
* then updates the queries with the matching customer IDs.
*
* @since 3.1.1
* @param array $query
* @return array
*/
private function parse_query_for_emails( $query ) {
if ( empty( $query['email'] ) && empty( $query['email__in'] ) && empty( $query['email__not_in'] ) ) {
return $query;
}
$operator = 'id__in';
$args = array(
'fields' => array( 'customer_id' ),
);
if ( ! empty( $query['email'] ) ) {
$args['email'] = $query['email'];
unset( $query['email'] );
} elseif ( ! empty( $query['email__in'] ) ) {
$args['email__in'] = $query['email__in'];
unset( $query['email__in'] );
} elseif ( ! empty( $query['email__not_in'] ) ) {
/**
* Speical treatment for email__not_in
*
* When we are searching for email__not_in, we want to actually find any email
* addresses in the customer email addresses table that match the email__not_in parameter
* find the customer IDs for these excluded email addresses, and pass them back in as id__not_in
* to the main query, so that we can ensure we're excluding them even if their main email value is
* one of the excluded ones.
*/
$operator = 'id__not_in';
$args['email__in'] = $query['email__not_in'];
}
$customer_ids = edd_get_customer_email_addresses( $args );
$query[ $operator ] = array_map( 'absint', wp_list_pluck( $customer_ids, 'customer_id' ) );
return $query;
}
}

View File

@ -38,7 +38,7 @@ final class Customers extends Table {
* @since 3.0
* @var int
*/
protected $version = 202006101;
protected $version = 202301021;
/**
* Array of upgrade versions and methods
@ -50,6 +50,7 @@ final class Customers extends Table {
protected $upgrades = array(
'202002141' => 202002141,
'202006101' => 202006101,
'202301021' => 202301021,
);
/**
@ -77,62 +78,27 @@ final class Customers extends Table {
KEY date_created (date_created)";
}
/**
* Override the Base class `maybe_upgrade()` routine to do a very unique and
* special check against the old option.
*
* Maybe upgrades the database table from 2.x to 3.x standards. This method
* should be kept up-to-date with schema changes in `set_schema()` above.
*
* - Hooked to the "admin_init" action.
* - Calls the parent class `maybe_upgrade()` method
*
* @since 3.0
*/
public function maybe_upgrade() {
if ( $this->needs_initial_upgrade() ) {
// Delete old/irrelevant database options.
delete_option( $this->table_prefix . 'edd_customers_db_version' );
delete_option( 'wp_edd_customers_db_version' );
// Modify existing columns.
$this->get_db()->query( "ALTER TABLE {$this->table_name} MODIFY `email` varchar(100) NOT NULL default ''" );
$this->get_db()->query( "ALTER TABLE {$this->table_name} MODIFY `name` varchar(255) NOT NULL default ''" );
$this->get_db()->query( "ALTER TABLE {$this->table_name} MODIFY `user_id` bigint(20) unsigned NOT NULL default '0'" );
$this->get_db()->query( "ALTER TABLE {$this->table_name} MODIFY `purchase_value` decimal(18,9) NOT NULL default '0'" );
$this->get_db()->query( "ALTER TABLE {$this->table_name} MODIFY `purchase_count` bigint(20) unsigned NOT NULL default '0'" );
$this->get_db()->query( "ALTER TABLE {$this->table_name} MODIFY `date_created` datetime NOT NULL default CURRENT_TIMESTAMP" );
if ( ! $this->column_exists( 'status' ) ) {
$this->get_db()->query( "ALTER TABLE {$this->table_name} ADD COLUMN `status` varchar(20) NOT NULL default 'active' AFTER `name`;" );
$this->get_db()->query( "ALTER TABLE {$this->table_name} ADD INDEX status (status(20))" );
}
if ( ! $this->column_exists( 'date_modified' ) ) {
$this->get_db()->query( "ALTER TABLE {$this->table_name} ADD COLUMN `date_modified` datetime DEFAULT CURRENT_TIMESTAMP AFTER `date_created`" );
$this->get_db()->query( "UPDATE {$this->table_name} SET `date_modified` = `date_created`" );
$this->get_db()->query( "ALTER TABLE {$this->table_name} ADD INDEX date_created (date_created)" );
}
if ( ! $this->column_exists( 'uuid' ) ) {
$this->get_db()->query( "ALTER TABLE {$this->table_name} ADD COLUMN `uuid` varchar(100) default '' AFTER `date_modified`;" );
}
}
parent::maybe_upgrade();
}
/**
* Whether the initial upgrade from the 1.0 database needs to be run.
*
* @since 3.0.3
* @since 3.1.1 Explicitly checks each of these cases to ensure a non-fully updated table is updated, but not currently used.
* @return bool
*/
private function needs_initial_upgrade() {
return $this->exists() && ! $this->column_exists( 'status' ) && ! $this->column_exists( 'uuid' );
if ( $this->exists() && ! $this->column_exists( 'status' ) ) {
return true;
}
if ( $this->exists() && ! $this->column_exists( 'uuid' ) ) {
return true;
}
if ( $this->exists() && ! $this->column_exists( 'date_modified' ) ) {
return true;
}
return false;
}
/**
@ -179,4 +145,107 @@ final class Customers extends Table {
return $this->is_success( $result );
}
/**
* Checks the status of the edd_customers table for health and state and performs
* any necessary changes that haven't been prevoiusly made.
*
* @since 3.1.1
* @return bool
*/
protected function __202301021() {
// Verify that columns that existed prior to 3.0 get the proper changes made.
$columns = $this->get_db()->get_results( "SHOW COLUMNS FROM {$this->table_name}" );
$existing_column_updates = array();
// Set an array to hold the result of each query run.
$query_results = array();
foreach ( $columns as $column ) {
switch ( $column->Field ) {
case 'email':
if ( 'varchar(100)' !== $column->Type ) {
$existing_column_updates['alter-email-type'] = "ALTER TABLE {$this->table_name} MODIFY `email` varchar(100) NOT NULL default ''";
}
break;
case 'name':
if ( 'varchar(255)' !== $column->Type ) {
$existing_column_updates['alter-name-type'] = "ALTER TABLE {$this->table_name} MODIFY `name` varchar(255) NOT NULL default ''";
}
break;
case 'user_id':
if ( 'bigint(20)' !== $column->Type ) {
$existing_column_updates['alter-user_id-type'] = "ALTER TABLE {$this->table_name} MODIFY `user_id` bigint(20) unsigned NOT NULL default '0'";
}
break;
case 'purchase_value':
if ( 'decimal(18,9)' !== $column->Type ) {
$existing_column_updates['alter-purchase_value-type'] = "ALTER TABLE {$this->table_name} MODIFY `purchase_value` decimal(18,9) NOT NULL default '0'";
}
break;
case 'purchase_count':
if ( 'bigint(20)' !== $column->Type ) {
$existing_column_updates['alter-purchase_count-type'] = "ALTER TABLE {$this->table_name} MODIFY `purchase_count` bigint(20) unsigned NOT NULL default '0'";
}
break;
case 'date_created':
if ( 'datetime' !== $column->Type ) {
$existing_column_updates['alter-date_created-type'] = "ALTER TABLE {$this->table_name} MODIFY `date_created` datetime NOT NULL default CURRENT_TIMESTAMP";
}
break;
case 'payment_ids':
$existing_column_updates['drop-payment_ids'] = "ALTER TABLE {$this->table_name} DROP COLUMN `payment_ids`";
break;
case 'notes':
// Only remove the customer notes column if they've already run the customer notes migration.
if ( edd_has_upgrade_completed( 'v30_legacy_data_removed' ) ) {
$existing_column_updates['drop-notes'] = "ALTER TABLE {$this->table_name} DROP COLUMN `notes`";
}
break;
}
}
if ( ! empty( $existing_column_updates ) ) {
foreach ( $existing_column_updates as $query_key => $update_sql ) {
$query_results[ $query_key ] = $this->is_success( $this->get_db()->query( $update_sql ) );
}
}
// Now verify that new columns are created and exist.
if ( ! $this->column_exists( 'status' ) ) {
$query_results['add-status-column'] = $this->is_success( $this->get_db()->query( "ALTER TABLE {$this->table_name} ADD COLUMN `status` varchar(20) NOT NULL default 'active' AFTER `name`;" ) );
$query_results['index-status'] = $this->is_success( $this->get_db()->query( "ALTER TABLE {$this->table_name} ADD INDEX status (status(20))" ) );
}
if ( ! $this->column_exists( 'date_modified' ) ) {
$query_results['add-date_modified-column'] = $this->is_success( $this->get_db()->query( "ALTER TABLE {$this->table_name} ADD COLUMN `date_modified` datetime DEFAULT CURRENT_TIMESTAMP AFTER `date_created`" ) );
$query_results['update-modified-with-created'] = $this->is_success( $this->get_db()->query( "UPDATE {$this->table_name} SET `date_modified` = `date_created`" ) );
$query_results['index-date_created'] = $this->is_success( $this->get_db()->query( "ALTER TABLE {$this->table_name} ADD INDEX date_created (date_created)" ) );
}
if ( ! $this->column_exists( 'uuid' ) ) {
$query_results['add-uuid-column'] = $this->is_success( $this->get_db()->query( "ALTER TABLE {$this->table_name} ADD COLUMN `uuid` varchar(100) default '' AFTER `date_modified`;" ) );
}
$return_result = true;
// Loop through each of the query results and force a debug log for any failures.
foreach ( $query_results as $query_key => $query_result ) {
if ( false === $query_result ) {
$return_result = false;
edd_debug_log( 'Customer\'s table version ' . $this->version . ' update failed for: ' . $query_key, true );
}
}
delete_option( $this->table_prefix . 'edd_customers_db_version' );
delete_option( 'wp_edd_customers_db_version' );
return $this->is_success( $return_result );
}
}

View File

@ -38,7 +38,7 @@ final class Orders extends Table {
* @since 3.0
* @var int
*/
protected $version = 202108041;
protected $version = 202302241;
/**
* Array of upgrade versions and methods.
@ -55,6 +55,7 @@ final class Orders extends Table {
'202103261' => 202103261,
'202105221' => 202105221,
'202108041' => 202108041,
'202302241' => 202302241,
);
/**
@ -96,7 +97,8 @@ final class Orders extends Table {
KEY customer_id (customer_id),
KEY email (email(100)),
KEY payment_key (payment_key(64)),
KEY date_created_completed (date_created,date_completed)";
KEY date_created_completed (date_created,date_completed),
KEY currency (currency)";
}
/**
@ -280,4 +282,23 @@ final class Orders extends Table {
return true;
}
/**
* Upgrade to version 202302241
* - Set an index for the 'currency' column as we use that in the admin frequenly.
*
* @since 3.1.1
*
* @return boolean
*/
protected function __202302241() {
if ( ! $this->index_exists( 'currency' ) ) {
$success = $this->get_db()->query( "ALTER TABLE {$this->table_name} ADD INDEX currency (currency)" );
} else {
$success = true;
}
return $this->is_success( $success );
}
}