updated plugin WP Mail SMTP version 2.1.1

This commit is contained in:
2020-06-20 17:12:03 +00:00
committed by Gitium
parent 04443ddae8
commit 12dae937d6
193 changed files with 20688 additions and 1869 deletions

View File

@ -13,20 +13,26 @@ use WPMailSMTP\Options;
class Area {
/**
* Slug of the admin area page.
*
* @since 1.0.0
*
* @var string Slug of the admin area page.
* @var string
*/
const SLUG = 'wp-mail-smtp';
/**
* Admin page unique hook.
*
* @since 1.0.0
*
* @var string Admin page unique hook.
* @var string
*/
public $hook;
/**
* List of admin area pages.
*
* @since 1.0.0
*
* @var PageAbstract[]
@ -34,11 +40,13 @@ class Area {
private $pages;
/**
* List of official registered pages.
*
* @since 1.5.0
*
* @var array List of official registered pages.
* @var array
*/
public static $pages_registered = array( 'general', 'logs', 'about' );
public static $pages_registered = [ 'general', 'logs', 'about' ];
/**
* Area constructor.
@ -46,6 +54,7 @@ class Area {
* @since 1.0.0
*/
public function __construct() {
$this->hooks();
}
@ -57,34 +66,39 @@ class Area {
protected function hooks() {
// Add the Settings link to a plugin on Plugins page.
add_filter( 'plugin_action_links_' . plugin_basename( WPMS_PLUGIN_FILE ), array( $this, 'add_plugin_action_link' ), 10, 1 );
add_filter( 'plugin_action_links_' . plugin_basename( WPMS_PLUGIN_FILE ), [ $this, 'add_plugin_action_link' ], 10, 1 );
// Add the options page.
add_action( 'admin_menu', array( $this, 'add_admin_options_page' ) );
add_action( 'admin_menu', [ $this, 'add_admin_options_page' ] );
// Register on load Email Log admin menu hook.
add_action( 'load-wp-mail-smtp_page_wp-mail-smtp-logs', [ $this, 'maybe_redirect_email_log_menu_to_email_log_settings_tab' ] );
// Admin footer text.
add_filter( 'admin_footer_text', array( $this, 'get_admin_footer' ), 1, 2 );
add_filter( 'admin_footer_text', [ $this, 'get_admin_footer' ], 1, 2 );
// Enqueue admin area scripts and styles.
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
// Process the admin page forms actions.
add_action( 'admin_init', array( $this, 'process_actions' ) );
add_action( 'admin_init', [ $this, 'process_actions' ] );
// Display custom notices based on the error/success codes.
add_action( 'admin_init', array( $this, 'display_custom_auth_notices' ) );
add_action( 'admin_init', [ $this, 'display_custom_auth_notices' ] );
// Display notice instructing the user to complete plugin setup.
add_action( 'admin_init', array( $this, 'display_setup_notice' ) );
add_action( 'admin_init', [ $this, 'display_setup_notice' ] );
// Outputs the plugin admin header.
add_action( 'in_admin_header', array( $this, 'display_admin_header' ), 100 );
add_action( 'in_admin_header', [ $this, 'display_admin_header' ], 100 );
// Hide all unrelated to the plugin notices on the plugin admin pages.
add_action( 'admin_print_scripts', array( $this, 'hide_unrelated_notices' ) );
add_action( 'admin_print_scripts', [ $this, 'hide_unrelated_notices' ] );
// Process all AJAX requests.
add_action( 'wp_ajax_wp_mail_smtp_ajax', array( $this, 'process_ajax' ) );
add_action( 'wp_ajax_wp_mail_smtp_ajax', [ $this, 'process_ajax' ] );
( new Review() )->hooks();
}
/**
@ -107,8 +121,7 @@ class Area {
switch ( $error ) {
case 'google_access_denied':
WP::add_admin_notice(
/* translators: %s - error code, returned by Google API. */
WP::add_admin_notice( /* translators: %s - error code, returned by Google API. */
sprintf( esc_html__( 'There was an error while processing the authentication request: %s. Please try again.', 'wp-mail-smtp' ), '<code>' . $error . '</code>' ),
WP::ADMIN_NOTICE_ERROR
);
@ -169,15 +182,14 @@ class Area {
// Display notice informing user further action is needed.
WP::add_admin_notice(
sprintf(
wp_kses(
/* translators: %s - Mailer anchor link. */
wp_kses( /* translators: %s - Mailer anchor link. */
__( 'Thanks for using WP Mail SMTP! To complete the plugin setup and start sending emails, <strong>please select and configure your <a href="%s">Mailer</a></strong>.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
),
'strong' => array(),
)
[
'a' => [
'href' => [],
],
'strong' => [],
]
),
wp_mail_smtp()->get_admin()->get_admin_page_url( self::SLUG . '#wp-mail-smtp-setting-row-mailer' )
),
@ -232,6 +244,26 @@ class Area {
}
}
/**
* Redirect the "Email Log" WP menu link to the "Email Log" setting tab for lite version of the plugin.
*
* @since 2.1.0
*/
public function maybe_redirect_email_log_menu_to_email_log_settings_tab() {
/**
* The Email Logs object to be used for loading the Email Log page.
*
* @var \WPMailSMTP\Admin\PageAbstract $logs
*/
$logs = $this->generate_display_logs_object();
if ( $logs instanceof \WPMailSMTP\Admin\Pages\Logs ) {
wp_safe_redirect( $logs->get_link() );
exit;
}
}
/**
* Enqueue admin area scripts and styles.
*
@ -269,6 +301,19 @@ class Area {
array(
'text_provider_remove' => esc_html__( 'Are you sure you want to reset the current provider connection? You will need to immediately create a new one to be able to send emails.', 'wp-mail-smtp' ),
'text_settings_not_saved' => esc_html__( 'Changes that you made to the settings are not saved!', 'wp-mail-smtp' ),
'default_mailer_notice' => array(
'title' => esc_html__( 'Heads up!', 'wp-mail-smtp' ),
'content' => wp_kses(
__( '<p>The Default (PHP) mailer is currently selected, but is not recommended because in most cases it does not resolve email delivery issues.</p><p>Please consider selecting and configuring one of the other mailers.</p>', 'wp-mail-smtp' ),
array(
'p' => true,
)
),
'save_button' => esc_html__( 'Save Settings', 'wp-mail-smtp' ),
'cancel_button' => esc_html__( 'Cancel', 'wp-mail-smtp' ),
'icon_alt' => esc_html__( 'Warning icon', 'wp-mail-smtp' ),
),
'plugin_url' => wp_mail_smtp()->plugin_url,
'education' => array(
'upgrade_icon_lock' => '<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="lock" class="svg-inline--fa fa-lock fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M400 224h-24v-72C376 68.2 307.8 0 224 0S72 68.2 72 152v72H48c-26.5 0-48 21.5-48 48v192c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V272c0-26.5-21.5-48-48-48zm-104 0H152v-72c0-39.7 32.3-72 72-72s72 32.3 72 72v72z"></path></svg>',
'upgrade_title' => esc_html__( '%name% is a PRO Feature', 'wp-mail-smtp' ),
@ -469,9 +514,12 @@ class Area {
break;
case self::SLUG . '-logs':
$logs_class = apply_filters( 'wp_mail_smtp_admin_display_get_logs_fqcn', '\WPMailSMTP\Admin\Pages\Logs' );
/** @var \WPMailSMTP\Admin\PageAbstract $logs */
$logs = new $logs_class();
/**
* The Email Logs object to be used for loading the Email Log page.
*
* @var \WPMailSMTP\Admin\PageAbstract $logs
*/
$logs = $this->generate_display_logs_object();
$is_archive = wp_mail_smtp()->is_pro() && wp_mail_smtp()->pro->get_logs()->is_archive();
?>
@ -500,6 +548,20 @@ class Area {
<?php
}
/**
* Generate the appropriate Email Log page object used for displaying the Email Log page.
*
* @since 2.1.0
*
* @return \WPMailSMTP\Admin\PageAbstract
*/
public function generate_display_logs_object() {
$logs_class = apply_filters( 'wp_mail_smtp_admin_display_get_logs_fqcn', \WPMailSMTP\Admin\Pages\Logs::class );
return new $logs_class();
}
/**
* Display General page tabs.
*

View File

@ -1,124 +1,137 @@
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\PageAbstract;
/**
* Class ControlTab is a placeholder for Pro Email Control tab settings.
* Displays an upsell.
*
* @since 1.6.0
*/
class ControlTab extends PageAbstract {
/**
* @since 1.6.0
*
* @var string Slug of a tab.
*/
protected $slug = 'control';
/**
* @inheritdoc
*/
public function get_label() {
return esc_html__( 'Email Controls', 'wp-mail-smtp' );
}
/**
* @inheritdoc
*/
public function get_title() {
return $this->get_label();
}
/**
* @inheritdoc
*/
public function display() {
$features = array(
array(
'image' => 'comments.png',
'title' => esc_html__( 'Comment Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Manage emails sent when comments are published or awaiting moderation.', 'wp-mail-smtp' ),
),
array(
'image' => 'admin.png',
'title' => esc_html__( 'Site Admin Email Change Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Manage emails sent when site admin\'s account has been changed.', 'wp-mail-smtp' ),
),
array(
'image' => 'users.png',
'title' => esc_html__( 'User Change Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Limit emails triggered by password changed/reset, email changed, and more.', 'wp-mail-smtp' ),
),
array(
'image' => 'personal.png',
'title' => esc_html__( 'Personal Data Requests Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Control emails for data requests and data removal actions.', 'wp-mail-smtp' ),
),
array(
'image' => 'update.png',
'title' => esc_html__( 'Automatic Update Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Manage emails sent by the core automatic update process.', 'wp-mail-smtp' ),
),
array(
'image' => 'user_new.png',
'title' => esc_html__( 'New User Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Toggle emails sent to both user and site administrator about new user accounts.', 'wp-mail-smtp' ),
),
)
?>
<div class="wp-mail-smtp-page-upsell">
<h2><?php esc_html_e( 'Unlock Email Controls', 'wp-mail-smtp' ); ?></h2>
<h3>
<?php esc_html_e( 'Email Controls allows you to granularly manage emails sent by WordPress.', 'wp-mail-smtp' ); ?>
</h3>
<div class="wp-mail-smtp-page-upsell-content">
<div class="wp-mail-smtp-page-upsell-features">
<?php foreach ( $features as $feature ) : ?>
<div class="wp-mail-smtp-page-upsell-feature">
<div class="wp-mail-smtp-page-upsell-feature-image">
<img src="<?php echo esc_url( wp_mail_smtp()->assets_url . '/images/control/' . $feature['image'] ); ?>" alt="">
</div>
<div class="wp-mail-smtp-page-upsell-feature-content">
<h4><?php echo esc_html( $feature['title'] ); ?></h4>
<p><?php echo esc_html( $feature['desc'] ); ?></p>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="wp-mail-smtp-page-upsell-button">
<a href="https://wpmailsmtp.com/lite-upgrade/?discount=LITEUPGRADE&amp;utm_source=WordPress&amp;utm_medium=logs&amp;utm_campaign=liteplugin"
class="wp-mail-smtp-btn wp-mail-smtp-btn-lg wp-mail-smtp-btn-orange" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'Upgrade to WP Mail SMTP Pro', 'wp-mail-smtp' ); ?>
</a>
</div>
</div>
<?php
}
/**
* Not used as we display an upsell.
*
* @since 1.6.0
*
* @param array $data
*/
public function process_post( $data ) {
}
}
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\PageAbstract;
/**
* Class ControlTab is a placeholder for Pro Email Control tab settings.
* Displays an upsell.
*
* @since 1.6.0
*/
class ControlTab extends PageAbstract {
/**
* @since 1.6.0
*
* @var string Slug of a tab.
*/
protected $slug = 'control';
/**
* @inheritdoc
*/
public function get_label() {
return esc_html__( 'Email Controls', 'wp-mail-smtp' );
}
/**
* @inheritdoc
*/
public function get_title() {
return $this->get_label();
}
/**
* {@inheritdoc}
*
* @since 2.1.0 Replaced images with SVGs.
*/
public function display() {
$features = [
[
'svg' => '<svg xmlns="http://www.w3.org/2000/svg" focusable="false" viewBox="0 0 64 64"><path class="st0" d="M39.1,35.5H18l-9.2,6.9c-0.5,0.4-1.2,0.3-1.5-0.2c-0.1-0.2-0.2-0.4-0.2-0.6v-6c-3.9,0-7.1-3.2-7.1-7.1V10.7c0-3.9,3.2-7.1,7.1-7.1h32c3.9,0,7.1,3.2,7.1,7.1v17.8C46.2,32.4,43,35.5,39.1,35.5C39.1,35.5,39.1,35.5,39.1,35.5z"/><path class="st1" d="M64,28.4v17.8c0,3.9-3.2,7.1-7.1,7.1h-3.6v6c0,0.6-0.5,1.1-1.1,1.1c-0.2,0-0.5-0.1-0.6-0.2l-9.2-6.9h-14c-3.9,0-7.1-3.2-7.1-7.1v-7.1h17.8c5.9,0,10.7-4.8,10.7-10.7v-7.1h7.1C60.8,21.3,64,24.5,64,28.4z"/></svg>',
'title' => esc_html__( 'Comment Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Manage emails sent when comments are published or awaiting moderation.', 'wp-mail-smtp' ),
],
[
'svg' => '<svg xmlns="http://www.w3.org/2000/svg" focusable="false" viewBox="0 0 64 64"><path class="st0" d="M63.6 45.2l-2.6-1.5c0.3-1.4 0.3-2.9 0-4.3l2.6-1.5c0.3-0.2 0.4-0.5 0.3-0.9 -0.7-2.1-1.8-4.1-3.3-5.7 -0.2-0.3-0.6-0.3-0.9-0.1l-2.6 1.5c-1.1-0.9-2.3-1.7-3.7-2.1v-3c0-0.3-0.2-0.6-0.6-0.7 -2.2-0.5-4.4-0.5-6.6 0 -0.3 0.1-0.6 0.4-0.6 0.7v3c-1.4 0.5-2.6 1.2-3.7 2.1l-2.6-1.5c-0.3-0.2-0.7-0.1-0.9 0.1C37 33 35.9 35 35.2 37.1c-0.1 0.3 0 0.7 0.3 0.9l2.6 1.5c-0.3 1.4-0.3 2.9 0 4.3l-2.6 1.5c-0.3 0.2-0.4 0.5-0.3 0.9 0.7 2.1 1.8 4.1 3.3 5.7 0.2 0.3 0.6 0.3 0.9 0.1l2.6-1.5c1.1 0.9 2.3 1.7 3.7 2.1v3c0 0.3 0.2 0.6 0.6 0.7 2.2 0.5 4.4 0.5 6.6 0 0.3-0.1 0.6-0.4 0.6-0.7v-3c1.4-0.5 2.6-1.2 3.7-2.1l2.6 1.5c0.3 0.2 0.7 0.1 0.9-0.1 1.5-1.6 2.7-3.6 3.3-5.7C64.1 45.7 63.9 45.4 63.6 45.2zM49.6 46.5c-2.7 0-4.9-2.2-4.9-4.9s2.2-4.9 4.9-4.9c2.7 0 4.9 2.2 4.9 4.9S52.3 46.5 49.6 46.5z"/><path class="st1" d="M42.5 55.6v-0.9c-0.2-0.1-0.5-0.3-0.7-0.4l-0.8 0.5c-1.6 0.9-3.6 0.6-4.9-0.7 -1.8-2-3.2-4.4-4-7 -0.6-1.8 0.2-3.7 1.8-4.6l0.8-0.5c0-0.3 0-0.5 0-0.8L34 40.8c-1.6-0.9-2.3-2.8-1.8-4.6 0.1-0.3 0.2-0.6 0.3-0.9 -0.4 0-0.8-0.1-1.1-0.1h-1.7c-4.6 2.1-10 2.1-14.6 0h-1.7C6 35.2 0 41.2 0 48.6v4.2c0 2.7 2.2 4.8 4.8 4.8l0 0H40c1 0 1.9-0.3 2.7-0.9C42.6 56.4 42.5 56 42.5 55.6zM22.4 32c7.1 0 12.8-5.7 12.8-12.8S29.5 6.4 22.4 6.4 9.6 12.1 9.6 19.2 15.3 32 22.4 32z"/></svg>',
'title' => esc_html__( 'Site Admin Email Change Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Manage emails sent when site admin\'s account has been changed.', 'wp-mail-smtp' ),
],
[
'svg' => '<svg xmlns="http://www.w3.org/2000/svg" focusable="false" viewBox="0 0 64 64"><path class="st0" d="M9.6 28.8c3.5 0 6.4-2.9 6.4-6.4S13.1 16 9.6 16s-6.4 2.9-6.4 6.4S6.1 28.8 9.6 28.8zM57.6 32h-6.4c-1.7 0-3.3 0.7-4.5 1.9 4.1 2.2 6.9 6.3 7.5 10.9h6.6c1.8 0 3.2-1.4 3.2-3.2v-3.2C64 34.9 61.1 32 57.6 32zM6.4 32C2.9 32 0 34.9 0 38.4v3.2c0 1.8 1.4 3.2 3.2 3.2h6.6c0.6-4.6 3.4-8.7 7.5-10.9 -1.2-1.2-2.8-1.9-4.5-1.9H6.4zM54.4 28.8c3.5 0 6.4-2.9 6.4-6.4S57.9 16 54.4 16 48 18.9 48 22.4 50.9 28.8 54.4 28.8z"/><path class="st1" d="M39.7 35.2h-0.8c-2.1 1-4.5 1.6-6.8 1.6 -2.5 0-4.8-0.6-6.9-1.6h-0.8c-6.4 0-11.5 5.2-11.5 11.5v2.9c0 2.7 2.1 4.8 4.8 4.8h28.8c2.6 0 4.8-2.2 4.8-4.8v-2.9C51.2 40.4 46 35.2 39.7 35.2zM32 32c6.2 0 11.2-5 11.2-11.2S38.2 9.6 32 9.6s-11.2 5-11.2 11.2C20.8 27 25.8 32 32 32L32 32z"/></svg>',
'title' => esc_html__( 'User Change Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Limit emails triggered by password changed/reset, email changed, and more.', 'wp-mail-smtp' ),
],
[
'svg' => '<svg xmlns="http://www.w3.org/2000/svg" focusable="false" viewBox="0 0 64 64"><path class="st0" d="M35.9 52.6L32 60l-3.9-7.4L30 44l-2.2-4.5c2.8 0.6 5.7 0.6 8.5 0L34 44 35.9 52.6zM32 35.9c8.8 0 16-7.1 16-15.9 -0.9 0.2-1.9 0.4-3 0.5v0.8c0 0-0.8 0.4-0.9 0.8 -0.5 1.6-1 3.3-2.2 4.5 -1.4 1.3-6.5 3-8.7-3.4 -0.4-1.1-2.1-1.1-2.5 0 -2.3 6.8-7.6 4.4-8.7 3.4 -1.3-1.2-1.7-2.9-2.2-4.5 -0.1-0.3-0.9-0.8-0.9-0.8v-0.8c-1.1-0.2-2.1-0.3-3-0.5C16 28.8 23.2 35.9 32 35.9z"/><path class="st1" d="M19 20.5v0.8c0 0 0.8 0.5 0.9 0.8 0.5 1.6 1 3.3 2.2 4.5 1.1 1 6.4 3.4 8.7-3.4 0.4-1.1 2.1-1.1 2.5 0 2.2 6.4 7.3 4.7 8.7 3.4 1.3-1.2 1.7-2.9 2.2-4.5 0.1-0.4 0.9-0.8 0.9-0.8v-0.8c6.6-1 11-2.7 11-4.6 0-1.7-3.4-3.3-8.8-4.3 -1.2-4-3.3-8-5-10.1C41 0 39-0.4 37.2 0.4l-3.5 1.7c-1.1 0.6-2.5 0.6-3.6 0l-3.5-1.7C25-0.4 23 0 21.8 1.5c-1.7 2.1-3.8 6.1-5 10.1 -5.4 1-8.8 2.5-8.8 4.3C8 17.8 12.3 19.6 19 20.5zM52 38.5l3-7.8c0.4-1-0.1-2.2-1.2-2.6 -0.2-0.1-0.5-0.1-0.7-0.1h-4L32 60 14.9 27.9H11c-1.1 0-2 0.9-2 2 0 0.3 0.1 0.5 0.2 0.8l3.2 7.5c-5.2 3-8.4 8.5-8.4 14.5V58c0 3.3 2.7 6 6 6l0 0H54c3.3 0 6-2.7 6-6l0 0v-5.2C60.1 46.9 57 41.5 52 38.5L52 38.5z"/></svg>',
'title' => esc_html__( 'Personal Data Requests Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Control emails for data requests and data removal actions.', 'wp-mail-smtp' ),
],
[
'svg' => '<svg xmlns="http://www.w3.org/2000/svg" focusable="false" viewBox="0 0 64 64"><path class="st0" d="M0 57.6V40.3c0-1.7 1.4-3.1 3.1-3.1h17.3c2.8 0 4.1 3.3 2.2 5.3l-5.4 5.4c4 3.8 9.3 5.9 14.8 5.8 10 0 18.6-6.9 21-16.4 0.2-0.7 0.8-1.2 1.5-1.2h7.4c0.9 0 1.5 0.7 1.5 1.5 0 0.1 0 0.2 0 0.3C60.7 52.8 47.6 64 32 64c-8.2 0-16.2-3.2-22.1-8.9l-4.6 4.6C3.3 61.7 0 60.3 0 57.6z"/><path class="st1" d="M0.6 26C3.3 11.2 16.4 0 32 0c8.2 0 16.2 3.2 22.1 8.9l4.6-4.6C60.7 2.3 64 3.7 64 6.5v17.3c0 1.7-1.4 3.1-3.1 3.1H43.6c-2.8 0-4.1-3.3-2.2-5.3l5.4-5.4c-4-3.8-9.3-5.9-14.8-5.8 -10 0-18.6 6.9-21 16.4 -0.2 0.7-0.8 1.2-1.5 1.2H2.1c-0.9 0-1.5-0.7-1.5-1.5C0.5 26.2 0.5 26.1 0.6 26z"/></svg>',
'title' => esc_html__( 'Automatic Update Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Manage emails sent by the core automatic update process.', 'wp-mail-smtp' ),
],
[
'svg' => '<svg xmlns="http://www.w3.org/2000/svg" focusable="false" viewBox="0 0 64 64"><path class="st0" d="M64 28.8V32c0 0.9-0.7 1.6-1.6 1.6H56V40c0 0.9-0.7 1.6-1.6 1.6h-3.2c-0.9 0-1.6-0.7-1.6-1.6v-6.4h-6.4c-0.9 0-1.6-0.7-1.6-1.6v-3.2c0-0.9 0.7-1.6 1.6-1.6h6.4v-6.4c0-0.9 0.7-1.6 1.6-1.6h3.2c0.9 0 1.6 0.7 1.6 1.6v6.4h6.4C63.3 27.2 64 27.9 64 28.8z"/><path class="st1" d="M22.4 32c7.1 0 12.8-5.7 12.8-12.8S29.5 6.4 22.4 6.4 9.6 12.1 9.6 19.2 15.3 32 22.4 32zM31.4 35.2h-1.7c-4.6 2.1-9.9 2.1-14.6 0h-1.7C6 35.2 0 41.2 0 48.6v4.2c0 2.7 2.2 4.8 4.8 4.8l0 0H40c2.7 0 4.8-2.1 4.8-4.8l0 0v-4.2C44.8 41.2 38.8 35.2 31.4 35.2z"/></svg>',
'title' => esc_html__( 'New User Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Toggle emails sent to both user and site administrator about new user accounts.', 'wp-mail-smtp' ),
],
];
$allowed_svg_html = [
'svg' => [
'xmlns' => [],
'focusable' => [],
'viewbox' => [],
],
'path' => [
'class' => [],
'd' => [],
],
];
?>
<div class="wp-mail-smtp-page-upsell">
<h2><?php esc_html_e( 'Unlock Email Controls', 'wp-mail-smtp' ); ?></h2>
<h3>
<?php esc_html_e( 'Email Controls allows you to granularly manage emails sent by WordPress.', 'wp-mail-smtp' ); ?>
</h3>
<div class="wp-mail-smtp-page-upsell-content">
<div class="wp-mail-smtp-page-upsell-features">
<?php foreach ( $features as $feature ) : ?>
<div class="wp-mail-smtp-page-upsell-feature">
<div class="wp-mail-smtp-page-upsell-feature-image">
<?php echo wp_kses( $feature['svg'], $allowed_svg_html ); ?>
</div>
<div class="wp-mail-smtp-page-upsell-feature-content">
<h4><?php echo esc_html( $feature['title'] ); ?></h4>
<p><?php echo esc_html( $feature['desc'] ); ?></p>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="wp-mail-smtp-page-upsell-button">
<a href="https://wpmailsmtp.com/lite-upgrade/?discount=LITEUPGRADE&amp;utm_source=WordPress&amp;utm_medium=logs&amp;utm_campaign=liteplugin"
class="wp-mail-smtp-btn wp-mail-smtp-btn-lg wp-mail-smtp-btn-orange" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'Upgrade to WP Mail SMTP Pro', 'wp-mail-smtp' ); ?>
</a>
</div>
</div>
<?php
}
/**
* Not used as we display an upsell.
*
* @since 1.6.0
*
* @param array $data
*/
public function process_post( $data ) {
}
}

View File

@ -1,85 +1,69 @@
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\Area;
use WPMailSMTP\Admin\PageAbstract;
/**
* Class Logs
*/
class Logs extends PageAbstract {
/**
* @since 1.5.0
*
* @var string Slug of a page.
*/
protected $slug = 'logs';
/**
* Get the page/tab link.
*
* @since 1.5.0
*
* @return string
*/
public function get_link() {
return add_query_arg(
'page',
Area::SLUG . '-' . $this->slug,
admin_url( 'admin.php' )
);
}
/**
* @inheritdoc
*/
public function get_label() {
return esc_html__( 'Email Log', 'wp-mail-smtp' );
}
/**
* @inheritdoc
*/
public function get_title() {
return $this->get_label();
}
/**
* @inheritdoc
*/
public function display() {
?>
<div class="wp-mail-smtp-page-title">
<h1 class="page-title">
<?php echo esc_html( $this->get_label() ); ?>
</h1>
</div>
<div class="wp-mail-smtp-page-upsell">
<h2><?php esc_html_e( 'Unlock Email Logging', 'wp-mail-smtp' ); ?></h2>
<h3>
<?php esc_html_e( 'Keep track of every email sent from your WordPress site with email logging.', 'wp-mail-smtp' ); ?><br>
<?php esc_html_e( 'Troubleshoot sending issues, recover lost emails, and more!', 'wp-mail-smtp' ); ?>
</h3>
<div class="wp-mail-smtp-page-upsell-images">
<img src="<?php echo esc_url( wp_mail_smtp()->assets_url . '/images/logs/archive.png' ); ?>" alt="<?php esc_attr_e( 'Logs Archive Page Screenshot', 'wp-mail-smtp' ); ?>">
<img src="<?php echo esc_url( wp_mail_smtp()->assets_url . '/images/logs/single.png' ); ?>" alt="<?php esc_attr_e( 'Logs Single Page Screenshot', 'wp-mail-smtp' ); ?>">
</div>
<div class="wp-mail-smtp-page-upsell-button">
<a href="https://wpmailsmtp.com/lite-upgrade/?discount=LITEUPGRADE&amp;utm_source=WordPress&amp;utm_medium=logs&amp;utm_campaign=liteplugin" class="wp-mail-smtp-btn wp-mail-smtp-btn-lg wp-mail-smtp-btn-orange wp-mail-smtp-upgrade-modal" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'Upgrade to WP Mail SMTP Pro', 'wp-mail-smtp' ); ?>
</a>
</div>
</div>
<?php
}
}
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\Area;
use WPMailSMTP\Admin\PageAbstract;
/**
* Class Logs
*
* @since 1.5.0
*/
class Logs extends PageAbstract {
/**
* Slug of a page.
*
* @since 1.5.0
*
* @var string
*/
protected $slug = 'logs';
/**
* Get the page/tab link.
*
* @since 1.5.0
* @since 2.1.0 Changed the URL to point to the email log settings tab.
*
* @return string
*/
public function get_link() {
return add_query_arg(
'tab',
$this->slug,
admin_url( 'admin.php?page=' . Area::SLUG )
);
}
/**
* Link label of a tab.
*
* @since 1.5.0
*
* @return string
*/
public function get_label() {
return esc_html__( 'Email Log', 'wp-mail-smtp' );
}
/**
* Title of a tab.
*
* @since 1.5.0
*
* @return string
*/
public function get_title() {
return $this->get_label();
}
/**
* Tab content.
*
* @since 2.1.0 Moved the display content to the email log settings tab.
*/
public function display() {}
}

View File

@ -1,73 +1,85 @@
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\Area;
use WPMailSMTP\Admin\PageAbstract;
/**
* Class LogsTab is a placeholder for Lite users and redirects them to Email Log page.
*
* @since 1.6.0
*/
class LogsTab extends PageAbstract {
/**
* Part of the slug of a tab.
*
* @since 1.6.0
*
* @var string
*/
protected $slug = 'logs';
/**
* @inheritdoc
*
* @since 1.6.0
*/
public function get_label() {
return esc_html__( 'Email Log', 'wp-mail-smtp' );
}
/**
* @inheritdoc
*
* @since 1.6.0
*/
public function get_title() {
return $this->get_label();
}
/**
* Custom URL for this tab, redirects to Email Log page.
*
* @since 1.6.0
*
* @return string
*/
public function get_link() {
return wp_mail_smtp()->get_admin()->get_admin_page_url( Area::SLUG . '-' . $this->slug );
}
/**
* Not used as we are simply redirecting users.
*
* @since 1.6.0
*/
public function display() {
}
/**
* Not used as we are simply redirecting users.
*
* @since 1.6.0
*
* @param array $data
*/
public function process_post( $data ) {
}
}
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\PageAbstract;
/**
* Class LogsTab is a placeholder for Lite users and redirects them to Email Log page.
*
* @since 1.6.0
*/
class LogsTab extends PageAbstract {
/**
* Part of the slug of a tab.
*
* @since 1.6.0
*
* @var string
*/
protected $slug = 'logs';
/**
* @inheritdoc
*
* @since 1.6.0
*/
public function get_label() {
return esc_html__( 'Email Log', 'wp-mail-smtp' );
}
/**
* @inheritdoc
*
* @since 1.6.0
*/
public function get_title() {
return $this->get_label();
}
/**
* Display the upsell content for the Email Log feature.
*
* @since 1.6.0
* @since 2.1.0 Moved the display content from the email log page (WP admin menu "Email Log" page).
*/
public function display() {
?>
<div class="wp-mail-smtp-page-upsell">
<h2><?php esc_html_e( 'Unlock Email Logging', 'wp-mail-smtp' ); ?></h2>
<h3>
<?php esc_html_e( 'Keep track of every email sent from your WordPress site with email logging.', 'wp-mail-smtp' ); ?><br>
<?php esc_html_e( 'Troubleshoot sending issues, recover lost emails, and more!', 'wp-mail-smtp' ); ?>
</h3>
<div class="wp-mail-smtp-page-upsell-images">
<img src="<?php echo esc_url( wp_mail_smtp()->assets_url . '/images/logs/archive.png' ); ?>" alt="<?php esc_attr_e( 'Logs Archive Page Screenshot', 'wp-mail-smtp' ); ?>">
<img src="<?php echo esc_url( wp_mail_smtp()->assets_url . '/images/logs/single.png' ); ?>" alt="<?php esc_attr_e( 'Logs Single Page Screenshot', 'wp-mail-smtp' ); ?>">
</div>
<div class="wp-mail-smtp-page-upsell-button">
<a href="https://wpmailsmtp.com/lite-upgrade/?discount=LITEUPGRADE&amp;utm_source=WordPress&amp;utm_medium=logs&amp;utm_campaign=liteplugin" class="wp-mail-smtp-btn wp-mail-smtp-btn-lg wp-mail-smtp-btn-orange wp-mail-smtp-upgrade-modal" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'Upgrade to WP Mail SMTP Pro', 'wp-mail-smtp' ); ?>
</a>
</div>
</div>
<?php
}
/**
* Not used as we are simply redirecting users.
*
* @since 1.6.0
*
* @param array $data
*/
public function process_post( $data ) {
}
}

View File

@ -88,19 +88,22 @@ class MiscTab extends PageAbstract {
'<code>wp-config.php</code>'
);
} else {
printf( /* translators: %s - file to put that constant in. */
esc_html__( 'If you want to enable this option using constants, put the lines below to your %s file:', 'wp-mail-smtp' ),
'<code>wp-config.php</code>'
printf(
wp_kses( /* translators: %s - The URL to the constants support article. */
__( 'Please read this <a href="%s" target="_blank" rel="noopener noreferrer">support article</a> if you want to enable this option using constants.', 'wp-mail-smtp' ),
[
'a' => [
'href' => [],
'target' => [],
'rel' => [],
],
]
),
'https://wpmailsmtp.com/docs/how-to-secure-smtp-settings-by-using-constants/'
);
}
?>
</p>
<?php if ( ! $options->is_const_defined( 'general', 'do_not_send' ) ) : ?>
<pre>
define( 'WPMS_ON', true );
define( 'WPMS_DO_NOT_SEND', true );
</pre>
<?php endif; ?>
</div>
</div>

View File

@ -98,12 +98,12 @@ class TestTab extends PageAbstract {
$disabled = '';
$help_text = '';
if (
! wp_mail_smtp()->get_providers()->get_mailer(
Options::init()->get( 'mail', 'mailer' ),
wp_mail_smtp()->get_processor()->get_phpmailer()
)->is_mailer_complete()
) {
$mailer = wp_mail_smtp()->get_providers()->get_mailer(
Options::init()->get( 'mail', 'mailer' ),
wp_mail_smtp()->get_processor()->get_phpmailer()
);
if ( ! $mailer || ! $mailer->is_mailer_complete() ) {
$btn = 'wp-mail-smtp-btn-red';
$disabled = 'disabled';
@ -435,6 +435,18 @@ Lead Developer, WP Mail SMTP';
$mailer_text .= $mailer->get_debug_info();
}
$phpmailer_error = $phpmailer->ErrorInfo; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
// Append any PHPMailer errors to the mailer debug (except SMTP mailer, which has the full error output below).
if (
! empty( $phpmailer_error ) &&
! $options->is_mailer_smtp()
) {
$mailer_text .= '<br><br><strong>PHPMailer Debug:</strong><br>' .
wp_strip_all_tags( $phpmailer_error ) .
'<br>';
}
/*
* General Debug.
*/
@ -486,137 +498,163 @@ Lead Developer, WP Mail SMTP';
$smtp_port = $options->get( 'smtp', 'port' );
$smtp_encryption = $options->get( 'smtp', 'encryption' );
$details = array(
$details = [
// [any] - cURL error 60/77.
array(
[
'mailer' => 'any',
'errors' => array(
array( 'cURL error 60' ),
array( 'cURL error 77' ),
),
'description' => array(
'errors' => [
[ 'cURL error 60' ],
[ 'cURL error 77' ],
],
'description' => [
'<strong>' . esc_html__( 'SSL certificate issue.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'This means your web server cannot reliably make secure connections (make requests to HTTPS sites).', 'wp-mail-smtp' ),
esc_html__( 'Typically this error is returned when web server is not configured properly.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Contact your web hosting provider and inform them your site has an issue with SSL certificates.', 'wp-mail-smtp' ),
esc_html__( 'The exact error you can provide them is in the Error log, available at the bottom of this page.', 'wp-mail-smtp' ),
esc_html__( 'Ask them to resolve the issue then try again.', 'wp-mail-smtp' ),
),
),
],
],
// [any] - cURL error 6/7.
array(
[
'mailer' => 'any',
'errors' => array(
array( 'cURL error 6' ),
array( 'cURL error 7' ),
),
'description' => array(
'errors' => [
[ 'cURL error 6' ],
[ 'cURL error 7' ],
],
'description' => [
'<strong>' . esc_html__( 'Could not connect to host.', 'wp-mail-smtp' ) . '</strong>',
! empty( $smtp_host )
? sprintf(
/* translators: %s - SMTP host address. */
? sprintf( /* translators: %s - SMTP host address. */
esc_html__( 'This means your web server was unable to connect to %s.', 'wp-mail-smtp' ),
$smtp_host
)
: esc_html__( 'This means your web server was unable to connect to the host server.', 'wp-mail-smtp' ),
esc_html__( 'Typically this error is returned your web server is blocking the connections or the SMTP host denying the request.', 'wp-mail-smtp' ),
),
'steps' => array(
sprintf(
/* translators: %s - SMTP host address. */
],
'steps' => [
sprintf( /* translators: %s - SMTP host address. */
esc_html__( 'Contact your web hosting provider and ask them to verify your server can connect to %s. Additionally, ask them if a firewall or security policy may be preventing the connection.', 'wp-mail-smtp' ),
$smtp_host
),
esc_html__( 'If using "Other SMTP" Mailer, triple check your SMTP settings including host address, email, and password.', 'wp-mail-smtp' ),
esc_html__( 'If using "Other SMTP" Mailer, contact your SMTP host to confirm they are accepting outside connections with the settings you have configured (address, username, port, security, etc).', 'wp-mail-smtp' ),
),
),
],
],
// [any] - cURL error XX (other).
array(
[
'mailer' => 'any',
'errors' => array(
array( 'cURL error' ),
),
'description' => array(
'errors' => [
[ 'cURL error' ],
],
'description' => [
'<strong>' . esc_html__( 'Could not connect to your host.', 'wp-mail-smtp' ) . '</strong>',
! empty( $smtp_host )
? sprintf(
/* translators: %s - SMTP host address. */
? sprintf( /* translators: %s - SMTP host address. */
esc_html__( 'This means your web server was unable to connect to %s.', 'wp-mail-smtp' ),
$smtp_host
)
: esc_html__( 'This means your web server was unable to connect to the host server.', 'wp-mail-smtp' ),
esc_html__( 'Typically this error is returned when web server is not configured properly.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Contact your web hosting provider and inform them you are having issues making outbound connections.', 'wp-mail-smtp' ),
esc_html__( 'The exact error you can provide them is in the Error log, available at the bottom of this page.', 'wp-mail-smtp' ),
esc_html__( 'Ask them to resolve the issue then try again.', 'wp-mail-smtp' ),
),
),
],
],
// [smtp] - SMTP Error: Count not authenticate.
array(
[
'mailer' => 'smtp',
'errors' => array(
array( 'SMTP Error: Could not authenticate.' ),
),
'description' => array(
'errors' => [
[ 'SMTP Error: Could not authenticate.' ],
],
'description' => [
'<strong>' . esc_html__( 'Could not authenticate your SMTP account.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'This means we were able to connect to your SMTP host, but were not able to proceed using the email/password in the settings.', 'wp-mail-smtp' ),
esc_html__( 'Typically this error is returned when the email or password is not correct or is not what the SMTP host is expecting.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Triple check your SMTP settings including host address, email, and password. If you have recently reset your password you will need to update the settings.', 'wp-mail-smtp' ),
esc_html__( 'Contact your SMTP host to confirm you are using the correct username and password.', 'wp-mail-smtp' ),
esc_html__( 'Verify with your SMTP host that your account has permissions to send emails using outside connections.', 'wp-mail-smtp' ),
),
),
],
],
// [smtp] - Sending bulk email, hitting rate limit.
array(
[
'mailer' => 'smtp',
'errors' => array(
array( 'We do not authorize the use of this system to transport unsolicited' ),
),
'description' => array(
'errors' => [
[ 'We do not authorize the use of this system to transport unsolicited' ],
],
'description' => [
'<strong>' . esc_html__( 'Error due to unsolicited and/or bulk e-mail.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'This means the connection to your SMTP host was made successfully, but the host rejected the email.', 'wp-mail-smtp' ),
esc_html__( 'Typically this error is returned when you are sending too many e-mails or e-mails that have been identified as spam.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Check the emails that are sending are sending individually. Example: email is not sending to 30 recipients. You can install any WordPress e-mail logging plugin to do that.', 'wp-mail-smtp' ),
esc_html__( 'Contact your SMTP host to ask about sending/rate limits.', 'wp-mail-smtp' ),
esc_html__( 'Verify with them your SMTP account is in good standing and your account has not been flagged.', 'wp-mail-smtp' ),
),
),
],
],
// [smtp] - Unauthenticated senders not allowed.
array(
[
'mailer' => 'smtp',
'errors' => array(
array( 'Unauthenticated senders not allowed' ),
),
'description' => array(
'errors' => [
[ 'Unauthenticated senders not allowed' ],
],
'description' => [
'<strong>' . esc_html__( 'Unauthenticated senders are not allowed.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'This means the connection to your SMTP host was made successfully, but you should enable Authentication and provide correct Username and Password.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Go to WP Mail SMTP plugin Settings page.', 'wp-mail-smtp' ),
esc_html__( 'Enable Authentication', 'wp-mail-smtp' ),
esc_html__( 'Enter correct SMTP Username (usually this is an email address) and Password in the appropriate fields.', 'wp-mail-smtp' ),
),
),
// [smtp] - SMTP connect() failed.
array(
],
],
// [smtp] - certificate verify failed.
// Has to be defined before "SMTP connect() failed" error, since this is a more specific error,
// which contains the "SMTP connect() failed" error message as well.
[
'mailer' => 'smtp',
'errors' => array(
array( 'SMTP connect() failed' ),
),
'description' => array(
'errors' => [
[ 'certificate verify failed' ],
],
'description' => [
'<strong>' . esc_html__( 'Misconfigured server certificate.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'This means OpenSSL on your server isn\'t able to verify the host certificate.', 'wp-mail-smtp' ),
esc_html__( 'There are a few reasons why this is happening. It could be that the host certificate is misconfigured, or this server\'s OpenSSL is using an outdated CA bundle.', 'wp-mail-smtp' ),
],
'steps' => [
esc_html__( 'Verify that the host\'s SSL certificate is valid.', 'wp-mail-smtp' ),
sprintf(
wp_kses( /* translators: %s - URL to the PHP openssl manual */
__( 'Contact your hosting support, show them the "full Error Log for debugging" below and share this <a href="%s" target="_blank" rel="noopener noreferrer">link</a> with them.', 'wp-mail-smtp' ),
[
'a' => [
'href' => [],
'target' => [],
'rel' => [],
],
]
),
'https://www.php.net/manual/en/migration56.openssl.php'
),
],
],
// [smtp] - SMTP connect() failed.
[
'mailer' => 'smtp',
'errors' => [
[ 'SMTP connect() failed' ],
],
'description' => [
'<strong>' . esc_html__( 'Could not connect to the SMTP host.', 'wp-mail-smtp' ) . '</strong>',
! empty( $smtp_host )
? sprintf(
/* translators: %s - SMTP host address. */
? sprintf( /* translators: %s - SMTP host address. */
esc_html__( 'This means your web server was unable to connect to %s.', 'wp-mail-smtp' ),
$smtp_host
)
@ -625,22 +663,21 @@ Lead Developer, WP Mail SMTP';
'-' . esc_html__( 'SMTP settings are incorrect (wrong port, security setting, incorrect host).', 'wp-mail-smtp' ) . '<br>' .
'-' . esc_html__( 'Your web server is blocking the connection.', 'wp-mail-smtp' ) . '<br>' .
'-' . esc_html__( 'Your SMTP host is rejecting the connection.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Triple check your SMTP settings including host address, email, and password, port, and security.', 'wp-mail-smtp' ),
sprintf(
wp_kses(
/* translators: %1$s - SMTP host address, %2$s - SMTP port, %3$s - SMTP encryption. */
wp_kses( /* translators: %1$s - SMTP host address, %2$s - SMTP port, %3$s - SMTP encryption. */
__( 'Contact your web hosting provider and ask them to verify your server can connect to %1$s on port %2$s using %3$s encryption. Additionally, ask them if a firewall or security policy may be preventing the connection - many shared hosts block certain ports.<br><strong>Note: this is the most common cause of this issue.</strong>', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
'strong' => array(),
'br' => array(),
)
[
'a' => [
'href' => [],
'rel' => [],
'target' => [],
],
'strong' => [],
'br' => [],
]
),
$smtp_host,
$smtp_port,
@ -648,281 +685,332 @@ Lead Developer, WP Mail SMTP';
),
esc_html__( 'Contact your SMTP host to confirm you are using the correct username and password.', 'wp-mail-smtp' ),
esc_html__( 'Verify with your SMTP host that your account has permissions to send emails using outside connections.', 'wp-mail-smtp' ),
),
),
],
],
// [mailgun] - Please activate your Mailgun account.
array(
[
'mailer' => 'mailgun',
'errors' => array(
array( 'Please activate your Mailgun account' ),
),
'description' => array(
'errors' => [
[ 'Please activate your Mailgun account' ],
],
'description' => [
'<strong>' . esc_html__( 'Mailgun failed.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'It seems that you forgot to activate your Mailgun account.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Check your inbox you used to create a Mailgun account. Click the activation link in an email from Mailgun.', 'wp-mail-smtp' ),
esc_html__( 'If you do not see activation email, go to your Mailgun control panel and resend the activation email.', 'wp-mail-smtp' ),
),
),
],
],
// [mailgun] - Forbidden.
array(
[
'mailer' => 'mailgun',
'errors' => array(
array( 'Forbidden' ),
),
'description' => array(
'errors' => [
[ 'Forbidden' ],
],
'description' => [
'<strong>' . esc_html__( 'Mailgun failed.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'Typically this error is because there is an issue with your Mailgun settings, in many cases the API key.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Verify your API key is correct.', 'wp-mail-smtp' ),
esc_html__( 'Go to your Mailgun account and view your API key.', 'wp-mail-smtp' ),
esc_html__( 'Note that the API key includes the "key" prefix, so make sure that it is in the WP Mail SMTP Mailgun API setting.', 'wp-mail-smtp' ),
),
),
],
],
// [mailgun] - Free accounts are for test purposes only.
array(
[
'mailer' => 'mailgun',
'errors' => array(
array( 'Free accounts are for test purposes only' ),
),
'description' => array(
'errors' => [
[ 'Free accounts are for test purposes only' ],
],
'description' => [
'<strong>' . esc_html__( 'Mailgun failed.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'Your Mailgun account does not have access to send emails.', 'wp-mail-smtp' ),
esc_html__( 'Typically this error is because you have not set up and/or complete domain name verification for your Mailgun account.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
sprintf(
wp_kses(
/* translators: %s - Mailgun documentation URL. */
wp_kses( /* translators: %s - Mailgun documentation URL. */
__( 'Go to our how-to guide for setting up <a href="%s" target="_blank" rel="noopener noreferrer">Mailgun with WP Mail SMTP</a>.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
)
[
'a' => [
'href' => [],
'rel' => [],
'target' => [],
],
]
),
'https://wpmailsmtp.com/docs/how-to-set-up-the-mailgun-mailer-in-wp-mail-smtp/'
),
esc_html__( 'Complete the steps in section "2. Verify Your Domain".', 'wp-mail-smtp' ),
),
),
],
],
// [gmail] - 401: Login Required.
array(
[
'mailer' => 'gmail',
'errors' => array(
array( '401', 'Login Required' ),
),
'description' => array(
'errors' => [
[ '401', 'Login Required' ],
],
'description' => [
'<strong>' . esc_html__( 'Google API Error.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'You have not properly configured Gmail mailer.', 'wp-mail-smtp' ),
esc_html__( 'Make sure that you have clicked the "Allow plugin to send emails using your Google account" button under Gmail settings.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Go to plugin Settings page and click the "Allow plugin to send emails using your Google account" button.', 'wp-mail-smtp' ),
esc_html__( 'After the click you should be redirected to a Gmail authorization screen, where you will be asked a permission to send emails on your behalf.', 'wp-mail-smtp' ),
esc_html__( 'Please click "Agree", if you see that button. If not - you will need to enable less secure apps first:', 'wp-mail-smtp' )
. '<ul>'
. '<li>' .
sprintf(
wp_kses(
/* translators: %s - Google support article URL. */
wp_kses( /* translators: %s - Google support article URL. */
__( 'if you are using regular Gmail account, please <a href="%s" target="_blank" rel="noopener noreferrer">read this article</a> to proceed.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'target' => array(),
'rel' => array(),
),
)
[
'a' => [
'href' => [],
'target' => [],
'rel' => [],
],
]
),
'https://support.google.com/accounts/answer/6010255?hl=en'
)
. '</li>'
. '<li>' .
sprintf(
wp_kses(
/* translators: %s - Google support article URL. */
wp_kses( /* translators: %s - Google support article URL. */
__( 'if you are using G Suite, please <a href="%s" target="_blank" rel="noopener noreferrer">read this article</a> to proceed.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'target' => array(),
'rel' => array(),
),
)
[
'a' => [
'href' => [],
'target' => [],
'rel' => [],
],
]
),
'https://support.google.com/cloudidentity/answer/6260879?hl=en'
)
. '</li>'
. '</ul>',
),
),
],
],
// [gmail] - 400: Recipient address required.
array(
[
'mailer' => 'gmail',
'errors' => array(
array( '400', 'Recipient address required' ),
),
'description' => array(
'errors' => [
[ '400', 'Recipient address required' ],
],
'description' => [
'<strong>' . esc_html__( 'Google API Error.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'Typically this error is because address the email was sent to is invalid or was empty.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Check the "Send To" email address used and confirm it is a valid email and was not empty.', 'wp-mail-smtp' ),
sprintf(
/* translators: 1 - correct email address example. 2 - incorrect email address example. */
sprintf( /* translators: 1 - correct email address example. 2 - incorrect email address example. */
esc_html__( 'It should be something like this: %1$s. These are incorrect values: %2$s.', 'wp-mail-smtp' ),
'<code>info@example.com</code>',
'<code>info@localhost</code>, <code>info@192.168.1.1</code>'
),
esc_html__( 'Make sure that the generated email has a TO header, useful when you are responsible for email creation.', 'wp-mail-smtp' ),
),
),
],
],
// [gmail] - Token has been expired or revoked.
array(
[
'mailer' => 'gmail',
'errors' => array(
array( 'invalid_grant', 'Token has been expired or revoked' ),
),
'description' => array(
'errors' => [
[ 'invalid_grant', 'Token has been expired or revoked' ],
],
'description' => [
'<strong>' . esc_html__( 'Google API Error.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'Unfortunately, this error can be due to many different reasons.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
sprintf(
wp_kses(
/* translators: %s - Blog article URL. */
wp_kses( /* translators: %s - Blog article URL. */
__( 'Please <a href="%s" target="_blank" rel="noopener noreferrer">read this article</a> to learn more about what can cause this error and how it can be resolved.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'target' => array(),
'rel' => array(),
),
)
[
'a' => [
'href' => [],
'target' => [],
'rel' => [],
],
]
),
'https://blog.timekit.io/google-oauth-invalid-grant-nightmare-and-how-to-fix-it-9f4efaf1da35'
),
),
),
],
],
// [gmail] - Code was already redeemed.
array(
[
'mailer' => 'gmail',
'errors' => array(
array( 'invalid_grant', 'Code was already redeemed' ),
),
'description' => array(
'errors' => [
[ 'invalid_grant', 'Code was already redeemed' ],
],
'description' => [
'<strong>' . esc_html__( 'Google API Error.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'Authentication code that Google returned to you has already been used on your previous auth attempt.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Make sure that you are not trying to manually clean up the plugin options to retry the "Allow..." step.', 'wp-mail-smtp' ),
esc_html__( 'Reinstall the plugin with clean plugin data turned on on Misc page. This will remove all the plugin options and you will be safe to retry.', 'wp-mail-smtp' ),
esc_html__( 'Make sure there is no aggressive caching on site admin area pages or try to clean cache between attempts.', 'wp-mail-smtp' ),
),
),
],
],
// [gmail] - 400: Mail service not enabled.
array(
[
'mailer' => 'gmail',
'errors' => array(
array( '400', 'Mail service not enabled' ),
),
'description' => array(
'errors' => [
[ '400', 'Mail service not enabled' ],
],
'description' => [
'<strong>' . esc_html__( 'Google API Error.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'There are various reasons for that, please review the steps below.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
sprintf(
wp_kses(
/* translators: %s - Google G Suite Admin area URL. */
wp_kses( /* translators: %s - Google G Suite Admin area URL. */
__( 'Make sure that your G Suite trial period has not expired. You can check the status <a href="%s" target="_blank" rel="noopener noreferrer">here</a>.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
)
[
'a' => [
'href' => [],
'rel' => [],
'target' => [],
],
]
),
'https://admin.google.com'
),
sprintf(
wp_kses(
/* translators: %s - Google G Suite Admin area URL. */
wp_kses( /* translators: %s - Google G Suite Admin area URL. */
__( 'Make sure that Gmail app in your G Suite is actually enabled. You can check that in Apps list in <a href="%s" target="_blank" rel="noopener noreferrer">G Suite Admin</a> area.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
)
[
'a' => [
'href' => [],
'rel' => [],
'target' => [],
],
]
),
'https://admin.google.com'
),
sprintf(
wp_kses(
/* translators: %s - Google Developers Console URL. */
wp_kses( /* translators: %s - Google Developers Console URL. */
__( 'Make sure that you have Gmail API enabled, and you can do that <a href="%s" target="_blank" rel="noopener noreferrer">here</a>.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
)
[
'a' => [
'href' => [],
'rel' => [],
'target' => [],
],
]
),
'https://console.developers.google.com/'
),
),
),
],
],
// [gmail] - 403: Project X is not found and cannot be used for API calls.
array(
[
'mailer' => 'gmail',
'errors' => array(
array( '403', 'is not found and cannot be used for API calls' ),
),
'description' => array(
'errors' => [
[ '403', 'is not found and cannot be used for API calls' ],
],
'description' => [
'<strong>' . esc_html__( 'Google API Error.', 'wp-mail-smtp' ) . '</strong>',
),
'steps' => array(
],
'steps' => [
esc_html__( 'Make sure that the used Client ID/Secret correspond to a proper project that has Gmail API enabled.', 'wp-mail-smtp' ),
sprintf(
wp_kses(
/* translators: %s - Gmail documentation URL. */
wp_kses( /* translators: %s - Gmail documentation URL. */
esc_html__( 'Please follow our <a href="%s" target="_blank" rel="noopener noreferrer">Gmail tutorial</a> to be sure that all the correct project and data is applied.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
)
[
'a' => [
'href' => [],
'rel' => [],
'target' => [],
],
]
),
'https://wpmailsmtp.com/docs/how-to-set-up-the-gmail-mailer-in-wp-mail-smtp/'
),
),
),
],
],
// [gmail] - The OAuth client was disabled.
array(
[
'mailer' => 'gmail',
'errors' => array(
array( 'disabled_client', 'The OAuth client was disabled' ),
),
'description' => array(
'errors' => [
[ 'disabled_client', 'The OAuth client was disabled' ],
],
'description' => [
'<strong>' . esc_html__( 'Google API Error.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'You may have added a new API to a project', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Make sure that the used Client ID/Secret correspond to a proper project that has Gmail API enabled.', 'wp-mail-smtp' ),
esc_html__( 'Try to use a separate project for your emails, so the project has only 1 Gmail API in it enabled. You will need to remove the old project and create a new one from scratch.', 'wp-mail-smtp' ),
),
),
);
],
],
// [SMTP.com] - The "channel - not found" issue.
[
'mailer' => 'smtpcom',
'errors' => [
[ 'channel - not found' ],
],
'description' => [
'<strong>' . esc_html__( 'SMTP.com API Error.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'Your Sender Name option is incorrect.', 'wp-mail-smtp' ),
],
'steps' => [
esc_html__( 'Please make sure you entered an accurate Sender Name in WP Mail SMTP plugin settings.', 'wp-mail-smtp' ),
],
],
// [gmail] - GuzzleHttp requires cURL, the allow_url_fopen ini setting, or a custom HTTP handler.
[
'mailer' => 'gmail',
'errors' => [
[ 'GuzzleHttp requires cURL, the allow_url_fopen ini setting, or a custom HTTP handler' ],
],
'description' => [
'<strong>' . esc_html__( 'GuzzleHttp requirements.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'GuzzleHttp requires cURL, the allow_url_fopen ini setting, or a custom HTTP handler.', 'wp-mail-smtp' ),
],
'steps' => [
esc_html__( 'Edit your php.ini file on your hosting server.', 'wp-mail-smtp' ),
esc_html__( '(Recommended) Enable PHP extension: cURL, by adding "extension=curl" to the php.ini file (without the quotation marks) OR', 'wp-mail-smtp' ),
esc_html__( '(If cURL can\'t be enabled on your hosting server) Enable PHP setting: allow_url_fopen, by adding "allow_url_fopen = On" to the php.ini file (without the quotation marks)', 'wp-mail-smtp' ),
esc_html__( 'If you don\'t know how to do the above we strongly suggest contacting your hosting support and provide them the "full Error Log for debugging" below and these steps. They should be able to fix this issue for you.', 'wp-mail-smtp' ),
],
],
];
/**
* [any] - PHP 7.4.x and PCRE library issues.
*
* @see https://wordpress.org/support/topic/cant-send-emails-using-php-7-4/
*/
if (
version_compare( phpversion(), '7.4', '>=' ) &&
defined( 'PCRE_VERSION' ) &&
version_compare( PCRE_VERSION, '10.0', '>' ) &&
version_compare( PCRE_VERSION, '10.32', '<=' )
) {
$details[] = [
'mailer' => 'any',
'errors' => [
[ 'Invalid address: (setFrom)' ],
],
'description' => [
'<strong>' . esc_html__( 'PCRE library issue', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'It looks like your server is running PHP version 7.4.x with an outdated PCRE library (libpcre2) that has a known issue with email address validation.', 'wp-mail-smtp' ),
esc_html__( 'There is a known issue with PHP version 7.4.x, when using libpcre2 library version lower than 10.33.', 'wp-mail-smtp' ),
],
'steps' => [
esc_html__( 'Contact your web hosting provider and inform them you are having issues with libpcre2 library on PHP 7.4.', 'wp-mail-smtp' ),
esc_html__( 'They should be able to resolve this issue for you.', 'wp-mail-smtp' ),
esc_html__( 'For a quick fix, until your web hosting resolves this, you can downgrade to PHP version 7.3 on your server.', 'wp-mail-smtp' ),
],
];
}
// Error detection logic.
foreach ( $details as $data ) {
@ -953,27 +1041,27 @@ Lead Developer, WP Mail SMTP';
}
// Return defaults.
return array(
'description' => array(
return [
'description' => [
'<strong>' . esc_html__( 'An issue was detected.', 'wp-mail-smtp' ) . '</strong>',
esc_html__( 'This means your test email was unable to be sent.', 'wp-mail-smtp' ),
esc_html__( 'Typically this error is returned for one of the following reasons:', 'wp-mail-smtp' ),
'- ' . esc_html__( 'Plugin settings are incorrect (wrong SMTP settings, invalid Mailer configuration, etc).', 'wp-mail-smtp' ) . '<br>' .
'- ' . esc_html__( 'Your web server is blocking the connection.', 'wp-mail-smtp' ) . '<br>' .
'- ' . esc_html__( 'Your host is rejecting the connection.', 'wp-mail-smtp' ),
),
'steps' => array(
],
'steps' => [
esc_html__( 'Triple check the plugin settings, consider reconfiguring to make sure everything is correct (eg bad copy and paste).', 'wp-mail-smtp' ),
wp_kses(
__( 'Contact your web hosting provider and ask them to verify your server can make outside connections. Additionally, ask them if a firewall or security policy may be preventing the connection - many shared hosts block certain ports.<br><strong>Note: this is the most common cause of this issue.</strong>', 'wp-mail-smtp' ),
array(
'strong' => array(),
'br' => array(),
)
[
'strong' => [],
'br' => [],
]
),
esc_html__( 'Try using a different mailer.', 'wp-mail-smtp' ),
),
);
],
];
}
/**

View File

@ -0,0 +1,203 @@
<?php
namespace WPMailSMTP\Admin;
use WPMailSMTP\Options;
/**
* Class for admin notice requesting plugin review.
*
* @since 2.1.0
*/
class Review {
/**
* The name of the WP option for the review notice data.
*
* Data attributes:
* - time
* - dismissed
*
* @since 2.1.0
*/
const NOTICE_OPTION = 'wp_mail_smtp_review_notice';
/**
* Days the plugin waits before displaying a review request.
*
* @since 2.1.0
*/
const WAIT_PERIOD = 14;
/**
* Initialize hooks.
*
* @since 2.1.0
*/
public function hooks() {
add_action( 'admin_notices', array( $this, 'review_request' ) );
add_action( 'wp_ajax_wp_mail_smtp_review_dismiss', array( $this, 'review_dismiss' ) );
}
/**
* Add admin notices as needed for reviews.
*
* @since 2.1.0
*/
public function review_request() {
// Only consider showing the review request to admin users.
if ( ! is_super_admin() ) {
return;
}
// Verify that we can do a check for reviews.
$review = get_option( self::NOTICE_OPTION );
$time = time();
$load = false;
if ( empty( $review ) ) {
$review = [
'time' => $time,
'dismissed' => false,
];
update_option( self::NOTICE_OPTION, $review );
} else {
// Check if it has been dismissed or not.
if ( isset( $review['dismissed'] ) && ! $review['dismissed'] ) {
$load = true;
}
}
// If we cannot load, return early.
if ( ! $load ) {
return;
}
$this->review();
}
/**
* Maybe show review request.
*
* @since 2.1.0
*/
private function review() {
// Get the currently selected mailer.
$mailer = Options::init()->get( 'mail', 'mailer' );
// Skip if the default mailer is selected.
if ( $mailer === 'mail' ) {
return;
}
// Fetch when plugin was initially activated.
$activated = get_option( 'wp_mail_smtp_activated_time' );
// Skip if the plugin activated time is not set.
if ( empty( $activated ) ) {
return;
}
// Check if mailer setup is complete.
$mailer_setup_complete = wp_mail_smtp()
->get_providers()
->get_mailer( $mailer, wp_mail_smtp()->get_processor()->get_phpmailer() )
->is_mailer_complete();
// Skip if the mailer is not set or the plugin is active for less then a defined number of days.
if ( ! $mailer_setup_complete || ( $activated + ( DAY_IN_SECONDS * self::WAIT_PERIOD ) ) > time() ) {
return;
}
// We have a candidate! Output a review message.
?>
<div class="notice notice-info is-dismissible wp-mail-smtp-review-notice">
<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>
</p>
</div>
<div class="wp-mail-smtp-review-step wp-mail-smtp-review-step-2" style="display: none">
<p><?php esc_html_e( 'We\'re sorry to hear you aren\'t enjoying WP Mail SMTP. We would love a chance to improve. Could you take a minute and let us know what we can do better?', 'wp-mail-smtp' ); ?></p>
<p>
<a href="https://wpmailsmtp.com/plugin-feedback/" class="wp-mail-smtp-dismiss-review-notice wp-mail-smtp-review-out" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'Give Feedback', 'wp-mail-smtp' ); ?>
</a><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( 'Thats 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>Lead Developer, WP Mail SMTP', 'wp-mail-smtp' ), [ 'br' => [] ] ); ?></strong></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>
<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>
</div>
<script type="text/javascript">
jQuery( document ).ready( function ( $ ) {
$( document ).on( 'click', '.wp-mail-smtp-dismiss-review-notice, .wp-mail-smtp-review-notice button', function( e ) {
if ( ! $( this ).hasClass( 'wp-mail-smtp-review-out' ) ) {
e.preventDefault();
}
$.post( ajaxurl, { action: 'wp_mail_smtp_review_dismiss' } );
$( '.wp-mail-smtp-review-notice' ).remove();
} );
$( document ).on( 'click', '.wp-mail-smtp-review-switch-step', function( e ) {
e.preventDefault();
var target = parseInt( $( this ).attr( 'data-step' ), 10 );
if ( target ) {
var $notice = $( this ).closest( '.wp-mail-smtp-review-notice' );
var $review_step = $notice.find( '.wp-mail-smtp-review-step-' + target );
if ( $review_step.length > 0 ) {
$notice.find( '.wp-mail-smtp-review-step:visible' ).fadeOut( function() {
$review_step.fadeIn();
} );
}
}
} );
} );
</script>
<?php
}
/**
* Dismiss the review admin notice.
*
* @since 2.1.0
*/
public function review_dismiss() {
$review = get_option( self::NOTICE_OPTION, [] );
$review['time'] = time();
$review['dismissed'] = true;
update_option( self::NOTICE_OPTION, $review );
if ( is_super_admin() && is_multisite() ) {
$site_list = get_sites();
foreach ( (array) $site_list as $site ) {
switch_to_blog( $site->blog_id );
update_option( self::NOTICE_OPTION, $review );
restore_current_blog();
}
}
wp_send_json_success();
}
}

View File

@ -95,6 +95,9 @@ class Core {
*/
public function hooks() {
// Action Scheduler requires a special early loading procedure.
add_action( 'plugins_loaded', array( $this, 'load_action_scheduler' ), -10 );
// Activation hook.
register_activation_hook( WPMS_PLUGIN_FILE, array( $this, 'activate' ) );
@ -107,6 +110,9 @@ class Core {
add_action( 'init', array( $this, 'init' ) );
// Initialize Action Scheduler tasks.
add_action( 'init', array( $this, 'get_tasks' ), 5 );
add_action( 'plugins_loaded', array( $this, 'get_pro' ) );
}
@ -188,6 +194,25 @@ class Core {
return $this->pro;
}
/**
* Get/Load the Tasks code of the plugin.
*
* @since 2.1.0
*
* @return \WPMailSMTP\Tasks\Tasks
*/
public function get_tasks() {
static $tasks;
if ( ! isset( $tasks ) ) {
$tasks = apply_filters( 'wp_mail_smtp_core_get_tasks', new Tasks\Tasks() );
$tasks->init();
}
return $tasks;
}
/**
* This method allows to overwrite certain core WP functions, because it's fired:
* - after `muplugins_loaded` hook,
@ -573,6 +598,13 @@ class Core {
// Save default options, only once.
Options::init()->set( Options::get_defaults(), true );
/**
* Store the timestamp of first plugin activation.
*
* @since 2.1.0
*/
add_option( 'wp_mail_smtp_activated_time', time(), '', false );
}
/**
@ -689,4 +721,16 @@ class Core {
return (bool) apply_filters( 'wp_mail_smtp_is_white_labeled', false );
}
/**
* Require the action scheduler in an early plugins_loaded hook (-10).
*
* @see https://actionscheduler.org/usage/#load-order
*
* @since 2.1.0
*/
public function load_action_scheduler() {
require_once $this->plugin_path . '/vendor/woocommerce/action-scheduler/action-scheduler.php';
}
}

View File

@ -1,145 +1,154 @@
<?php
namespace WPMailSMTP;
// Load PHPMailer class, so we can subclass it.
if ( ! class_exists( 'PHPMailer', false ) ) {
require_once ABSPATH . WPINC . '/class-phpmailer.php';
}
/**
* Class MailCatcher replaces the \PHPMailer and modifies the email sending logic.
* Thus, we can use other mailers API to do what we need, or stop emails completely.
*
* @since 1.0.0
*/
class MailCatcher extends \PHPMailer {
/**
* Callback Action function name.
*
* The function that handles the result of the send email action.
* It is called out by send() for each email sent.
*
* @since 1.3.0
*
* @var string
*/
public $action_function = '\WPMailSMTP\Processor::send_callback';
/**
* Modify the default send() behaviour.
* For those mailers, that relies on PHPMailer class - call it directly.
* For others - init the correct provider and process it.
*
* @since 1.0.0
* @since 1.4.0 Process "Do Not Send" option, but always allow test email.
*
* @throws \phpmailerException When sending via PhpMailer fails for some reason.
*
* @return bool
*/
public function send() {
$options = new Options();
$mail_mailer = sanitize_key( $options->get( 'mail', 'mailer' ) );
$is_emailing_blocked = false;
if ( wp_mail_smtp()->is_blocked() ) {
$is_emailing_blocked = true;
}
// Always allow a test email - check for the specific header.
foreach ( (array) $this->getCustomHeaders() as $header ) {
if (
! empty( $header[0] ) &&
! empty( $header[1] ) &&
$header[0] === 'X-Mailer-Type' &&
trim( $header[1] ) === 'WPMailSMTP/Admin/Test'
) {
$is_emailing_blocked = false;
}
};
// Do not send emails if admin desired that.
if ( $is_emailing_blocked ) {
return false;
}
// Define a custom header, that will be used to identify the plugin and the mailer.
$this->XMailer = 'WPMailSMTP/Mailer/' . $mail_mailer . ' ' . 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'
) {
try {
// Prepare all the headers.
if ( ! $this->preSend() ) {
return false;
}
// Allow to hook after all the preparation before the actual sending.
do_action( 'wp_mail_smtp_mailcatcher_smtp_send_before', $this );
return $this->postSend();
} catch ( \phpmailerException $e ) {
$this->mailHeader = '';
$this->setError( $e->getMessage() );
if ( $this->exceptions ) {
throw $e;
}
return false;
}
}
// We need this so that the \PHPMailer class will correctly prepare all the headers.
$this->Mailer = 'mail';
// Prepare everything (including the message) for sending.
if ( ! $this->preSend() ) {
return false;
}
$mailer = wp_mail_smtp()->get_providers()->get_mailer( $mail_mailer, $this );
if ( ! $mailer ) {
return false;
}
if ( ! $mailer->is_php_compatible() ) {
return false;
}
/*
* Send the actual email.
* We reuse everything, that was preprocessed for usage in \PHPMailer.
*/
$mailer->send();
$is_sent = $mailer->is_email_sent();
// Allow to perform any actions with the data.
do_action( 'wp_mail_smtp_mailcatcher_send_after', $mailer, $this );
return $is_sent;
}
/**
* Returns all custom headers.
* In older versions of \PHPMailer class this method didn't exist.
* As we support WordPress 3.6+ - we need to make sure this method is always present.
*
* @since 1.5.0
*
* @return array
*/
public function getCustomHeaders() {
return $this->CustomHeader;
}
}
<?php
namespace WPMailSMTP;
// Load PHPMailer class, so we can subclass it.
if ( ! class_exists( 'PHPMailer', false ) ) {
require_once ABSPATH . WPINC . '/class-phpmailer.php';
}
/**
* Class MailCatcher replaces the \PHPMailer and modifies the email sending logic.
* Thus, we can use other mailers API to do what we need, or stop emails completely.
*
* @since 1.0.0
*/
class MailCatcher extends \PHPMailer {
/**
* Callback Action function name.
*
* The function that handles the result of the send email action.
* It is called out by send() for each email sent.
*
* @since 1.3.0
*
* @var string
*/
public $action_function = '\WPMailSMTP\Processor::send_callback';
/**
* Modify the default send() behaviour.
* For those mailers, that relies on PHPMailer class - call it directly.
* For others - init the correct provider and process it.
*
* @since 1.0.0
* @since 1.4.0 Process "Do Not Send" option, but always allow test email.
*
* @throws \phpmailerException When sending via PhpMailer fails for some reason.
*
* @return bool
*/
public function send() {
$options = new Options();
$mail_mailer = sanitize_key( $options->get( 'mail', 'mailer' ) );
$is_emailing_blocked = false;
if ( wp_mail_smtp()->is_blocked() ) {
$is_emailing_blocked = true;
}
// Always allow a test email - check for the specific header.
foreach ( (array) $this->getCustomHeaders() as $header ) {
if (
! empty( $header[0] ) &&
! empty( $header[1] ) &&
$header[0] === 'X-Mailer-Type' &&
trim( $header[1] ) === 'WPMailSMTP/Admin/Test'
) {
$is_emailing_blocked = false;
}
};
// Do not send emails if admin desired that.
if ( $is_emailing_blocked ) {
return false;
}
// Define a custom header, that will be used to identify the plugin and the mailer.
$this->XMailer = 'WPMailSMTP/Mailer/' . $mail_mailer . ' ' . 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'
) {
try {
// Prepare all the headers.
if ( ! $this->preSend() ) {
return false;
}
// Allow to hook after all the preparation before the actual sending.
do_action( 'wp_mail_smtp_mailcatcher_smtp_send_before', $this );
return $this->postSend();
} catch ( \phpmailerException $e ) {
$this->mailHeader = '';
$this->setError( $e->getMessage() );
// Set the debug error, but not for default PHP mailer.
if ( $mail_mailer !== 'mail' ) {
Debug::set(
'Mailer: ' . esc_html( wp_mail_smtp()->get_providers()->get_options( $mail_mailer )->get_title() ) . PHP_EOL .
$e->getMessage()
);
}
if ( $this->exceptions ) {
throw $e;
}
return false;
}
}
// We need this so that the \PHPMailer class will correctly prepare all the headers.
$this->Mailer = 'mail';
// Prepare everything (including the message) for sending.
if ( ! $this->preSend() ) {
return false;
}
$mailer = wp_mail_smtp()->get_providers()->get_mailer( $mail_mailer, $this );
if ( ! $mailer ) {
return false;
}
if ( ! $mailer->is_php_compatible() ) {
return false;
}
/*
* Send the actual email.
* We reuse everything, that was preprocessed for usage in \PHPMailer.
*/
$mailer->send();
$is_sent = $mailer->is_email_sent();
// Allow to perform any actions with the data.
do_action( 'wp_mail_smtp_mailcatcher_send_after', $mailer, $this );
return $is_sent;
}
/**
* Returns all custom headers.
* In older versions of \PHPMailer class this method didn't exist.
* As we support WordPress 3.6+ - we need to make sure this method is always present.
*
* @since 1.5.0
*
* @return array
*/
public function getCustomHeaders() {
return $this->CustomHeader;
}
}

View File

@ -1,257 +1,401 @@
<?php
namespace WPMailSMTP;
/**
* Class Migration helps migrate all plugin options saved into DB to a new storage location.
*
* @since 1.0.0
*/
class Migration {
/**
* All old values for pre 1.0 version of a plugin.
*
* @since 1.0.0
*
* @var array
*/
protected $old_keys = array(
'pepipost_ssl',
'pepipost_port',
'pepipost_pass',
'pepipost_user',
'smtp_pass',
'smtp_user',
'smtp_auth',
'smtp_ssl',
'smtp_port',
'smtp_host',
'mail_set_return_path',
'mailer',
'mail_from_name',
'mail_from',
'wp_mail_smtp_am_notifications_hidden',
);
/**
* Old values, taken from $old_keys options.
*
* @since 1.0.0
*
* @var array
*/
protected $old_values = array();
/**
* Converted array of data from previous option values.
*
* @since 1.0.0
*
* @var array
*/
protected $new_values = array();
/**
* Migration constructor.
*
* @since 1.0.0
*/
public function __construct() {
if ( $this->is_migrated() ) {
return;
}
$this->old_values = $this->get_old_values();
$this->new_values = $this->get_converted_options();
Options::init()->set( $this->new_values, true );
// Removing all old options will be enabled some time in the future.
// $this->clean_deprecated_data();
}
/**
* Whether we already migrated or not.
*
* @since 1.0.0
*
* @return bool
*/
protected function is_migrated() {
$is_migrated = false;
$new_values = get_option( Options::META_KEY, array() );
if ( ! empty( $new_values ) ) {
$is_migrated = true;
}
return $is_migrated;
}
/**
* Get all old values from DB.
*
* @since 1.0.0
*
* @return array
*/
protected function get_old_values() {
$old_values = array();
foreach ( $this->old_keys as $old_key ) {
$value = get_option( $old_key, '' );
if ( ! empty( $value ) ) {
$old_values[ $old_key ] = $value;
}
}
return $old_values;
}
/**
* Convert old values from key=>value to a multidimensional array of data.
*
* @since 1.0.0
*/
protected function get_converted_options() {
$converted = array();
foreach ( $this->old_keys as $old_key ) {
$old_value = isset( $this->old_values[ $old_key ] ) ? $this->old_values[ $old_key ] : '';
switch ( $old_key ) {
case 'pepipost_user':
case 'pepipost_pass':
case 'pepipost_port':
case 'pepipost_ssl':
// Do not migrate pepipost options if it's not activated at the moment.
if ( isset( $this->old_values['mailer'] ) && $this->old_values['mailer'] === 'pepipost' ) {
$shortcut = explode( '_', $old_key );
if ( $old_key === 'pepipost_ssl' ) {
$converted[ $shortcut[0] ]['encryption'] = $old_value;
} else {
$converted[ $shortcut[0] ][ $shortcut[1] ] = $old_value;
}
}
break;
case 'smtp_host':
case 'smtp_port':
case 'smtp_ssl':
case 'smtp_auth':
case 'smtp_user':
case 'smtp_pass':
$shortcut = explode( '_', $old_key );
if ( $old_key === 'smtp_ssl' ) {
$converted[ $shortcut[0] ]['encryption'] = $old_value;
} elseif ( $old_key === 'smtp_auth' ) {
$converted[ $shortcut[0] ][ $shortcut[1] ] = ( $old_value === 'true' ? 'yes' : 'no' );
} else {
$converted[ $shortcut[0] ][ $shortcut[1] ] = $old_value;
}
break;
case 'mail_from':
$converted['mail']['from_email'] = $old_value;
break;
case 'mail_from_name':
$converted['mail']['from_name'] = $old_value;
break;
case 'mail_set_return_path':
$converted['mail']['return_path'] = ( $old_value === 'true' );
break;
case 'mailer':
$converted['mail']['mailer'] = $old_value;
break;
case 'wp_mail_smtp_am_notifications_hidden':
$converted['general']['am_notifications_hidden'] = ( isset( $old_value ) && $old_value === 'true' );
break;
}
}
$converted = $this->get_converted_constants_options( $converted );
return $converted;
}
/**
* Some users use constants in wp-config.php to define values.
* We need to prioritize them and reapply data to options.
* Use only those that are actually defined.
*
* @since 1.0.0
*
* @param array $converted
*
* @return array
*/
protected function get_converted_constants_options( $converted ) {
// Are we configured via constants?
if ( ! defined( 'WPMS_ON' ) || ! WPMS_ON ) {
return $converted;
}
/*
* Mail settings.
*/
if ( defined( 'WPMS_MAIL_FROM' ) ) {
$converted['mail']['from_email'] = WPMS_MAIL_FROM;
}
if ( defined( 'WPMS_MAIL_FROM_NAME' ) ) {
$converted['mail']['from_name'] = WPMS_MAIL_FROM_NAME;
}
if ( defined( 'WPMS_MAILER' ) ) {
$converted['mail']['mailer'] = WPMS_MAILER;
}
if ( defined( 'WPMS_SET_RETURN_PATH' ) ) {
$converted['mail']['return_path'] = WPMS_SET_RETURN_PATH;
}
/*
* SMTP settings.
*/
if ( defined( 'WPMS_SMTP_HOST' ) ) {
$converted['smtp']['host'] = WPMS_SMTP_HOST;
}
if ( defined( 'WPMS_SMTP_PORT' ) ) {
$converted['smtp']['port'] = WPMS_SMTP_PORT;
}
if ( defined( 'WPMS_SSL' ) ) {
$converted['smtp']['ssl'] = WPMS_SSL;
}
if ( defined( 'WPMS_SMTP_AUTH' ) ) {
$converted['smtp']['auth'] = WPMS_SMTP_AUTH;
}
if ( defined( 'WPMS_SMTP_USER' ) ) {
$converted['smtp']['user'] = WPMS_SMTP_USER;
}
if ( defined( 'WPMS_SMTP_PASS' ) ) {
$converted['smtp']['pass'] = WPMS_SMTP_PASS;
}
return $converted;
}
/**
* Delete all old values that are stored separately each.
*
* @since 1.0.0
*/
protected function clean_deprecated_data() {
foreach ( $this->old_keys as $old_key ) {
delete_option( $old_key );
}
}
}
<?php
namespace WPMailSMTP;
use WPMailSMTP\Tasks\Meta;
/**
* Class Migration helps migrate plugin options, DB tables and more.
*
* @since 1.0.0 Migrate all plugin options saved from separate WP options into one.
* @since 2.1.0 Major overhaul of this class to use DB migrations (or any other migrations per version).
*/
class Migration {
/**
* Version of the latest migration.
*
* @since 2.1.0
*/
const VERSION = 2;
/**
* Option key where we save the current migration version.
*
* @since 2.1.0
*/
const OPTION_NAME = 'wp_mail_smtp_migration_version';
/**
* Current migration version, received from self::OPTION_NAME WP option
*
* @since 2.1.0
*
* @var int
*/
protected $cur_ver;
/**
* All old values for pre 1.0 version of a plugin.
*
* @since 1.0.0
*
* @var array
*/
protected $old_keys = array(
'pepipost_ssl',
'pepipost_port',
'pepipost_pass',
'pepipost_user',
'smtp_pass',
'smtp_user',
'smtp_auth',
'smtp_ssl',
'smtp_port',
'smtp_host',
'mail_set_return_path',
'mailer',
'mail_from_name',
'mail_from',
'wp_mail_smtp_am_notifications_hidden',
);
/**
* Old values, taken from $old_keys options.
*
* @since 1.0.0
*
* @var array
*/
protected $old_values = array();
/**
* Converted array of data from previous option values.
*
* @since 1.0.0
*
* @var array
*/
protected $new_values = array();
/**
* Migration constructor.
*
* @since 1.0.0
* @since 2.1.0 Redefined constructor - major overhaul.
*/
public function __construct() {
$this->cur_ver = self::get_cur_version();
$this->maybe_migrate();
}
/**
* Static on purpose, to get current migration version without __construct() and validation.
*
* @since 2.1.0
*
* @return int
*/
public static function get_cur_version() {
return (int) get_option( self::OPTION_NAME, 0 );
}
/**
* Run the migration if needed.
*
* @since 2.1.0
*/
protected function maybe_migrate() {
if ( ! is_admin() ) {
return;
}
if ( version_compare( $this->cur_ver, self::VERSION, '<' ) ) {
$this->run( self::VERSION );
}
}
/**
* Actual migration launcher.
*
* @since 2.1.0
*
* @param int $version The version of migration to run.
*/
protected function run( $version ) {
$function_version = (int) $version;
if ( method_exists( $this, 'migrate_to_' . $function_version ) ) {
$this->{'migrate_to_' . $function_version}();
} else {
$message = sprintf( /* translators: %1$s - WP Mail SMTP, %2$s - error message. */
esc_html__( 'There was an error while upgrading the database. Please contact %1$s support with this information: %2$s.', 'wp-mail-smtp' ),
'<strong>WP Mail SMTP</strong>',
'<code>migration from v' . self::get_cur_version() . ' to v' . self::VERSION . ' failed. Plugin version: v' . WPMS_PLUGIN_VER . '</code>'
);
WP::add_admin_notice( $message, WP::ADMIN_NOTICE_ERROR );
}
}
/**
* Update migration version in options table.
*
* @since 2.1.0
*
* @param int $version Migration version.
*/
protected function update_db_ver( $version ) {
if ( empty( $version ) ) {
$version = self::VERSION;
}
// Autoload it, because this value is checked all the time
// and no need to request it separately from all autoloaded options.
update_option( self::OPTION_NAME, $version, true );
}
/**
* Prevent running the same migration twice.
* Run migration only when required.
*
* @since 2.1.0
*
* @param string $version The version of migration to check for potential execution.
*/
protected function maybe_required_older_migrations( $version ) {
if ( version_compare( $this->cur_ver, $version, '<' ) ) {
$this->run( $version );
}
}
/**
* Migration from 0.x to 1.0.0.
* Move separate plugin WP options to one main plugin WP option setting.
*
* @since 2.1.0
*/
private function migrate_to_1() {
if ( $this->is_migrated() ) {
return;
}
$this->old_values = $this->get_old_values();
$this->new_values = $this->get_converted_options();
Options::init()->set( $this->new_values, true );
$this->update_db_ver( 1 );
}
/**
* Migration from 1.x to 2.1.0.
* Create Tasks\Meta table, if it does not exist.
*
* @since 2.1.0
*/
private function migrate_to_2() {
$this->maybe_required_older_migrations( 1 );
$meta = new Meta();
// Create the table if it doesn't exist.
if ( $meta && ! $meta->table_exists() ) {
$meta->create_table();
}
$this->update_db_ver( 2 );
}
/**
* Whether we already migrated or not.
*
* @since 1.0.0
*
* @return bool
*/
protected function is_migrated() {
$is_migrated = false;
$new_values = get_option( Options::META_KEY, array() );
if ( ! empty( $new_values ) ) {
$is_migrated = true;
}
return $is_migrated;
}
/**
* Get all old values from DB.
*
* @since 1.0.0
*
* @return array
*/
protected function get_old_values() {
$old_values = array();
foreach ( $this->old_keys as $old_key ) {
$value = get_option( $old_key, '' );
if ( ! empty( $value ) ) {
$old_values[ $old_key ] = $value;
}
}
return $old_values;
}
/**
* Convert old values from key=>value to a multidimensional array of data.
*
* @since 1.0.0
*/
protected function get_converted_options() {
$converted = array();
foreach ( $this->old_keys as $old_key ) {
$old_value = isset( $this->old_values[ $old_key ] ) ? $this->old_values[ $old_key ] : '';
switch ( $old_key ) {
case 'pepipost_user':
case 'pepipost_pass':
case 'pepipost_port':
case 'pepipost_ssl':
// Do not migrate pepipost options if it's not activated at the moment.
if ( isset( $this->old_values['mailer'] ) && $this->old_values['mailer'] === 'pepipost' ) {
$shortcut = explode( '_', $old_key );
if ( $old_key === 'pepipost_ssl' ) {
$converted[ $shortcut[0] ]['encryption'] = $old_value;
} else {
$converted[ $shortcut[0] ][ $shortcut[1] ] = $old_value;
}
}
break;
case 'smtp_host':
case 'smtp_port':
case 'smtp_ssl':
case 'smtp_auth':
case 'smtp_user':
case 'smtp_pass':
$shortcut = explode( '_', $old_key );
if ( $old_key === 'smtp_ssl' ) {
$converted[ $shortcut[0] ]['encryption'] = $old_value;
} elseif ( $old_key === 'smtp_auth' ) {
$converted[ $shortcut[0] ][ $shortcut[1] ] = ( $old_value === 'true' ? 'yes' : 'no' );
} else {
$converted[ $shortcut[0] ][ $shortcut[1] ] = $old_value;
}
break;
case 'mail_from':
$converted['mail']['from_email'] = $old_value;
break;
case 'mail_from_name':
$converted['mail']['from_name'] = $old_value;
break;
case 'mail_set_return_path':
$converted['mail']['return_path'] = ( $old_value === 'true' );
break;
case 'mailer':
$converted['mail']['mailer'] = $old_value;
break;
case 'wp_mail_smtp_am_notifications_hidden':
$converted['general']['am_notifications_hidden'] = ( isset( $old_value ) && $old_value === 'true' );
break;
}
}
$converted = $this->get_converted_constants_options( $converted );
return $converted;
}
/**
* Some users use constants in wp-config.php to define values.
* We need to prioritize them and reapply data to options.
* Use only those that are actually defined.
*
* @since 1.0.0
*
* @param array $converted
*
* @return array
*/
protected function get_converted_constants_options( $converted ) {
// Are we configured via constants?
if ( ! defined( 'WPMS_ON' ) || ! WPMS_ON ) {
return $converted;
}
/*
* Mail settings.
*/
if ( defined( 'WPMS_MAIL_FROM' ) ) {
$converted['mail']['from_email'] = WPMS_MAIL_FROM;
}
if ( defined( 'WPMS_MAIL_FROM_NAME' ) ) {
$converted['mail']['from_name'] = WPMS_MAIL_FROM_NAME;
}
if ( defined( 'WPMS_MAILER' ) ) {
$converted['mail']['mailer'] = WPMS_MAILER;
}
if ( defined( 'WPMS_SET_RETURN_PATH' ) ) {
$converted['mail']['return_path'] = WPMS_SET_RETURN_PATH;
}
/*
* SMTP settings.
*/
if ( defined( 'WPMS_SMTP_HOST' ) ) {
$converted['smtp']['host'] = WPMS_SMTP_HOST;
}
if ( defined( 'WPMS_SMTP_PORT' ) ) {
$converted['smtp']['port'] = WPMS_SMTP_PORT;
}
if ( defined( 'WPMS_SSL' ) ) {
$converted['smtp']['ssl'] = WPMS_SSL;
}
if ( defined( 'WPMS_SMTP_AUTH' ) ) {
$converted['smtp']['auth'] = WPMS_SMTP_AUTH;
}
if ( defined( 'WPMS_SMTP_USER' ) ) {
$converted['smtp']['user'] = WPMS_SMTP_USER;
}
if ( defined( 'WPMS_SMTP_PASS' ) ) {
$converted['smtp']['pass'] = WPMS_SMTP_PASS;
}
return $converted;
}
/**
* Delete all old values that are stored separately each.
*
* @since 1.0.0
*/
protected function clean_deprecated_data() {
foreach ( $this->old_keys as $old_key ) {
delete_option( $old_key );
}
}
}

View File

@ -19,21 +19,22 @@ class Options {
* @since 1.4.0 Added Mailgun:region.
* @since 1.5.0 Added Outlook/AmazonSES.
* @since 1.8.0 Added Pepipost API.
* @since 2.0.0 Added SMTP.com API.
*
* @since
*
* @var array Map of all the default options of the plugin.
*/
private static $map = array(
'mail' => array(
private static $map = [
'mail' => [
'from_name',
'from_email',
'mailer',
'return_path',
'from_name_force',
'from_email_force',
),
'smtp' => array(
],
'smtp' => [
'host',
'port',
'encryption',
@ -41,62 +42,64 @@ class Options {
'auth',
'user',
'pass',
),
'gmail' => array(
],
'gmail' => [
'client_id',
'client_secret',
),
'outlook' => array(
],
'outlook' => [
'client_id',
'client_secret',
),
'amazonses' => array(
],
'amazonses' => [
'client_id',
'client_secret',
'region',
'emails_pending',
),
'mailgun' => array(
],
'mailgun' => [
'api_key',
'domain',
'region',
),
'sendgrid' => array(
],
'sendgrid' => [
'api_key',
),
'smtpcom' => array(
],
'smtpcom' => [
'api_key',
'channel',
),
'sendinblue' => array(
],
'sendinblue' => [
'api_key',
),
'pepipostapi' => array(
],
'pepipostapi' => [
'api_key',
),
'pepipost' => array(
],
'pepipost' => [
'host',
'port',
'encryption',
'auth',
'user',
'pass',
),
'license' => array(
],
'license' => [
'key',
),
);
],
];
/**
* That's where plugin options are saved in wp_options table.
*
* @var string
* @since 1.0.0
*/
const META_KEY = 'wp_mail_smtp';
/**
* All the plugin options.
*
* @since 1.0.0
*
* @var array
*/
private $_options = array();
@ -141,6 +144,7 @@ class Options {
* Default options that are saved on plugin activation.
*
* @since 1.3.0
* @since 2.1.0 Set the Force from email to "on" by default.
*
* @return array
*/
@ -152,7 +156,7 @@ class Options {
'from_name' => get_bloginfo( 'name' ),
'mailer' => 'mail',
'return_path' => false,
'from_email_force' => false,
'from_email_force' => true,
'from_name_force' => false,
),
'smtp' => array(
@ -784,7 +788,7 @@ class Options {
* @since 1.5.0 Added Outlook/AmazonSES, Email Log. Stop saving const values into DB.
*
* @param array $options Plugin options to save.
* @param bool $once Whether to update existing options or to add these options only once.
* @param bool $once Whether to update existing options or to add these options only once.
*/
public function set( $options, $once = false ) {
/*

View File

@ -9,6 +9,18 @@ namespace WPMailSMTP;
*/
class Processor {
/**
* This attribute will hold the "original" WP from email address passed to the wp_mail_from filter,
* that is not equal to the default email address.
*
* It should hold an email address set via the wp_mail_from filter, before we might overwrite it.
*
* @since 2.1.0
*
* @var string
*/
protected $wp_mail_from;
/**
* Processor constructor.
*
@ -81,6 +93,11 @@ class Processor {
$phpmailer->SMTPAutoTLS = false;
}
// Check if original WP from email can be set as the reply_to attribute.
if ( $this->allow_setting_original_from_email_to_reply_to( $phpmailer->getReplyToAddresses(), $mailer ) ) {
$phpmailer->addReplyTo( $this->wp_mail_from );
}
// If we're sending via SMTP, set the host.
if ( 'smtp' === $mailer ) {
// Set the other options.
@ -104,12 +121,62 @@ class Processor {
$phpmailer->Password = $options->get( $mailer, 'pass' );
}
// Maybe set default reply-to header.
$this->set_default_reply_to( $phpmailer );
// You can add your own options here.
// See the phpmailer documentation for more info: https://github.com/PHPMailer/PHPMailer/tree/5.2-stable.
/** @noinspection PhpUnusedLocalVariableInspection It's passed by reference. */
$phpmailer = apply_filters( 'wp_mail_smtp_custom_options', $phpmailer );
}
/**
* Check if it's allowed to set the original WP from email to the reply_to field.
*
* @since 2.1.0
*
* @param array $reply_to Array of currently set reply to emails.
* @param string $mailer The slug of current mailer.
*
* @return bool
*/
protected function allow_setting_original_from_email_to_reply_to( $reply_to, $mailer ) {
$options = new Options();
$forced = $options->get( 'mail', 'from_email_force' );
$from_email = $options->get( 'mail', 'from_email' );
if ( ! empty( $reply_to ) ) {
return false;
}
if ( in_array( $mailer, array( 'gmail', 'outlook' ), true ) ) {
$forced = true;
switch ( $mailer ) {
case 'gmail':
$sender = wp_mail_smtp()->get_providers()->get_auth( 'gmail' )->get_user_info();
break;
case 'outlook':
$sender = $options->get( 'outlook', 'user_details' );
break;
}
$from_email = ! empty( $sender['email'] ) ? $sender['email'] : '';
}
if (
empty( $this->wp_mail_from ) ||
$from_email === $this->wp_mail_from ||
! $forced
) {
return false;
}
return true;
}
/**
* This method will be called every time 'smtp' and 'mail' mailers will be used to send emails.
*
@ -157,6 +224,11 @@ class Processor {
$from_email = $options->get( 'mail', 'from_email' );
$def_email = $this->get_default_email();
// Save the "original" set WP email from address for later use.
if ( $wp_email !== $def_email ) {
$this->wp_mail_from = $wp_email;
}
// Return FROM EMAIL if forced in settings.
if ( $forced & ! empty( $from_email ) ) {
return $from_email;
@ -250,4 +322,34 @@ class Processor {
return $phpmailer;
}
/**
* Set the default reply_to header, if:
* - no other reply_to headers are already set and,
* - the default reply_to address filter `wp_mail_smtp_processor_default_reply_to_addresses` is configured.
*
* @since 2.1.1
*
* @param \PHPMailer $phpmailer The PHPMailer object.
*/
private function set_default_reply_to( $phpmailer ) {
if ( ! empty( $phpmailer->getReplyToAddresses() ) ) {
return;
}
$default_reply_to_emails = apply_filters( 'wp_mail_smtp_processor_set_default_reply_to', '' );
if ( empty( $default_reply_to_emails ) ) {
return;
}
foreach ( explode( ',', $default_reply_to_emails ) as $email ) {
$email = trim( $email );
if ( filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
$phpmailer->addReplyTo( $email );
}
}
}
}

View File

@ -92,26 +92,28 @@ class Mailer extends MailerAbstract {
$this->phpmailer->Sender = $gmail_creds['email'];
}
// Get the raw MIME email using MailCatcher data.
// We need here to make base64URL-safe string.
$base64 = str_replace(
array( '+', '/', '=' ),
array( '-', '_', '' ),
base64_encode( $this->phpmailer->getSentMIMEMessage() )
);
$message->setRaw( $base64 );
$service = new \Google_Service_Gmail( $auth->get_client() );
try {
// Prepare a message for sending.
$this->phpmailer->preSend();
// Get the raw MIME email using MailCatcher data.
// We need here to make base64URL-safe string.
$base64 = str_replace(
[ '+', '/', '=' ],
[ '-', '_', '' ],
base64_encode( $this->phpmailer->getSentMIMEMessage() ) //phpcs:ignore
);
$message->setRaw( $base64 );
$service = new \Google_Service_Gmail( $auth->get_client() );
$response = $service->users_messages->send( 'me', $message );
$this->process_response( $response );
} catch ( \Exception $e ) {
Debug::set(
'Mailer: Gmail' . "\r\n" .
$e->getMessage()
$this->process_exception_message( $e->getMessage() )
);
return;
@ -124,7 +126,7 @@ class Mailer extends MailerAbstract {
* @since 1.0.0
* @since 1.5.0 Added action "wp_mail_smtp_providers_gmail_mailer_process_response" with $response.
*
* @param \Google_Service_Gmail_Message $response
* @param \Google_Service_Gmail_Message $response Instance of Gmail response.
*/
protected function process_response( $response ) {
@ -160,7 +162,12 @@ class Mailer extends MailerAbstract {
}
/**
* @inheritdoc
* This method is relevant to SMTP and Pepipost.
* All other custom mailers should override it with own information.
*
* @since 1.2.0
*
* @return string
*/
public function get_debug_info() {
@ -200,7 +207,11 @@ class Mailer extends MailerAbstract {
}
/**
* @inheritdoc
* Whether the mailer has all its settings correctly set up and saved.
*
* @since 1.4.0
*
* @return bool
*/
public function is_mailer_complete() {
@ -219,4 +230,75 @@ class Mailer extends MailerAbstract {
return false;
}
/**
* Process the exception message and append additional explanation to it.
*
* @since 2.1.0
*
* @param mixed $message A string or an object with strings.
*
* @return string
*/
protected function process_exception_message( $message ) {
// Transform the passed message to a string.
if ( ! is_string( $message ) ) {
$message = wp_json_encode( $message );
} else {
$message = wp_strip_all_tags( $message, false );
}
// Define known errors, that we will scan the message with.
$known_errors = array(
array(
'errors' => array(
'invalid_grant',
),
'explanation' => esc_html__( 'Please re-grant Google app permissions!', 'wp-mail-smtp' ) . ' ' . PHP_EOL .
esc_html__( 'Go to WP Mail SMTP plugin settings page. Click the “Remove Connection” button.', 'wp-mail-smtp' ) . ' ' . PHP_EOL .
esc_html__( 'Then click the “Allow plugin to send emails using your Google account” button and re-enable access.', 'wp-mail-smtp' ),
),
);
// Check if we get a match and append the explanation to the original message.
foreach ( $known_errors as $error ) {
foreach ( $error['errors'] as $error_fragment ) {
if ( false !== strpos( $message, $error_fragment ) ) {
return $message . PHP_EOL . $error['explanation'];
}
}
}
// If we get no match we return the original message (as a string).
return $message;
}
/**
* Get the default email addresses for the reply to email parameter.
*
* @deprecated 2.1.1
*
* @since 2.1.0
* @since 2.1.1 Not used anymore.
*
* @return array
*/
public function default_reply_to_addresses() {
_deprecated_function( __CLASS__ . '::' . __METHOD__, '2.1.1 of WP Mail SMTP plugin' );
$gmail_creds = ( new Auth() )->get_user_info();
if ( empty( $gmail_creds['email'] ) ) {
return [];
}
return [
$gmail_creds['email'] => [
$gmail_creds['email'],
'',
],
];
}
}

View File

@ -132,8 +132,8 @@ class Loader {
*
* @since 1.0.0
*
* @param string $provider
* @param MailCatcher $phpmailer
* @param string $provider The provider name.
* @param MailCatcher|\PHPMailer $phpmailer The MailCatcher object.
*
* @return MailerAbstract|null
*/

View File

@ -414,4 +414,54 @@ abstract class MailerAbstract implements MailerInterface {
return implode( '<br>', $smtp_text );
}
/**
* Get the email addresses for the reply to email parameter.
*
* @deprecated 2.1.1
*
* @since 2.1.0
* @since 2.1.1 Not used anymore.
*
* @return array
*/
public function get_reply_to_addresses() {
_deprecated_function( __CLASS__ . '::' . __METHOD__, '2.1.1 of WP Mail SMTP plugin' );
$reply_to = $this->phpmailer->getReplyToAddresses();
// Return the passed reply to addresses, if defined.
if ( ! empty( $reply_to ) ) {
return $reply_to;
}
// Return the default reply to addresses.
return apply_filters(
'wp_mail_smtp_providers_mailer_default_reply_to_addresses',
$this->default_reply_to_addresses()
);
}
/**
* Get the default email addresses for the reply to email parameter.
*
* @deprecated 2.1.1
*
* @since 2.1.0
* @since 2.1.1 Not used anymore.
*
* @return array
*/
public function default_reply_to_addresses() {
_deprecated_function( __CLASS__ . '::' . __METHOD__, '2.1.1 of WP Mail SMTP plugin' );
return [
$this->phpmailer->From => [
$this->phpmailer->From,
$this->phpmailer->FromName,
],
];
}
}

View File

@ -344,20 +344,12 @@ abstract class OptionsAbstract implements OptionsInterface {
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-pass" spellcheck="false" autocomplete="new-password"
/>
<p class="desc">
<?php esc_html_e( 'The password is stored in plain text. We highly recommend you set up your password in your WordPress configuration file for improved security.', 'wp-mail-smtp' ); ?>
<?php esc_html_e( 'The password will be stored in plain text. For improved security, we highly recommend using your site\'s WordPress configuration file to set your password.', 'wp-mail-smtp' ); ?>
<br>
<?php
printf(
/* translators: %s - wp-config.php. */
esc_html__( 'To do this add the lines below to your %s file:', 'wp-mail-smtp' ),
'<code>wp-config.php</code>'
);
?>
<a href="https://wpmailsmtp.com/docs/how-to-secure-smtp-settings-by-using-constants/" target="_blank" rel="noopener noreferrer">
<strong><?php esc_html_e( 'Learn More', 'wp-mail-smtp' ); ?></strong>
</a>
</p>
<pre>
define( 'WPMS_ON', true );
define( 'WPMS_SMTP_PASS', 'your_password' );
</pre>
<?php endif; ?>
</div>
</div>
@ -440,13 +432,21 @@ abstract class OptionsAbstract implements OptionsInterface {
<blockquote>
<?php
printf(
/* translators: %s - Provider name. */
esc_html__( '%s requires a SSL certificate on a site to work and does not support your current installation. Please contact your host and request a SSL certificate or install a free one, like Let\'s Encrypt.', 'wp-mail-smtp' ),
wp_kses( /* translators: %s - Provider name */
__( '%s requires an SSL certificate, and so is not currently compatible with your site. Please contact your host to request a SSL certificate, or check out <a href="https://www.wpbeginner.com/wp-tutorials/how-to-add-ssl-and-https-in-wordpress/" target="_blank">WPBeginner\'s tutorial on how to set up SSL</a>.', 'wp-mail-smtp' ),
[
'a' => [
'href' => [],
'target' => [],
],
]
),
esc_html( $this->get_title() )
);
?>
<br>
<?php esc_html_e( 'Meanwhile you can switch to some other mailers.', 'wp-mail-smtp' ); ?>
<br>
<?php esc_html_e( 'If you\'d prefer not to set up SSL, or need an SMTP solution in the meantime, please select a different mailer option.', 'wp-mail-smtp' ); ?>
</blockquote>
<?php

View File

@ -38,7 +38,7 @@ class Options extends OptionsAbstract {
$description = sprintf(
wp_kses( /* translators: %s - URL to smtp.com site. */
__( '<strong><a href="%s" target="_blank" rel="noopener noreferrer">SMTP.com</a> is a recommended transactional email service.</strong> With over 22 years of email delivery expertise, SMTP.com has been around for almost as long as email itself. They are known among internet providers as one of the most reliable senders on the internet. Their easy integration process lets you start sending emails in minutes and benefit from years of experience. SMTP.com provides users 10,000 free emails the first 30 days.', 'wp-mail-smtp' ),
__( '<strong><a href="%s" target="_blank" rel="noopener noreferrer">SMTP.com</a> is a recommended transactional email service.</strong> With a 22 years of track record of reliable email delivery, SMTP.com is a premiere solution for WordPress developers and website owners. SMTP.com has been around for almost as long as email itself. Their super simple integration interface makes it easy to get started while a powerful API and robust documentation make it a preferred choice among developers. Start a 30-day free trial with 50,000 emails.', 'wp-mail-smtp' ),
$allowed_kses_html
),
'https://wpmailsmtp.com/go/smtp/'

View File

@ -0,0 +1,527 @@
<?php
namespace WPMailSMTP\Tasks;
/**
* Class Meta helps to manage the tasks meta information
* between Action Scheduler and WP Mail SMTP hooks arguments.
* We can't pass arguments longer than >191 chars in JSON to AS,
* so we need to store them somewhere (and clean from time to time).
*
* @since 2.1.0
*/
class Meta {
/**
* Database table name.
*
* @since 2.1.0
*
* @var string
*/
public $table_name;
/**
* Database version.
*
* @since 2.1.0
*
* @var string
*/
public $version;
/**
* Primary key (unique field) for the database table.
*
* @since 2.1.0
*
* @var string
*/
public $primary_key = 'id';
/**
* Database type identifier.
*
* @since 2.1.0
*
* @var string
*/
public $type = 'tasks_meta';
/**
* Primary class constructor.
*
* @since 2.1.0
*/
public function __construct() {
$this->table_name = self::get_table_name();
}
/**
* Get the DB table name.
*
* @since 2.1.0
*
* @return string
*/
public static function get_table_name() {
global $wpdb;
return $wpdb->prefix . 'wpmailsmtp_tasks_meta';
}
/**
* Get table columns.
*
* @since 2.1.0
*/
public function get_columns() {
return array(
'id' => '%d',
'action' => '%s',
'data' => '%s',
'date' => '%s',
);
}
/**
* Default column values.
*
* @since 2.1.0
*
* @return array
*/
public function get_column_defaults() {
return array(
'action' => '',
'data' => '',
'date' => gmdate( 'Y-m-d H:i:s' ),
);
}
/**
* Retrieve a row from the database based on a given row ID.
*
* @since 2.1.0
*
* @param int $row_id Row ID.
*
* @return null|object
*/
private function get_from_db( $row_id ) {
global $wpdb;
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
return $wpdb->get_row(
$wpdb->prepare(
"SELECT * FROM {$this->table_name} WHERE {$this->primary_key} = %s LIMIT 1;", // phpcs:ignore
$row_id
)
);
}
/**
* Retrieve a row based on column and row ID.
*
* @since 2.1.0
*
* @param string $column Column name.
* @param int|string $row_id Row ID.
*
* @return object|null|bool Database query result, object or null on failure.
*/
public function get_by( $column, $row_id ) {
global $wpdb;
if ( empty( $row_id ) || ! array_key_exists( $column, $this->get_columns() ) ) {
return false;
}
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
return $wpdb->get_row(
$wpdb->prepare(
"SELECT * FROM $this->table_name WHERE $column = '%s' LIMIT 1;", // phpcs:ignore
$row_id
)
);
}
/**
* Retrieve a value based on column name and row ID.
*
* @since 2.1.0
*
* @param string $column Column name.
* @param int|string $row_id Row ID.
*
* @return string|null Database query result (as string), or null on failure.
*/
public function get_column( $column, $row_id ) {
global $wpdb;
if ( empty( $row_id ) || ! array_key_exists( $column, $this->get_columns() ) ) {
return false;
}
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
return $wpdb->get_var(
$wpdb->prepare(
"SELECT $column FROM $this->table_name WHERE $this->primary_key = '%s' LIMIT 1;", // phpcs:ignore
$row_id
)
);
}
/**
* Retrieve one column value based on another given column and matching value.
*
* @since 2.1.0
*
* @param string $column Column name.
* @param string $column_where Column to match against in the WHERE clause.
* @param string $column_value Value to match to the column in the WHERE clause.
*
* @return string|null Database query result (as string), or null on failure.
*/
public function get_column_by( $column, $column_where, $column_value ) {
global $wpdb;
if ( empty( $column ) || empty( $column_where ) || empty( $column_value ) || ! array_key_exists( $column, $this->get_columns() ) ) {
return false;
}
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
return $wpdb->get_var(
$wpdb->prepare(
"SELECT $column FROM $this->table_name WHERE $column_where = %s LIMIT 1;", // phpcs:ignore
$column_value
)
);
}
/**
* Insert a new record into the database.
*
* @since 2.1.0
*
* @param array $data Column data.
* @param string $type Optional. Data type context.
*
* @return int ID for the newly inserted record. 0 otherwise.
*/
private function add_to_db( $data, $type = '' ) {
global $wpdb;
// Set default values.
$data = wp_parse_args( $data, $this->get_column_defaults() );
do_action( 'wp_mail_smtp_pre_insert_' . $type, $data );
// Initialise column format array.
$column_formats = $this->get_columns();
// Force fields to lower case.
$data = array_change_key_case( $data );
// White list columns.
$data = array_intersect_key( $data, $column_formats );
// Reorder $column_formats to match the order of columns given in $data.
$data_keys = array_keys( $data );
$column_formats = array_merge( array_flip( $data_keys ), $column_formats );
$wpdb->insert( $this->table_name, $data, $column_formats );
do_action( 'wp_mail_smtp_post_insert_' . $type, $wpdb->insert_id, $data );
return $wpdb->insert_id;
}
/**
* Update an existing record in the database.
*
* @since 2.1.0
*
* @param int|string $row_id Row ID for the record being updated.
* @param array $data Optional. Array of columns and associated data to update. Default empty array.
* @param string $where Optional. Column to match against in the WHERE clause. If empty, $primary_key
* will be used. Default empty.
* @param string $type Optional. Data type context, e.g. 'affiliate', 'creative', etc. Default empty.
*
* @return bool False if the record could not be updated, true otherwise.
*/
public function update( $row_id, $data = array(), $where = '', $type = '' ) {
global $wpdb;
// Row ID must be a positive integer.
$row_id = absint( $row_id );
if ( empty( $row_id ) ) {
return false;
}
if ( empty( $where ) ) {
$where = $this->primary_key;
}
do_action( 'wp_mail_smtp_pre_update_' . $type, $data );
// Initialise column format array.
$column_formats = $this->get_columns();
// Force fields to lower case.
$data = array_change_key_case( $data );
// White list columns.
$data = array_intersect_key( $data, $column_formats );
// Reorder $column_formats to match the order of columns given in $data.
$data_keys = array_keys( $data );
$column_formats = array_merge( array_flip( $data_keys ), $column_formats );
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
if ( false === $wpdb->update( $this->table_name, $data, array( $where => $row_id ), $column_formats ) ) {
return false;
}
do_action( 'wp_mail_smtp_post_update_' . $type, $data );
return true;
}
/**
* Delete a record from the database.
*
* @since 2.1.0
*
* @param int|string $row_id Row ID.
*
* @return bool False if the record could not be deleted, true otherwise.
*/
public function delete( $row_id = 0 ) {
global $wpdb;
// Row ID must be positive integer.
$row_id = absint( $row_id );
if ( empty( $row_id ) ) {
return false;
}
do_action( 'wp_mail_smtp_pre_delete', $row_id );
do_action( 'wp_mail_smtp_pre_delete_' . $this->type, $row_id );
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
if ( false === $wpdb->query( $wpdb->prepare( "DELETE FROM {$this->table_name} WHERE {$this->primary_key} = %d", $row_id ) ) ) { // phpcs:ignore
return false;
}
do_action( 'wp_mail_smtp_post_delete', $row_id );
do_action( 'wp_mail_smtp_post_delete_' . $this->type, $row_id );
return true;
}
/**
* Delete a record from the database by column.
*
* @since 2.1.0
*
* @param string $column Column name.
* @param int|string $column_value Column value.
*
* @return bool False if the record could not be deleted, true otherwise.
*/
public function delete_by( $column, $column_value ) {
global $wpdb;
if ( empty( $column ) || empty( $column_value ) || ! array_key_exists( $column, $this->get_columns() ) ) {
return false;
}
do_action( 'wp_mail_smtp_pre_delete', $column_value );
do_action( 'wp_mail_smtp_pre_delete_' . $this->type, $column_value );
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
if ( false === $wpdb->query( $wpdb->prepare( "DELETE FROM {$this->table_name} WHERE $column = %s", $column_value ) ) ) { // phpcs:ignore
return false;
}
do_action( 'wp_mail_smtp_post_delete', $column_value );
do_action( 'wp_mail_smtp_post_delete_' . $this->type, $column_value );
return true;
}
/**
* Check if the given table exists.
*
* @since 2.1.0
*
* @param string $table The table name. Defaults to the child class table name.
*
* @return string|null If the table name exists.
*/
public function table_exists( $table = '' ) {
global $wpdb;
if ( ! empty( $table ) ) {
$table = sanitize_text_field( $table );
} else {
$table = $this->table_name;
}
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
return $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) === $table;
}
/**
* Create custom entry meta database table.
* Used in migration.
*
* @since 2.1.0
*/
public function create_table() {
global $wpdb;
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
$charset_collate = '';
if ( ! empty( $wpdb->charset ) ) {
$charset_collate .= "DEFAULT CHARACTER SET {$wpdb->charset}";
}
if ( ! empty( $wpdb->collate ) ) {
$charset_collate .= " COLLATE {$wpdb->collate}";
}
$sql = "CREATE TABLE {$this->table_name} (
id bigint(20) NOT NULL AUTO_INCREMENT,
action varchar(255) NOT NULL,
data longtext NOT NULL,
date datetime NOT NULL,
PRIMARY KEY (id)
) {$charset_collate};";
dbDelta( $sql );
}
/**
* Remove queue records for a defined period of time in the past.
* Calling this method will remove queue records that are older than $period seconds.
*
* @since 2.1.0
*
* @param string $action Action that should be cleaned up.
* @param int $interval Number of seconds from now.
*
* @return int Number of removed tasks meta records.
*/
public function clean_by( $action, $interval ) {
global $wpdb;
if ( empty( $action ) || empty( $interval ) ) {
return 0;
}
$table = self::get_table_name();
$action = sanitize_key( $action );
$date = gmdate( 'Y-m-d H:i:s', time() - (int) $interval );
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
return (int) $wpdb->query(
$wpdb->prepare(
"DELETE FROM `$table` WHERE action = %s AND date < %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$action,
$date
)
);
}
/**
* Inserts a new record into the database.
*
* @since 2.1.0
*
* @param array $data Column data.
* @param string $type Optional. Data type context.
*
* @return int ID for the newly inserted record. 0 otherwise.
*/
public function add( $data, $type = '' ) {
if ( empty( $data['action'] ) || ! is_string( $data['action'] ) ) {
return 0;
}
$data['action'] = sanitize_key( $data['action'] );
if ( isset( $data['data'] ) ) {
$string = wp_json_encode( $data['data'] );
if ( $string === false ) {
$string = '';
}
/*
* We are encoding the string representation of all the data
* to make sure that nothing can harm the database.
* This is not an encryption, and we need this data later as is,
* so we are using one of the fastest way to do that.
* This data is removed from DB on a daily basis.
*/
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
$data['data'] = base64_encode( $string );
}
if ( empty( $type ) ) {
$type = $this->type;
}
return $this->add_to_db( $data, $type );
}
/**
* Retrieve a row from the database based on a given row ID.
*
* @since 2.1.0}
*
* @param int $meta_id Meta ID.
*
* @return null|object
*/
public function get( $meta_id ) {
$meta = $this->get_from_db( $meta_id );
if ( empty( $meta ) || empty( $meta->data ) ) {
return $meta;
}
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
$decoded = base64_decode( $meta->data );
if ( $decoded === false || ! is_string( $decoded ) ) {
$meta->data = '';
} else {
$meta->data = json_decode( $decoded, true );
}
return $meta;
}
}

View File

@ -0,0 +1,304 @@
<?php
namespace WPMailSMTP\Tasks;
/**
* Class Task.
*
* @since 2.1.0
*/
class Task {
/**
* This task is async (runs asap).
*
* @since 2.1.0
*/
const TYPE_ASYNC = 'async';
/**
* This task is a recurring.
*
* @since 2.1.0
*/
const TYPE_RECURRING = 'scheduled';
/**
* This task is run once.
*
* @since 2.1.0
*/
const TYPE_ONCE = 'once';
/**
* Type of the task.
*
* @since 2.1.0
*
* @var string
*/
private $type;
/**
* Action that will be used as a hook.
*
* @since 2.1.0
*
* @var string
*/
private $action;
/**
* Task meta ID.
*
* @since 2.1.0
*
* @var int
*/
private $meta_id;
/**
* All the params that should be passed to the hook.
*
* @since 2.1.0
*
* @var array
*/
private $params;
/**
* When the first instance of the job will run.
* Used for ONCE ane RECURRING tasks.
*
* @since 2.1.0
*
* @var int
*/
private $timestamp;
/**
* How long to wait between runs.
* Used for RECURRING tasks.
*
* @since 2.1.0
*
* @var int
*/
private $interval;
/**
* Task constructor.
*
* @since 2.1.0
*
* @param string $action Action of the task.
*
* @throws \InvalidArgumentException When action is not a string.
* @throws \UnexpectedValueException When action is empty.
*/
public function __construct( $action ) {
if ( ! is_string( $action ) ) {
throw new \InvalidArgumentException( 'Task action should be a string.' );
}
$this->action = sanitize_key( $action );
if ( empty( $this->action ) ) {
throw new \UnexpectedValueException( 'Task action cannot be empty.' );
}
}
/**
* Define the type of the task as async.
*
* @since 2.1.0
*
* @return Task
*/
public function async() {
$this->type = self::TYPE_ASYNC;
return $this;
}
/**
* Define the type of the task as recurring.
*
* @since 2.1.0
*
* @param int $timestamp When the first instance of the job will run.
* @param int $interval How long to wait between runs.
*
* @return Task
*/
public function recurring( $timestamp, $interval ) {
$this->type = self::TYPE_RECURRING;
$this->timestamp = (int) $timestamp;
$this->interval = (int) $interval;
return $this;
}
/**
* Define the type of the task as one-time.
*
* @since 2.1.0
*
* @param int $timestamp When the first instance of the job will run.
*
* @return Task
*/
public function once( $timestamp ) {
$this->type = self::TYPE_ONCE;
$this->timestamp = (int) $timestamp;
return $this;
}
/**
* Pass any number of params that should be saved to Meta table.
*
* @since 2.1.0
*
* @return Task
*/
public function params() {
$this->params = func_get_args();
return $this;
}
/**
* Register the action.
* Should be the final call in a chain.
*
* @since 2.1.0
*
* @return null|string Action ID.
*/
public function register() {
$action_id = null;
// No processing if ActionScheduler is not usable.
if ( ! wp_mail_smtp()->get_tasks()->is_usable() ) {
return $action_id;
}
// Save data to tasks meta table.
$task_meta = new Meta();
$this->meta_id = $task_meta->add(
[
'action' => $this->action,
'data' => $this->params,
]
);
if ( empty( $this->meta_id ) ) {
return $action_id;
}
switch ( $this->type ) {
case self::TYPE_ASYNC:
$action_id = $this->register_async();
break;
case self::TYPE_RECURRING:
$action_id = $this->register_recurring();
break;
case self::TYPE_ONCE:
$action_id = $this->register_once();
break;
}
return $action_id;
}
/**
* Register the async task.
*
* @since 2.1.0
*
* @return null|string Action ID.
*/
protected function register_async() {
if ( ! function_exists( 'as_enqueue_async_action' ) ) {
return null;
}
return as_enqueue_async_action(
$this->action,
[ 'tasks_meta_id' => $this->meta_id ],
Tasks::GROUP
);
}
/**
* Register the recurring task.
*
* @since 2.1.0
*
* @return null|string Action ID.
*/
protected function register_recurring() {
if ( ! function_exists( 'as_schedule_recurring_action' ) ) {
return null;
}
return as_schedule_recurring_action(
$this->timestamp,
$this->interval,
$this->action,
[ 'tasks_meta_id' => $this->meta_id ],
Tasks::GROUP
);
}
/**
* Register the one-time task.
*
* @since 2.1.0
*
* @return null|string Action ID.
*/
protected function register_once() {
if ( ! function_exists( 'as_schedule_single_action' ) ) {
return null;
}
return as_schedule_single_action(
$this->timestamp,
$this->action,
[ 'tasks_meta_id' => $this->meta_id ],
Tasks::GROUP
);
}
/**
* Cancel all occurrences of this task.
*
* @since 2.1.0
*
* @return null|bool|string Null if no matching action found,
* false if AS library is missing,
* string of the scheduled action ID if a scheduled action was found and unscheduled.
*/
public function cancel() {
// Exit if AS function does not exist.
if ( ! function_exists( 'as_unschedule_all_actions' ) ) {
return false;
}
return as_unschedule_all_actions( $this->action );
}
}

View File

@ -0,0 +1,150 @@
<?php
namespace WPMailSMTP\Tasks;
/**
* Class Tasks manages the tasks queue and provides API to work with it.
*
* @since 2.1.0
*/
class Tasks {
/**
* Group that will be assigned to all actions.
*
* @since 2.1.0
*/
const GROUP = 'wp_mail_smtp';
/**
* Perform certain things on class init.
*
* @since 2.1.0
*/
public function init() {
// Register tasks.
foreach ( $this->get_tasks() as $task ) {
if ( ! is_subclass_of( $task, '\WPMailSMTP\Tasks\Task' ) ) {
continue;
}
$new_task = new $task();
// Run the init method, if a task has one defined.
if ( method_exists( $new_task, 'init' ) ) {
$new_task->init();
}
}
add_action( 'admin_menu', array( $this, 'admin_hide_as_menu' ), PHP_INT_MAX );
}
/**
* Get the list of default scheduled tasks.
* Tasks, that are fired under certain specific circumstances
* (like sending emails) are not listed here.
*
* @since 2.1.0
*
* @return Task[] List of tasks classes.
*/
public function get_tasks() {
return apply_filters( 'wp_mail_smtp_tasks_get_tasks', array() );
}
/**
* Hide Action Scheduler admin area when not in debug mode.
*
* @since 2.1.0
*/
public function admin_hide_as_menu() {
// Filter to redefine that WP Mail SMTP hides Tools > Action Scheduler menu item.
if ( apply_filters( 'wp_mail_smtp_tasks_admin_hide_as_menu', true ) ) {
remove_submenu_page( 'tools.php', 'action-scheduler' );
}
}
/**
* Create a new task.
* Used for "inline" tasks, that require additional information
* from the plugin runtime before they can be scheduled.
*
* Example:
* wp_mail_smtp()->get( 'tasks' )
* ->create( 'i_am_the_dude' )
* ->async()
* ->params( 'The Big Lebowski', 1998 )
* ->register();
*
* This `i_am_the_dude` action will be later processed as:
* add_action( 'i_am_the_dude', 'thats_what_you_call_me' );
*
* @since 2.1.0
*
* @param string $action Action that will be used as a hook.
*
* @return \WPMailSMTP\Tasks\Task
*/
public function create( $action ) {
return new Task( $action );
}
/**
* Cancel all the AS actions for a group.
*
* @since 2.1.0
*
* @param string $group Group to cancel all actions for.
*/
public function cancel_all( $group = '' ) {
if ( empty( $group ) ) {
$group = self::GROUP;
} else {
$group = sanitize_key( $group );
}
if ( class_exists( 'ActionScheduler_DBStore' ) ) {
\ActionScheduler_DBStore::instance()->cancel_actions_by_group( $group );
}
}
/**
* Whether ActionScheduler thinks that it has migrated or not.
*
* @since 2.1.0
*
* @return bool
*/
public function is_usable() {
// No tasks if ActionScheduler wasn't loaded.
if ( ! class_exists( 'ActionScheduler_DataController' ) ) {
return false;
}
return \ActionScheduler_DataController::is_migration_complete();
}
/**
* Whether task has been scheduled and is pending.
*
* @since 2.1.0
*
* @param string $hook Hook to check for.
*
* @return bool
*/
public function is_scheduled( $hook ) {
if ( ! function_exists( 'as_next_scheduled_action' ) ) {
return false;
}
return as_next_scheduled_action( $hook );
}
}

View File

@ -18,24 +18,32 @@ class WP {
*/
protected static $admin_notices = array();
/**
* CSS class for a success notice.
*
* @since 1.0.0
*
* @var string
*/
const ADMIN_NOTICE_SUCCESS = 'notice-success';
/**
* CSS class for an error notice.
*
* @since 1.0.0
*
* @var string
*/
const ADMIN_NOTICE_ERROR = 'notice-error';
/**
* CSS class for an info notice.
*
* @since 1.0.0
*
* @var string
*/
const ADMIN_NOTICE_INFO = 'notice-info';
/**
* CSS class for a warning notice.
*
* @since 1.0.0
*
* @var string
@ -43,7 +51,7 @@ class WP {
const ADMIN_NOTICE_WARNING = 'notice-warning';
/**
* True is WP is processing an AJAX call.
* True if WP is processing an AJAX call.
*
* @since 1.0.0
*
@ -103,7 +111,7 @@ class WP {
<div class="notice wp-mail-smtp-notice <?php echo esc_attr( $notice['class'] ); ?> notice <?php echo esc_attr( $dismissible ); ?>">
<p>
<?php echo $notice['message']; ?>
<?php echo wp_kses_post( $notice['message'] ); ?>
</p>
</div>
@ -160,7 +168,7 @@ class WP {
*
* @since 1.5.0
*
* @param string $string
* @param string $string String we want to test if it's json.
*
* @return bool
*/
@ -178,8 +186,7 @@ class WP {
*/
public static function datetime_format() {
return sprintf(
/* translators: %1$s - date, \a\t - specially escaped "at", %2$s - time. */
return sprintf( /* translators: %1$s - date, \a\t - specially escaped "at", %2$s - time. */
esc_html__( '%1$s \a\t %2$s', 'wp-mail-smtp' ),
get_option( 'date_format' ),
get_option( 'time_format' )
@ -199,14 +206,14 @@ class WP {
}
/**
* Sanitize the value, similar to sanitize_text_field(), but a bit differently.
* Sanitize the value, similar to `sanitize_text_field()`, but a bit differently.
* It preserves `<` and `>` for non-HTML tags.
*
* @since 1.5.0
*
* @param string $value
* @param string $value String we want to sanitize.
*
* @return mixed|string|string[]|null
* @return string
*/
public static function sanitize_value( $value ) {