אם כבר קיבלת מייל וורדפרס "איפוס סיסמה" עם עיבוד לקוי, או גרוע מכך, הודעה שמגיעה בטקסט רגיל לאחר שהכנתם בקפידה תבנית HTML, כבר נגעתם בבעיה האמיתית: וורדפרס שולחת מיילים ממקומות שונים מאוד (ליבה, תוספים, טפסים), עם כותרות משתנות וללא מערכת תבניות HTML מאוחדת.
הבעיה / הצורך
אתה רוצה הודעות דוא"ל יוצאות ממך אתר יש לזהות עקבית: לוגו, צבעים, טיפוגרפיה, כותרת תחתונה משפטית, ובאופן אידיאלי גרסת טקסט חלופית. כמו כן, כדאי להימנע מאימיילים שלא מגיעים עקב כותרות שגויות או HTML מורכב מדי.
צורך זה חל הן על אתרים פשוטים (מיילים של תגובות, מיילים של חשבונות משתמשים) והן על אתרים מתקדמים יותר (WooCommerce, טפסים, חברות). מניסיוני, נקודת החיכוך נוצרת כאשר מעורבבים מספר מקורות דוא"ל: תבנית שכופה HTML, תוסף SMTP שכותב מחדש כותרות, ובונה תוכן שמזריק CSS שאינו תואם דוא"ל.
בסופו של דבר, תדעו:
- כפיית הגשת HTML נקייה דרך
wp_mail()בלי לפגוע בתוספים, - מרכז תבנית HTML רב פעמית,
- ניהול משתנים (כותרת, תוכן, כפתור, כותרת תחתונה) בצורה מאובטחת,
- ניפוי שגיאות בכותרות ובעיבוד,
- לתכנן וריאציות (אימיילים של מנהלים, אימיילים של משתמשים, אימיילים של "טרנזקציות").
סיכום קצר
- אנו יוצרים מיני-תוסף שמקיף
wp_mail()ומיישם תבנית HTML שיטתית. - אנו משתמשים במסנני וורדפרס אמינים:
wp_mail_content_type,wp_mail_from,wp_mail_from_nameו -wp_mail(לבחון/לתקן את הטיעונים). - אנו יוצרים את ה-HTML באמצעות פונקציית רינדור שמקבלת משתנים, ואנחנו מבצעים escape בצורה נכונה (XSS קורה במיילים).
- אנו מוסיפים גרסת טקסט (חלופה) וכותרות עקביות.
- אנו מתעדים אסטרטגיית בדיקות (MailHog / Mailpit, יומני רישום, בדיקת כותרות) ושיטת פתרון בעיות.
מתי להשתמש בפתרון זה
- אתם רוצים מדיניות דוא"ל אחידה עבור דוא"ל שנשלח דרך
wp_mail()(הליבה + התוספים שלך, במידה שהם עוברים דרך ה-API של וורדפרס). - אתם צריכים מעטפת "ביתית" עבור האימיילים המותאמים אישית שלכם (הרשמה, תזכורת, הודעה פנימית).
- עליך לתקן אימיילים שנשלחים בטקסט רגיל לאחר שהכנת קוד HTML.
- אתם רוצים להוסיף כותרת תחתונה משפטית, קישור לביטול הרשמה (אם רלוונטי) או פרטי קשר.
- יש לך דרישות אספקה ואתה רוצה לשלוט על
From:ו -Reply-To:.
מתי לא להשתמש בפתרון זה
- אם אתם שולחים קמפיינים שיווקיים (ניוזלטרים), השתמשו ב-ESP (Brevo, Mailchimp וכו'). וורדפרס לא מיועדת לנפחי תפוקה גבוהים, ותתקשו עם יכולת המסירה.
- יש לכם WooCommerce ואתם רוצים להתאים אישית רק את האימיילים שלה: ל-WooCommerce יש מערכת תבניות משלה. אתם יכולים לעשות את זה, אבל מדריך זה מתמקד בצנרת.
wp_mail()כְּלָלִי. - אתם צריכים עורך אימייל ויזואלי עבור אנשים שאינם טכנולוגיים: תוסף ייעודי (עם תבניות) יתאים יותר.
- אתם צריכים לנהל תוכן רב-לשוני מורכב לכל משתמש: אתם יכולים לעשות זאת כאן, אבל שכבת i18n מובנית יותר (או פתרון ייעודי) תהיה נוחה יותר.
דרישות מוקדמות / לפני שמתחילים
הקשר: אפריל 2026, WordPress 6.9.4, PHP 8.1+. הקוד שלהלן מכוון לגרסאות אלו ונמנע מתבניות ממדריכים ישנים יותר (במיוחד פריצות גלובליות בלתי הפיכות על wp_mail_content_type).
- גיבוי (קבצים + מסד נתונים) לפני כל שינוי באתר ייצור.
- סביבה מקומית או סביבה בימוי.
- גישה ל
wp-content/pluginsכדי ליצור מיני-תוסף (מומלץ) או, אם זה לא עובד, תוסף אמין של snippets. - כלי בדיקת דוא"ל מקומי:
- Mailpit או MailHog (לכידת SMTP), או
- תוסף SMTP המאפשר לך לתעד אימיילים (תוך זהירות עם נתונים אישיים).
מקורות עיון שימושיים:
- תיעוד רשמי עבור wp_mail()
- מסנן wp_mail_content_type
- מסנן wp_mail_from
- מסנן wp_mail_from_name
- PHP: מסנני חיטוי
הגישה הנאיבית (ומדוע להימנע ממנה)
הקוד שאני רואה לרוב בביקורות נראה כך: ה-HTML נכפה באופן גלובלי, HTML מוטבע מוכנס להודעה, וסוג התוכן הקודם נשכח. התוצאה: תוסף של צד שלישי שולח אימייל HTML כאשר ציפה לטקסט רגיל, או להיפך.
<?php
// ❌ Exemple naïf : à ne pas copier tel quel.
add_filter('wp_mail_content_type', function () {
return 'text/html';
});
function mon_email_naif($to) {
$subject = 'Bienvenue';
$message = '<h1>Bienvenue</h1><p>Merci !</p>'; // HTML brut
wp_mail($to, $subject, $message);
}
למה זה אנטי-דפוס:
- תופעת לוואי כללית כל האימיילים באתר הם כעת ב-HTML, כולל אלו מתוספים שלא כללו אותו.
- כותרות לא עקביות חלק מתוספי ה-SMTP מוסיפים כותרות משלהם. שילוב גרוע יכול לפגוע ביכולת המסירה.
- אפס תחזוקה תשכפל את ה-HTML בעשרה מקומות.
- אבטחה אם תוכן ה-HTML מכיל נתוני משתמש שאינם בורחים, ניתן להחדיר HTML להודעות דוא"ל (פישינג פנימי, מעקב לא רצוי וכו').
הגישה הנכונה - מדריך שלב אחר שלב
שלב 1 - צור מיני-תוסף (ולא קטע טקסט בתוך ערכת העיצוב)
ערכת הנושא (אפילו ערכת נושא של צאצאים) אינה מקום טוב ללוגיקה של דוא"ל: אתם מסתכנים בשבירת הכל בעת שינוי ערכות נושא. צרו תוסף: wp-content/plugins/bpcab-email-kit/bpcab-email-kit.php.
שלב 2 - הגדרת "שכבת דוא"ל": עטיפת תבנית + תבנית
הרעיון: אתה מתקשר bpcab_mail() בקוד שלך. פונקציה זו:
- מכין את הכותרות,
- יוצר HTML נקי באמצעות תבנית.
- כופה את סוג התוכן רק במהלך תהליך השליחה,
- מחזירה את התוצאה של
wp_mail().
שלב 3 - יצירת HTML תואם לדוא"ל (וריאליסטי)
לקוחות הדוא"ל לא אוהבים:
- CSS חיצוני,
- פלקסבוקס/רשתות,
- les
<style>שאפתני מדי - תמונות חסרות ממדים
- קישורים ללא כתובות URL מוחלטות.
אז אנחנו נשארים עם טבלה ראשית, עם סגנון פשוט ומוטמע. זה "בסגנון הישן", אבל זה מה שעובד בכל מקום.
שלב 4 - אבטחת המשתנים (escape + הוספה לרשימה הלבנה)
אינך צריך לאפשר את כל ה-HTML בגוף. ברוב המקרים, רשימה לבנה דרך wp_kses() זה מספיק. עבור כתובות URL, השתמשו ב- esc_url()עבור הטקסט, esc_html().
שלב 5 - הוספת גרסת טקסט (אופציונלי אך שימושי)
פתרונות רבים של "HTML בלבד" מתעלמים מקוראי טקסט, וחלק ממערכות האנטי-ספאם מעריכות גיבוי. כאן, אנו גם יוצרים גרסת טקסט פשוטה (אותה ניתן לשלוח בנפרד אם תרצו, או להשתמש בה לצורך ניפוי שגיאות).
שלב 6 - תכנון התאמה אישית באמצעות פילטרים
תרצו להסתגל:
- לוגו / שם אתר,
- צבע הכפתור,
- כותרת תחתונה,
- כתובת "מאת".
חשופים מסננים ייעודיים. בתוסף שלנו, במקום לבקש מאנשים לשנות את הקובץ.
קוד מלא
העתיקו והדביקו את הקובץ למטה אל wp-content/plugins/bpcab-email-kit/bpcab-email-kit.phpהפעל אותו, ולאחר מכן בדוק אותו באמצעות פעולה פשוטה (ראה סעיף "בדיקות").
<?php
/**
* Plugin Name: BPCAB Email Kit (HTML templates)
* Description: Centralise la personnalisation des emails WordPress (HTML + filtres) via wp_mail().
* Version: 1.0.0
* Requires at least: 6.9
* Requires PHP: 8.1
* Author: BPCAB
* License: GPLv2 or later
*/
if (!defined('ABSPATH')) {
exit;
}
/**
* Retourne l'adresse email "From" par défaut.
* Vous pouvez la surcharger via le filtre bpcab_email_from.
*/
function bpcab_email_default_from(): string
{
$admin_email = get_option('admin_email');
$domain = wp_parse_url(home_url(), PHP_URL_HOST);
// Si l'admin_email est invalide, on tente un fallback.
if (!is_email($admin_email) && is_string($domain) && $domain !== '') {
$admin_email = 'no-reply@' . $domain;
}
/**
* Filtre interne : permet de définir l'adresse From.
* Retour attendu: string (email).
*/
$from = apply_filters('bpcab_email_from', $admin_email);
$from = sanitize_email($from);
if (!is_email($from)) {
// Dernier filet de sécurité : évite d'envoyer un header From cassé.
$from = 'no-reply@' . (is_string($domain) && $domain !== '' ? $domain : 'example.invalid');
}
return $from;
}
/**
* Retourne le nom "From" par défaut.
* Surcharge via bpcab_email_from_name.
*/
function bpcab_email_default_from_name(): string
{
$name = wp_specialchars_decode(get_bloginfo('name'), ENT_QUOTES);
/**
* Filtre interne : permet de définir le nom From.
* Retour attendu: string.
*/
$name = apply_filters('bpcab_email_from_name', $name);
// Évite les retours à la ligne dans les headers.
$name = preg_replace("/[rn]+/", ' ', (string) $name);
return trim($name);
}
/**
* Construit un template HTML compatible email.
*
* @param array $args {
* @type string $title Titre de l'email (affiché).
* @type string $preheader Texte court (préheader).
* @type string $content_html Contenu HTML (whitelisté).
* @type string $button_text Texte bouton (optionnel).
* @type string $button_url URL bouton (optionnel).
* @type string $footer_html Footer HTML (optionnel).
* }
* @return string HTML complet.
*/
function bpcab_email_render_html(array $args): string
{
$defaults = [
'title' => '',
'preheader' => '',
'content_html' => '',
'button_text' => '',
'button_url' => '',
'footer_html' => '',
];
$args = array_merge($defaults, $args);
$site_name = wp_specialchars_decode(get_bloginfo('name'), ENT_QUOTES);
$site_url = home_url('/');
// Couleurs simples, modifiables via filtres.
$brand_color = (string) apply_filters('bpcab_email_brand_color', '#1e40af'); // bleu
$bg_color = (string) apply_filters('bpcab_email_bg_color', '#f3f4f6'); // gris clair
$card_color = (string) apply_filters('bpcab_email_card_color', '#ffffff');
// Préheader : souvent affiché dans les clients email.
$preheader = trim((string) $args['preheader']);
$preheader_esc = esc_html($preheader);
// Whitelist HTML autorisé dans le contenu.
$allowed = [
'a' => ['href' => true, 'target' => true, 'rel' => true],
'br' => [],
'p' => [],
'strong' => [],
'em' => [],
'ul' => [],
'ol' => [],
'li' => [],
'span' => [],
];
$title = esc_html((string) $args['title']);
$content_html = wp_kses((string) $args['content_html'], $allowed);
$button_text = trim((string) $args['button_text']);
$button_url = trim((string) $args['button_url']);
$has_button = ($button_text !== '' && $button_url !== '');
$button_url_esc = $has_button ? esc_url($button_url) : '';
$button_text_esc = $has_button ? esc_html($button_text) : '';
$default_footer = sprintf(
'<p style="margin:0;font-size:12px;line-height:18px;color:#6b7280;">Email envoyé par <a href="%s" target="_blank" rel="noopener" style="color:#6b7280;text-decoration:underline;">%s</a>.</p>',
esc_url($site_url),
esc_html($site_name)
);
$footer_html = (string) $args['footer_html'];
$footer_html = $footer_html !== '' ? wp_kses($footer_html, $allowed) : $default_footer;
// Petit “hack” classique : préheader caché (sans CSS avancé).
$preheader_block = $preheader !== ''
? '<div style="display:none;max-height:0;overflow:hidden;color:transparent;opacity:0;height:0;width:0;">' . $preheader_esc . '</div>'
: '';
$html = '
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="x-apple-disable-message-reformatting">
<title>' . $title . '</title>
</head>
<body style="margin:0;padding:0;background:' . esc_attr($bg_color) . ';">
' . $preheader_block . '
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="background:' . esc_attr($bg_color) . ';">
<tr>
<td align="center" style="padding:24px 12px;">
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="600" style="width:600px;max-width:600px;">
<tr>
<td style="padding:0 0 12px 0;font-family:Arial,Helvetica,sans-serif;">
<div style="font-size:14px;line-height:20px;color:#111827;">
<a href="' . esc_url($site_url) . '" target="_blank" rel="noopener" style="color:#111827;text-decoration:none;"><strong>' . esc_html($site_name) . '</strong></a>
</div>
</td>
</tr>
<tr>
<td style="background:' . esc_attr($card_color) . ';border-radius:12px;padding:22px;font-family:Arial,Helvetica,sans-serif;">
<h2 style="margin:0 0 12px 0;font-size:20px;line-height:28px;color:#111827;">' . $title . '</h2>
<div style="font-size:14px;line-height:22px;color:#111827;">
' . $content_html . '
</div>
';
if ($has_button) {
$html .= '
<div style="padding:18px 0 0 0;">
<a href="' . $button_url_esc . '" target="_blank" rel="noopener"
style="display:inline-block;background:' . esc_attr($brand_color) . ';color:#ffffff;text-decoration:none;padding:10px 14px;border-radius:10px;font-size:14px;line-height:20px;">
' . $button_text_esc . '
</a>
</div>
';
}
$html .= '
<hr style="border:none;border-top:1px solid #e5e7eb;margin:20px 0;">
<div style="font-size:12px;line-height:18px;color:#6b7280;">
' . $footer_html . '
</div>
</td>
</tr>
<tr>
<td style="padding:12px 0 0 0;font-family:Arial,Helvetica,sans-serif;">
<div style="font-size:11px;line-height:16px;color:#9ca3af;">
<span>Si vous ne reconnaissez pas cet email, vous pouvez l’ignorer.</span>
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
';
/**
* Filtre interne : permet d'altérer le HTML final (ex: tracking, footer légal).
* Attention aux impacts délivrabilité.
*/
return (string) apply_filters('bpcab_email_html', $html, $args);
}
/**
* Génère une version texte simple à partir de paramètres proches.
* Utile pour fallback, logs, ou envoi alternatif.
*/
function bpcab_email_render_text(array $args): string
{
$title = (string) ($args['title'] ?? '');
$content_html = (string) ($args['content_html'] ?? '');
// Convertit grossièrement : dans les emails, on préfère simple et lisible.
$content_text = wp_strip_all_tags($content_html, true);
$lines = [];
if ($title !== '') {
$lines[] = $title;
$lines[] = str_repeat('=', min(60, max(10, strlen($title))));
}
if (trim($content_text) !== '') {
$lines[] = trim($content_text);
}
return trim(implode("nn", $lines));
}
/**
* Envoie un email HTML via wp_mail(), en limitant au maximum les effets de bord.
*
* @param string|array $to
* @param string $subject
* @param array $template_args Voir bpcab_email_render_html()
* @param array $mail_args {
* @type array $headers Headers supplémentaires (optionnel).
* @type array $attachments Pièces jointes (optionnel).
* @type string $reply_to Email Reply-To (optionnel).
* }
* @return bool True si wp_mail() a accepté l'envoi.
*/
function bpcab_mail($to, string $subject, array $template_args, array $mail_args = []): bool
{
$subject = wp_specialchars_decode($subject, ENT_QUOTES);
$subject = preg_replace("/[rn]+/", ' ', $subject); // protège les headers
$html = bpcab_email_render_html($template_args);
$headers = [];
// From (cohérent, filtrable).
$from_email = bpcab_email_default_from();
$from_name = bpcab_email_default_from_name();
$headers[] = 'From: ' . $from_name . ' <' . $from_email . '>';
// Reply-To optionnel.
if (!empty($mail_args['reply_to'])) {
$reply_to = sanitize_email((string) $mail_args['reply_to']);
if (is_email($reply_to)) {
$headers[] = 'Reply-To: ' . $reply_to;
}
}
// Headers additionnels.
if (!empty($mail_args['headers']) && is_array($mail_args['headers'])) {
foreach ($mail_args['headers'] as $h) {
// On évite d'injecter n'importe quoi dans les headers.
$h = (string) $h;
$h = preg_replace("/[rn]+/", '', $h);
if ($h !== '') {
$headers[] = $h;
}
}
}
$attachments = [];
if (!empty($mail_args['attachments']) && is_array($mail_args['attachments'])) {
$attachments = $mail_args['attachments'];
}
/**
* Filtre interne : permet d'altérer les arguments finaux.
* Exemple: ajouter un header List-Unsubscribe.
*/
$payload = apply_filters('bpcab_mail_payload', [
'to' => $to,
'subject' => $subject,
'message' => $html,
'headers' => $headers,
'attachments' => $attachments,
'template' => $template_args,
]);
// Forcer le content-type uniquement pendant cet envoi.
$content_type_callback = static function () {
return 'text/html; charset=UTF-8';
};
add_filter('wp_mail_content_type', $content_type_callback, 1000);
// Optionnel : on peut aussi filtrer From/FromName globalement,
// mais ici on les met explicitement dans les headers pour éviter la “guerre” des filtres.
try {
$sent = wp_mail(
$payload['to'] ?? $to,
$payload['subject'] ?? $subject,
$payload['message'] ?? $html,
$payload['headers'] ?? $headers,
$payload['attachments'] ?? $attachments
);
} finally {
remove_filter('wp_mail_content_type', $content_type_callback, 1000);
}
return (bool) $sent;
}
/**
* Exemple de point d'entrée pour tester rapidement (admin uniquement).
* URL: /wp-admin/?bpcab_test_mail=1
*/
add_action('admin_init', function () {
if (!current_user_can('manage_options')) {
return;
}
if (!isset($_GET['bpcab_test_mail'])) {
return;
}
check_admin_referer('bpcab_test_mail');
$to = get_option('admin_email');
$ok = bpcab_mail(
$to,
'Test email HTML (BPCAB Email Kit)',
[
'title' => 'Votre template HTML fonctionne',
'preheader' => 'Préheader: vérifiez le rendu dans votre boîte de réception.',
'content_html' => '<p>Si vous voyez cet email avec un bouton et un footer, le pipeline HTML est OK.</p><p><strong>Astuce</strong> : testez sur Gmail + Outlook, pas uniquement votre webmail.</p>',
'button_text' => 'Ouvrir le site',
'button_url' => home_url('/'),
],
[
'reply_to' => get_option('admin_email'),
]
);
$redirect = add_query_arg([
'bpcab_test_mail_sent' => $ok ? '1' : '0',
], admin_url());
wp_safe_redirect($redirect);
exit;
});
/**
* Affiche une notice après test.
*/
add_action('admin_notices', function () {
if (!current_user_can('manage_options')) {
return;
}
if (!isset($_GET['bpcab_test_mail_sent'])) {
return;
}
$ok = $_GET['bpcab_test_mail_sent'] === '1';
$msg = $ok
? 'Email de test déclenché. Vérifiez la réception (et le dossier spam).'
: 'Échec wp_mail(). Vérifiez SMTP/serveur, logs PHP et configuration.';
echo '<div class="notice ' . ($ok ? 'notice-success' : 'notice-error') . '"><p>' . esc_html($msg) . '</p></div>';
});
כדי להפעיל את הבדיקה כראוי (עם nonce):
<?php
// Collez ce lien dans votre navigateur (en étant connecté admin).
// Remplacez NONCE par la valeur générée par wp_nonce_url().
הדרך הפשוטה ביותר: להוסיף באופן זמני קישור לדף ניהול באמצעות קטע טקסט, או ליצור אותו בקונסולת WP-CLI. בפועל, אני עושה לעתים קרובות את הפעולות הבאות:
wp eval "echo wp_nonce_url(admin_url('/?bpcab_test_mail=1'), 'bpcab_test_mail') . PHP_EOL;"
הסבר על הקוד
למה עטיפה במקום "לסנן הכל"?
וורדפרס חושפת מסננים גלובליים (wp_mail_from, wp_mail_from_name, wp_mail_content_typeהמלכודת היא שהם חלים על כל האימיילים, כולל אלו שמגיעים מתוסף קריטי (אבטחה, חיוב) שמצפה לפורמט מסוים.
כאן, נבחרה גישה היברידית:
- אנחנו משתמשים
wp_mail()(לכן תואם לרוב תוספי ה-SMTP), - אנו כופים את סוג התוכן רק במהלך השיחה (הוספה + הסרה של המסנן),
- שמנו את ה
From:בכותרות של אימייל זה, כדי להגביל התנגשויות בעדיפויות.
רינדור ה-HTML: wp_kses() במקום "HTML חינמי"
גוף האימייל מכיל לעתים קרובות קטעים מאפשרויות, שדות או קלט. גם אם אתם חושבים ש"זה פנימי", ראיתי שדות בפרופיל משתמש מוזרקים לתוך אימיילים של מנהלים.
אנו מיישמים רשימה לבנה מינימליסטית:
- חיבורים
<a>(עםhref), - עיצוב
<strong>,<em>, - רשימות, פסקאות.
אם אתם זקוקים לטבלאות או לתמונות, הוסיפו אותן במפורש לרשימה הלבנה (סעיף "וריאנטים").
מדוע סוג התוכן נוסף עם עדיפות 1000?
באתרים עם הרבה תוספים, לעתים קרובות יש כמה פילטרים מופעלים wp_mail_content_typeהגדרת עדיפות גבוהה מגדילה את הסיכויים שלך לזכות... מבלי לחסום את השאר, מכיוון שאתה מסיר את המסנן מיד לאחר מכן. נתקלתי לעתים קרובות באתרים שבהם תוסף כופה טקסט/רגיל לעדיפות של 10, מה שגורם לתבניות ה-HTML להיראות אקראיות.
כותרות: מניעת הזרקה
כותרות אימייל רגישות להחזרות גררה. נתונים שלא נוקו יכולים ליצור כותרת נוספת. לכן, אנו מסירים אותה. r et n בנושא ובכותרות נוספות.
למה לא להשתמש ישירות ב-PHPMailer?
וורדפרס משתמשת ב-PHPMailer באופן פנימי, אבל עובר אורח נָקוּב wp_mail() זוהי נותרה השיטה התואמת ביותר (תוספי SMTP, יומני רישום, ווים). גישה ישירה ל-PHPMailer דרך phpmailer_init זה אולי שימושי, אבל זה מוסיף שכבה נוספת של מורכבות, ואתה עלול לפגוע בהגדרות SMTP.
מקורות רשמיים שימושיים:
וריאנטים ומקרי שימוש
גרסה 1 - התאמה אישית של "מאת" באופן גלובלי באמצעות מסנני ליבה
אם אתם מעדיפים לרכז ברמת וורדפרס (ולא בכותרות של bpcab_mail()), ניתן להפעיל את המסננים הללו. אזהרה: זה משפיע tous מיילים.
<?php
add_filter('wp_mail_from', function ($from) {
$custom = bpcab_email_default_from();
return is_email($custom) ? $custom : $from;
}, 20);
add_filter('wp_mail_from_name', function ($name) {
return bpcab_email_default_from_name();
}, 20);
אפשרות 2 - אפשר תמונות וטבלאות בתוכן
מקרה נפוץ: הודעות דוא"ל מסוג "סדר" או "סיכום" עם טבלה קטנה. הוסף במפורש img et table הוסף לרשימה הלבנה. אל תאפשר את כל ההגדרות.
<?php
// Exemple : à intégrer dans bpcab_email_render_html(), dans $allowed.
$allowed['img'] = [
'src' => true,
'alt' => true,
'width' => true,
'height' => true,
'style' => true,
];
$allowed['table'] = ['role' => true, 'cellpadding' => true, 'cellspacing' => true, 'border' => true, 'width' => true, 'style' => true];
$allowed['tbody'] = [];
$allowed['thead'] = [];
$allowed['tr'] = [];
$allowed['td'] = ['style' => true, 'colspan' => true, 'rowspan' => true];
$allowed['th'] = ['style' => true, 'colspan' => true, 'rowspan' => true];
גרסה 3 - הוספת כותרת רשימה של ביטול מנוי (יכולת מסירה)
עבור הודעות דוא"ל חוזרות מסוימות (הודעות, תקצירים), הוסף List-Unsubscribe זה יכול לעזור. אל תציבו את זה במיילים עסקיים בלבד ללא אפשרות ביטול הרשמה.
<?php
add_filter('bpcab_mail_payload', function (array $payload) {
$unsubscribe_url = add_query_arg([
'my_unsub' => 1,
'email' => rawurlencode(is_array($payload['to']) ? (string) $payload['to'][0] : (string) $payload['to']),
], home_url('/'));
$payload['headers'][] = 'List-Unsubscribe: <' . esc_url($unsubscribe_url) . '>';
return $payload;
});
תאימות Divi 5 / Elementor / Avada
בוני דפים כמעט ולא מתערבים ישירות ב wp_mail()אבל הם משפיעים תוכן שניתן להכניס לתוך אימייל (קודים קצרים, CSS, בלוקים). שלושה מקרים עולים לעתים קרובות.
Divi 5
- הימנעו מהחדרת קודי קיצור של Divi למיילים: הרינדור תלוי בקצה הקדמי, בנכסים ובהקשר של הדף.
- אם אתם צריכים לעשות שימוש חוזר בטקסט שנערך באמצעות Divi, אחסן גרסה נפרדת "בטוחה לדוא"ל" (טקסט + קישורים), או בצע המרה מבוקרת מאוד (למשל, חילץ רק את הפסקאות).
Elementor
- אל תנסה להציג תבנית אלמנטור בדוא"ל. הודעות דוא"ל אינן טוענות את קוד ה-CSS/JS של הקצה הקדמי שלך.
- אם אתם מאחזרים תוכן מווידג'ט של אלמנטור (המאוחסן במטא של פוסט), חשבו עליו כלא מהימן והעבירו אותו דרכו.
wp_kses()עם רשימה לבנה קפדנית.
אבדה / פיוז'ן בונה
- אותו היגיון: קודי קיצור של Fusion אינם מיועדים לדוא"ל.
- אם אתם מאחזרים תוכן "בונה", הפכו אותו לתוכן מינימלי בדוא"ל (p, ul, a), אחרת יהיו לכם מיילים ריקים או בלתי קריאים.
כלל מעשי: אימייל HTML חייב להיות עצמאי. אין תלות ב-CSS של ערכת נושא, אין JS, אין גופני אינטרנט "חובה".
בדיקות לאחר ההתקנה
- שליחה לבדיקה עם כתובת ה-URL nonce (קטע הקוד) וודא ש
wp_mail()מחזיר אמת. - בדוק את הכותרות דרך כלי ה-SMTP שלך (Mailpit/MailHog):
Content-Type: text/html; charset=UTF-8,From:לתקן. - פתח את האימייל לְפָחוֹת:
- ג'ימייל אינטרנט,
- אאוטלוק (מחשב שולחני או אינטרנטי),
- לקוח נייד.
- בדוק את הקישורים כתובות URL מוחלטות, ללא קישורים יחסיים.
- שליטה בספאם שלחו את האימייל לכתובת אימייל חיצונית. אם הוא מגיע לספאם, בדקו את הגדרות From/DKIM/DMARC שלכם (לעתים קרובות אינן נמצאות בוורדפרס).
טבלת אבחון (מהירה)
| סימפטום | סיבה סבירה | אימות | פתרון |
|---|---|---|---|
| אימייל שהתקבל בטקסט רגיל | סוג התוכן לא הוחל או נדרס | בדיקת כותרות ב-Mailpit/MailHog | בדוק שהמסנן wp_mail_content_type נוסף/הוסר כהלכה, העלה עדיפות, בדוק התנגשויות תוספים |
| לוגו/קישורים שבורים | כתובות URL יחסיות ב-HTML | צפה בקוד המקור של הדוא"ל | Utiliser home_url() + esc_url(), להימנע /wp-content/... ללא דומיין |
| wp_mail() מחזירה שקר | SMTP/משרת נדחה, הגדרת דואר PHP מושבתת | יומני שרת, תוסף SMTP, בדיקות מקומיות | הגדרת SMTP, בדיקת DNS, יומני רישום, הגבלות אירוח |
| רינדור "מכוער" באאוטלוק | CSS אינו נתמך | בדיקת Outlook | מזער CSS, העדיף טבלאות + סגנונות פשוטים בתוך השורה |
| שגיאה 500 לאחר הוספת קוד | תחביר PHP (נקודה-פסיק, סוגריים) | הפעל את WP_DEBUG, בדוק את הלוגים | תקן את התחביר, פריס באמצעות staging, השתמש בעורך עם lint |
אם זה לא עובד
1) ודא שהקוד שלך נטען
- האם התוסף מופעל?
- האם הקובץ נמצא במקום הנכון?
wp-content/plugins/bpcab-email-kit/bpcab-email-kit.php) - אין שגיאות PHP בטעינה (בדוק את הלוגים)?
2) הפעלת ניפוי שגיאות כראוי
על במה, הפעל:
<?php
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
3) בדוק אם יש התנגשויות בין מסננים
ראיתי לעתים קרובות:
- תוסף "התאמה אישית של דוא"ל" שמאלץ
text/plain, - תוסף SMTP שכותב מחדש את הכותרות,
- קטע ישן שעוזב
wp_mail_content_typeלצמיתות ב-HTML.
השבת זמנית את הרכיבים הללו ובדוק שוב.
4) בדוק את PHP ואת האחסון
- PHP 8.1+ (אחרת, שגיאות הקלדה או בעיות תאימות).
- פונקציית הדוא"ל מושבתת? (נפוץ אצל חלק מספקי האירוח).
- מגבלות SMTP יוצאות?
5) נקו את המטמון
- תוסף מטמון (מטמון עמוד / מטמון אובייקט) אם אתם בודקים דרך ממשק משתמש שתלוי באפשרויות.
- מטמון דפדפן אם הוספת כפתור ניהול.
מלכודות וטעויות נפוצות
| שגיאה | לגרום | פתרון |
|---|---|---|
קוד הודבק לתוך functions.php של ערכת הנושא של האב |
עדכון ערכת נושא = אובדן קוד | שימו את זה במיני-תוסף או תבנית ילדים |
שוכחים א ; או גשר |
העתקה-הדבקה חלקית | הפעל את WP_DEBUG_LOG, בדוק את השורה ביומנים, השתמש ב-IDE |
| בלבול בין פעולה לפילטר | Utiliser add_action במקום add_filter |
בדוק את תיעוד הווים (wp_mail_content_type הוא פילטר) |
| וו לא מתאים / עדיפות נמוכה מדי | תוסף דורס את סוג התוכן שלך אחריך | הגדל את העדיפות (למשל, 1000) והסר את המסנן לאחר השליחה. |
| תבנית HTML ריקה עם הקבלה | HTML פגום (תגיות לא סגורות) או סינון תוכן קפדני מדי | אימות ה-HTML, הרחב את הרשימה הלבנה wp_kses() בצורה מבוקרת |
| תמונות לא מוצגות | כתובת URL יחסית, חסימת תמונות בצד הלקוח | כתובת URL מוחלטת, הוסף altממדים, קבלו שחלק מהלקוחות חוסמים כברירת מחדל |
| אימייל מסומן כספאם | לא תואם ל-SPF/DKIM/DMARC | יישור דומיין שולח, תצורת DNS, הימנעות gmail.com מִן |
| בדיקות בסביבת ייצור ללא גיבוי | שינויים בכותרת = השפעה כוללת | תחילה הכנה, לאחר מכן פריסה הדרגתית |
| קטע הקוד שבור על ידי תוסף הקטעים | טעינת הזמנה / שגיאה חמורה | מיני-תוסף גרסה, בדיקות אוטומטיות במידת האפשר |
| מדריך ישן יותר שממליץ על PHPMailer Direct | אי-תאימות וסכסוכים ב-SMTP | לְהַעֲדִיף wp_mail() + מסננים, אין להשתמש phpmailer_init שאם יש צורך |
טיפים לבטיחות, ביצועים ותחזוקה
אבטחה
- לעולם אל תשים HTML גולמי של משתמש באימייל: עברו על זה
wp_kses(). - יש לנקות תמיד את הכותרות (להסיר מעברי שורה) כדי למנוע הזרקה.
- הימנעו מחשיפת כתובת URL לבדיקה ללא nonce (כאן אנו משתמשים
check_admin_referer()).
ביצוע
- רינדור ה-HTML קל משקל: אין צורך בשאילתות SQL נוספות מלבד
get_option/get_bloginfo. - אם אתם שולחים הרבה מיילים, העבירו את השליחה לתור (מתזמן פעולות, cron) במקום לחסום בקשה מקדמית.
תחזוקה
- שמרו על יציבות התבנית וגירסאותיה. אפילו שינויים קטנים בדוא"ל HTML עלולים לגרום נזק ל-Outlook.
- תעד את המסננים הפנימיים שלך (
bpcab_email_brand_color,bpcab_email_html, וכו '). - לאחר עדכון תוסף הוורדפרס/SMTP שלך, בדוק שוב לפחות את כתובת האימייל לאיפוס הסיסמה ואת כתובת האימייל העיקרית שלך לביצוע עסקאות.
משאבים
- wp_mail() - הפניה
- מסנן wp_mail_content_type
- מסנן wp_mail_from
- מסנן wp_mail_from_name
- wp_kses() - רשימת היתרים של HTML
- sanitize_email()
- מעקב אחר ליבות WordPress (חיפוש כרטיסים הקשורים ל-wp_mail)
- קוד מקור של GitHub mirror של wordpress-develop
- פילטר PHP_var()
שאלות נפוצות
למה האימיילים שלי בוורדפרס לא מגיעים, אפילו עם תבנית HTML תקינה?
HTML בדרך כלל אינו הגורם העיקרי. הבעיות הנפוצות ביותר הן: תצורת SMTP חסרה או שגויה, דומיין שאינו מיושר עם SPF/DKIM/DMARC, או ספק אירוח שחוסם אותו. mail()התחל בבדיקת הניתוב (יומני SMTP), לאחר מכן בבדיקת התוכן.
האם התוסף הזה יביא אישית את האימיילים מכל התוספים שלי?
רק אלו שעוברים דרכו wp_mail()רובם עושים זאת, אך חלק מהמערכות (או שירותים חיצוניים) שולחים נתונים בצורה שונה. גם ל-WooCommerce יש שכבת תבנית משלה.
למה לא לעזוב wp_mail_content_type לצמיתות ב-HTML?
מכיוון שתשבור את הודעות הטקסט הצפויות על ידי תוספים (או אינטגרציות) מסוימים. דפוס "הוסף מסנן ואז הסר אותו" מגביל את תופעות הלוואי.
איך אני מוסיף לוגו לראש המייל?
הוסף תג <img> בכותרת התבנית, עם כתובת URL מוחלטת, width/height, ולאפשר img ברשימה הלבנה wp_kses()קחו בחשבון שחלק מהלקוחות חוסמים תמונות כברירת מחדל.
האם ניתן להשתמש בתוכן של דף (גוטןברג) כגוף של אימייל?
טכנית כן, אבל הימנעו מרינדור בלוקים מורכבים. אחזרו את התוכן, הוסיפו אותו לרשימת ההיתרים ובדקו את הרינדור. אימיילים לא יטענו את ה-CSS של ערכת הנושא שלכם.
איך לעשות בדיקה בלי לשלוח מיילים אמיתיים?
השתמשו ב-Mailpit/MailHog באופן מקומי, או בשרת SMTP לבדיקה. בשלב ההפעלה, תוכלו גם לתעד עומסי אחסון (היזהרו עם נתונים אישיים).
אני רואה כמה תווים (מבטאים) מוזרים במייל.
בדוק את ה charset=UTF-8 בסוג התוכן. כאן אנו מתייחסים text/html; charset=UTF-8כמו כן, בדוק ששורת הנושא שלך אינה מכילה תווים מקודדים באופן שגוי (אנו משתמשים ב- wp_specialchars_decode).
הכפתור שלי לא נראה כמו כפתור באאוטלוק
Outlook ידוע לשמצה בשל היותו גמיש. היצמדו לסגנונות פשוטים ומוטמעים. אם אתם זקוקים לעיצוב חסין כדורים, עברו למבנה ספציפי יותר (כמו כפתור בטבלה). שמרו על תבנית מינימלית.
האם זה תואם ל-PHP 8.1+ ו-WordPress 6.9.4?
כן. הקוד נמנע מ-APIs מיושנים ונשאר בתוך המסגרת wp_mail() + פונקציות פליטה/חיטוי סטנדרטיות.
איך אני מחבר את זה לטפסים שלי (Contact Form 7, WPForms וכו')?
שתי גישות: או שתאפשרו לתוסף הטופס לשלוח דרך wp_mail() ואתה מתאים אישית באופן גלובלי (בזהירות), או שאתה מיירט את ה-hooks והקריאה הספציפיים שלו bpcab_mail() עבור האימיילים המותאמים אישית שלך. האפשרות השנייה לרוב יציבה יותר.