$options Complete option value.
*
* @return bool
*/
public static function update_raw( array $options ): bool {
self::$raw_write = true;
try {
return update_option( SMTP_Email::OPTION_NAME, $options );
} finally {
self::$raw_write = false;
}
}
/**
* Option keys that only Pro's routing/failover/logging settings UI
* ever writes.
*
* @return string[]
*/
protected function get_pro_only_option_keys(): array {
return [
'additional_profiles',
'routing',
'rules',
'delivery_fallback',
'enable_delivery_log',
'delivery_log_retention_days',
];
}
/**
* Constructor
*
* @param array $options Array of options.
*/
public function __construct( array $options ) {
$this->options = $options;
add_action( 'admin_init', [ $this, 'init' ] );
add_action( 'wp_ajax_adminoptim_smtp_email_test', [ $this, 'send_email_test' ] );
add_action( 'wp_ajax_adminoptim_smtp_send_email', [ $this, 'send_email' ] );
add_action( 'admin_notices', [ $this, 'maybe_show_auth_change_notice' ] );
add_action( 'admin_bar_menu', [ $this, 'add_admin_bar_quick_mail_link' ], 100 );
add_action( 'wp_dashboard_setup', [ $this, 'add_dashboard_email_widget' ] );
}
/**
* Start the engine running
*
* @return void
*/
public function init() {
$this->settings_options = [
[
'option_group' => SMTP_Email::OPTION_NAME,
'option_name' => SMTP_Email::OPTION_NAME,
'args' => [ 'sanitize_callback' => [ $this, 'sanitize_settings' ] ],
],
];
// The settings screen is rendered by hand (see render_settings_page()), so only the option itself is registered; no WP Settings API sections or fields.
$this->setup();
}
/**
* Render Settings page
*
* @return void
*/
public function render_settings_page() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- sanitized via sanitize_key() inside sanitize_active_tab().
$active_tab = $this->sanitize_active_tab( $_GET['tab'] ?? 'settings' );
$send_prefill = 'send' === $active_tab ? $this->get_send_email_prefill() : [];
// sanitize_settings() always writes smtp_provider, so its presence means the form has been saved.
$smtp_saved = isset( $this->options['smtp_provider'] );
?>
>
', '' );
echo wp_kses( $upgrade_message, 'a' );
?>
$options SMTP options.
*
* @return void
*/
private function render_profiles_table( array $options ) {
$provider = $options['smtp_provider'] ?? 'generic';
$name = ! empty( $options['primary_profile_name'] ) ? $options['primary_profile_name'] : ( $this->get_provider_choices()[ $provider ] ?? __( 'Generic (Custom SMTP)', 'admin-optimizer' ) );
if ( $this->resets_on_delete_primary() ) {
$delete_message = __( 'Delete this SMTP configuration and start over? The saved credentials will be removed.', 'admin-optimizer' );
} else {
$next = reset( $options['additional_profiles'] );
/* translators: %s: name of the SMTP profile that becomes the primary. */
$delete_message = sprintf( __( 'Delete the primary SMTP configuration? “%s” becomes the primary profile.', 'admin-optimizer' ), ! empty( $next['name'] ) ? $next['name'] : __( 'The next profile', 'admin-optimizer' ) );
}
/**
* Filters the "Last Test" cell text for a profile row.
*
* Free keeps no test history; Pro answers this from its Delivery Log
* (test emails are logged with the `smtp_test` source).
*
* @param string $label Plain text, escaped on output. Default ''.
* @param string $profile_id Profile ID (`primary` for this row).
*/
$last_test = (string) apply_filters( 'adminoptim_smtp_profile_last_test', '', 'primary' );
?>
get_provider_choices()[ $provider ] ?? __( 'Generic (Custom SMTP)', 'admin-optimizer' ) ); ?>
$options SMTP options.
*
* @return void
*/
private function render_editor_rows( array $options ) {
// First run: start from the same defaults as a new additional profile (TLS, port 587, auth on).
if ( ! isset( $options['smtp_provider'] ) ) {
$options = array_merge( [ 'smtp_auth' => 1, 'smtp_secure' => 'tls', 'smtp_port' => 587 ], $options );
}
$name = static function ( $key ) {
return SMTP_Email::OPTION_NAME . '[editor][' . $key . ']';
};
/**
* Fires before the first editor row.
*
* Free renders the "Profile Name" row itself just after this hook;
* Pro can use it to add rows above that one.
*
* @param array $options Free's own SMTP options.
*/
do_action( 'adminoptim_smtp_primary_settings_rows_before', $options );
?>
get_provider_choices() as $value => $label ) : ?>
>
render_ses_region_select( $name( 'ses_region' ), 'smtp-ses-region', $options['smtp_ses_region'] ?? 'us-east-1' ); ?>
>
render_encryption_select( $name( 'encryption' ), 'smtp-secure', $options['smtp_secure'] ?? 'none' ); ?>
[ 'SMTP Server', 'text', 'smtp-server', 'smtp_server' ],
'port' => [ 'SMTP Port', 'number', 'smtp-port', 'smtp_port' ],
'username' => [ 'SMTP Username', 'text', 'smtp-username', 'smtp_username' ],
'password' => [ 'SMTP Password', 'password', 'smtp-password', 'smtp_password' ],
'from_name' => [ 'From Name', 'text', 'send-from', 'send_from', 'identity' ],
'from_email' => [ 'From Email', 'email', 'email-from', 'email_from', 'identity' ],
'reply_to' => [ 'Reply-To', 'email', 'reply-to', 'reply_to', 'identity' ],
];
?>
$field ) : ?>
>
>
>
>
*/
private function get_provider_choices() {
return [
'default_wp_mail' => __( 'Default WordPress Mail', 'admin-optimizer' ),
'generic' => __( 'Generic (Custom SMTP)', 'admin-optimizer' ),
'gmail' => __( 'Gmail', 'admin-optimizer' ),
'mailgun' => __( 'Mailgun', 'admin-optimizer' ),
'ses' => __( 'Amazon SES', 'admin-optimizer' ),
'sendgrid' => __( 'SendGrid', 'admin-optimizer' ),
'brevo' => __( 'Brevo (Sendinblue)', 'admin-optimizer' ),
'postmark' => __( 'Postmark', 'admin-optimizer' ),
];
}
/**
* Render SES region select.
*
* @param string $name Field name.
* @param string $id Field ID.
* @param string $selected Selected region.
*
* @return void
*/
private function render_ses_region_select( $name, $id, $selected ) {
?>
>
get_ses_regions() as $value => $label ) : ?>
>
>
'None', 'tls' => 'TLS', 'ssl' => 'SSL' ] as $value => $label ) : ?>
>
*/
private function get_ses_regions() {
return [
'us-east-1' => 'US East (N. Virginia)',
'us-east-2' => 'US East (Ohio)',
'us-west-1' => 'US West (N. California)',
'us-west-2' => 'US West (Oregon)',
'eu-west-1' => 'EU (Ireland)',
'eu-west-2' => 'EU (London)',
'eu-west-3' => 'EU (Paris)',
'eu-central-1' => 'EU (Frankfurt)',
'eu-north-1' => 'EU (Stockholm)',
'ap-southeast-1' => 'Asia Pacific (Singapore)',
'ap-southeast-2' => 'Asia Pacific (Sydney)',
'ap-northeast-1' => 'Asia Pacific (Tokyo)',
'ap-south-1' => 'Asia Pacific (Mumbai)',
'ca-central-1' => 'Canada (Central)',
'sa-east-1' => 'South America (Sao Paulo)',
];
}
/**
* Build an SMTP settings tab URL.
*
* @param string $tab Tab key.
*
* @return string
*/
private function get_tab_url( $tab ) {
return SMTP_Email::get_module_admin_url(
[ 'tab' => $this->sanitize_active_tab( $tab ) ]
);
}
/**
* Sanitize the active SMTP settings tab.
*
* @param mixed $tab Active tab value.
*
* @return string
*/
private function sanitize_active_tab( $tab ) {
$tab = sanitize_key( (string) $tab );
// The old "profiles" tab was merged into "settings"; it falls through to the default.
return in_array( $tab, [ 'settings', 'routing', 'send', 'delivery_log' ], true ) ? $tab : 'settings';
}
/**
* Read sanitized composer prefill values from the current request.
*
* @return array
*/
private function get_send_email_prefill() {
if ( ! current_user_can( 'manage_options' ) ) {
return [];
}
$query_map = [
'ao_email_to' => 'to',
'ao_email_cc' => 'cc',
'ao_email_bcc' => 'bcc',
'ao_email_subject' => 'subject',
'ao_email_message' => 'message',
'ao_email_context_type' => 'context_type',
'ao_email_context_id' => 'context_id',
'ao_email_return_url' => 'return_url',
'ao_email_profile' => 'profile_id',
];
$args = [];
$has_input = false;
foreach ( $query_map as $query_key => $arg_key ) {
if ( isset( $_GET[ $query_key ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$args[ $arg_key ] = wp_unslash( $_GET[ $query_key ] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$has_input = true;
}
}
// esc_url() (run on the composer URL wherever it's output) strips
// encoded line breaks and HTML delimiters from href values, so a
// multi-line or HTML body travels as base64 instead of plain text
// — see adminoptim_email_compose_url() in functions.php.
if ( isset( $_GET['ao_email_message_b64'] ) && is_scalar( $_GET['ao_email_message_b64'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$encoded_message = wp_unslash( (string) $_GET['ao_email_message_b64'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$encoded_message = strtr( $encoded_message, '-_', '+/' );
$padding_length = ( 4 - strlen( $encoded_message ) % 4 ) % 4;
$decoded_message = base64_decode( $encoded_message . str_repeat( '=', $padding_length ), true );
if ( false !== $decoded_message ) {
$args['message'] = $decoded_message;
$has_input = true;
}
}
if ( isset( $_GET['ao_email_html'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$args['html'] = ! empty( $_GET['ao_email_html'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$has_input = true;
}
if ( ! $has_input ) {
return [];
}
return adminoptim_email_sanitize_compose_args( $args );
}
/**
* Build a compact context note for the composer.
*
* @param array $prefill Prefill data.
*
* @return string
*/
private function get_send_email_context_note( array $prefill ) {
$context_type = isset( $prefill['context_type'] ) && is_scalar( $prefill['context_type'] ) ? sanitize_key( (string) $prefill['context_type'] ) : '';
$context_id = isset( $prefill['context_id'] ) && is_scalar( $prefill['context_id'] ) ? sanitize_text_field( (string) $prefill['context_id'] ) : '';
if ( '' === $context_type ) {
return '';
}
$labels = [
'form_entry' => __( 'Form Entry', 'admin-optimizer' ),
'woocommerce_order' => __( 'WooCommerce Order', 'admin-optimizer' ),
'user' => __( 'User', 'admin-optimizer' ),
];
$label = $labels[ $context_type ] ?? ucwords( str_replace( '_', ' ', $context_type ) );
$suffix = '' !== $context_id ? ' #' . $context_id : '';
return sprintf(
/* translators: %1$s: context label, %2$s: context ID. */
__( 'Composing email for %1$s%2$s.', 'admin-optimizer' ),
$label,
$suffix
);
}
/**
* Render routing selects.
*
* @return void
*/
private function render_routing_fields() {
$fields = [
'default_profile' => __( 'Default / Unknown Emails', 'admin-optimizer' ),
'transactional_profile' => __( 'Transactional Emails', 'admin-optimizer' ),
'marketing_profile' => __( 'Marketing Emails', 'admin-optimizer' ),
'admin_profile' => __( 'Admin Notifications', 'admin-optimizer' ),
'password_reset_profile' => __( 'Password Reset Emails', 'admin-optimizer' ),
'new_user_profile' => __( 'New User Emails', 'admin-optimizer' ),
'form_notification_profile' => __( 'Form Builder Notifications', 'admin-optimizer' ),
'form_autoresponder_profile' => __( 'Form Builder Autoresponders', 'admin-optimizer' ),
];
if ( class_exists( 'WooCommerce' ) ) {
$fields['woocommerce_profile'] = __( 'WooCommerce Emails', 'admin-optimizer' );
}
?>
$prefill Prefilled composer values.
*
* @return void
*/
private function render_send_email_fields( array $prefill = [] ) {
$context_note = $this->get_send_email_context_note( $prefill );
$return_url = isset( $prefill['return_url'] ) ? (string) $prefill['return_url'] : '';
?>
$options SMTP options.
*
* @return void
*/
private function render_send_email_shortcut_settings( array $options ) {
?>
options['add_quick_mail_admin_bar'] ) || ! current_user_can( 'manage_options' ) || ! is_admin_bar_showing() ) {
return;
}
if ( ! is_object( $wp_admin_bar ) || ! method_exists( $wp_admin_bar, 'add_node' ) ) {
return;
}
$wp_admin_bar->add_node(
[
'id' => 'adminoptim-smtp-quick-mail',
'title' => __( 'Quick Email', 'admin-optimizer' ),
'href' => $this->get_tab_url( 'send' ),
]
);
}
/**
* Add dashboard email widget.
*
* @return void
*/
public function add_dashboard_email_widget() {
if ( empty( $this->options['add_email_dashboard_widget'] ) || ! current_user_can( 'manage_options' ) ) {
return;
}
wp_add_dashboard_widget(
'adminoptim_smtp_email_widget',
__( 'Send Email', 'admin-optimizer' ),
[ $this, 'render_dashboard_email_widget' ]
);
}
/**
* Render dashboard email widget.
*
* @return void
*/
public function render_dashboard_email_widget() {
?>
$options Raw submitted options.
*
* @return array
*/
private function resolve_editor_input( array $options ) {
$map = [
'name' => 'primary_profile_name',
'provider' => 'smtp_provider',
'ses_region' => 'smtp_ses_region',
'host' => 'smtp_server',
'auth' => 'smtp_auth',
'encryption' => 'smtp_secure',
'port' => 'smtp_port',
'username' => 'smtp_username',
'password' => 'smtp_password',
'from_name' => 'send_from',
'from_email' => 'email_from',
'reply_to' => 'reply_to',
'auth_change_check' => 'auth_change_check',
'force_from' => 'force_from',
];
$editor = isset( $options['editor'] ) && is_array( $options['editor'] ) ? $options['editor'] : [];
if ( isset( $editor['target'] ) && 'primary' === $editor['target'] ) {
foreach ( $map as $from => $to ) {
unset( $options[ $to ] );
if ( isset( $editor[ $from ] ) ) {
$options[ $to ] = $editor[ $from ];
}
}
return $options;
}
$stored = get_option( SMTP_Email::OPTION_NAME, [] );
$stored = is_array( $stored ) ? $stored : [];
foreach ( $map as $to ) {
if ( ! isset( $options[ $to ] ) && isset( $stored[ $to ] ) ) {
$options[ $to ] = $stored[ $to ];
}
}
return $options;
}
/**
* Whether deleting the primary resets it to the first-run form. When
* Pro is active and additional profiles exist, Pro promotes the next
* profile instead (see SMTP_Email_Settings_Pro::sanitize_pro_fields()).
*
* @return bool
*/
private function resets_on_delete_primary() {
return ! Module_Registry::is_pro_active() || empty( $this->options['additional_profiles'] );
}
/**
* Saved options with the primary connection, sender identity and
* profile name removed, so the SMTP tab shows the first-run form again.
* Everything else (shortcut toggles, Pro routing/logging) is kept.
*
* @return array
*/
private function reset_primary_settings() {
$options = is_array( $this->options ) ? $this->options : [];
foreach ( [ 'smtp_provider', 'smtp_ses_region', 'smtp_server', 'smtp_auth', 'smtp_secure', 'smtp_port', 'smtp_username', 'smtp_password', 'send_from', 'email_from', 'reply_to', 'primary_profile_name', 'force_from', 'auth_change_check', 'auth_fingerprint' ] as $key ) {
unset( $options[ $key ] );
}
return $options;
}
/**
* Callback function to sanitize user options
*
* @param array $options User options.
*
* @return array
*/
public function sanitize_settings( $options ) {
// An internal write of already-validated settings (see update_raw()).
if ( self::$raw_write ) {
return $options;
}
$sanitized_options = [];
$protocol = [ 'none', 'tls', 'ssl' ];
$allowed_providers = array_keys( $this->get_provider_choices() );
$allowed_regions = [ 'us-east-1', 'us-east-2', 'us-west-1', 'us-west-2', 'eu-west-1', 'eu-west-2', 'eu-west-3', 'eu-central-1', 'eu-north-1', 'ap-southeast-1', 'ap-southeast-2', 'ap-northeast-1', 'ap-south-1', 'ca-central-1', 'sa-east-1' ];
if ( is_array( $options ) && Module_Registry::is_pro_active() ) {
/**
* Lets Pro save a part of the settings on its own (the Delivery
* Log tab's form) without rebuilding the whole option from a
* partial submission. Return the complete option array to use it
* as the saved value, or null to continue normally.
*
* @param array|null $result Null by default.
* @param array $options Raw submitted options.
*/
$short_circuit = apply_filters( 'adminoptim_smtp_sanitize_settings_short_circuit', null, $options );
if ( is_array( $short_circuit ) ) {
return $short_circuit;
}
}
if ( is_array( $options ) && ! empty( $options['delete_primary'] ) && $this->resets_on_delete_primary() ) {
return $this->reset_primary_settings();
}
if ( is_array( $options ) ) {
$options = $this->resolve_editor_input( $options );
// Only when submitted: a save that doesn't touch the primary (e.g. the Delivery Log form on a fresh install) must not mark it as configured.
if ( isset( $options['smtp_provider'] ) ) {
$sanitized_options['smtp_provider'] = in_array( $options['smtp_provider'], $allowed_providers, true ) ? $options['smtp_provider'] : 'generic';
}
if ( isset( $options['smtp_ses_region'] ) ) {
$sanitized_options['smtp_ses_region'] = in_array( $options['smtp_ses_region'], $allowed_regions, true ) ? $options['smtp_ses_region'] : 'us-east-1';
}
if ( isset( $options['primary_profile_name'] ) ) {
$sanitized_options['primary_profile_name'] = sanitize_text_field( $options['primary_profile_name'] );
}
if ( isset( $options['smtp_server'] ) ) {
$sanitized_options['smtp_server'] = sanitize_text_field( $options['smtp_server'] );
}
if ( isset( $options['smtp_auth'] ) ) {
$sanitized_options['smtp_auth'] = 1;
}
if ( isset( $options['smtp_secure'] ) ) {
$sanitized_options['smtp_secure'] = in_array( $options['smtp_secure'], $protocol, true ) ? sanitize_text_field( $options['smtp_secure'] ) : 'none';
}
if ( isset( $options['smtp_port'] ) ) {
$sanitized_options['smtp_port'] = absint( $options['smtp_port'] );
}
if ( isset( $options['smtp_username'] ) ) {
$sanitized_options['smtp_username'] = sanitize_text_field( $options['smtp_username'] );
}
$password_reentered = false;
if ( isset( $options['smtp_password'] ) ) {
$raw_password = SMTP_Email::sanitize_password( $options['smtp_password'] );
$existing_options = get_option( SMTP_Email::OPTION_NAME, [] );
if ( '' === $raw_password ) {
if ( ! empty( $existing_options['smtp_password'] ) ) {
$sanitized_options['smtp_password'] = $existing_options['smtp_password'];
}
} elseif ( SMTP_Email::is_stored_password( $raw_password ) ) {
// An already-stored value (an "enc:" value or a reference) is carried forward, not typed in.
$sanitized_options['smtp_password'] = $raw_password;
} else {
$sanitized_options['smtp_password'] = SMTP_Email::store_password( $raw_password, 'primary', $existing_options['smtp_password'] ?? '' );
$password_reentered = true;
}
}
$sanitized_options['auth_change_check'] = ! empty( $options['auth_change_check'] ) ? 1 : 0;
if ( isset( $options['send_from'] ) ) {
$sanitized_options['send_from'] = sanitize_text_field( $options['send_from'] );
}
if ( isset( $options['email_from'] ) ) {
$sanitized_options['email_from'] = sanitize_email( $options['email_from'] );
}
if ( isset( $options['reply_to'] ) ) {
$sanitized_options['reply_to'] = sanitize_email( $options['reply_to'] );
}
$sanitized_options['force_from'] = ! empty( $options['force_from'] ) ? 1 : 0;
$sanitized_options['add_quick_mail_admin_bar'] = ! empty( $options['add_quick_mail_admin_bar'] ) ? 1 : 0;
$sanitized_options['add_email_dashboard_widget'] = ! empty( $options['add_email_dashboard_widget'] ) ? 1 : 0;
// Only re-stamp the fingerprint when the password was typed in again (or none is stamped yet); otherwise an unrelated save would silence the AUTH-key-change warning while the saved password is still unreadable.
$stored_options = get_option( SMTP_Email::OPTION_NAME, [] );
$stored_fingerprint = is_array( $stored_options ) ? (string) ( $stored_options['auth_fingerprint'] ?? '' ) : '';
$sanitized_options['auth_fingerprint'] = ( $password_reentered || '' === $stored_fingerprint ) ? SMTP_Email::auth_fingerprint() : $stored_fingerprint;
if ( Module_Registry::is_pro_active() ) {
/**
* Filters in sanitized values for the Pro-owned SMTP
* settings (additional profiles, routing, advanced rules,
* delivery fallback) submitted from this same form.
*
* Free has no notion of these fields' shape; re-checking
* is_pro_active() here (rather than trusting that the
* submitted array simply contains them) is what keeps a
* crafted POST from writing Pro-owned data while Pro is
* inactive. Pro's callback receives the raw submitted
* $options and Free's own already-sanitized
* $sanitized_options, and must return only the keys it
* owns (see get_pro_only_option_keys()).
*
* @param array $pro_sanitized Empty by default.
* @param array $options Raw submitted options.
* @param array $sanitized_options Free's own sanitized values so far.
*/
$sanitized_options = array_merge(
$sanitized_options,
apply_filters( 'adminoptim_smtp_sanitize_pro_fields', [], $options, $sanitized_options )
);
}
}
return $this->carry_forward_inactive_pro_keys( $sanitized_options );
}
/**
* Show a warning if the auth keys/salts changed.
*
* @return void
*/
public function maybe_show_auth_change_notice() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$this->render_auth_change_notice();
}
/**
* Render the auth change notice if needed.
*
* @return void
*/
private function render_auth_change_notice() {
$options = get_option( SMTP_Email::OPTION_NAME, [] );
if ( ! SMTP_Email::has_auth_changed( $options ) ) {
return;
}
$settings_url = SMTP_Email::get_module_admin_url();
?>
'error',
]
)
)
);
}
check_ajax_referer( 'test_smtp_email', 'nonce' );
$response = [];
$success = false;
$profile_id = '';
$email_to = isset( $_POST['email_to'] ) && is_email( wp_unslash( $_POST['email_to'] ) ) ? sanitize_email( wp_unslash( $_POST['email_to'] ) ) : '';
if ( ! empty( $email_to ) ) {
$subject = get_bloginfo( 'name' ) . ' Email Test';
$body = "Congrats, test email was sent successfully. \n\nYour Faithful servant";
/**
* Optional SMTP profile ID to send this test through, submitted
* only by Pro's per-profile "Send test email" control. Free
* has no notion of profiles; it only relays the value through
* the two narrow actions below, which are no-ops unless Pro
* hooks them.
*/
$profile_id = isset( $_POST['profile_id'] ) && is_scalar( $_POST['profile_id'] ) ? sanitize_text_field( wp_unslash( $_POST['profile_id'] ) ) : '';
if ( '' !== $profile_id ) {
do_action( 'adminoptim_smtp_push_profile', $profile_id );
}
try {
// Tagged so Pro's Delivery Log can show it as the profile's last test (a no-op without Pro).
$sent = adminoptim_smtp_with_source(
'smtp_test',
static function () use ( $email_to, $subject, $body ) {
return wp_mail( $email_to, $subject, $body );
}
);
} finally {
if ( '' !== $profile_id ) {
do_action( 'adminoptim_smtp_pop_profile' );
}
}
if ( $sent ) {
$success = true;
} else {
$response['message'] = 'Sending is not successful.';
}
} else {
$response['message'] = 'Email address is empty.';
}
if ( $success ) {
wp_send_json_success( $response );
} else {
wp_send_json_error( $response );
}
}
/**
* Send a custom admin email.
*
* @return void
*/
public function send_email() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_send_json_error( [ 'message' => __( 'Unauthorized action.', 'admin-optimizer' ) ] );
}
check_ajax_referer( 'adminoptim_smtp_send_email', 'nonce' );
$return_url = '';
if ( isset( $_POST['return_url'] ) ) {
$raw_return_url = wp_unslash( $_POST['return_url'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$raw_return_url = is_scalar( $raw_return_url ) ? esc_url_raw( (string) $raw_return_url ) : '';
$return_url = '' !== $raw_return_url ? wp_validate_redirect( $raw_return_url, '' ) : '';
}
// adminoptim_email_send() applies this itself (via
// adminoptim_smtp_with_profile(), a no-op unless Pro hooks it) once
// it sanitizes the 'profile_id' key below.
$profile_id = isset( $_POST['profile_id'] ) && is_scalar( $_POST['profile_id'] ) ? wp_unslash( $_POST['profile_id'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$result = adminoptim_email_send(
[
'to' => isset( $_POST['to'] ) ? wp_unslash( $_POST['to'] ) : '', // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
'cc' => isset( $_POST['cc'] ) ? wp_unslash( $_POST['cc'] ) : '', // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
'bcc' => isset( $_POST['bcc'] ) ? wp_unslash( $_POST['bcc'] ) : '', // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
'subject' => isset( $_POST['subject'] ) ? wp_unslash( $_POST['subject'] ) : '', // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
'message' => isset( $_POST['message'] ) ? wp_unslash( $_POST['message'] ) : '', // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
'html' => ! empty( $_POST['send_as_html'] ),
'profile_id' => $profile_id,
]
);
if ( true === $result ) {
wp_send_json_success(
[
'message' => __( 'Delivery successful.', 'admin-optimizer' ),
'return_url' => $return_url,
]
);
}
$error_message = is_wp_error( $result ) ? $result->get_error_message() : __( 'wp_mail returned false.', 'admin-optimizer' );
wp_send_json_error(
[
'message' => __( 'Email delivery failed.', 'admin-optimizer' ),
'error' => $error_message,
]
);
}
}