plugin updates
This commit is contained in:
@@ -53,17 +53,15 @@ class Area {
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
$this->hooks();
|
||||
}
|
||||
public function __construct() {}
|
||||
|
||||
/**
|
||||
* Assign all hooks to proper places.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @since 4.0.0 Changed visibility to public.
|
||||
*/
|
||||
protected function hooks() {
|
||||
public function hooks() {
|
||||
|
||||
// Add the Settings link to a plugin on Plugins page.
|
||||
add_filter( 'plugin_action_links_' . plugin_basename( WPMS_PLUGIN_FILE ), [ $this, 'add_plugin_action_link' ], 10, 1 );
|
||||
@@ -559,6 +557,10 @@ class Area {
|
||||
'one_click_setup_upgrade_title' => wp_kses( __( 'One-Click Setup for Google Mailer <br> is a Pro Feature', 'wp-mail-smtp' ), [ 'br' => [] ] ),
|
||||
'one_click_setup_upgrade_content' => esc_html__( 'We\'re sorry, One-Click Setup for Google Mailer is not available on your plan. Please upgrade to the Pro plan to unlock all these awesome features.', 'wp-mail-smtp' ),
|
||||
],
|
||||
'rate_limit' => [
|
||||
'upgrade_title' => wp_kses( __( 'Email Rate Limiting <br> is a Pro Feature', 'wp-mail-smtp' ), [ 'br' => [] ] ),
|
||||
'upgrade_content' => esc_html__( 'We\'re sorry, Email Rate Limiting is not available on your plan. Please upgrade to the Pro plan to unlock all these awesome features.', 'wp-mail-smtp' ),
|
||||
],
|
||||
],
|
||||
'all_mailers_supports' => wp_mail_smtp()->get_providers()->get_supports_all(),
|
||||
'nonce' => wp_create_nonce( 'wp-mail-smtp-admin' ),
|
||||
|
||||
@@ -40,15 +40,7 @@ class DashboardWidget {
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
// Prevent the class initialization, if the dashboard widget hidden setting is enabled.
|
||||
if ( Options::init()->get( 'general', 'dashboard_widget_hidden' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action( 'admin_init', [ $this, 'init' ] );
|
||||
}
|
||||
public function __construct() {}
|
||||
|
||||
/**
|
||||
* Init class.
|
||||
@@ -57,23 +49,34 @@ class DashboardWidget {
|
||||
*/
|
||||
public function init() {
|
||||
|
||||
// This widget should be displayed for certain high-level users only.
|
||||
if ( ! current_user_can( wp_mail_smtp()->get_capability_manage_options() ) ) {
|
||||
// Prevent the class initialization, if the dashboard widget hidden setting is enabled.
|
||||
if ( Options::init()->get( 'general', 'dashboard_widget_hidden' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters whether the initialization of the dashboard widget should be allowed.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param bool $var If the dashboard widget should be initialized.
|
||||
*/
|
||||
if ( ! apply_filters( 'wp_mail_smtp_admin_dashboard_widget', '__return_true' ) ) {
|
||||
return;
|
||||
}
|
||||
add_action(
|
||||
'admin_init',
|
||||
function() {
|
||||
|
||||
$this->hooks();
|
||||
// This widget should be displayed for certain high-level users only.
|
||||
if ( ! current_user_can( wp_mail_smtp()->get_capability_manage_options() ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters whether the initialization of the dashboard widget should be allowed.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param bool $var If the dashboard widget should be initialized.
|
||||
*/
|
||||
if ( ! apply_filters( 'wp_mail_smtp_admin_dashboard_widget', '__return_true' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->hooks();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -104,6 +104,10 @@ class DebugEvents {
|
||||
wp_send_json_error( esc_html__( 'You don\'t have the capability to perform this action.', 'wp-mail-smtp' ) );
|
||||
}
|
||||
|
||||
if ( ! self::is_valid_db() ) {
|
||||
wp_send_json_error( esc_html__( 'For some reason the database table was not installed correctly. Please contact plugin support team to diagnose and fix the issue.', 'wp-mail-smtp' ) );
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$table = self::get_table_name();
|
||||
@@ -143,6 +147,10 @@ class DebugEvents {
|
||||
wp_send_json_error( esc_html__( 'You don\'t have the capability to perform this action.', 'wp-mail-smtp' ) );
|
||||
}
|
||||
|
||||
if ( ! self::is_valid_db() ) {
|
||||
wp_send_json_error( esc_html__( 'For some reason the database table was not installed correctly. Please contact plugin support team to diagnose and fix the issue.', 'wp-mail-smtp' ) );
|
||||
}
|
||||
|
||||
$event_id = isset( $_POST['id'] ) ? intval( $_POST['id'] ) : false;
|
||||
|
||||
if ( empty( $event_id ) ) {
|
||||
@@ -171,6 +179,10 @@ class DebugEvents {
|
||||
*/
|
||||
public static function add( $message = '', $type = 0 ) {
|
||||
|
||||
if ( ! self::is_valid_db() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! in_array( $type, array_keys( Event::get_types() ), true ) ) {
|
||||
return false;
|
||||
}
|
||||
@@ -277,6 +289,10 @@ class DebugEvents {
|
||||
return new WP_Error( 'wp_mail_smtp_admin_debug_events_get_error_debug_events_count_invalid_time', 'Invalid time span.' );
|
||||
}
|
||||
|
||||
if ( ! self::is_valid_db() ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$transient_key = self::ERROR_DEBUG_EVENTS_TRANSIENT . '_' . sanitize_title_with_dashes( $span_of_time );
|
||||
$cached_error_events_count = get_transient( $transient_key );
|
||||
|
||||
|
||||
@@ -645,6 +645,10 @@ class AboutTab extends PageAbstract {
|
||||
|
||||
$plugin_basename = $installer->plugin_info();
|
||||
|
||||
if ( $plugin_basename === 'wpforms-lite/wpforms.php' ) {
|
||||
add_option( 'wpforms_installation_source', 'wp-mail-smtp-about-us' );
|
||||
}
|
||||
|
||||
// Activate the plugin silently.
|
||||
$activated = activate_plugin( $plugin_basename );
|
||||
|
||||
|
||||
@@ -470,6 +470,24 @@ class DebugEventsTab extends PageAbstract {
|
||||
private function display_debug_events_not_installed() {
|
||||
|
||||
$error_message = get_option( Migration::ERROR_OPTION_NAME );
|
||||
|
||||
$create_missing_tables_url = wp_nonce_url(
|
||||
add_query_arg(
|
||||
[
|
||||
'create-missing-db-tables' => 1,
|
||||
],
|
||||
$this->get_link()
|
||||
),
|
||||
Area::SLUG . '-create-missing-db-tables'
|
||||
);
|
||||
|
||||
$contact_support_url = wp_mail_smtp()->get_utm_url(
|
||||
'https://wpmailsmtp.com/account/support/',
|
||||
[
|
||||
'medium' => 'debug-events',
|
||||
'content' => 'Debug Events not installed correctly',
|
||||
]
|
||||
);
|
||||
?>
|
||||
|
||||
<div class="notice-inline notice-error">
|
||||
@@ -478,11 +496,37 @@ class DebugEventsTab extends PageAbstract {
|
||||
<p>
|
||||
<?php
|
||||
if ( ! empty( $error_message ) ) {
|
||||
esc_html_e( 'The database table was not installed correctly. Please contact plugin support to diagnose and fix the issue. Provide them the error message below:', 'wp-mail-smtp' );
|
||||
echo wp_kses(
|
||||
sprintf( /* translators: %1$s - create missing tables link; %2$s - contact support link. */
|
||||
__( 'WP Mail SMTP is using custom database tables for some of its features. In order to work properly, the custom tables should be created, and it seems they are missing. Please try to <a href="%1$s">create the missing DB tables by clicking on this link</a>. If this issue persists, please <a href="%2$s" target="_blank" rel="noopener noreferrer">contact our support</a> and provide the error message below:', 'wp-mail-smtp' ),
|
||||
esc_url( $create_missing_tables_url ),
|
||||
esc_url( $contact_support_url )
|
||||
),
|
||||
[
|
||||
'a' => [
|
||||
'href' => [],
|
||||
'target' => [],
|
||||
'rel' => [],
|
||||
],
|
||||
]
|
||||
);
|
||||
echo '<br><br>';
|
||||
echo '<code>' . esc_html( $error_message ) . '</code>';
|
||||
} else {
|
||||
esc_html_e( 'For some reason the database table was not installed correctly. Please contact plugin support team to diagnose and fix the issue.', 'wp-mail-smtp' );
|
||||
echo wp_kses(
|
||||
sprintf( /* translators: %1$s - create missing tables link; %2$s - contact support link. */
|
||||
__( 'WP Mail SMTP is using custom database tables for some of its features. In order to work properly, the custom tables should be created, and it seems they are missing. Please try to <a href="%1$s">create the missing DB tables by clicking on this link</a>. If this issue persists, please <a href="%2$s" target="_blank" rel="noopener noreferrer">contact our support</a>.', 'wp-mail-smtp' ),
|
||||
esc_url( $create_missing_tables_url ),
|
||||
esc_url( $contact_support_url )
|
||||
),
|
||||
[
|
||||
'a' => [
|
||||
'href' => [],
|
||||
'target' => [],
|
||||
'rel' => [],
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
?>
|
||||
</p>
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace WPMailSMTP\Admin\Pages;
|
||||
use WPMailSMTP\Admin\Area;
|
||||
use WPMailSMTP\Admin\PageAbstract;
|
||||
use WPMailSMTP\Helpers\UI;
|
||||
use WPMailSMTP\OptimizedEmailSending;
|
||||
use WPMailSMTP\Options;
|
||||
use WPMailSMTP\UsageTracking\UsageTracking;
|
||||
use WPMailSMTP\Reports\Emails\Summary as SummaryReportEmail;
|
||||
@@ -309,6 +310,55 @@ class MiscTab extends PageAbstract {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Optimize email sending -->
|
||||
<div id="wp-mail-smtp-setting-row-optimize-email-sending" class="wp-mail-smtp-setting-row wp-mail-smtp-clear">
|
||||
<div class="wp-mail-smtp-setting-label">
|
||||
<label for="wp-mail-smtp-setting-optimize-email-sending">
|
||||
<?php esc_html_e( 'Optimize Email Sending', 'wp-mail-smtp' ); ?>
|
||||
</label>
|
||||
</div>
|
||||
<div class="wp-mail-smtp-setting-field">
|
||||
<?php
|
||||
UI::toggle(
|
||||
[
|
||||
'name' => 'wp-mail-smtp[general][' . OptimizedEmailSending::SETTINGS_SLUG . ']',
|
||||
'id' => 'wp-mail-smtp-setting-optimize-email-sending',
|
||||
'value' => 'true',
|
||||
'checked' => (bool) OptimizedEmailSending::is_enabled(),
|
||||
]
|
||||
);
|
||||
?>
|
||||
<p class="desc">
|
||||
<?php
|
||||
printf(
|
||||
wp_kses( /* translators: %1$s - Documentation URL. */
|
||||
__( 'Send emails asynchronously, which will make pages with email requests load faster, but may delay email delivery by a minute or two. <a href="%1$s" target="_blank" rel="noopener noreferrer">Learn More</a>', 'wp-mail-smtp' ),
|
||||
[
|
||||
'a' => [
|
||||
'href' => [],
|
||||
'rel' => [],
|
||||
'target' => [],
|
||||
],
|
||||
]
|
||||
),
|
||||
esc_url(
|
||||
wp_mail_smtp()->get_utm_url(
|
||||
'https://wpmailsmtp.com/docs/a-complete-guide-to-miscellaneous-settings/#optimize-email-sending',
|
||||
[
|
||||
'medium' => 'misc-settings',
|
||||
'content' => 'Optimize Email Sending - support article',
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Rate limit -->
|
||||
<?php $this->display_rate_limit_settings(); ?>
|
||||
|
||||
<!-- Uninstall -->
|
||||
<div id="wp-mail-smtp-setting-row-uninstall" class="wp-mail-smtp-setting-row wp-mail-smtp-clear">
|
||||
<div class="wp-mail-smtp-setting-label">
|
||||
@@ -343,6 +393,57 @@ class MiscTab extends PageAbstract {
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Display rate limit settings.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected function display_rate_limit_settings() {
|
||||
?>
|
||||
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-rate_limit-lite" class="wp-mail-smtp-setting-row wp-mail-smtp-clear">
|
||||
<div class="wp-mail-smtp-setting-label">
|
||||
<label for="<?php echo 'wp-mail-smtp-setting-' . esc_attr( $this->get_slug() ) . '-rate_limit-lite'; ?>">
|
||||
<?php esc_html_e( 'Email Rate Limiting', 'wp-mail-smtp' ); ?>
|
||||
</label>
|
||||
</div>
|
||||
<div class="wp-mail-smtp-setting-field">
|
||||
<?php
|
||||
UI::toggle(
|
||||
[
|
||||
'id' => 'wp-mail-smtp-setting-' . esc_attr( $this->get_slug() ) . '-rate_limit-lite',
|
||||
]
|
||||
);
|
||||
?>
|
||||
<p class="desc">
|
||||
<?php
|
||||
printf(
|
||||
wp_kses( /* translators: %1$s - Documentation URL. */
|
||||
__( 'Limit the number of emails this site will send in each time interval (per minute, hour, day, week and month). Emails that will cross those set limits will be queued and sent as soon as your limits allow. <a href="%1$s" target="_blank" rel="noopener noreferrer">Learn More</a>', 'wp-mail-smtp' ),
|
||||
[
|
||||
'a' => [
|
||||
'href' => [],
|
||||
'rel' => [],
|
||||
'target' => [],
|
||||
],
|
||||
]
|
||||
),
|
||||
esc_url(
|
||||
wp_mail_smtp()->get_utm_url(
|
||||
'https://wpmailsmtp.com/docs/a-complete-guide-to-miscellaneous-settings/#email-rate-limiting',
|
||||
[
|
||||
'medium' => 'misc-settings',
|
||||
'content' => 'Email Rate Limiting - support article',
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Process tab form submission ($_POST).
|
||||
*
|
||||
@@ -379,6 +480,9 @@ class MiscTab extends PageAbstract {
|
||||
if ( empty( $data['general'][ SummaryReportEmail::SETTINGS_SLUG ] ) ) {
|
||||
$data['general'][ SummaryReportEmail::SETTINGS_SLUG ] = false;
|
||||
}
|
||||
if ( empty( $data['general'][ OptimizedEmailSending::SETTINGS_SLUG ] ) ) {
|
||||
$data['general'][ OptimizedEmailSending::SETTINGS_SLUG ] = false;
|
||||
}
|
||||
|
||||
$is_summary_report_email_opt_changed = $options->is_option_changed(
|
||||
$options->parse_boolean( $data['general'][ SummaryReportEmail::SETTINGS_SLUG ] ),
|
||||
|
||||
@@ -136,8 +136,8 @@ class Review {
|
||||
<div class="wp-mail-smtp-review-step wp-mail-smtp-review-step-1">
|
||||
<p><?php esc_html_e( 'Are you enjoying WP Mail SMTP?', 'wp-mail-smtp' ); ?></p>
|
||||
<p>
|
||||
<a href="#" class="wp-mail-smtp-review-switch-step" data-step="3"><?php esc_html_e( 'Yes', 'wp-mail-smtp' ); ?></a><br />
|
||||
<a href="#" class="wp-mail-smtp-review-switch-step" data-step="2"><?php esc_html_e( 'Not Really', 'wp-mail-smtp' ); ?></a>
|
||||
<a href="#" class="wp-mail-smtp-review-switch-step" data-step="3"><?php esc_html_e( 'Yes', 'wp-mail-smtp' ); ?></a> •
|
||||
<a href="#" class="wp-mail-smtp-review-switch-step" data-step="2"><?php esc_html_e( 'No', 'wp-mail-smtp' ); ?></a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="wp-mail-smtp-review-step wp-mail-smtp-review-step-2" style="display: none">
|
||||
@@ -147,24 +147,23 @@ class Review {
|
||||
printf(
|
||||
'<a href="%1$s" class="wp-mail-smtp-dismiss-review-notice wp-mail-smtp-review-out" target="_blank" rel="noopener noreferrer">%2$s</a>',
|
||||
// phpcs:ignore WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
|
||||
esc_url( wp_mail_smtp()->get_utm_url( 'https://wpmailsmtp.com/plugin-feedback/', [ 'medium' => 'review-notice', 'content' => 'Give Feedback' ] ) ),
|
||||
esc_html__( 'Give Feedback', 'wp-mail-smtp' )
|
||||
esc_url( wp_mail_smtp()->get_utm_url( 'https://wpmailsmtp.com/plugin-feedback/', [ 'medium' => 'review-notice', 'content' => 'Provide Feedback' ] ) ),
|
||||
esc_html__( 'Provide Feedback', 'wp-mail-smtp' )
|
||||
);
|
||||
?>
|
||||
<br>
|
||||
•
|
||||
<a href="#" class="wp-mail-smtp-dismiss-review-notice" target="_blank" rel="noopener noreferrer">
|
||||
<?php esc_html_e( 'No thanks', 'wp-mail-smtp' ); ?>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="wp-mail-smtp-review-step wp-mail-smtp-review-step-3" style="display: none">
|
||||
<p><?php esc_html_e( 'That’s awesome! Could you please do me a BIG favor and give it a 5-star rating on WordPress to help us spread the word and boost our motivation?', 'wp-mail-smtp' ); ?></p>
|
||||
<p><strong><?php echo wp_kses( __( '~ Jared Atchison<br>Co-Founder, WP Mail SMTP', 'wp-mail-smtp' ), [ 'br' => [] ] ); ?></strong></p>
|
||||
<p><?php esc_html_e( 'That\'s fantastic! Would you consider giving it a 5-star rating on WordPress.org? It will help other users with email issues and it will mean the world to us!', 'wp-mail-smtp' ); ?></p>
|
||||
<p>
|
||||
<a href="https://wordpress.org/support/plugin/wp-mail-smtp/reviews/?filter=5#new-post" class="wp-mail-smtp-dismiss-review-notice wp-mail-smtp-review-out" target="_blank" rel="noopener noreferrer">
|
||||
<?php esc_html_e( 'Ok, you deserve it', 'wp-mail-smtp' ); ?>
|
||||
</a><br>
|
||||
<a href="#" class="wp-mail-smtp-dismiss-review-notice" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Nope, maybe later', 'wp-mail-smtp' ); ?></a><br>
|
||||
<?php esc_html_e( 'Yes, I\'ll rate it with 5-stars', 'wp-mail-smtp' ); ?>
|
||||
</a> •
|
||||
<a href="#" class="wp-mail-smtp-dismiss-review-notice" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'No, maybe later', 'wp-mail-smtp' ); ?></a> •
|
||||
<a href="#" class="wp-mail-smtp-dismiss-review-notice" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'I already did', 'wp-mail-smtp' ); ?></a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -944,6 +944,7 @@ class SetupWizard {
|
||||
// Disable the WPForms redirect after plugin activation.
|
||||
if ( $slug === 'wpforms-lite' ) {
|
||||
update_option( 'wpforms_activation_redirect', true );
|
||||
add_option( 'wpforms_installation_source', 'wp-mail-smtp-setup-wizard' );
|
||||
}
|
||||
|
||||
// Disable the AIOSEO redirect after plugin activation.
|
||||
|
||||
@@ -28,10 +28,7 @@ class Compatibility {
|
||||
*/
|
||||
public function init() {
|
||||
|
||||
// Setup compatibility only in admin area.
|
||||
if ( WP::in_wp_admin() ) {
|
||||
$this->setup_compatibility();
|
||||
}
|
||||
$this->setup_compatibility();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,7 +39,10 @@ class Compatibility {
|
||||
public function setup_compatibility() {
|
||||
|
||||
$plugins = [
|
||||
'admin-2020' => '\WPMailSMTP\Compatibility\Plugin\Admin2020',
|
||||
'admin-2020' => '\WPMailSMTP\Compatibility\Plugin\Admin2020',
|
||||
'wpforms-lite' => '\WPMailSMTP\Compatibility\Plugin\WPFormsLite',
|
||||
'wpforms' => '\WPMailSMTP\Compatibility\Plugin\WPForms',
|
||||
'woocommerce' => '\WPMailSMTP\Compatibility\Plugin\WooCommerce',
|
||||
];
|
||||
|
||||
foreach ( $plugins as $key => $classname ) {
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace WPMailSMTP\Compatibility\Plugin;
|
||||
|
||||
use WPMailSMTP\WP;
|
||||
|
||||
/**
|
||||
* Admin 2020 Lite compatibility plugin.
|
||||
*
|
||||
@@ -9,6 +11,18 @@ namespace WPMailSMTP\Compatibility\Plugin;
|
||||
*/
|
||||
class Admin2020 extends PluginAbstract {
|
||||
|
||||
/**
|
||||
* If plugin can be loaded.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_applicable() {
|
||||
|
||||
return parent::is_applicable() && WP::in_wp_admin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin name.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Compatibility\Plugin;
|
||||
|
||||
/**
|
||||
* WPForms compatibility plugin.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class WPForms extends WPFormsLite {
|
||||
|
||||
/**
|
||||
* Get plugin name.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
|
||||
return 'WPForms';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin path.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_path() {
|
||||
|
||||
return 'wpforms/wpforms.php';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Compatibility\Plugin;
|
||||
|
||||
/**
|
||||
* WPForms Lite compatibility plugin.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class WPFormsLite extends PluginAbstract {
|
||||
|
||||
/**
|
||||
* Get plugin name.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
|
||||
return 'WPForms Lite';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin path.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_path() {
|
||||
|
||||
return 'wpforms-lite/wpforms.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute on init action.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function load() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
|
||||
|
||||
if ( wp_mail_smtp()->get_queue()->is_enabled() ) {
|
||||
add_filter( 'wpforms_tasks_entry_emails_trigger_send_same_process', '__return_true', PHP_INT_MAX );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Compatibility\Plugin;
|
||||
|
||||
/**
|
||||
* WooCommerce compatibility plugin.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class WooCommerce extends PluginAbstract {
|
||||
|
||||
/**
|
||||
* Get plugin name.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
|
||||
return 'WooCommerce';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin path.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_path() {
|
||||
|
||||
return 'woocommerce/woocommerce.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute on init action.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function load() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
|
||||
|
||||
if ( wp_mail_smtp()->get_queue()->is_enabled() ) {
|
||||
add_filter( 'woocommerce_defer_transactional_emails', '__return_false', PHP_INT_MAX );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,13 +6,13 @@ use WPMailSMTP\Admin\AdminBarMenu;
|
||||
use WPMailSMTP\Admin\DashboardWidget;
|
||||
use WPMailSMTP\Admin\DebugEvents\DebugEvents;
|
||||
use WPMailSMTP\Admin\Notifications;
|
||||
use WPMailSMTP\Helpers\Helpers;
|
||||
use WPMailSMTP\Tasks\Meta;
|
||||
use WPMailSMTP\UsageTracking\UsageTracking;
|
||||
use WPMailSMTP\Compatibility\Compatibility;
|
||||
use WPMailSMTP\Reports\Reports;
|
||||
use ReflectionFunction;
|
||||
use Exception;
|
||||
use WPMailSMTP\Queue\Queue;
|
||||
|
||||
/**
|
||||
* Class Core to handle all plugin initialization.
|
||||
@@ -114,6 +114,9 @@ class Core {
|
||||
// Activation hook.
|
||||
register_activation_hook( WPMS_PLUGIN_FILE, [ $this, 'activate' ] );
|
||||
|
||||
// Initialize DB migrations.
|
||||
add_action( 'plugins_loaded', [ $this, 'get_migrations' ] );
|
||||
|
||||
// Load Pro if available.
|
||||
add_action( 'plugins_loaded', [ $this, 'get_pro' ] );
|
||||
|
||||
@@ -129,9 +132,6 @@ class Core {
|
||||
// Initialize Action Scheduler tasks.
|
||||
add_action( 'init', [ $this, 'get_tasks' ], 5 );
|
||||
|
||||
// Initialize DB migrations.
|
||||
add_action( 'admin_init', [ $this, 'init_migrations' ] );
|
||||
|
||||
add_action( 'plugins_loaded', [ $this, 'get_usage_tracking' ] );
|
||||
add_action( 'plugins_loaded', [ $this, 'get_admin_bar_menu' ] );
|
||||
add_action( 'plugins_loaded', [ $this, 'get_notifications' ] );
|
||||
@@ -142,6 +142,13 @@ class Core {
|
||||
add_action( 'plugins_loaded', [ $this, 'get_db_repair' ] );
|
||||
add_action( 'plugins_loaded', [ $this, 'get_connections_manager' ], 20 );
|
||||
add_action( 'plugins_loaded', [ $this, 'get_wp_mail_initiator' ] );
|
||||
add_action( 'plugins_loaded', [ $this, 'get_queue' ] );
|
||||
add_action(
|
||||
'plugins_loaded',
|
||||
function() {
|
||||
( new OptimizedEmailSending() )->hooks();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,7 +291,18 @@ class Core {
|
||||
static $processor;
|
||||
|
||||
if ( ! isset( $processor ) ) {
|
||||
$processor = apply_filters( 'wp_mail_smtp_core_get_processor', new Processor() );
|
||||
|
||||
/**
|
||||
* Filters Processor instance.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param Processor $processor Processor instance.
|
||||
*/
|
||||
$processor = apply_filters(
|
||||
'wp_mail_smtp_core_get_processor',
|
||||
new Processor()
|
||||
);
|
||||
|
||||
if ( method_exists( $processor, 'hooks' ) ) {
|
||||
$processor->hooks();
|
||||
@@ -307,6 +325,10 @@ class Core {
|
||||
|
||||
if ( ! isset( $admin ) ) {
|
||||
$admin = apply_filters( 'wp_mail_smtp_core_get_admin', new Admin\Area() );
|
||||
|
||||
if ( method_exists( $admin, 'hooks' ) ) {
|
||||
$admin->hooks();
|
||||
}
|
||||
}
|
||||
|
||||
return $admin;
|
||||
@@ -355,34 +377,35 @@ class Core {
|
||||
/**
|
||||
* Initialize DB migrations.
|
||||
*
|
||||
* @deprecated 4.0.0
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function init_migrations() {
|
||||
|
||||
if ( WP::is_doing_ajax() || wp_doing_cron() ) {
|
||||
return;
|
||||
_deprecated_function( __METHOD__, '3.10.0', '\WPMailSMTP\Migrations::init_migrations_on_request' );
|
||||
|
||||
$this->get_migrations()->init_migrations_on_request();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Migrations object.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return Migrations
|
||||
*/
|
||||
public function get_migrations() {
|
||||
|
||||
static $migrations;
|
||||
|
||||
if ( ! isset( $migrations ) ) {
|
||||
$migrations = new Migrations();
|
||||
|
||||
$migrations->hooks();
|
||||
}
|
||||
|
||||
$migrations = [
|
||||
Migration::class,
|
||||
\WPMailSMTP\Admin\DebugEvents\Migration::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Filters DB migrations.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param array $migrations Migrations classes.
|
||||
*/
|
||||
$migrations = apply_filters( 'wp_mail_smtp_core_init_migrations', $migrations );
|
||||
|
||||
foreach ( $migrations as $migration ) {
|
||||
if ( is_subclass_of( $migration, '\WPMailSMTP\MigrationAbstract' ) && $migration::is_enabled() ) {
|
||||
$new_migration = new $migration();
|
||||
$new_migration->init();
|
||||
}
|
||||
}
|
||||
return $migrations;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -398,6 +421,10 @@ class Core {
|
||||
|
||||
if ( ! isset( $upgrade ) ) {
|
||||
$upgrade = apply_filters( 'wp_mail_smtp_core_get_upgrade', new Upgrade() );
|
||||
|
||||
if ( method_exists( $upgrade, 'run' ) ) {
|
||||
$upgrade->run();
|
||||
}
|
||||
}
|
||||
|
||||
return $upgrade;
|
||||
@@ -871,6 +898,10 @@ class Core {
|
||||
DebugEvents::get_table_name(),
|
||||
];
|
||||
|
||||
if ( $this->get_queue()->is_enabled() ) {
|
||||
$tables[] = Queue::get_table_name();
|
||||
}
|
||||
|
||||
return apply_filters( 'wp_mail_smtp_core_get_custom_db_tables', $tables );
|
||||
}
|
||||
|
||||
@@ -1147,6 +1178,10 @@ class Core {
|
||||
*/
|
||||
$class_name = apply_filters( 'wp_mail_smtp_core_get_dashboard_widget', DashboardWidget::class );
|
||||
$dashboard_widget = new $class_name();
|
||||
|
||||
if ( method_exists( $dashboard_widget, 'init' ) ) {
|
||||
$dashboard_widget->init();
|
||||
}
|
||||
}
|
||||
|
||||
return $dashboard_widget;
|
||||
@@ -1365,4 +1400,29 @@ class Core {
|
||||
*/
|
||||
return apply_filters( 'wp_mail_smtp_core_get_capability_manage_options', 'manage_options' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the queue functionality.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return Queue
|
||||
*/
|
||||
public function get_queue() {
|
||||
|
||||
static $queue;
|
||||
|
||||
if ( ! isset( $queue ) ) {
|
||||
/**
|
||||
* Filter the Queue object.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param Queue $queue The Queue object.
|
||||
*/
|
||||
$queue = apply_filters( 'wp_mail_smtp_core_get_queue', new Queue() );
|
||||
}
|
||||
|
||||
return $queue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ namespace WPMailSMTP;
|
||||
use WPMailSMTP\Admin\Area;
|
||||
use WPMailSMTP\Admin\DebugEvents\DebugEvents;
|
||||
use WPMailSMTP\Admin\DebugEvents\Migration as DebugMigration;
|
||||
use WPMailSMTP\Queue\Migration as QueueMigration;
|
||||
use WPMailSMTP\Queue\Queue;
|
||||
use WPMailSMTP\Tasks\Meta;
|
||||
|
||||
/**
|
||||
@@ -49,11 +51,17 @@ class DBRepair {
|
||||
}
|
||||
|
||||
$redirect_page = isset( $_GET['page'] ) ? sanitize_key( $_GET['page'] ) : Area::SLUG;
|
||||
$redirect_tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : '';
|
||||
$query_args = [
|
||||
'check-db-tables' => 1,
|
||||
];
|
||||
|
||||
if ( ! empty( $redirect_tab ) ) {
|
||||
$query_args['tab'] = $redirect_tab;
|
||||
}
|
||||
|
||||
$redirect_url = add_query_arg(
|
||||
[
|
||||
'check-db-tables' => 1,
|
||||
],
|
||||
$query_args,
|
||||
wp_mail_smtp()->get_admin()->get_admin_page_url( $redirect_page )
|
||||
);
|
||||
|
||||
@@ -76,6 +84,8 @@ class DBRepair {
|
||||
update_option( DebugMigration::OPTION_NAME, 0 );
|
||||
} elseif ( $missing_table === Meta::get_table_name() ) {
|
||||
update_option( Migration::OPTION_NAME, 1 );
|
||||
} elseif ( $missing_table === Queue::get_table_name() ) {
|
||||
update_option( QueueMigration::OPTION_NAME, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +132,11 @@ class DBRepair {
|
||||
$missing_table,
|
||||
get_option( Migration::ERROR_OPTION_NAME, $this->get_missing_table_default_error_message() )
|
||||
);
|
||||
} elseif ( $missing_table === Queue::get_table_name() ) {
|
||||
$reason .= $this->get_reason_output_message(
|
||||
$missing_table,
|
||||
get_option( QueueMigration::ERROR_OPTION_NAME, $this->get_missing_table_default_error_message() )
|
||||
);
|
||||
}
|
||||
|
||||
$reasons[] = $reason;
|
||||
|
||||
@@ -167,4 +167,14 @@ class Helpers {
|
||||
/** \Plugin_Upgrader class */
|
||||
require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the current request is a WP CLI request.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public static function is_wp_cli() {
|
||||
|
||||
return defined( 'WP_CLI' ) && WP_CLI;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace WPMailSMTP;
|
||||
|
||||
use phpmailerException;
|
||||
|
||||
// Load PHPMailer class, so we can subclass it.
|
||||
if ( ! class_exists( 'PHPMailer', false ) ) {
|
||||
require_once ABSPATH . WPINC . '/class-phpmailer.php';
|
||||
@@ -54,4 +56,18 @@ class MailCatcher extends \PHPMailer implements MailCatcherInterface {
|
||||
|
||||
return $this->LE; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw PHPMailer exception.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $error Error message.
|
||||
*
|
||||
* @throws phpmailerException PHPMailer exception.
|
||||
*/
|
||||
protected function throw_exception( $error ) {
|
||||
|
||||
throw new phpmailerException( $error );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,10 +79,7 @@ trait MailCatcherTrait {
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function send() { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.MaxExceeded, Generic.Metrics.NestingLevel.MaxExceeded
|
||||
|
||||
$connection = wp_mail_smtp()->get_connections_manager()->get_mail_connection();
|
||||
$mail_mailer = $connection->get_mailer_slug();
|
||||
public function send() { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||
|
||||
// Reset email related variables.
|
||||
$this->debug_event_id = false;
|
||||
@@ -116,171 +113,257 @@ trait MailCatcherTrait {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If it's not a test email,
|
||||
// check if the email should be enqueued
|
||||
// instead of being sent immediately.
|
||||
if ( ! $this->is_test_email && ! $this->is_setup_wizard_test_email ) {
|
||||
|
||||
/**
|
||||
* Filters whether an email should be enqueued or sent immediately.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param bool $should_enqueue Whether to enqueue an email, or send it.
|
||||
* @param array $wp_mail_args Original arguments of the `wp_mail` call.
|
||||
*/
|
||||
$should_enqueue_email = apply_filters(
|
||||
'wp_mail_smtp_mail_catcher_send_enqueue_email',
|
||||
false,
|
||||
wp_mail_smtp()->get_processor()->get_filtered_wp_mail_args()
|
||||
);
|
||||
|
||||
$queue = wp_mail_smtp()->get_queue();
|
||||
|
||||
// If we should enqueue the email,
|
||||
// and the email has been enqueued,
|
||||
// bail.
|
||||
if ( $should_enqueue_email && $queue->enqueue_email() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$connection = wp_mail_smtp()->get_connections_manager()->get_mail_connection();
|
||||
$mailer_slug = $connection->get_mailer_slug();
|
||||
|
||||
// Define a custom header, that will be used to identify the plugin and the mailer.
|
||||
$this->XMailer = 'WPMailSMTP/Mailer/' . $mail_mailer . ' ' . WPMS_PLUGIN_VER; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
// phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
$this->XMailer = 'WPMailSMTP/Mailer/' . $mailer_slug . ' ' . WPMS_PLUGIN_VER;
|
||||
|
||||
// Use the default PHPMailer, as we inject our settings there for certain providers.
|
||||
if (
|
||||
$mail_mailer === 'mail' ||
|
||||
$mail_mailer === 'smtp' ||
|
||||
$mail_mailer === 'pepipost'
|
||||
$mailer_slug === 'mail' ||
|
||||
$mailer_slug === 'smtp' ||
|
||||
$mailer_slug === 'pepipost'
|
||||
) {
|
||||
try {
|
||||
if ( DebugEvents::is_debug_enabled() && ! $this->is_test_email ) {
|
||||
$this->SMTPDebug = 3; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
$this->Debugoutput = [ $this, 'debug_output_callback' ]; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
}
|
||||
return $this->smtp_send( $connection );
|
||||
} else {
|
||||
return $this->api_send( $connection );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires before email pre send via SMTP.
|
||||
*
|
||||
* Allow to hook early to catch any early failed emails.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param MailCatcherInterface $mailcatcher The MailCatcher object.
|
||||
*/
|
||||
do_action( 'wp_mail_smtp_mailcatcher_smtp_pre_send_before', $this );
|
||||
/**
|
||||
* Send email via SMTP.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param ConnectionInterface $connection The connection object.
|
||||
*
|
||||
* @throws Exception When sending via PhpMailer fails for some reason.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function smtp_send( $connection ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||
|
||||
// Prepare all the headers.
|
||||
if ( ! $this->preSend() ) {
|
||||
return false;
|
||||
}
|
||||
$mailer_slug = $connection->get_mailer_slug();
|
||||
|
||||
/**
|
||||
* Fires before email send via SMTP.
|
||||
*
|
||||
* Allow to hook after all the preparation before the actual sending.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param MailCatcherInterface $mailcatcher The MailCatcher object.
|
||||
*/
|
||||
do_action( 'wp_mail_smtp_mailcatcher_smtp_send_before', $this );
|
||||
|
||||
$post_send = $this->postSend();
|
||||
|
||||
DebugEvents::add_debug(
|
||||
esc_html__( 'An email request was sent.', 'wp-mail-smtp' )
|
||||
);
|
||||
|
||||
return $post_send;
|
||||
} catch ( Exception $e ) {
|
||||
|
||||
// phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
$this->mailHeader = '';
|
||||
|
||||
$this->setError( $e->getMessage() );
|
||||
|
||||
// phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
$error_message = 'Mailer: ' . esc_html( wp_mail_smtp()->get_providers()->get_options( $mail_mailer )->get_title() ) . "\r\n" . $this->ErrorInfo;
|
||||
|
||||
// Set the debug error, but not for default PHP mailer.
|
||||
if ( $mail_mailer !== 'mail' ) {
|
||||
$this->debug_event_id = Debug::set( $error_message );
|
||||
$this->latest_error = $error_message;
|
||||
|
||||
if ( DebugEvents::is_debug_enabled() && ! empty( $this->debug_output_buffer ) ) {
|
||||
$debug_message = $error_message . "\r\n" . esc_html__( 'Debug Output:', 'wp-mail-smtp' ) . "\r\n";
|
||||
$debug_message .= implode( "\r\n", $this->debug_output_buffer );
|
||||
|
||||
$this->debug_event_id = DebugEvents::add_debug( $debug_message );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires after email sent failure via SMTP.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @param string $error_message Error message.
|
||||
* @param MailCatcherInterface $mailcatcher The MailCatcher object.
|
||||
* @param string $mail_mailer Current mailer name.
|
||||
*/
|
||||
do_action( 'wp_mail_smtp_mailcatcher_send_failed', $error_message, $this, $mail_mailer );
|
||||
|
||||
if ( $this->exceptions ) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return false;
|
||||
} finally {
|
||||
|
||||
// Clear debug output buffer.
|
||||
$this->debug_output_buffer = [];
|
||||
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
try {
|
||||
if ( DebugEvents::is_debug_enabled() && ! $this->is_test_email ) {
|
||||
$this->SMTPDebug = 3;
|
||||
$this->Debugoutput = [ $this, 'debug_output_callback' ];
|
||||
}
|
||||
}
|
||||
|
||||
// We need this so that the \PHPMailer class will correctly prepare all the headers.
|
||||
$this->Mailer = 'mail'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
/**
|
||||
* Fires before email pre send via SMTP.
|
||||
*
|
||||
* Allow to hook early to catch any early failed emails.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param MailCatcherInterface $mailcatcher The MailCatcher object.
|
||||
*/
|
||||
do_action( 'wp_mail_smtp_mailcatcher_smtp_pre_send_before', $this );
|
||||
|
||||
/**
|
||||
* Fires before email pre send.
|
||||
*
|
||||
* Allow to hook early to catch any early failed emails.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param MailCatcherInterface $mailcatcher The MailCatcher object.
|
||||
*/
|
||||
do_action( 'wp_mail_smtp_mailcatcher_pre_send_before', $this );
|
||||
// Prepare all the headers.
|
||||
if ( ! $this->preSend() ) {
|
||||
$this->throw_exception( $this->ErrorInfo );
|
||||
}
|
||||
|
||||
// Prepare everything (including the message) for sending.
|
||||
if ( ! $this->preSend() ) {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Fires before email send via SMTP.
|
||||
*
|
||||
* Allow to hook after all the preparation before the actual sending.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param MailCatcherInterface $mailcatcher The MailCatcher object.
|
||||
*/
|
||||
do_action( 'wp_mail_smtp_mailcatcher_smtp_send_before', $this );
|
||||
|
||||
$mailer = wp_mail_smtp()->get_providers()->get_mailer( $mail_mailer, $this, $connection );
|
||||
if ( ! $this->postSend() ) {
|
||||
$this->throw_exception( $this->ErrorInfo );
|
||||
}
|
||||
|
||||
if ( ! $mailer ) {
|
||||
return false;
|
||||
}
|
||||
DebugEvents::add_debug(
|
||||
esc_html__( 'An email request was sent.', 'wp-mail-smtp' )
|
||||
);
|
||||
|
||||
if ( ! $mailer->is_php_compatible() ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch ( Exception $e ) {
|
||||
$this->mailHeader = '';
|
||||
|
||||
/**
|
||||
* Fires before email send.
|
||||
*
|
||||
* Allows to hook after all the preparation before the actual sending.
|
||||
*
|
||||
* @since 3.3.0
|
||||
*
|
||||
* @param MailerAbstract $mailer The Mailer object.
|
||||
*/
|
||||
do_action( 'wp_mail_smtp_mailcatcher_send_before', $mailer );
|
||||
// We need this to append SMTP error to the `PHPMailer::ErrorInfo` property.
|
||||
$this->setError( $e->getMessage() );
|
||||
|
||||
/*
|
||||
* Send the actual email.
|
||||
* We reuse everything, that was preprocessed for usage in \PHPMailer.
|
||||
*/
|
||||
$mailer->send();
|
||||
|
||||
$is_sent = $mailer->is_email_sent();
|
||||
|
||||
if ( ! $is_sent ) {
|
||||
$error = $mailer->get_response_error();
|
||||
$error_message = '';
|
||||
|
||||
if ( ! empty( $error ) ) {
|
||||
// Add mailer to the beginning and save to display later.
|
||||
$message = 'Mailer: ' . esc_html( wp_mail_smtp()->get_providers()->get_options( $mailer->get_mailer_name() )->get_title() ) . "\r\n";
|
||||
|
||||
$conflicts = new Conflicts();
|
||||
|
||||
if ( $conflicts->is_detected() ) {
|
||||
$conflict_plugin_names = implode( ', ', $conflicts->get_all_conflict_names() );
|
||||
|
||||
$message .= 'Conflicts: ' . esc_html( $conflict_plugin_names ) . "\r\n";
|
||||
}
|
||||
|
||||
$error_message = $message . $error;
|
||||
// Set the debug error, but not for default PHP mailer.
|
||||
if ( $mailer_slug !== 'mail' ) {
|
||||
$error_message = 'Mailer: ' . esc_html( wp_mail_smtp()->get_providers()->get_options( $mailer_slug )->get_title() ) . "\r\n" . $this->ErrorInfo;
|
||||
|
||||
$this->debug_event_id = Debug::set( $error_message );
|
||||
$this->latest_error = $error_message;
|
||||
|
||||
if ( DebugEvents::is_debug_enabled() && ! empty( $this->debug_output_buffer ) ) {
|
||||
$debug_message = $error_message . "\r\n" . esc_html__( 'Debug Output:', 'wp-mail-smtp' ) . "\r\n";
|
||||
$debug_message .= implode( "\r\n", $this->debug_output_buffer );
|
||||
|
||||
$this->debug_event_id = DebugEvents::add_debug( $debug_message );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires after email sent failure via SMTP.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @param string $error_message Error message.
|
||||
* @param MailCatcherInterface $mailcatcher The MailCatcher object.
|
||||
* @param string $mailer_slug Current mailer name.
|
||||
*/
|
||||
do_action( 'wp_mail_smtp_mailcatcher_send_failed', $this->ErrorInfo, $this, $mailer_slug );
|
||||
|
||||
if ( $this->exceptions ) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return false;
|
||||
} finally {
|
||||
|
||||
// Clear debug output buffer.
|
||||
$this->debug_output_buffer = [];
|
||||
}
|
||||
// phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
}
|
||||
|
||||
/**
|
||||
* Send email via API integration.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param ConnectionInterface $connection The connection object.
|
||||
*
|
||||
* @throws Exception When sending fails for some reason.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function api_send( $connection ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||
|
||||
$mailer_slug = $connection->get_mailer_slug();
|
||||
|
||||
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
try {
|
||||
// We need this so that the \PHPMailer class will correctly prepare all the headers.
|
||||
$this->Mailer = 'mail';
|
||||
|
||||
/**
|
||||
* Fires before email pre send.
|
||||
*
|
||||
* Allow to hook early to catch any early failed emails.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param MailCatcherInterface $mailcatcher The MailCatcher object.
|
||||
*/
|
||||
do_action( 'wp_mail_smtp_mailcatcher_pre_send_before', $this );
|
||||
|
||||
// Prepare everything (including the message) for sending.
|
||||
if ( ! $this->preSend() ) {
|
||||
$this->throw_exception( $this->ErrorInfo );
|
||||
}
|
||||
|
||||
$mailer = wp_mail_smtp()->get_providers()->get_mailer( $mailer_slug, $this, $connection );
|
||||
|
||||
if ( ! $mailer ) {
|
||||
$this->throw_exception( esc_html__( 'The selected mailer not found.', 'wp-mail-smtp' ) );
|
||||
}
|
||||
|
||||
if ( ! $mailer->is_php_compatible() ) {
|
||||
$this->throw_exception( esc_html__( 'The selected mailer is not compatible with your PHP version.', 'wp-mail-smtp' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires before email send.
|
||||
*
|
||||
* Allows to hook after all the preparation before the actual sending.
|
||||
*
|
||||
* @since 3.3.0
|
||||
*
|
||||
* @param MailerAbstract $mailer The Mailer object.
|
||||
*/
|
||||
do_action( 'wp_mail_smtp_mailcatcher_send_before', $mailer );
|
||||
|
||||
/*
|
||||
* Send the actual email.
|
||||
* We reuse everything, that was preprocessed for usage in \PHPMailer.
|
||||
*/
|
||||
$mailer->send();
|
||||
|
||||
$is_sent = $mailer->is_email_sent();
|
||||
|
||||
/**
|
||||
* Fires after email send.
|
||||
*
|
||||
* Allow to perform any actions with the data.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @param MailerAbstract $mailer The Mailer object.
|
||||
* @param MailCatcherInterface $mailcatcher The MailCatcher object.
|
||||
*/
|
||||
do_action( 'wp_mail_smtp_mailcatcher_send_after', $mailer, $this );
|
||||
|
||||
if ( $is_sent !== true ) {
|
||||
$this->throw_exception( $mailer->get_response_error() );
|
||||
}
|
||||
|
||||
// Clear debug messages if email is successfully sent.
|
||||
Debug::clear();
|
||||
|
||||
return true;
|
||||
} catch ( Exception $e ) {
|
||||
// Add mailer to the beginning and save to display later.
|
||||
$message = 'Mailer: ' . esc_html( wp_mail_smtp()->get_providers()->get_options( $mailer_slug )->get_title() ) . "\r\n";
|
||||
|
||||
$conflicts = new Conflicts();
|
||||
|
||||
if ( $conflicts->is_detected() ) {
|
||||
$conflict_plugin_names = implode( ', ', $conflicts->get_all_conflict_names() );
|
||||
$message .= 'Conflicts: ' . esc_html( $conflict_plugin_names ) . "\r\n";
|
||||
}
|
||||
|
||||
$error_message = $message . $e->getMessage();
|
||||
$this->debug_event_id = Debug::set( $error_message );
|
||||
$this->latest_error = $error_message;
|
||||
|
||||
/**
|
||||
* Fires after email sent failure.
|
||||
*
|
||||
@@ -288,28 +371,17 @@ trait MailCatcherTrait {
|
||||
*
|
||||
* @param string $error_message Error message.
|
||||
* @param MailCatcherInterface $mailcatcher The MailCatcher object.
|
||||
* @param string $mail_mailer Current mailer name.
|
||||
* @param string $mailer_slug Current mailer name.
|
||||
*/
|
||||
do_action( 'wp_mail_smtp_mailcatcher_send_failed', $error_message, $this, $mail_mailer );
|
||||
} else {
|
||||
do_action( 'wp_mail_smtp_mailcatcher_send_failed', $e->getMessage(), $this, $mailer_slug );
|
||||
|
||||
// Clear debug messages if email is successfully sent.
|
||||
Debug::clear();
|
||||
if ( $this->exceptions ) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires after email send.
|
||||
*
|
||||
* Allow to perform any actions with the data.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @param MailerAbstract $mailer The Mailer object.
|
||||
* @param MailCatcherInterface $mailcatcher The MailCatcher object.
|
||||
*/
|
||||
do_action( 'wp_mail_smtp_mailcatcher_send_after', $mailer, $this );
|
||||
|
||||
return $is_sent;
|
||||
// phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -393,4 +465,84 @@ trait MailCatcherTrait {
|
||||
|
||||
return $this->is_emailing_blocked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of properties representing
|
||||
* this class' state.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return array State of this class.
|
||||
*/
|
||||
private function get_state_properties() {
|
||||
|
||||
return [
|
||||
'CharSet',
|
||||
'ContentType',
|
||||
'Encoding',
|
||||
'CustomHeader',
|
||||
'Subject',
|
||||
'Body',
|
||||
'AltBody',
|
||||
'ReplyTo',
|
||||
'to',
|
||||
'cc',
|
||||
'bcc',
|
||||
'attachment',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of relevant properties.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return array State of this class.
|
||||
*/
|
||||
public function get_state() {
|
||||
|
||||
$state = [];
|
||||
|
||||
foreach ( $this->get_state_properties() as $property ) {
|
||||
$state[ $property ] = $this->{$property};
|
||||
}
|
||||
|
||||
return $state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set properties from a provided array of data.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $state Array of properties to apply.
|
||||
*/
|
||||
public function set_state( $state ) { // phpcs:ignore Generic.Metrics.NestingLevel.MaxExceeded
|
||||
|
||||
// Filter out non-allowed properties.
|
||||
$state = array_intersect_key(
|
||||
$state,
|
||||
array_flip( $this->get_state_properties() )
|
||||
);
|
||||
|
||||
foreach ( $state as $property => $value ) {
|
||||
if ( $property !== 'attachment' ) {
|
||||
$this->{$property} = $value;
|
||||
} else {
|
||||
// Handle potential I/O exceptions
|
||||
// in PHPMailer when attaching files.
|
||||
$this->clearAttachments();
|
||||
|
||||
foreach ( $state['attachment'] as $attachment ) {
|
||||
[ $path, , $name ] = $attachment;
|
||||
|
||||
try {
|
||||
$this->addAttachment( $path, $name );
|
||||
} catch ( Exception $e ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace WPMailSMTP;
|
||||
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
|
||||
/**
|
||||
* Class MailCatcher replaces the \PHPMailer\PHPMailer\PHPMailer introduced in WP 5.5 and
|
||||
* modifies the email sending logic. Thus, we can use other mailers API to do what we need, or stop emails completely.
|
||||
@@ -47,4 +49,18 @@ class MailCatcherV6 extends \PHPMailer\PHPMailer\PHPMailer implements MailCatche
|
||||
|
||||
return static::$LE; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw PHPMailer exception.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $error Error message.
|
||||
*
|
||||
* @throws Exception PHPMailer exception.
|
||||
*/
|
||||
protected function throw_exception( $error ) {
|
||||
|
||||
throw new Exception( $error );
|
||||
}
|
||||
}
|
||||
|
||||
170
wp/wp-content/plugins/wp-mail-smtp/src/Migrations.php
Normal file
170
wp/wp-content/plugins/wp-mail-smtp/src/Migrations.php
Normal file
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP;
|
||||
|
||||
use WP_Upgrader;
|
||||
use WPMailSMTP\Admin\DebugEvents\Migration as DebugEventsMigration;
|
||||
use WPMailSMTP\Queue\Migration as QueueMigration;
|
||||
|
||||
/**
|
||||
* Class Migrations.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class Migrations {
|
||||
|
||||
/**
|
||||
* Register hooks.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function hooks() {
|
||||
|
||||
// Initialize migrations during request in the admin panel only.
|
||||
add_action( 'admin_init', [ $this, 'init_migrations_on_request' ] );
|
||||
|
||||
// Initialize migrations after plugin update.
|
||||
add_action( 'upgrader_process_complete', [ $this, 'init_migrations_after_upgrade' ], PHP_INT_MAX, 2 );
|
||||
add_action(
|
||||
'wp_ajax_nopriv_wp_mail_smtp_init_migrations',
|
||||
[ $this, 'init_migrations_ajax_handler' ]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize DB migrations during request.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function init_migrations_on_request() {
|
||||
|
||||
// Do not initialize migrations during AJAX and cron requests.
|
||||
if ( WP::is_doing_ajax() || wp_doing_cron() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->init_migrations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize DB migrations.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
private function init_migrations() {
|
||||
|
||||
$migrations = $this->get_migrations();
|
||||
|
||||
foreach ( $migrations as $migration ) {
|
||||
if ( is_subclass_of( $migration, MigrationAbstract::class ) && $migration::is_enabled() ) {
|
||||
( new $migration() )->init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get migrations classes.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return array Migrations classes.
|
||||
*/
|
||||
private function get_migrations() {
|
||||
|
||||
$migrations = [
|
||||
Migration::class,
|
||||
DebugEventsMigration::class,
|
||||
QueueMigration::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Filters DB migrations classes.
|
||||
*
|
||||
* @deprecated 4.0.0
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param array $migrations Migrations classes.
|
||||
*/
|
||||
$migrations = apply_filters_deprecated(
|
||||
'wp_mail_smtp_core_init_migrations',
|
||||
[ $migrations ],
|
||||
'3.10.0',
|
||||
'wp_mail_smtp_migrations_get_migrations'
|
||||
);
|
||||
|
||||
/**
|
||||
* Filters DB migrations classes.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $migrations Migrations classes.
|
||||
*/
|
||||
return apply_filters( 'wp_mail_smtp_migrations_get_migrations', $migrations );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize DB migrations after plugin update.
|
||||
* Initiate ajax call to perform the migration with the new plugin version code.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param WP_Upgrader $upgrader WP_Upgrader instance.
|
||||
* @param array $options Array of update data.
|
||||
*/
|
||||
public function init_migrations_after_upgrade( $upgrader, $options ) {
|
||||
|
||||
if (
|
||||
// Skip if in admin panel.
|
||||
( is_admin() && ! wp_doing_ajax() ) ||
|
||||
// Skip if it's update from plugins list page.
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
( wp_doing_ajax() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] === 'update-plugin' )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$plugins = [];
|
||||
|
||||
if ( isset( $options['plugins'] ) && is_array( $options['plugins'] ) ) {
|
||||
$plugins = $options['plugins'];
|
||||
} elseif ( isset( $options['plugin'] ) && is_string( $options['plugin'] ) ) {
|
||||
$plugins = [ $options['plugin'] ];
|
||||
}
|
||||
|
||||
if (
|
||||
! in_array( 'wp-mail-smtp/wp_mail_smtp.php', $plugins, true ) &&
|
||||
! in_array( 'wp-mail-smtp-pro/wp_mail_smtp.php', $plugins, true )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$url = add_query_arg(
|
||||
[
|
||||
'action' => 'wp_mail_smtp_init_migrations',
|
||||
],
|
||||
admin_url( 'admin-ajax.php' )
|
||||
);
|
||||
|
||||
$timeout = (int) ini_get( 'max_execution_time' );
|
||||
|
||||
$args = [
|
||||
'sslverify' => false,
|
||||
'timeout' => $timeout ? $timeout : 30,
|
||||
];
|
||||
|
||||
wp_remote_post( $url, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize migrations via AJAX request.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function init_migrations_ajax_handler() {
|
||||
|
||||
$this->init_migrations();
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP;
|
||||
|
||||
/**
|
||||
* OptimizedEmailSending class.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class OptimizedEmailSending {
|
||||
|
||||
/**
|
||||
* The slug of the option that toggles optimized email sending.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
const SETTINGS_SLUG = 'optimize_email_sending_enabled';
|
||||
|
||||
/**
|
||||
* Register hooks.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function hooks() {
|
||||
|
||||
// Avoid enqueueing emails if current request
|
||||
// is a cron request, a CLI request,
|
||||
// or an ActionScheduler task as 3rd party plugins might
|
||||
// be carrying out their own sending optimizations
|
||||
// through it.
|
||||
if (
|
||||
self::is_enabled() &&
|
||||
! ( defined( 'WP_CLI' ) && WP_CLI ) &&
|
||||
! wp_doing_cron() &&
|
||||
! doing_action( 'action_scheduler_run_queue' )
|
||||
) {
|
||||
// Enable the queue.
|
||||
add_filter( 'wp_mail_smtp_queue_is_enabled', '__return_true' );
|
||||
|
||||
// Start enqueueing emails.
|
||||
add_filter( 'wp_mail_smtp_mail_catcher_send_enqueue_email', '__return_true' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether optimized email sending is enabled.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_enabled() {
|
||||
|
||||
$value = Options::init()->get( 'general', self::SETTINGS_SLUG );
|
||||
|
||||
return (bool) $value;
|
||||
}
|
||||
}
|
||||
@@ -785,12 +785,20 @@ class Options {
|
||||
/** @noinspection PhpUndefinedConstantInspection */
|
||||
$return = $this->is_const_defined( $group, $key ) ? WPMS_DO_NOT_SEND : $value;
|
||||
break;
|
||||
|
||||
case SummaryReportEmail::SETTINGS_SLUG:
|
||||
/** No inspection comment @noinspection PhpUndefinedConstantInspection */
|
||||
$return = $this->is_const_defined( $group, $key ) ?
|
||||
$this->parse_boolean( WPMS_SUMMARY_REPORT_EMAIL_DISABLED ) :
|
||||
$value;
|
||||
break;
|
||||
|
||||
case OptimizedEmailSending::SETTINGS_SLUG:
|
||||
/** No inspection comment @noinspection PhpUndefinedConstantInspection */
|
||||
$return = $this->is_const_defined( $group, $key ) ?
|
||||
$this->parse_boolean( WPMS_OPTIMIZED_EMAIL_SENDING_ENABLED ) :
|
||||
$value;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1108,9 +1116,14 @@ class Options {
|
||||
/** @noinspection PhpUndefinedConstantInspection */
|
||||
$return = defined( 'WPMS_DO_NOT_SEND' ) && WPMS_DO_NOT_SEND;
|
||||
break;
|
||||
|
||||
case SummaryReportEmail::SETTINGS_SLUG:
|
||||
$return = defined( 'WPMS_SUMMARY_REPORT_EMAIL_DISABLED' );
|
||||
break;
|
||||
|
||||
case OptimizedEmailSending::SETTINGS_SLUG:
|
||||
$return = defined( 'WPMS_OPTIMIZED_EMAIL_SENDING_ENABLED' );
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1236,6 +1249,7 @@ class Options {
|
||||
case 'uninstall':
|
||||
case UsageTracking::SETTINGS_SLUG:
|
||||
case SummaryReportEmail::SETTINGS_SLUG:
|
||||
case OptimizedEmailSending::SETTINGS_SLUG:
|
||||
$options[ $group ][ $option_name ] = (bool) $option_value;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,42 @@ class Processor {
|
||||
*/
|
||||
private $connections_manager;
|
||||
|
||||
/**
|
||||
* This attribute will hold the arguments passed to the `wp_mail` function.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $original_wp_mail_args;
|
||||
|
||||
/**
|
||||
* This attribute will hold the arguments passed to the `wp_mail` function and filtered via `wp_mail` filter.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $filtered_wp_mail_args;
|
||||
|
||||
/**
|
||||
* This attribute will hold the From address filtered via the `wp_mail_from` filter.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $filtered_from_email;
|
||||
|
||||
/**
|
||||
* This attribute will hold the From name filtered via the `wp_mail_from_name` filter.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $filtered_from_name;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
@@ -58,6 +94,9 @@ class Processor {
|
||||
// High priority number tries to ensure our plugin code executes last and respects previous hooks, if not forced.
|
||||
add_filter( 'wp_mail_from', array( $this, 'filter_mail_from_email' ), PHP_INT_MAX );
|
||||
add_filter( 'wp_mail_from_name', array( $this, 'filter_mail_from_name' ), PHP_INT_MAX );
|
||||
|
||||
add_action( 'wp_mail', [ $this, 'capture_early_wp_mail_filter_call' ], - PHP_INT_MAX );
|
||||
add_action( 'wp_mail', [ $this, 'capture_late_wp_mail_filter_call' ], PHP_INT_MAX );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,6 +282,9 @@ class Processor {
|
||||
*/
|
||||
public function filter_mail_from_email( $wp_email ) {
|
||||
|
||||
// Save the original from address.
|
||||
$this->filtered_from_email = filter_var( $wp_email, FILTER_VALIDATE_EMAIL );
|
||||
|
||||
$connection = $this->connections_manager->get_mail_connection();
|
||||
$connection_options = $connection->get_options();
|
||||
$forced = $connection_options->get( 'mail', 'from_email_force' );
|
||||
@@ -279,6 +321,9 @@ class Processor {
|
||||
*/
|
||||
public function filter_mail_from_name( $name ) {
|
||||
|
||||
// Save the original from name.
|
||||
$this->filtered_from_name = $name;
|
||||
|
||||
$connection = $this->connections_manager->get_mail_connection();
|
||||
$connection_options = $connection->get_options();
|
||||
$force = $connection_options->get( 'mail', 'from_name_force' );
|
||||
@@ -377,4 +422,106 @@ class Processor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture `wp_mail` filter call on earliest priority.
|
||||
*
|
||||
* Currently used to capture the original `wp_mail` arguments before they are filtered.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $args The original `wp_mail` arguments.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function capture_early_wp_mail_filter_call( $args ) {
|
||||
|
||||
$this->original_wp_mail_args = $args;
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture `wp_mail` filter call on latest priority.
|
||||
*
|
||||
* Currently used to capture the `wp_mail` arguments after they are filtered
|
||||
* and capture `wp_mail` function call.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $args The filtered `wp_mail` arguments.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function capture_late_wp_mail_filter_call( $args ) {
|
||||
|
||||
$this->filtered_wp_mail_args = $args;
|
||||
|
||||
$this->capture_wp_mail_call();
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture `wp_mail` function call.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
private function capture_wp_mail_call() {
|
||||
|
||||
/**
|
||||
* Fires on `wp_mail` function call.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
do_action( 'wp_mail_smtp_processor_capture_wp_mail_call' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the original `wp_mail` arguments.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_original_wp_mail_args() {
|
||||
|
||||
return $this->original_wp_mail_args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filtered `wp_mail` arguments.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_filtered_wp_mail_args() {
|
||||
|
||||
return $this->filtered_wp_mail_args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filtered `wp_mail_from` value.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_filtered_from_email() {
|
||||
|
||||
return $this->filtered_from_email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filtered `wp_mail_from_name` value.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_filtered_from_name() {
|
||||
|
||||
return $this->filtered_from_name;
|
||||
}
|
||||
}
|
||||
|
||||
242
wp/wp-content/plugins/wp-mail-smtp/src/Queue/Attachments.php
Normal file
242
wp/wp-content/plugins/wp-mail-smtp/src/Queue/Attachments.php
Normal file
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Queue;
|
||||
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use WPMailSMTP\Uploads;
|
||||
|
||||
/**
|
||||
* Class Attachments.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class Attachments {
|
||||
|
||||
/**
|
||||
* Process a list of file attachments.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $attachments List of attachments.
|
||||
*
|
||||
* @return array List of attachments.
|
||||
*/
|
||||
public function process_attachments( $attachments ) {
|
||||
|
||||
$attachments = array_map(
|
||||
function( $attachment ) {
|
||||
[ $path, , $name, , , $is_string_attachment ] = $attachment;
|
||||
|
||||
$path = $this->process_attachment( $path, $name, $is_string_attachment );
|
||||
|
||||
if ( ! empty( $path ) ) {
|
||||
$attachment[0] = $path;
|
||||
}
|
||||
|
||||
return $attachment;
|
||||
},
|
||||
$attachments
|
||||
);
|
||||
|
||||
return $attachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an attachment,obfuscating its path
|
||||
* and storing its file on disk.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $path The path to obfuscate.
|
||||
* @param string $name The name of the file at $path.
|
||||
* @param bool $is_string_attachment Whether this attachment is a string attachment.
|
||||
*
|
||||
* @return string|false New path of the attachment, or false for no path.
|
||||
*/
|
||||
private function process_attachment( $path, $name = '', $is_string_attachment = false ) {
|
||||
|
||||
$file_content = $this->get_attachment_file_content( $path, $is_string_attachment );
|
||||
|
||||
if ( $file_content === false ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $is_string_attachment && $name === '' ) {
|
||||
$name = wp_basename( $path );
|
||||
}
|
||||
|
||||
$name = sanitize_file_name( $name );
|
||||
$obfuscated_path = $this->store_file( $file_content, $name );
|
||||
|
||||
if ( empty( $obfuscated_path ) ) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
return $obfuscated_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the contents of a given file.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $path The file's path.
|
||||
* @param bool $is_string_attachment Whether this file is a string attachment.
|
||||
*
|
||||
* @return string File contents.
|
||||
*/
|
||||
private function get_attachment_file_content( $path, $is_string_attachment ) {
|
||||
|
||||
if ( ! $is_string_attachment ) {
|
||||
if ( ! file_exists( $path ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return file_get_contents( $path );
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a file.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $file_content The file's contents.
|
||||
* @param string $original_filename The original file's name.
|
||||
*
|
||||
* @return string The file's path.
|
||||
*/
|
||||
private function store_file( $file_content, $original_filename ) {
|
||||
|
||||
$uploads_directory = $this->get_uploads_directory();
|
||||
|
||||
if ( is_wp_error( $uploads_directory ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! is_dir( $uploads_directory ) ) {
|
||||
wp_mkdir_p( $uploads_directory );
|
||||
|
||||
// Check if the .htaccess exists in the root upload directory, if not - create it.
|
||||
Uploads::create_upload_dir_htaccess_file();
|
||||
|
||||
// Check if the index.html exists in the directories, if not - create them.
|
||||
Uploads::create_index_html_file( Uploads::upload_dir()['path'] );
|
||||
Uploads::create_index_html_file( $uploads_directory );
|
||||
}
|
||||
|
||||
$file_extension = pathinfo( $original_filename, PATHINFO_EXTENSION );
|
||||
$filename = wp_unique_filename( $uploads_directory, wp_generate_password( 32, false, false ) . '.' . $file_extension );
|
||||
$uploads_directory = trailingslashit( $uploads_directory );
|
||||
|
||||
if ( ! is_writeable( $uploads_directory ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$upload_path = $uploads_directory . $filename;
|
||||
|
||||
if ( file_put_contents( $upload_path, $file_content ) !== false ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents
|
||||
return $upload_path;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete attachments, removing their files from disk.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param null|array $attachments List of attachments to cleanup, or null for all attachments.
|
||||
* @param null|DateTime $before_datetime The datetime attachments should be older than
|
||||
* to be removed, or null for all attachments.
|
||||
*
|
||||
* @return void.
|
||||
*/
|
||||
public function delete_attachments( $attachments = null, $before_datetime = null ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||
|
||||
$uploads_directory = $this->get_uploads_directory();
|
||||
|
||||
if (
|
||||
is_wp_error( $uploads_directory ) ||
|
||||
! is_dir( $uploads_directory )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$files = [];
|
||||
|
||||
// If no attachment list is provided, just iterate over all files in our uploads directory.
|
||||
if ( is_null( $attachments ) ) {
|
||||
$nodes = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator( $uploads_directory, RecursiveDirectoryIterator::SKIP_DOTS ),
|
||||
RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
$files = [];
|
||||
|
||||
foreach ( $nodes as $fileinfo ) {
|
||||
if ( ! $fileinfo->isDir() ) {
|
||||
$files[] = $fileinfo->getRealPath();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Map attachments to their paths.
|
||||
$files = wp_list_pluck( $attachments, 0 );
|
||||
|
||||
// Exclude any files that aren't in our uploads directory.
|
||||
$files = array_filter(
|
||||
$files,
|
||||
function( $file ) use ( $uploads_directory ) {
|
||||
return trailingslashit( dirname( $file ) ) === $uploads_directory;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Skip any file that doesn't exist.
|
||||
$files = array_filter(
|
||||
$files,
|
||||
function( $file ) {
|
||||
return file_exists( $file );
|
||||
}
|
||||
);
|
||||
|
||||
if ( ! is_null( $before_datetime ) ) {
|
||||
// Skip any file that isn't older than the provided datetime.
|
||||
$before_timestamp = $before_datetime->getTimestamp();
|
||||
$files = array_filter(
|
||||
$files,
|
||||
function( $file ) use ( $before_timestamp ) {
|
||||
return (
|
||||
filemtime( $file ) !== false &&
|
||||
filemtime( $file ) < $before_timestamp
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
foreach ( $files as $file ) {
|
||||
@unlink( $file );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the upload directory path.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return string|WP_Error The upload directory path.
|
||||
*/
|
||||
private function get_uploads_directory() {
|
||||
|
||||
$uploads_directory = Uploads::upload_dir();
|
||||
|
||||
if ( is_wp_error( $uploads_directory ) ) {
|
||||
return $uploads_directory;
|
||||
}
|
||||
|
||||
return trailingslashit( trailingslashit( $uploads_directory['path'] ) . 'queue_attachments' );
|
||||
}
|
||||
}
|
||||
608
wp/wp-content/plugins/wp-mail-smtp/src/Queue/Email.php
Normal file
608
wp/wp-content/plugins/wp-mail-smtp/src/Queue/Email.php
Normal file
@@ -0,0 +1,608 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Queue;
|
||||
|
||||
use WPMailSMTP\WP;
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class Email.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class Email {
|
||||
|
||||
/**
|
||||
* This email is enqueued.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
const STATUS_QUEUED = 0;
|
||||
|
||||
/**
|
||||
* This email is being processed.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
const STATUS_PROCESSING = 1;
|
||||
|
||||
/**
|
||||
* This email has been processed.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
const STATUS_PROCESSED = 2;
|
||||
|
||||
/**
|
||||
* ID of the email.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $id = 0;
|
||||
|
||||
/**
|
||||
* Serialized WPMailInitiator state of this email.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $initiator_state = [];
|
||||
|
||||
/**
|
||||
* Serialized arguments of this email's original wp_mail call.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $wp_mail_args = [];
|
||||
|
||||
/**
|
||||
* Serialized connection data of this email.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $connection_data = [];
|
||||
|
||||
/**
|
||||
* Serialized MailCatcher state of this email.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $mailer_state = [];
|
||||
|
||||
/**
|
||||
* Status of this email.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $status = 0;
|
||||
|
||||
/**
|
||||
* Date and time this email was enqueued at.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
private $date_enqueued;
|
||||
|
||||
/**
|
||||
* Date and time this email was processed at.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
private $date_processed;
|
||||
|
||||
/**
|
||||
* Email constructor.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
$this->date_enqueued = new DateTime( 'now', new DateTimeZone( 'UTC' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of allowed statuses.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_statuses() {
|
||||
|
||||
return [
|
||||
self::STATUS_QUEUED,
|
||||
self::STATUS_PROCESSING,
|
||||
self::STATUS_PROCESSED,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an email from an array of data.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param object $data Database row object.
|
||||
*
|
||||
* @throws Exception If supplied data is missing or malformed.
|
||||
*
|
||||
* @return Email
|
||||
*/
|
||||
public static function from_data( $data ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||
|
||||
if ( is_null( $data ) ) {
|
||||
throw new Exception( esc_html__( 'Record not found in DB', 'wp-mail-smtp' ) );
|
||||
}
|
||||
|
||||
if (
|
||||
! is_object( $data ) ||
|
||||
! property_exists( $data, 'data' ) ||
|
||||
! isset(
|
||||
$data->id,
|
||||
$data->status,
|
||||
$data->date_enqueued
|
||||
)
|
||||
) {
|
||||
throw new Exception( esc_html__( 'Invalid record format', 'wp-mail-smtp' ) );
|
||||
}
|
||||
|
||||
// Data can be null if email has been anonymized.
|
||||
// Only check for valid JSON if data isn't null.
|
||||
if ( ! is_null( $data->data ) && ! WP::is_json( $data->data ) ) {
|
||||
throw new Exception(
|
||||
sprintf(
|
||||
/* translators: %1$s - JSON error message. */
|
||||
esc_html__( 'Data JSON decoding error: %1$s', 'wp-mail-smtp' ),
|
||||
esc_html( json_last_error_msg() )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$email = new Email();
|
||||
$email_data = is_null( $data->data ) ? [] : json_decode( $data->data, true );
|
||||
$email_data = wp_parse_args(
|
||||
$email_data,
|
||||
[
|
||||
'initiator_state' => [],
|
||||
'wp_mail_args' => [],
|
||||
'connection_data' => [],
|
||||
'mailer_state' => [],
|
||||
]
|
||||
);
|
||||
|
||||
$email->id = (int) $data->id;
|
||||
$email->initiator_state = $email_data['initiator_state'];
|
||||
$email->wp_mail_args = $email_data['wp_mail_args'];
|
||||
$email->connection_data = $email_data['connection_data'];
|
||||
$email->mailer_state = $email_data['mailer_state'];
|
||||
$email->status = (int) $data->status;
|
||||
$email->date_enqueued = $email->get_datetime( $data->date_enqueued );
|
||||
|
||||
if ( isset( $data->date_processed ) ) {
|
||||
$email->date_processed = $email->get_datetime( $data->date_processed );
|
||||
}
|
||||
|
||||
return $email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this email's ID.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_id() {
|
||||
|
||||
return (int) $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this email's status.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_status() {
|
||||
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this email's status.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param int $status Email status.
|
||||
*
|
||||
* @return Email
|
||||
*/
|
||||
public function set_status( $status ) {
|
||||
|
||||
$status = (int) $status;
|
||||
|
||||
if ( ! in_array( $status, self::get_statuses(), true ) ) {
|
||||
$status = self::STATUS_QUEUED;
|
||||
}
|
||||
|
||||
$this->status = $status;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this email's `wp_mail` call arguments.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_wp_mail_args() {
|
||||
|
||||
return $this->wp_mail_args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this email's `wp_mail` call arguments.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $args Array of arguments.
|
||||
*
|
||||
* @return Email
|
||||
*/
|
||||
public function set_wp_mail_args( $args ) {
|
||||
|
||||
$args = wp_parse_args(
|
||||
$args,
|
||||
[
|
||||
'headers' => '',
|
||||
'attachments' => [],
|
||||
]
|
||||
);
|
||||
|
||||
$this->wp_mail_args = $args;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this email's MailCatcher state.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_connection_data() {
|
||||
|
||||
return $this->connection_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this email's connection data.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $data Connection data.
|
||||
*
|
||||
* @return Email
|
||||
*/
|
||||
public function set_connection_data( $data ) {
|
||||
|
||||
$this->connection_data = wp_parse_args(
|
||||
$data,
|
||||
[
|
||||
'from_email' => '',
|
||||
'from_name' => '',
|
||||
]
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this email's MailCatcher state.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_mailer_state() {
|
||||
|
||||
return $this->mailer_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this email's MailCatcher state.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $state MailCatcher state.
|
||||
*
|
||||
* @return Email
|
||||
*/
|
||||
public function set_mailer_state( $state ) {
|
||||
|
||||
$this->mailer_state = wp_parse_args(
|
||||
$state,
|
||||
[
|
||||
'CharSet' => '',
|
||||
'ContentType' => '',
|
||||
'Encoding' => '',
|
||||
'CustomHeader' => '',
|
||||
'Subject' => '',
|
||||
'Body' => '',
|
||||
'AltBody' => '',
|
||||
'ReplyTo' => '',
|
||||
'to' => '',
|
||||
'cc' => '',
|
||||
'bcc' => '',
|
||||
'attachment' => '',
|
||||
]
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this email's WPMailInitiator state.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_initiator_state() {
|
||||
|
||||
return $this->initiator_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this email's WPMailInitiator state.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $state MailCatcher state.
|
||||
*
|
||||
* @return Email
|
||||
*/
|
||||
public function set_initiator_state( $state ) {
|
||||
|
||||
$this->initiator_state = wp_parse_args(
|
||||
$state,
|
||||
[
|
||||
'file' => '',
|
||||
'line' => '',
|
||||
'backtrace' => '',
|
||||
]
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the date and time this email
|
||||
* was enqueued at.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return DateTime
|
||||
*/
|
||||
public function get_date_enqueued() {
|
||||
|
||||
return $this->date_enqueued;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the date and time this email
|
||||
* was enqueued at.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param DateTime $datetime Date and time of enqueueing.
|
||||
*
|
||||
* @return Email
|
||||
*/
|
||||
public function set_date_enqueued( $datetime ) {
|
||||
|
||||
$this->date_enqueued = $this->get_datetime( $datetime );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the date and time this email
|
||||
* was processed at.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return DateTime
|
||||
*/
|
||||
public function get_date_processed() {
|
||||
|
||||
return $this->date_processed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the date and time this email
|
||||
* was processed at.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param DateTime $datetime Date and time of processing.
|
||||
*
|
||||
* @return Email
|
||||
*/
|
||||
public function set_date_processed( $datetime ) {
|
||||
|
||||
$this->date_processed = $this->get_datetime( $datetime );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a database string to a DateTime
|
||||
* object, if necessary.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param string $datetime Date and time.
|
||||
*
|
||||
* @return DateTime
|
||||
*/
|
||||
private function get_datetime( $datetime ) {
|
||||
|
||||
if ( ! is_a( $datetime, DateTime::class ) ) {
|
||||
// Validate the date. Time is ignored.
|
||||
$mm = substr( $datetime, 5, 2 );
|
||||
$jj = substr( $datetime, 8, 2 );
|
||||
$aa = substr( $datetime, 0, 4 );
|
||||
|
||||
$valid_date = wp_checkdate( $mm, $jj, $aa, $datetime );
|
||||
$timezone = new DateTimeZone( 'UTC' );
|
||||
|
||||
if ( $valid_date ) {
|
||||
$datetime = DateTime::createFromFormat( WP::datetime_mysql_format(), $datetime, $timezone );
|
||||
} else {
|
||||
$datetime = new DateTime( 'now', $timezone );
|
||||
}
|
||||
}
|
||||
|
||||
return $datetime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase any potentially sensitive data.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return @return Email
|
||||
*/
|
||||
public function anonymize() {
|
||||
|
||||
$this->initiator_state = null;
|
||||
$this->wp_mail_args = null;
|
||||
$this->connection_data = null;
|
||||
$this->mailer_state = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a new or modified email in DB.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @throws Exception If data can't be encoded,
|
||||
* or a database error occurred.
|
||||
*
|
||||
* @return int New or updated email ID.
|
||||
*/
|
||||
public function save() {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$table = Queue::get_table_name();
|
||||
$data = [
|
||||
'initiator_state' => $this->initiator_state,
|
||||
'wp_mail_args' => $this->wp_mail_args,
|
||||
'connection_data' => $this->connection_data,
|
||||
'mailer_state' => $this->mailer_state,
|
||||
];
|
||||
|
||||
$data = array_filter( $data );
|
||||
|
||||
if ( ! empty( $data ) ) {
|
||||
$data = wp_json_encode(
|
||||
[
|
||||
'initiator_state' => $this->initiator_state,
|
||||
'wp_mail_args' => $this->wp_mail_args,
|
||||
'connection_data' => $this->connection_data,
|
||||
'mailer_state' => $this->mailer_state,
|
||||
]
|
||||
);
|
||||
|
||||
if ( $data === false ) {
|
||||
throw new Exception(
|
||||
sprintf(
|
||||
/* translators: %1$s - JSON error message. */
|
||||
esc_html__( 'Data JSON encoding error: %1$s', 'wp-mail-smtp' ),
|
||||
esc_html( json_last_error_msg() )
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$data = null;
|
||||
}
|
||||
|
||||
if ( (bool) $this->get_id() ) {
|
||||
// Update the existing DB table record.
|
||||
$result = $wpdb->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
|
||||
$table,
|
||||
[
|
||||
'data' => $data,
|
||||
'status' => $this->status,
|
||||
'date_processed' => $this->get_date_processed()->format( WP::datetime_mysql_format() ),
|
||||
],
|
||||
[
|
||||
'id' => $this->get_id(),
|
||||
],
|
||||
[
|
||||
'%s', // data.
|
||||
'%s', // status.
|
||||
'%s', // date_processed.
|
||||
],
|
||||
[
|
||||
'%d',
|
||||
]
|
||||
);
|
||||
|
||||
$email_id = $this->get_id();
|
||||
} else {
|
||||
// Create a new DB table record.
|
||||
$result = $wpdb->insert(
|
||||
$table,
|
||||
[
|
||||
'data' => $data,
|
||||
'status' => $this->status,
|
||||
'date_enqueued' => $this->get_date_enqueued()->format( WP::datetime_mysql_format() ),
|
||||
],
|
||||
[
|
||||
'%s', // data.
|
||||
'%s', // status.
|
||||
'%s', // date_enqueued.
|
||||
]
|
||||
);
|
||||
|
||||
$email_id = $wpdb->insert_id;
|
||||
}
|
||||
|
||||
if ( $result === false ) {
|
||||
throw new Exception(
|
||||
sprintf(
|
||||
/* translators: %1$s - Database error message. */
|
||||
esc_html__( 'Insert/update SQL query error: %1$s', 'wp-mail-smtp' ),
|
||||
esc_html( $wpdb->last_error )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return (int) $email_id;
|
||||
}
|
||||
}
|
||||
87
wp/wp-content/plugins/wp-mail-smtp/src/Queue/Migration.php
Normal file
87
wp/wp-content/plugins/wp-mail-smtp/src/Queue/Migration.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Queue;
|
||||
|
||||
use WPMailSMTP\MigrationAbstract;
|
||||
|
||||
/**
|
||||
* Class Migration.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class Migration extends MigrationAbstract {
|
||||
|
||||
/**
|
||||
* Version of the database table(s) for queue functionality.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
const DB_VERSION = 1;
|
||||
|
||||
/**
|
||||
* Option key where we save the current DB version for queue functionality.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
const OPTION_NAME = 'wp_mail_smtp_queue_db_version';
|
||||
|
||||
/**
|
||||
* Option key where we save any errors while creating the queue DB table.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
const ERROR_OPTION_NAME = 'wp_mail_smtp_queue_db_error';
|
||||
|
||||
/**
|
||||
* Whether the queue is enabled.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_enabled() {
|
||||
|
||||
return wp_mail_smtp()->get_queue()->is_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial migration - create the table structure.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected function migrate_to_1() {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$table = Queue::get_table_name();
|
||||
$collate = ! empty( $wpdb->collate ) ? "COLLATE='{$wpdb->collate}'" : '';
|
||||
|
||||
/*
|
||||
* Create the table.
|
||||
*/
|
||||
$sql = "
|
||||
CREATE TABLE `$table` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`data` LONGTEXT NULL,
|
||||
`status` TINYINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
`date_enqueued` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`date_processed` TIMESTAMP NULL,
|
||||
PRIMARY KEY (id),
|
||||
INDEX status (status),
|
||||
INDEX date_processed (date_processed)
|
||||
)
|
||||
ENGINE='InnoDB'
|
||||
{$collate};";
|
||||
|
||||
$result = $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching
|
||||
|
||||
if ( ! empty( $wpdb->last_error ) ) {
|
||||
update_option( self::ERROR_OPTION_NAME, $wpdb->last_error, false );
|
||||
}
|
||||
|
||||
// Save the current version to DB.
|
||||
if ( $result !== false ) {
|
||||
$this->update_db_ver( 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
760
wp/wp-content/plugins/wp-mail-smtp/src/Queue/Queue.php
Normal file
760
wp/wp-content/plugins/wp-mail-smtp/src/Queue/Queue.php
Normal file
@@ -0,0 +1,760 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Queue;
|
||||
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
use Exception;
|
||||
use WPMailSMTP\Admin\DebugEvents\DebugEvents;
|
||||
use WPMailSMTP\Tasks\Queue\SendEnqueuedEmailTask;
|
||||
use WPMailSMTP\WPMailArgs;
|
||||
use WPMailSMTP\WP;
|
||||
|
||||
/**
|
||||
* Class Queue.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class Queue {
|
||||
|
||||
/**
|
||||
* The email being currently handled.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @var Email
|
||||
*/
|
||||
private $email;
|
||||
|
||||
/**
|
||||
* A list of registered hooks at the time
|
||||
* of email sending.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $registered_wp_mail_hooks = [];
|
||||
|
||||
/**
|
||||
* Whether the queue is currently enabled.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_enabled() {
|
||||
|
||||
/**
|
||||
* Filters whether the queue is currently enabled.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param bool $enabled Whether the queue is currently enabled.
|
||||
*/
|
||||
return apply_filters( 'wp_mail_smtp_queue_is_enabled', false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Short-circuit and handle an ongoing PHPMailer `send` call.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function enqueue_email() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
|
||||
|
||||
if ( ! $this->is_valid_db() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
global $phpmailer;
|
||||
|
||||
$wp_mail_args = wp_mail_smtp()->get_processor()->get_filtered_wp_mail_args();
|
||||
$initiator = wp_mail_smtp()->get_wp_mail_initiator();
|
||||
$processor = wp_mail_smtp()->get_processor();
|
||||
$initiator_state = [
|
||||
'file' => $initiator->get_file(),
|
||||
'line' => $initiator->get_line(),
|
||||
'backtrace' => $initiator->get_backtrace(),
|
||||
];
|
||||
$connection_data = [
|
||||
'from_email' => $processor->get_filtered_from_email(),
|
||||
'from_name' => $processor->get_filtered_from_name(),
|
||||
];
|
||||
|
||||
// Keep a reference to the original attachments,
|
||||
// if something goes wrong while enqueueing the email.
|
||||
$original_attachments = $phpmailer->getAttachments();
|
||||
|
||||
// Obfuscate attachment paths for the enqueued email.
|
||||
$processed_attachments = ( new Attachments() )->process_attachments( $original_attachments );
|
||||
|
||||
// Set obfuscated path attachments.
|
||||
$this->set_attachments( $processed_attachments );
|
||||
|
||||
// Add queued date header in the same format as "Date" header.
|
||||
$phpmailer->addCustomHeader( 'X-WP-Mail-SMTP-Queued', $phpmailer::rfcDate() );
|
||||
|
||||
$email = ( new Email() )
|
||||
->set_wp_mail_args( $wp_mail_args )
|
||||
->set_initiator_state( $initiator_state )
|
||||
->set_connection_data( $connection_data )
|
||||
->set_mailer_state( $phpmailer->get_state() );
|
||||
|
||||
// Add the email to the queue.
|
||||
try {
|
||||
$this->add_email( $email );
|
||||
} catch ( Exception $e ) {
|
||||
// Cleanup any obfuscated path attachments.
|
||||
$this->cleanup_attachments();
|
||||
|
||||
// Reset original attachments.
|
||||
$this->set_attachments( $original_attachments );
|
||||
|
||||
$message = sprintf(
|
||||
/* translators: %1$s - exception message. */
|
||||
esc_html__( '[Emails Queue] Skipped enqueueing email. %1$s.', 'wp-mail-smtp' ),
|
||||
esc_html( $e->getMessage() )
|
||||
);
|
||||
|
||||
DebugEvents::add_debug( $message );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an email. Can only be called
|
||||
* by a running SendEnqueuedEmailTask.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param int|string $email_id Email's ID.
|
||||
*/
|
||||
public function send_email( $email_id ) { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
|
||||
|
||||
// This method can't be called directly.
|
||||
if ( ! doing_action( SendEnqueuedEmailTask::ACTION ) ) {
|
||||
$message = sprintf(
|
||||
/* translators: %1$d - email ID. */
|
||||
esc_html__( '[Emails Queue] Skipped email sending from the queue. Queue::send_email method was called directly. Email ID: %1$d.', 'wp-mail-smtp' ),
|
||||
$email_id
|
||||
);
|
||||
|
||||
DebugEvents::add_debug( $message );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$email = $this->get_email( $email_id );
|
||||
} catch ( Exception $e ) {
|
||||
$this->delete_email( $email_id );
|
||||
|
||||
$message = sprintf(
|
||||
/* translators: %1$s - exception message; %2$s - email ID. */
|
||||
esc_html__( '[Emails Queue] Skipped email sending from the queue. %1$s. Email ID: %2$s', 'wp-mail-smtp' ),
|
||||
esc_html( $e->getMessage() ),
|
||||
$email_id
|
||||
);
|
||||
|
||||
DebugEvents::add_debug( $message );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Bail early if the email still enqueued, or already processed.
|
||||
if ( $email->get_status() !== Email::STATUS_PROCESSING ) {
|
||||
$message = sprintf(
|
||||
/* translators: %1$d - email ID; %2$s - email status. */
|
||||
esc_html__( '[Emails Queue] Skipped email sending from the queue. Wrong email status. Email ID: %1$d, email status: %2$s.', 'wp-mail-smtp' ),
|
||||
$email_id,
|
||||
$email->get_status()
|
||||
);
|
||||
|
||||
DebugEvents::add_debug( $message );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep a reference to the email
|
||||
// being sent so that it's accessible
|
||||
// across hooks.
|
||||
$this->email = $email;
|
||||
|
||||
// Un-hook all user-defined hooks.
|
||||
$this->clear_wp_mail_hooks();
|
||||
|
||||
// Stop enqueueing emails.
|
||||
add_filter( 'wp_mail_smtp_mail_catcher_send_enqueue_email', '__return_false', PHP_INT_MAX );
|
||||
|
||||
// Re-hook Processor functionality, before applying PHPMailer state,
|
||||
// so that From and From Name are correctly filtered.
|
||||
wp_mail_smtp()->get_processor()->hooks();
|
||||
|
||||
// Apply the email's PHPMailer state.
|
||||
add_action( 'phpmailer_init', [ $this, 'apply_mailer_state' ], PHP_INT_MAX );
|
||||
|
||||
// Retrieve original wp_mail arguments.
|
||||
$wp_mail_args = new WPMailArgs( $email->get_wp_mail_args() );
|
||||
|
||||
// Inject user-filtered From and From Name.
|
||||
$wp_mail_headers = $wp_mail_args->get_headers();
|
||||
$wp_mail_headers[] = $this->get_connection_from_header( $email->get_connection_data() );
|
||||
|
||||
// Inject the original initiator state.
|
||||
add_filter( 'wp_mail_smtp_wp_mail_initiator_set_initiator', [ $this, 'apply_initiator_state' ] );
|
||||
|
||||
// Send the email.
|
||||
wp_mail(
|
||||
$wp_mail_args->get_to_email(),
|
||||
$wp_mail_args->get_subject(),
|
||||
$wp_mail_args->get_message(),
|
||||
$wp_mail_headers,
|
||||
$wp_mail_args->get_attachments()
|
||||
);
|
||||
|
||||
// Update the email.
|
||||
try {
|
||||
$this->email->set_status( Email::STATUS_PROCESSED )
|
||||
->set_date_processed( new DateTime( 'now', new DateTimeZone( 'UTC' ) ) )
|
||||
->anonymize()
|
||||
->save();
|
||||
} catch ( Exception $e ) {
|
||||
$this->delete_email( $email_id );
|
||||
|
||||
$message = sprintf(
|
||||
/* translators: %1$s - exception message; %2$d - email ID. */
|
||||
esc_html__( '[Emails Queue] Failed to update queue record after sending email from the queue. %1$s. Email ID: %2$d', 'wp-mail-smtp' ),
|
||||
esc_html( $e->getMessage() ),
|
||||
$email_id
|
||||
);
|
||||
|
||||
DebugEvents::add_debug( $message );
|
||||
}
|
||||
|
||||
// Cleanup any attachments.
|
||||
$this->cleanup_attachments();
|
||||
|
||||
// Stop applying PHPMailer state.
|
||||
remove_action( 'phpmailer_init', [ $this, 'apply_mailer_state' ], PHP_INT_MAX );
|
||||
|
||||
// Clear the email reference.
|
||||
$this->email = null;
|
||||
|
||||
// Re-hook all user-defined hooks.
|
||||
$this->restore_wp_mail_hooks();
|
||||
|
||||
// Start enqueueing emails again.
|
||||
remove_filter( 'wp_mail_smtp_mail_catcher_send_enqueue_email', '__return_false', PHP_INT_MAX );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current email's WPMailInitiator state.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return array WPMailInitiator state.
|
||||
*/
|
||||
public function apply_initiator_state() {
|
||||
|
||||
return $this->email->get_initiator_state();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply state to the current mailer.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param PHPMailer $phpmailer PHPMailer instance.
|
||||
*/
|
||||
public function apply_mailer_state( &$phpmailer ) {
|
||||
|
||||
$phpmailer->set_state( $this->email->get_mailer_state() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the table name.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return string Table name, prefixed.
|
||||
*/
|
||||
public static function get_table_name() {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->prefix . 'wpmailsmtp_emails_queue';
|
||||
}
|
||||
|
||||
/**
|
||||
* Count processing or processed emails since a given date.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param null|DateTime $since_datetime Date to count from, or null for all emails.
|
||||
*
|
||||
* @return int Email count.
|
||||
*/
|
||||
public function count_processed_emails( DateTime $since_datetime = null ) {
|
||||
|
||||
if ( ! $this->is_valid_db() ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$table = self::get_table_name();
|
||||
$where = $wpdb->prepare(
|
||||
'status IN (%d, %d)',
|
||||
Email::STATUS_PROCESSING,
|
||||
Email::STATUS_PROCESSED
|
||||
);
|
||||
|
||||
if ( ! is_null( $since_datetime ) ) {
|
||||
$where .= $wpdb->prepare(
|
||||
' AND date_processed >= %s',
|
||||
$since_datetime->format( WP::datetime_mysql_format() )
|
||||
);
|
||||
}
|
||||
|
||||
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
$count = $wpdb->get_var(
|
||||
"SELECT COUNT(*)
|
||||
FROM $table
|
||||
WHERE $where;"
|
||||
);
|
||||
// phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
|
||||
return (int) $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count queued emails.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return int Email count.
|
||||
*/
|
||||
public function count_queued_emails() {
|
||||
|
||||
if ( ! $this->is_valid_db() ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$table = self::get_table_name();
|
||||
$where = $wpdb->prepare( 'status = %d', Email::STATUS_QUEUED );
|
||||
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
$count = $wpdb->get_var(
|
||||
"SELECT COUNT(*)
|
||||
FROM $table
|
||||
WHERE $where;"
|
||||
);
|
||||
// phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
|
||||
return (int) $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule emails for sending.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function process() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
|
||||
|
||||
if ( ! $this->is_valid_db() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the amount of emails the queue should process.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param int|null $count Amount of emails to process.
|
||||
*/
|
||||
$count = apply_filters( 'wp_mail_smtp_queue_process_count', null );
|
||||
|
||||
// If the queue has been disabled, just process all emails.
|
||||
if ( ! $this->is_enabled() ) {
|
||||
$count = null;
|
||||
}
|
||||
|
||||
$emails = $this->get_emails( $count );
|
||||
$task = new SendEnqueuedEmailTask();
|
||||
|
||||
foreach ( $emails as $email ) {
|
||||
try {
|
||||
$email->set_status( Email::STATUS_PROCESSING )
|
||||
->set_date_processed( new DateTime( 'now', new DateTimeZone( 'UTC' ) ) )
|
||||
->save();
|
||||
} catch ( Exception $e ) {
|
||||
$this->delete_email( $email->get_id() );
|
||||
|
||||
$message = sprintf(
|
||||
/* translators: %1$s - exception message. */
|
||||
esc_html__( '[Emails Queue] Skipped processing enqueued email. %1$s. Email ID: %2$d', 'wp-mail-smtp' ),
|
||||
esc_html( $e->getMessage() ),
|
||||
$email->get_id()
|
||||
);
|
||||
|
||||
DebugEvents::add_debug( $message );
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$task->schedule( $email->get_id() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup emails processed before a given date.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function cleanup() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
|
||||
|
||||
/**
|
||||
* Filters the date before which emails should
|
||||
* be removed from the queue.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param DateTime|null $datetime Date before which to remove emails.
|
||||
*/
|
||||
$datetime = apply_filters( 'wp_mail_smtp_queue_cleanup_before_datetime', null );
|
||||
|
||||
// If the queue has been disabled, just cleanup all emails.
|
||||
if ( ! $this->is_enabled() ) {
|
||||
$datetime = null;
|
||||
}
|
||||
|
||||
$this->delete_emails_before( $datetime );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the DB table exists.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_valid_db() {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
static $is_valid = null;
|
||||
|
||||
// Return cached value only if table already exists.
|
||||
if ( $is_valid === true ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$table = self::get_table_name();
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
|
||||
$is_valid = (bool) $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s;', $table ) );
|
||||
|
||||
return $is_valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current email's attachments.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $attachments List of attachments.
|
||||
*/
|
||||
private function set_attachments( $attachments ) {
|
||||
|
||||
global $phpmailer;
|
||||
|
||||
$phpmailer->clearAttachments();
|
||||
|
||||
foreach ( $attachments as $attachment ) {
|
||||
[ $path, , $name, $encoding, $type, , $disposition ] = $attachment;
|
||||
|
||||
try {
|
||||
$phpmailer->addAttachment( $path, $name, $encoding, $type, $disposition );
|
||||
} catch ( Exception $e ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove email attachments after sending.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
private function cleanup_attachments() {
|
||||
|
||||
global $phpmailer;
|
||||
|
||||
$attachments = $phpmailer->getAttachments();
|
||||
|
||||
( new Attachments() )->delete_attachments( $attachments );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the From/From Name header
|
||||
* from an email's connection data.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $connection_data Email's connection data.
|
||||
*/
|
||||
private function get_connection_from_header( $connection_data ) {
|
||||
|
||||
[
|
||||
'from_email' => $from_email,
|
||||
'from_name' => $from_name
|
||||
] = $connection_data;
|
||||
|
||||
$from = (
|
||||
$from_name === '' ?
|
||||
$from_email :
|
||||
sprintf( '%1s <%2s>', $from_name, $from_email )
|
||||
);
|
||||
|
||||
$from_header = sprintf(
|
||||
'From:%s',
|
||||
$from
|
||||
);
|
||||
|
||||
return $from_header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of the `wp_mail` related hooks
|
||||
* that should be de-registered before sending
|
||||
* an enqueued email.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return array List of hooks.
|
||||
*/
|
||||
private function get_wp_mail_hooks() {
|
||||
|
||||
return [
|
||||
'wp_mail',
|
||||
'pre_wp_mail',
|
||||
'wp_mail_from',
|
||||
'wp_mail_from_name',
|
||||
'wp_mail_succeeded',
|
||||
'wp_mail_failed',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear any user-defined `wp_mail` related hooks
|
||||
* before sending an enqueued email.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
private function clear_wp_mail_hooks() {
|
||||
|
||||
global $wp_filter;
|
||||
|
||||
$wp_mail_hooks = array_intersect_key(
|
||||
$wp_filter,
|
||||
array_flip( $this->get_wp_mail_hooks() )
|
||||
);
|
||||
|
||||
foreach ( $wp_mail_hooks as $hook_name => $hook ) {
|
||||
foreach ( $hook->callbacks as $priority => $callbacks ) {
|
||||
foreach ( $callbacks as $callback ) {
|
||||
$this->registered_wp_mail_hooks[] = [
|
||||
$hook_name,
|
||||
$callback['function'],
|
||||
$priority,
|
||||
$callback['accepted_args'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
remove_all_filters( $hook_name );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-register any previous de-registered `wp_mail` related hooks
|
||||
* after sending an enqueued email.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
private function restore_wp_mail_hooks() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
|
||||
|
||||
foreach ( $this->registered_wp_mail_hooks as $hook ) {
|
||||
list( $hook_name, $callback, $priority, $accepted_args ) = $hook;
|
||||
|
||||
add_filter( $hook_name, $callback, $priority, $accepted_args );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an email to the queue.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @throws Exception When email couldn't be saved.
|
||||
*
|
||||
* @param Email $email The email to enqueue.
|
||||
*/
|
||||
private function add_email( Email $email ) {
|
||||
|
||||
if ( ! $this->is_valid_db() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$email->set_date_enqueued( new DateTime( 'now', new DateTimeZone( 'UTC' ) ) )
|
||||
->set_status( Email::STATUS_QUEUED )
|
||||
->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an email.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param int|string $email_id The email's ID.
|
||||
*
|
||||
* @return null|Email The email, or null if not found.
|
||||
*/
|
||||
private function get_email( $email_id ) {
|
||||
|
||||
if ( ! $this->is_valid_db() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$table = self::get_table_name();
|
||||
$where = $wpdb->prepare( 'ID = %d', (int) $email_id );
|
||||
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
$data = $wpdb->get_row( "SELECT * FROM $table WHERE $where" );
|
||||
// phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
|
||||
$email = Email::from_data( $data );
|
||||
|
||||
return $email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get queued emails from the queue.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param null|int $count Amount of emails to return, or null for all emails.
|
||||
*
|
||||
* @return Email[] Array of emails.
|
||||
*/
|
||||
private function get_emails( $count = null ) {
|
||||
|
||||
if ( ! $this->is_valid_db() ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$table = self::get_table_name();
|
||||
$where = $wpdb->prepare( 'status = %d', Email::STATUS_QUEUED );
|
||||
$limit = '';
|
||||
|
||||
if ( ! is_null( $count ) ) {
|
||||
$limit = $wpdb->prepare(
|
||||
'LIMIT 0, %d',
|
||||
max( 0, intval( $count ) )
|
||||
);
|
||||
}
|
||||
|
||||
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
$data = $wpdb->get_results(
|
||||
"SELECT *
|
||||
FROM $table
|
||||
WHERE $where
|
||||
ORDER BY date_enqueued ASC
|
||||
$limit;"
|
||||
);
|
||||
// phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
|
||||
$emails = [];
|
||||
|
||||
foreach ( $data as $row ) {
|
||||
try {
|
||||
$emails[] = Email::from_data( $row );
|
||||
} catch ( Exception $e ) {
|
||||
$this->delete_email( $row->id );
|
||||
|
||||
$message = sprintf(
|
||||
/* translators: %1$s - exception message. */
|
||||
esc_html__( '[Emails Queue] Skipped processing enqueued email. %1$s. Email ID: %2$d', 'wp-mail-smtp' ),
|
||||
esc_html( $e->getMessage() ),
|
||||
$row->id
|
||||
);
|
||||
|
||||
DebugEvents::add_debug( $message );
|
||||
}
|
||||
}
|
||||
|
||||
return $emails;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete emails processed before a given date.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param DateTime|null $before_datetime Date before which to remove emails, or null for all emails.
|
||||
*/
|
||||
private function delete_emails_before( $before_datetime ) {
|
||||
|
||||
if ( ! $this->is_valid_db() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$table = self::get_table_name();
|
||||
$where = $wpdb->prepare( 'status = %d', Email::STATUS_PROCESSED );
|
||||
|
||||
if ( is_a( $before_datetime, DateTime::class ) ) {
|
||||
$where .= $wpdb->prepare(
|
||||
' AND date_processed < %s',
|
||||
$before_datetime->format( WP::datetime_mysql_format() )
|
||||
);
|
||||
}
|
||||
|
||||
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
$wpdb->query( "DELETE FROM $table WHERE $where" );
|
||||
// phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an email.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param int $email_id ID of the email.
|
||||
*/
|
||||
private function delete_email( $email_id ) {
|
||||
|
||||
if ( ! $this->is_valid_db() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$table = self::get_table_name();
|
||||
|
||||
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
$wpdb->query(
|
||||
$wpdb->prepare( "DELETE FROM $table WHERE ID = %d", $email_id )
|
||||
);
|
||||
// phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Tasks\Queue;
|
||||
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
use WPMailSMTP\Queue\Attachments;
|
||||
use WPMailSMTP\Tasks\Task;
|
||||
use WPMailSMTP\Tasks\Tasks;
|
||||
|
||||
/**
|
||||
* Class CleanupQueueTask.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class CleanupQueueTask extends Task {
|
||||
|
||||
/**
|
||||
* Action name for this task.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
const ACTION = 'wp_mail_smtp_queue_cleanup';
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
parent::__construct( self::ACTION );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the task.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function init() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
|
||||
|
||||
// Register the action handler.
|
||||
add_action( self::ACTION, [ $this, 'process' ] );
|
||||
|
||||
// Exit if this task the queue is disabled, or it's already scheduled.
|
||||
if (
|
||||
! wp_mail_smtp()->get_queue()->is_enabled() ||
|
||||
Tasks::is_scheduled( self::ACTION ) !== false
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Schedule the task.
|
||||
$this->recurring( strtotime( 'now' ), DAY_IN_SECONDS )
|
||||
->unique()
|
||||
->register();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform email sending.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function process() {
|
||||
|
||||
$queue = wp_mail_smtp()->get_queue();
|
||||
$attachments = new Attachments();
|
||||
|
||||
// Cleanup processed emails.
|
||||
$queue->cleanup();
|
||||
|
||||
// Cleanup older-than-a-month attachments.
|
||||
$attachments->delete_attachments( null, new DateTime( '1 month ago', new DateTimeZone( 'UTC' ) ) );
|
||||
|
||||
if ( ! $queue->is_enabled() ) {
|
||||
// If the query has been disabled in the meanwhile,
|
||||
// and there aren't any emails left,
|
||||
// cancel the cleanup task.
|
||||
$queued_emails_count = $queue->count_queued_emails();
|
||||
$processed_emails_count = $queue->count_processed_emails();
|
||||
|
||||
if ( $queued_emails_count === 0 && $processed_emails_count === 0 ) {
|
||||
// Cleanup any remaining, older-than-an-hour attachments.
|
||||
$attachments->delete_attachments( null, new DateTime( '1 hour ago', new DateTimeZone( 'UTC' ) ) );
|
||||
|
||||
$this->cancel_force();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Tasks\Queue;
|
||||
|
||||
use WPMailSMTP\Tasks\Task;
|
||||
use WPMailSMTP\Tasks\Tasks;
|
||||
|
||||
/**
|
||||
* Class ProcessQueueTask.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class ProcessQueueTask extends Task {
|
||||
|
||||
/**
|
||||
* Action name for this task.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
const ACTION = 'wp_mail_smtp_queue_process';
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
parent::__construct( self::ACTION );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the task.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function init() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
|
||||
|
||||
// Register the action handler.
|
||||
add_action( self::ACTION, [ $this, 'process' ] );
|
||||
|
||||
// Exit if this task the queue is disabled, or it's already scheduled.
|
||||
if (
|
||||
! wp_mail_smtp()->get_queue()->is_enabled() ||
|
||||
Tasks::is_scheduled( self::ACTION ) !== false
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Schedule the task.
|
||||
$this->recurring( strtotime( 'now' ), MINUTE_IN_SECONDS )
|
||||
->unique()
|
||||
->register();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform email sending.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function process() {
|
||||
|
||||
$queue = wp_mail_smtp()->get_queue();
|
||||
|
||||
$queue->process();
|
||||
|
||||
if ( ! $queue->is_enabled() ) {
|
||||
$this->cancel_force();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP\Tasks\Queue;
|
||||
|
||||
use WPMailSMTP\Tasks\Meta;
|
||||
use WPMailSMTP\Tasks\Task;
|
||||
|
||||
/**
|
||||
* Class SendEnqueuedEmailTask.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class SendEnqueuedEmailTask extends Task {
|
||||
|
||||
/**
|
||||
* Action name for this task.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
const ACTION = 'wp_mail_smtp_send_enqueued_email';
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
parent::__construct( self::ACTION );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the task.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function init() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
|
||||
|
||||
// Register the action handler.
|
||||
add_action( self::ACTION, [ $this, 'process' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule email sending.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param int $email_id Email id.
|
||||
*/
|
||||
public function schedule( $email_id ) {
|
||||
|
||||
// Exit if AS function does not exist.
|
||||
if ( ! function_exists( 'as_has_scheduled_action' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Schedule the task.
|
||||
$this->async()
|
||||
->params( $email_id )
|
||||
->register();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform email sending.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param int $meta_id The Meta ID with the stored task parameters.
|
||||
*/
|
||||
public function process( $meta_id ) {
|
||||
|
||||
$task_meta = new Meta();
|
||||
$meta = $task_meta->get( (int) $meta_id );
|
||||
|
||||
// We should actually receive the passed parameter.
|
||||
if ( empty( $meta ) || empty( $meta->data ) || count( $meta->data ) < 1 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$email_id = $meta->data[0];
|
||||
|
||||
wp_mail_smtp()->get_queue()->send_email( $email_id );
|
||||
}
|
||||
}
|
||||
@@ -86,6 +86,15 @@ class Task {
|
||||
*/
|
||||
private $interval;
|
||||
|
||||
/**
|
||||
* Whether this task is unique.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $unique = false;
|
||||
|
||||
/**
|
||||
* Task constructor.
|
||||
*
|
||||
@@ -159,6 +168,20 @@ class Task {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this task as unique.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return Task
|
||||
*/
|
||||
public function unique() {
|
||||
|
||||
$this->unique = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass any number of params that should be saved to Meta table.
|
||||
*
|
||||
@@ -249,7 +272,8 @@ class Task {
|
||||
return as_enqueue_async_action(
|
||||
$this->action,
|
||||
[ $this->meta_id ],
|
||||
Tasks::GROUP
|
||||
Tasks::GROUP,
|
||||
$this->unique
|
||||
);
|
||||
}
|
||||
|
||||
@@ -271,7 +295,8 @@ class Task {
|
||||
$this->interval,
|
||||
$this->action,
|
||||
[ $this->meta_id ],
|
||||
Tasks::GROUP
|
||||
Tasks::GROUP,
|
||||
$this->unique
|
||||
);
|
||||
}
|
||||
|
||||
@@ -292,7 +317,8 @@ class Task {
|
||||
$this->timestamp,
|
||||
$this->action,
|
||||
[ $this->meta_id ],
|
||||
Tasks::GROUP
|
||||
Tasks::GROUP,
|
||||
$this->unique
|
||||
);
|
||||
}
|
||||
|
||||
@@ -316,4 +342,15 @@ class Task {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel all occurrences of this task,
|
||||
* preventing it from re-registering itself.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function cancel_force() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
|
||||
|
||||
add_action( 'shutdown', [ $this, 'cancel' ], PHP_INT_MAX );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@ namespace WPMailSMTP\Tasks;
|
||||
use ActionScheduler_Action;
|
||||
use ActionScheduler_DataController;
|
||||
use ActionScheduler_DBStore;
|
||||
use WPMailSMTP\Tasks\Queue\CleanupQueueTask;
|
||||
use WPMailSMTP\Tasks\Queue\ProcessQueueTask;
|
||||
use WPMailSMTP\Tasks\Queue\SendEnqueuedEmailTask;
|
||||
use WPMailSMTP\Tasks\Reports\SummaryEmailTask;
|
||||
|
||||
/**
|
||||
@@ -77,6 +80,9 @@ class Tasks {
|
||||
$tasks = [
|
||||
SummaryEmailTask::class,
|
||||
DebugEventsCleanupTask::class,
|
||||
ProcessQueueTask::class,
|
||||
CleanupQueueTask::class,
|
||||
SendEnqueuedEmailTask::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,7 +15,14 @@ class Upgrade {
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public function __construct() {
|
||||
public function __construct() {}
|
||||
|
||||
/**
|
||||
* Run upgrades.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function run() {
|
||||
|
||||
$upgrades = $this->upgrades();
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use WPMailSMTP\Admin\SetupWizard;
|
||||
use WPMailSMTP\Conflicts;
|
||||
use WPMailSMTP\Debug;
|
||||
use WPMailSMTP\Helpers\Helpers;
|
||||
use WPMailSMTP\OptimizedEmailSending;
|
||||
use WPMailSMTP\Options;
|
||||
use WPMailSMTP\WP;
|
||||
|
||||
@@ -144,6 +145,7 @@ class UsageTracking {
|
||||
'wp_mail_smtp_setup_wizard_completed_time' => isset( $setup_wizard_stats['completed_time'] ) ? (int) $setup_wizard_stats['completed_time'] : 0,
|
||||
'wp_mail_smtp_setup_wizard_completed_successfully' => ! empty( $setup_wizard_stats['was_successful'] ),
|
||||
'wp_mail_smtp_source' => sanitize_title( get_option( 'wp_mail_smtp_source', '' ) ),
|
||||
'wp_mail_smtp_optimize_email_sending' => (bool) OptimizedEmailSending::is_enabled(),
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
252
wp/wp-content/plugins/wp-mail-smtp/src/WPMailArgs.php
Normal file
252
wp/wp-content/plugins/wp-mail-smtp/src/WPMailArgs.php
Normal file
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
|
||||
namespace WPMailSMTP;
|
||||
|
||||
/**
|
||||
* Class WPMailArgs. This class responsible for `wp_mail` function arguments parsing.
|
||||
*
|
||||
* Parsing algorithms copied from `wp_mail` function.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*/
|
||||
class WPMailArgs {
|
||||
|
||||
/**
|
||||
* Array of the `wp_mail` function arguments.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $args;
|
||||
|
||||
/**
|
||||
* Parsed headers.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $headers = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*
|
||||
* @param array $args {
|
||||
* Array of the `wp_mail` function arguments.
|
||||
*
|
||||
* @type string|string[] $to Array or comma-separated list of email addresses to send message.
|
||||
* @type string $subject Email subject.
|
||||
* @type string $message Message contents.
|
||||
* @type string|string[] $headers Additional headers.
|
||||
* @type string|string[] $attachments Paths to files to attach.
|
||||
* }
|
||||
*/
|
||||
public function __construct( $args ) {
|
||||
|
||||
$this->args = $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get arguments.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_args() {
|
||||
|
||||
return $this->args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get to email.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_to_email() {
|
||||
|
||||
return $this->get_arg( 'to' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get subject.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_subject() {
|
||||
|
||||
return $this->get_arg( 'subject' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get message.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_message() {
|
||||
|
||||
return $this->get_arg( 'message' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get from email.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_from_email() {
|
||||
|
||||
$from = $this->get_from();
|
||||
|
||||
return $from['email'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get from name.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_from_name() {
|
||||
|
||||
$from = $this->get_from();
|
||||
|
||||
return $from['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parsed headers.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_headers() { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||
|
||||
if ( ! is_null( $this->headers ) ) {
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
$this->headers = [];
|
||||
|
||||
if ( ! empty( $this->args['headers'] ) ) {
|
||||
if ( ! is_array( $this->args['headers'] ) ) {
|
||||
$headers = explode( "\n", str_replace( "\r\n", "\n", $this->args['headers'] ) );
|
||||
} else {
|
||||
$headers = $this->args['headers'];
|
||||
}
|
||||
|
||||
foreach ( (array) $headers as $header ) {
|
||||
if ( strpos( $header, ':' ) === false ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list( $name, $content ) = array_map( 'trim', explode( ':', trim( $header ), 2 ) );
|
||||
|
||||
$name = strtolower( $name );
|
||||
|
||||
if ( isset( $this->headers[ $name ] ) && in_array( $name, [ 'cc', 'bcc', 'reply-to' ], true ) ) {
|
||||
$this->headers[ $name ] .= ', ' . $content;
|
||||
} else {
|
||||
$this->headers[ $name ] = $content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get particular header value.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*
|
||||
* @param string $name Header name.
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_header( $name ) {
|
||||
|
||||
$name = strtolower( $name );
|
||||
$headers = $this->get_headers();
|
||||
|
||||
return isset( $headers[ $name ] ) ? $headers[ $name ] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get argument value.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*
|
||||
* @param string $key Argument key.
|
||||
* @param mixed $default Default value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_arg( $key, $default = '' ) {
|
||||
|
||||
return isset( $this->args[ $key ] ) ? $this->args[ $key ] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get from address.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_from() {
|
||||
|
||||
$from_email = '';
|
||||
$from_name = '';
|
||||
$value = $this->get_header( 'from' );
|
||||
$value = is_null( $value ) ? '' : $value;
|
||||
|
||||
$bracket_pos = strpos( $value, '<' );
|
||||
|
||||
if ( $bracket_pos !== false ) {
|
||||
// Text before the bracketed email is the "From" name.
|
||||
if ( $bracket_pos > 0 ) {
|
||||
$from_name = substr( $value, 0, $bracket_pos - 1 );
|
||||
$from_name = str_replace( '"', '', $from_name );
|
||||
$from_name = trim( $from_name );
|
||||
}
|
||||
|
||||
$from_email = substr( $value, $bracket_pos + 1 );
|
||||
$from_email = str_replace( '>', '', $from_email );
|
||||
$from_email = trim( $from_email );
|
||||
|
||||
// Avoid setting an empty $from_email.
|
||||
} elseif ( trim( $value ) !== '' ) {
|
||||
$from_email = trim( $value );
|
||||
}
|
||||
|
||||
return [
|
||||
'email' => $from_email,
|
||||
'name' => $from_name,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attachments.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_attachments() {
|
||||
|
||||
return $this->get_arg( 'attachments', [] );
|
||||
}
|
||||
}
|
||||
@@ -79,15 +79,18 @@ class WPMailInitiator {
|
||||
*/
|
||||
public function hooks() {
|
||||
|
||||
// Initialize initiator data.
|
||||
add_filter(
|
||||
'wp_mail',
|
||||
function ( $args ) {
|
||||
$this->set_initiator();
|
||||
// Capture `wp_mail` function call.
|
||||
add_action( 'wp_mail_smtp_processor_capture_wp_mail_call', [ $this, 'capture_wp_mail_call' ], 0 );
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
);
|
||||
/**
|
||||
* Capture `wp_mail` function call.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function capture_wp_mail_call() {
|
||||
|
||||
$this->set_initiator();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,6 +183,15 @@ class WPMailInitiator {
|
||||
|
||||
$backtrace = $this->get_wpmail_backtrace();
|
||||
|
||||
/**
|
||||
* Filter the `wp_mail` function initiator data.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param array $backtrace Backtrace data.
|
||||
*/
|
||||
$backtrace = apply_filters( 'wp_mail_smtp_wp_mail_initiator_set_initiator', $backtrace );
|
||||
|
||||
if ( empty( $backtrace['file'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user