get_bool( 'smtp_enabled', false ) ) { return; } $host = trim( (string) $s->get( 'smtp_host', '' ) ); $port = $s->get_int( 'smtp_port', 587 ); $user = trim( (string) $s->get( 'smtp_user', '' ) ); $pass = ADSD_RCC_Crypto::decrypt( (string) $s->get( 'smtp_pass', '' ) ); // decrypt stored password $enc = $s->get( 'smtp_encryption', 'tls' ); if ( ! $host || ! $user ) { return; } $phpmailer->isSMTP(); $phpmailer->Host = $host; $phpmailer->SMTPAuth = true; $phpmailer->Port = $port; $phpmailer->Username = $user; $phpmailer->Password = $pass; $phpmailer->SMTPSecure = ( $enc === 'ssl' ) ? PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_SMTPS : PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS; $phpmailer->setFrom( $this->from_email(), $this->from_name() ); $phpmailer->addReplyTo( $this->from_email(), $this->from_name() ); } // ─── Public API ─────────────────────────────────────────────────────────── public function send( string $to, string $template_key, array $vars = [] ): bool { $template = ADSD_RCC_DB::instance()->get_email_template( $template_key ); if ( ! $template ) { $this->log_mail_error( $to, $template_key, 'Template not found.' ); return false; } $vars = array_merge( $this->default_vars(), $vars ); $subject = $this->replace( $template->subject, $vars ); $heading = $this->replace( $template->heading, $vars ); $body = $this->replace( $template->body, $vars ); $btn = $this->replace( $template->button_text ?? '', $vars ); $footer = $this->replace( $template->footer ?? '', $vars ); $btn_url = $vars['{button_url}'] ?? ''; $html = $this->render_html( $heading, $body, $btn, $btn_url, $footer ); return $this->dispatch( $to, $subject, $html, $template_key ); } public function send_raw( string $to, string $subject, string $html ): bool { return $this->dispatch( $to, $subject, $html, 'raw' ); } public function get_last_error(): string { return $this->last_error; } // ─── Internal dispatch ──────────────────────────────────────────────────── private function dispatch( string $to, string $subject, string $html, string $context ): bool { $this->last_error = ''; // Guard: From Email must be configured $from = $this->from_email(); if ( ! $from || ! is_email( $from ) ) { $this->last_error = __( 'No valid From Email address configured. Go to Referral Rewards → Settings → Section 7 and set a From Email Address.', 'adsd-referral-couponcore' ); $this->log_mail_error( $to, $context, $this->last_error ); return false; } add_action( 'wp_mail_failed', [ $this, 'capture_mail_error' ] ); add_filter( 'wp_mail_content_type', [ $this, 'html_content_type' ] ); add_filter( 'wp_mail_from', [ $this, 'filter_from_email' ] ); add_filter( 'wp_mail_from_name', [ $this, 'filter_from_name' ] ); $sent = wp_mail( $to, $subject, $html, $this->build_headers() ); remove_filter( 'wp_mail_from_name', [ $this, 'filter_from_name' ] ); remove_filter( 'wp_mail_from', [ $this, 'filter_from_email' ] ); remove_filter( 'wp_mail_content_type', [ $this, 'html_content_type' ] ); remove_action( 'wp_mail_failed', [ $this, 'capture_mail_error' ] ); if ( ! $sent ) { $this->log_mail_error( $to, $context, $this->last_error ?: 'wp_mail returned false.' ); } return $sent; } // ─── WP filters ────────────────────────────────────────────────────────── public function html_content_type(): string { return 'text/html'; } public function filter_from_email(): string { return $this->from_email(); } public function filter_from_name(): string { return $this->from_name(); } public function capture_mail_error( WP_Error $error ): void { $msgs = $error->get_error_messages(); $this->last_error = implode( ' | ', $msgs ); } // ─── Test email AJAX ────────────────────────────────────────────────────── public function ajax_send_test_email(): void { if ( ! current_user_can( 'manage_options' ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ?? '' ) ), 'adsd_rcc_admin_nonce' ) ) { wp_send_json_error( [ 'message' => __( 'Security check failed.', 'adsd-referral-couponcore' ) ] ); return; } $to = sanitize_email( wp_unslash( $_POST['test_email'] ?? '' ) ); if ( ! is_email( $to ) ) { wp_send_json_error( [ 'message' => __( 'Please enter a valid recipient email address.', 'adsd-referral-couponcore' ) ] ); return; } $site = get_bloginfo( 'name' ); $from = $this->from_email(); $subject = sprintf( '[%s] ' . __( 'Test Email', 'adsd-referral-couponcore' ), $site ); /* translators: %1$s: site name, %2$s: configured From email address */ $body = sprintf( __( "Hi, This is a test email from %1\$s. From address: %2\$s If you received this, your email configuration is working correctly!", 'adsd-referral-couponcore' ), $site, $from ); $html = $this->render_html( __( 'Test Email — Sending works!', 'adsd-referral-couponcore' ), $body, '', '', __( 'Sent by AD-SD Referral CouponCore EcoSystem', 'adsd-referral-couponcore' ) ); $sent = $this->send_raw( $to, $subject, $html ); if ( $sent ) { wp_send_json_success( [ 'message' => sprintf( /* translators: %s: email */ __( '✓ Test email sent to %s. Check your inbox (and spam folder).', 'adsd-referral-couponcore' ), $to ), ] ); } else { wp_send_json_error( [ 'message' => sprintf( /* translators: %s: error */ __( '✗ Email failed. Error: %s', 'adsd-referral-couponcore' ), $this->last_error ?: __( 'Unknown error — check your SMTP or server mail settings.', 'adsd-referral-couponcore' ) ), ] ); } } // ─── Private helpers ────────────────────────────────────────────────────── private function from_name(): string { $name = trim( (string) ADSD_RCC_Settings::instance()->get( 'mail_from_name', '' ) ); return $name ?: get_bloginfo( 'name' ); } private function from_email(): string { $email = sanitize_email( (string) ADSD_RCC_Settings::instance()->get( 'mail_from_email', '' ) ); return is_email( $email ) ? $email : (string) get_option( 'admin_email' ); } private function build_headers(): array { return [ 'Content-Type: text/html; charset=UTF-8', 'MIME-Version: 1.0', ]; } private function default_vars(): array { return [ '{site_name}' => get_bloginfo( 'name' ), '{site_url}' => home_url( '/' ), ]; } private function replace( string $text, array $vars ): string { return str_replace( array_keys( $vars ), array_values( $vars ), $text ); } private function log_mail_error( string $to, string $template, string $error ): void { ADSD_RCC_DB::instance()->log( 'mail_error', null, null, "Failed [{$template}] to {$to}: {$error}", [ 'template' => $template, 'to' => $to, 'error' => $error ] ); } // ─── HTML renderer ──────────────────────────────────────────────────────── private function render_html( string $heading, string $body, string $btn_text, string $btn_url, string $footer ): string { // Safe HTML body — convert newlines then allow basic tags $body_html = wp_kses( wpautop( nl2br( $body ) ), [ 'p' => [ 'style' => [] ], 'br' => [], 'strong' => [], 'b' => [], 'em' => [], 'i' => [], 'a' => [ 'href' => [], 'style' => [] ], 'span' => [ 'style' => [] ], 'code' => [], ] ); $btn_html = ''; if ( $btn_text && $btn_url ) { $btn_html = '
' . esc_html__( 'Button not working? Copy this link:', 'adsd-referral-couponcore' ) . '
' . esc_url( $btn_url ) . '