site_name = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
$this->site_url = get_site_url();
$this->footer = (is_array(JVB_EMAIL['content']['footer'])) ? implode('', JVB_EMAIL['content']['footer']) : JVB_EMAIL['content']['footer'];
add_filter('wp_mail_content_type', [$this, 'setHtmlContentType']);
// User registration emails
add_filter('wp_new_user_notification_email', [$this, 'customizeNewUserEmail'], 999, 3);
add_filter('wp_new_user_notification_email_admin', [$this, 'customizeNewUserEmailAdmin'], 999, 3);
// Password reset emails
add_filter('retrieve_password_message', [$this, 'customizePasswordResetEmail'], 999, 4);
add_filter('retrieve_password_title', [$this, 'customizePasswordResetTitle'], 999, 3);
// User email change emails
add_filter('email_change_email', [$this, 'customizeEmailChangeEmail'], 999, 3);
add_filter('new_user_email_content', [$this, 'customizeNewUserEmailContent'], 999, 2);
// Password change notification
add_filter('password_change_email', [$this, 'customizePasswordChangeEmail'], 999, 3);
// User request/export data emails
add_filter('user_request_action_email_content', [$this, 'customizeUserRequestEmail'], 999, 2);
add_filter('wp_privacy_personal_data_email_content', [$this, 'customizePersonalDataEmail'], 999, 3);
}
/**
* Helper to set content type to HTML
* @return string
*/
public function setHtmlContentType():string
{
return 'text/html';
}
/**
* Send a styled email using the common template
*
* @param string $to Recipient email address
* @param string $subject Email subject line
* @param string $message Email body content (can contain HTML)
* @param string $header Optional header text for the template
* @return bool Whether the email was sent successfully
*/
public function sendEmail(string $to, string $subject, string $message, string $header = '', string $preheader = '', array $headers = [], array $attachments = []):bool
{
// Make sure the content type is set to HTML
add_filter('wp_mail_content_type', [$this, 'setHtmlContentType']);
// Format the message with our template
$formatted_message = $this->getEmailTemplate($message, $header, $preheader);
// Send the email
$result = wp_mail($to, $subject, $formatted_message, $headers, $attachments);
// Reset content type filter to avoid affecting other emails
remove_filter('wp_mail_content_type', [$this, 'setHtmlContentType']);
return $result;
}
/**
* Common email wrapper template
* @param string $content
* @param string $header
*
* @return string
*/
private function getEmailTemplate(string $content, string $headerText = '', string $preheader = ''):string
{
$custom_logo_id = get_theme_mod( 'custom_logo' );
$logo_thumbnail = wp_get_attachment_image_src( $custom_logo_id, 'custom-logo-thumbnail' );
$logo = ($logo_thumbnail) ? '' : '';
// Default header if none provided
if (empty($headerText)) {
$headerText = $this->title;
}
$preheaderHtml = '';
if (!empty($preheader)) {
$preheaderHtml = '
' . $headerText . '
Hi %s!
Thanks for signing up for an account on %s.
Your username: %s
Your password: Your chosen password.
', $user->display_name, get_bloginfo('name'), $user->user_login, ); $message = apply_filters('jvbNewUserEmail', $message, $user); $wp_new_user_notification_email['message'] = $this->getEmailTemplate($message, JVB_EMAIL['types']['newUser']['subject']?:'New User'); // Change the subject line $prefix = JVB_EMAIL['types']['newUser']['showPrefix']??true; $prefix = ($prefix) ? $this->prefix : ''; $wp_new_user_notification_email['subject'] = $prefix.JVB_EMAIL['types']['newUser']['subject']?:'New User'; return $wp_new_user_notification_email; } /** * New user registration email to admin * @param array $emailData * @param WP_User $user * @param string $blogname * * @return array */ public function customizeNewUserEmailAdmin(array $emailData, WP_User $user, string $blogname):array { $message = 'A new user has registered on ' . $this->site_name . ':
'; $message .= 'Username: ' . $user->user_login . '
'; $message .= 'Email: ' . $user->user_email . '
'; $message = apply_filters('jvbNewUserAdminEmail', $message, $user); $emailData['message'] = $this->getEmailTemplate($message, 'New User Registration'); $emailData['subject'] = $this->prefix .'New ' . str_replace(BASE, '', array_values($user->roles)[0]).': '.$user->display_name; return $emailData; } /** * Password reset email * @param string $message * @param string $key * @param string $user_login * @param WP_User $user_data * * @return string */ public function customizePasswordResetEmail(string $message, string $key, string $user_login, WP_User $user):string { return $this->passwordResetEmail($user, $key); } public function passwordResetEmail(WP_User $user, string $key):string { $reset_url = network_site_url("login/?action=resetpass&key=$key&login=" . rawurlencode($user->user_login), 'login'); $content = sprintf( 'Hi %s!
We received a request to reset the password for an account associated with this email:
Username: %s
If you didn\'t make this request, you can safely ignore this email and nothing will happen to your account.
To reset your password, click the button below:
%sOr copy and paste this link into your browser:
%s %sThis password reset link is only valid for 24 hours.
', $user->display_name, $user->user_login, $this->button($reset_url,'Reset Password'), $this->link($reset_url), $this->divider() ); return apply_filters('jvbPasswordResetEmail', $content, $user->user_login, $user, $reset_url); } public function sendPasswordResetEmail(WP_User $user, string $key):bool { return $this->sendEmail($user->user_email, $this->passwordResetTitle(), $this->passwordResetEmail($user, $key), '', 'Reset your Password'); } /** * Customize the password reset email title * @param string $title * @param string $user_login * @param WP_User $user_data * @return string */ public function customizePasswordResetTitle(string $title, string $user_login, WP_User $user_data):string { return $this->passwordResetTitle(); } public function passwordResetTitle():string { $prefix = JVB_EMAIL['types']['resetPass']['showPrefix']??true; $prefix = ($prefix) ? $this->prefix : ''; return $prefix.JVB_EMAIL['types']['resetPass']['subject']?:'Password Reset'; } /** * Email change notification to admin * @param array $email_change_email * @param array $oldUser * @param array $newUser * * @return array */ public function customizeEmailChangeEmail(array $email_change_email, array $oldUser, array $newUser):array { $content = sprintf( 'Hi %s,
Ideally you already know this: someone asked to change the email for your account.
Old Email: %s
New Email: %s
%sIf this is news to you, or you did not request this - please contact us immediately. You can text us or reply to this email.">
%s', $newUser['first_name'], $oldUser['user_email'], $newUser['user_email'], $this->divider(), $this->button(wp_login_url(), 'Log In To Your Account') ); $content = apply_filters('jvbEmailChangeRequestEmail', $content, $oldUser, $newUser); $email_change_email['message'] = $this->getEmailTemplate($content, 'Email Address Changed'); $prefix = JVB_EMAIL['types']['emailChange']['showPrefix']??true; $prefix = ($prefix) ? $this->prefix : ''; $email_change_email['subject'] = $prefix.JVB_EMAIL['types']['emailChange']['subject']?:'Email Address Changed'; return $email_change_email; } /** * New email address confirmation * @param string $email_text * @param array $user * * @return string */ public function customizeNewUserEmailContent(string $email_text, array $new_user_email):string { $confirm_url = esc_url( add_query_arg('newuseremail', $new_user_email['hash'], self_admin_url('profile.php'))); $content = sprintf( 'Hey,
There was a request to change the email address associated with your account to this one.
This is just a friendly email to ensure you would like this change.
You can confirm this change by clicking the button below:
%sOr copy and paste this link into your browser:
%s', $this->button($confirm_url, 'Confirm this Email'), $this->link($confirm_url) ); $content = apply_filters('jvbEmailChangedEmail', $content, $confirm_url); $content .= $this->divider(); $content .= 'If you did not request this change, you can safely ignore this email and nothing will change.
'; return $this->getEmailTemplate($content, 'Confirm Email Change'); } /** * Password change notification * @param array $pass_change_email * @param array $oldUser * @param array $newUser * * @return array */ public function customizePasswordChangeEmail(array $pass_change_email, array $oldUser, array $newUser):array { $content = sprintf( 'Hi %s,
This is a confirmation email to let you know your password has successfully been changed.
If you\'re not expecting this email, and did not change your password - please contact us immediately
You can text us, or reply to this email.
%s', $oldUser['first_name'], $this->button(wp_login_url(), 'Log In to Your Account') ); $content = apply_filters('jvbPasswordChangeEmail', $content, $oldUser, $newUser); $pass_change_email['message'] = $this->getEmailTemplate($content, 'Password Changed'); $prefix = JVB_EMAIL['types']['passwordChange']['showPrefix']??true; $prefix = ($prefix) ? $this->prefix : ''; $pass_change_email['subject'] = $prefix.JVB_EMAIL['types']['passwordChange']['subject']?:'Password Changed'; return $pass_change_email; } /** * User data request confirmation email * @param string $content * @param array $request_data * * @return string */ public function customizeUserRequestEmail(string $content, array $email_data):string { $confirm_url = $email_data['confirm_url']; $request_type = $email_data['action_name']; switch ($request_type) { case 'export_personal_data': $request_name = 'Export Personal Data'; break; case 'remove_personal_data': $request_name = 'Erase Personal Data'; break; default: $request_name = 'Data Request'; } $message = sprintf( 'Hi,
You\'re receiving this email because a request has been made to %s
If you\'re the one who made this request, you can confirm it by clicking the button below:
%sOr copy and paste this link into your browser:
%s', $request_name, $this->button($confirm_url, 'Confirm'), $this->link($confirm_url) ); $message = apply_filters('jvbPersonalDataExport', $message, $request_type, $confirm_url, $email_data); $message .= $this->divider(); $message .= 'If you did not make this request, you can safely ignore this email.
'; return $this->getEmailTemplate($message, 'Action Confirmation'); } /** * Personal data export email * @param string $content * @param int $request_id * @param array $email_data * * @return string */ public function customizePersonalDataEmail(string $content, int $request_id, array $email_data):string { $download_url = $email_data['export_file_url']; $expiresAt = $email_data['expiration_date']; $message = sprintf( 'Hi,
You\'re receiving this email because you requested an export of your personal data.
You can download your personal data by clicking the button below:
%sOr you can copy and paste this link into your browser:
%s %sImportant: For privacy and security, this link will expire at %s.
', $this->button($download_url, 'Download Your Data'), $this->link($download_url), $this->divider(), $expiresAt ); $message = apply_filters('jvbPersonalDataExported', $message, $download_url, $expiresAt, $email_data); return $this->getEmailTemplate($message, 'Your Personal Data Export'); } public function signature():string { return ''.$this->signature.'
'; } public function button(string $link, string $title):string { return sprintf( '', $link, $this->colours['action-0'], $this->colours['action-contrast'], $title ); } public function link(string $link):string { return sprintf( '%s',
$this->colours['dark-200'],
$this->colours['dark-100'],
$this->colours['light-100'],
$link
);
}
public function divider():string
{
return '';
}
public function notice(string $text):string
{
return '%s
', $this->colours['dark-200'], esc_html($description) ) : ''; return sprintf( '')) { $html .= $description; }else { $html .= sprintf( '
%s
', $description ); } } else { $html .= implode('',array_map(function ($p) { return sprintf('%s
', $p); }, $description)); } } } $html .= '%s',
$this->colours['light-100'],
$this->colours['dark-200'],
esc_html($code)
);
}
public function badge(string $text, string $type = 'default'):string
{
$colors = [
'success' => ['bg' => '#d4edda', 'text' => '#155724'],
'warning' => ['bg' => '#fff3cd', 'text' => '#856404'],
'error' => ['bg' => '#f8d7da', 'text' => '#721c24'],
'info' => ['bg' => '#d1ecf1', 'text' => '#0c5460'],
'default' => ['bg' => $this->colours['light-200'], 'text' => $this->colours['dark-200']]
];
$color = $colors[$type] ?? $colors['default'];
return sprintf(
'%s',
$color['bg'],
$color['text'],
esc_html($text)
);
}
public function alert(string $text, string $type = 'info'):string
{
$configs = [
'success' => ['bg' => '#d4edda', 'border' => '#28a745', 'text' => '#155724', 'icon' => '✓'],
'warning' => ['bg' => '#fff3cd', 'border' => '#ffc107', 'text' => '#856404', 'icon' => '⚠'],
'error' => ['bg' => '#f8d7da', 'border' => '#dc3545', 'text' => '#721c24', 'icon' => '✕'],
'info' => ['bg' => '#d1ecf1', 'border' => $this->colours['action-0'], 'text' => '#0c5460', 'icon' => 'ℹ']
];
$config = $configs[$type] ?? $configs['info'];
return sprintf(
'