408 lines
11 KiB
PHP
408 lines
11 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* Email Summary Class.
|
||
|
*
|
||
|
* @package EDD
|
||
|
* @subpackage Emails
|
||
|
* @copyright Copyright (c) 2022, Easy Digital Downloads, LLC
|
||
|
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||
|
* @since 3.1
|
||
|
*/
|
||
|
|
||
|
// Exit if accessed directly.
|
||
|
defined( 'ABSPATH' ) || exit;
|
||
|
|
||
|
/**
|
||
|
* EDD_Email_Summary Class.
|
||
|
*
|
||
|
* Takes care of preparing the necessary dataset, building the
|
||
|
* email template and sending the Email Summary.
|
||
|
*
|
||
|
* @since 3.1
|
||
|
*/
|
||
|
class EDD_Email_Summary {
|
||
|
|
||
|
/**
|
||
|
* Are we in a test mode.
|
||
|
*
|
||
|
* @since 3.1
|
||
|
*
|
||
|
* @var bool
|
||
|
*/
|
||
|
private $test_mode;
|
||
|
|
||
|
/**
|
||
|
* Email options.
|
||
|
*
|
||
|
* @since 3.1
|
||
|
*
|
||
|
* @var string
|
||
|
*/
|
||
|
private $email_options;
|
||
|
|
||
|
/**
|
||
|
* Class constructor.
|
||
|
*
|
||
|
* @since 3.1
|
||
|
*/
|
||
|
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 ),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get site URL.
|
||
|
*
|
||
|
* @since 3.1
|
||
|
*
|
||
|
* @return string Host of the site url.
|
||
|
*/
|
||
|
public function get_site_url() {
|
||
|
$site_url = get_site_url();
|
||
|
$site_url_parsed = wp_parse_url( $site_url );
|
||
|
$site_url = isset( $site_url_parsed['host'] ) ? $site_url_parsed['host'] : $site_url;
|
||
|
|
||
|
return $site_url;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get email subject.
|
||
|
*
|
||
|
* @since 3.1
|
||
|
*
|
||
|
* @return string Email subject.
|
||
|
*/
|
||
|
public function get_email_subject() {
|
||
|
/* Translators: Site domain name */
|
||
|
$email_subject = sprintf( __( 'Easy Digital Downloads Summary - %s', 'easy-digital-downloads' ), $this->get_site_url() );
|
||
|
|
||
|
if ( $this->test_mode ) {
|
||
|
$email_subject = '[TEST] ' . $email_subject;
|
||
|
}
|
||
|
|
||
|
return $email_subject;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get email recipients.
|
||
|
*
|
||
|
* @since 3.1
|
||
|
*
|
||
|
* @return array Recipients to receive the email.
|
||
|
*/
|
||
|
public function get_email_recipients() {
|
||
|
$recipients = array();
|
||
|
|
||
|
if ( 'admin' === edd_get_option( 'email_summary_recipient', 'admin' ) ) {
|
||
|
$recipients[] = get_option( 'admin_email' );
|
||
|
} else {
|
||
|
$emails = edd_get_option( 'email_summary_custom_recipients', '' );
|
||
|
$emails = array_map( 'trim', explode( "\n", $emails ) );
|
||
|
foreach ( $emails as $email ) {
|
||
|
if ( is_email( $email ) ) {
|
||
|
$recipients[] = $email;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( empty( $recipients ) ) {
|
||
|
edd_debug_log( __( 'Missing email recipients for Email Summary', 'easy-digital-downloads' ), true );
|
||
|
}
|
||
|
|
||
|
return apply_filters( 'edd_email_summary_recipients', $recipients );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get report start date.
|
||
|
*
|
||
|
* @since 3.1
|
||
|
*
|
||
|
* @return EDD\Utils\Date An array of start date and its relative counterpart as the EDD date object set at the UTC equivalent time.
|
||
|
*/
|
||
|
public function get_report_start_date() {
|
||
|
$date = EDD()->utils->date( 'now', edd_get_timezone_id(), false );
|
||
|
|
||
|
if ( 'monthly' === $this->email_options['email_summary_frequency'] ) {
|
||
|
$start_date = $date->copy()->subMonth( 1 )->startOfMonth();
|
||
|
$relative_start_date = $date->copy()->subMonth( 2 )->startOfMonth();
|
||
|
} else {
|
||
|
$start_date = $date->copy()->subDay( 7 )->startOfDay();
|
||
|
$relative_start_date = $date->copy()->subDay( 14 )->startOfDay();
|
||
|
}
|
||
|
|
||
|
return array(
|
||
|
'start_date' => $start_date,
|
||
|
'relative_start_date' => $relative_start_date,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get report end date.
|
||
|
*
|
||
|
* @since 3.1
|
||
|
*
|
||
|
* @return EDD\Utils\Date An array of end date and its relative counterpart as the EDD date object set at the UTC equivalent time.
|
||
|
*/
|
||
|
public function get_report_end_date() {
|
||
|
$date = EDD()->utils->date( 'now', edd_get_timezone_id(), false );
|
||
|
|
||
|
if ( 'monthly' === $this->email_options['email_summary_frequency'] ) {
|
||
|
$end_date = $date->copy()->subMonth( 1 )->endOfMonth();
|
||
|
$relative_end_date = $date->copy()->subMonth( 2 )->endOfMonth();
|
||
|
} else {
|
||
|
$end_date = $date->copy()->endOfDay();
|
||
|
$relative_end_date = $date->copy()->subDay( 7 )->endOfDay();
|
||
|
}
|
||
|
|
||
|
return array(
|
||
|
'end_date' => $end_date,
|
||
|
'relative_end_date' => $relative_end_date,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get report date range.
|
||
|
*
|
||
|
* @since 3.1
|
||
|
*
|
||
|
* @return array Array of start and end date objects in \EDD\Utils\Date[] format.
|
||
|
*/
|
||
|
public function get_report_date_range() {
|
||
|
// @todo - Check if we have to convert this to UTC because of DB?
|
||
|
return array_merge(
|
||
|
$this->get_report_start_date(),
|
||
|
$this->get_report_end_date()
|
||
|
);
|
||
|
}
|
||
|
/**
|
||
|
* Retrieve ! TEST ! dataset for email content.
|
||
|
*
|
||
|
* @since 3.1
|
||
|
*
|
||
|
* @return array Data and statistics for the period.
|
||
|
*/
|
||
|
public function get_test_report_dataset() {
|
||
|
$stats = new EDD\Stats();
|
||
|
$args = array(
|
||
|
'post_type' => 'download',
|
||
|
'posts_per_page' => 5,
|
||
|
'fields' => 'ids',
|
||
|
'no_found_rows' => true,
|
||
|
);
|
||
|
|
||
|
$downloads = new WP_Query( $args );
|
||
|
$top_selling_products = array();
|
||
|
|
||
|
foreach ( $downloads->posts as $post ) {
|
||
|
$download = new EDD_Download( $post );
|
||
|
|
||
|
$product = new stdClass();
|
||
|
$product->object = $download;
|
||
|
$product->total = 100;
|
||
|
|
||
|
$top_selling_products[] = $product;
|
||
|
}
|
||
|
|
||
|
$data = array(
|
||
|
'earnings_gross' => array(
|
||
|
'value' => 5000,
|
||
|
'relative_data' => $stats->generate_relative_data( 5000, 4000 ),
|
||
|
),
|
||
|
'earnings_net' => array(
|
||
|
'value' => 4500,
|
||
|
'relative_data' => $stats->generate_relative_data( 4500, 3500 ),
|
||
|
),
|
||
|
'average_order_value' => array(
|
||
|
'value' => 29,
|
||
|
'relative_data' => $stats->generate_relative_data( 20, 35 ),
|
||
|
),
|
||
|
'new_customers' => array(
|
||
|
'value' => 25,
|
||
|
'relative_data' => $stats->generate_relative_data( 25, 20 ),
|
||
|
),
|
||
|
'top_selling_products' => $top_selling_products,
|
||
|
'order_count' => array( 'value' => 172 ),
|
||
|
);
|
||
|
|
||
|
return $data;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieve dataset for email content.
|
||
|
*
|
||
|
* @since 3.1
|
||
|
*
|
||
|
* @return array Data and statistics for the period.
|
||
|
*/
|
||
|
public function get_report_dataset() {
|
||
|
if ( $this->test_mode ) {
|
||
|
return $this->get_test_report_dataset();
|
||
|
}
|
||
|
|
||
|
$date_range = $this->get_report_date_range();
|
||
|
$start_date = $date_range['start_date']->format( 'Y-m-d H:i:s' );
|
||
|
$end_date = $date_range['end_date']->format( 'Y-m-d H:i:s' );
|
||
|
$relative_start_date = $date_range['relative_start_date']->format( 'Y-m-d H:i:s' );
|
||
|
$relative_end_date = $date_range['relative_end_date']->format( 'Y-m-d H:i:s' );
|
||
|
$stats = new EDD\Stats(
|
||
|
array(
|
||
|
'output' => 'array',
|
||
|
'start' => $start_date,
|
||
|
'end' => $end_date,
|
||
|
'relative' => true,
|
||
|
'relative_start' => $relative_start_date,
|
||
|
'relative_end' => $relative_end_date,
|
||
|
)
|
||
|
);
|
||
|
|
||
|
$earnings_gross = $stats->get_order_earnings(
|
||
|
array(
|
||
|
'function' => 'SUM',
|
||
|
'exclude_taxes' => false,
|
||
|
'revenue_type' => 'gross',
|
||
|
)
|
||
|
);
|
||
|
|
||
|
$earnings_net = $stats->get_order_earnings(
|
||
|
array(
|
||
|
'function' => 'SUM',
|
||
|
'exclude_taxes' => true,
|
||
|
'revenue_type' => 'net',
|
||
|
)
|
||
|
);
|
||
|
|
||
|
$average_order_value = $stats->get_order_earnings(
|
||
|
array(
|
||
|
'function' => 'AVG',
|
||
|
'exclude_taxes' => false,
|
||
|
)
|
||
|
);
|
||
|
|
||
|
$new_customers = $stats->get_customer_count();
|
||
|
|
||
|
$top_selling_products = $stats->get_most_valuable_order_items(
|
||
|
array(
|
||
|
'number' => 5,
|
||
|
)
|
||
|
);
|
||
|
|
||
|
$order_count = $stats->get_order_count();
|
||
|
|
||
|
return compact(
|
||
|
'earnings_gross',
|
||
|
'earnings_net',
|
||
|
'average_order_value',
|
||
|
'new_customers',
|
||
|
'top_selling_products',
|
||
|
'order_count'
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Generate HTML for relative markup.
|
||
|
*
|
||
|
* @since 3.1
|
||
|
*
|
||
|
* @param array $relative_data Calculated relative data.
|
||
|
*
|
||
|
* @return string HTML for relative markup.
|
||
|
*/
|
||
|
private function build_relative_markup( $relative_data ) {
|
||
|
$arrow = $relative_data['positive_change'] ? 'icon-arrow-up.png' : 'icon-arrow-down.png';
|
||
|
$output = __( 'No data to compare', 'easy-digital-downloads' );
|
||
|
if ( $relative_data['no_change'] ) {
|
||
|
$output = __( 'No Change', 'easy-digital-downloads' );
|
||
|
} elseif ( $relative_data['comparable'] ) {
|
||
|
$output = $relative_data['formatted_percentage_change'] . '%';
|
||
|
}
|
||
|
ob_start();
|
||
|
?>
|
||
|
<?php if ( $relative_data['comparable'] ) : ?>
|
||
|
<img src="<?php echo esc_url( EDD_PLUGIN_URL . '/assets/images/icons/' . $arrow ); ?>" width="12" height="10" style="outline: none; text-decoration: none; -ms-interpolation-mode: bicubic; width: 12px; height: 10px; max-width: 100%; clear: both; vertical-align: text-top;">
|
||
|
<?php endif; ?>
|
||
|
<span style="padding-left: 1px;">
|
||
|
<?php echo esc_html( $output ); ?>
|
||
|
</span>
|
||
|
<?php
|
||
|
|
||
|
return ob_get_clean();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Build email template.
|
||
|
*
|
||
|
* @since 3.1
|
||
|
*
|
||
|
* @param array|bool $blurb Structured blurb data.
|
||
|
*
|
||
|
* @return string|bool The string of the email template or false if the email template couldn't be built.
|
||
|
*/
|
||
|
public function build_email_template( $blurb = false ) {
|
||
|
$dataset = $this->get_report_dataset();
|
||
|
// If there were no sales, do not build an email template.
|
||
|
if ( empty( $dataset['order_count'] ) || 0 === $dataset['order_count'] ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
$date_range = $this->get_report_date_range();
|
||
|
$site_url = get_site_url();
|
||
|
$view_more_url = edd_get_admin_url(
|
||
|
array(
|
||
|
'page' => 'edd-reports',
|
||
|
'range' => ( 'monthly' === $this->email_options['email_summary_frequency'] ) ? 'last_month' : 'last_week',
|
||
|
'relative_range' => 'previous_period',
|
||
|
)
|
||
|
);
|
||
|
$wp_date_format = get_option( 'date_format' );
|
||
|
$period_name = ( 'monthly' === $this->email_options['email_summary_frequency'] ) ? __( 'month', 'easy-digital-downloads' ) : __( 'week', 'easy-digital-downloads' );
|
||
|
/* Translators: period name (e.g. week) */
|
||
|
$relative_text = sprintf( __( 'vs previous %s', 'easy-digital-downloads' ), $period_name );
|
||
|
|
||
|
ob_start();
|
||
|
include EDD_PLUGIN_DIR . 'includes/emails/email-summary/edd-email-summary-template.php';
|
||
|
|
||
|
return ob_get_clean();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Prepare and send email.
|
||
|
*
|
||
|
* @since 3.1
|
||
|
*
|
||
|
* @return bool True if email was sent, false if there was an error.
|
||
|
*/
|
||
|
public function send_email() {
|
||
|
// Get next blurb.
|
||
|
$email_blurbs = new EDD_Email_Summary_Blurb();
|
||
|
$next_blurb = false;
|
||
|
|
||
|
if ( ! $this->test_mode ) {
|
||
|
$next_blurb = $email_blurbs->get_next();
|
||
|
}
|
||
|
|
||
|
// Prepare email.
|
||
|
$email_body = $this->build_email_template( $next_blurb );
|
||
|
// If there is no email body, we cannot continue.
|
||
|
if ( ! $email_body ) {
|
||
|
edd_debug_log( __( 'Email body for Email Summary was empty.', 'easy-digital-downloads' ), true );
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
$email_subject = $this->get_email_subject();
|
||
|
$email_recipients = $this->get_email_recipients();
|
||
|
$email_headers = array( 'Content-Type: text/html; charset=UTF-8' );
|
||
|
|
||
|
// Everything is ok, send email.
|
||
|
$email_sent = wp_mail( $email_recipients, $email_subject, $email_body, $email_headers );
|
||
|
if ( $email_sent ) {
|
||
|
$email_blurbs->mark_blurb_sent( $next_blurb );
|
||
|
}
|
||
|
|
||
|
return $email_sent;
|
||
|
}
|
||
|
|
||
|
}
|