¿Cómo y cuándo utilizar wp_mail()?

Necesito crear un flujo de envío de emails a usuarios después de que se produzca una compra. Cuando un pedido contenga productos de ciertas categorías, le voy a mandar un email al comprador para pedirle que me envíe una copia del DNI y otra documentación obligatoria.

En el desarrollo de plugins o temas a medida para WordPress, nos veremos obligados a utilizar wp_mail(). Una función muy interesante para enviar notificaciones vía email.

Requiere configurar SMTP en nuestro servidor para que puedan salir los emails. Utiliza la clase PHPMailer que contiene la configuración SMTP y es la encargada de enviar correos electrónicos.

Para utilizar la clase PHPMailer tenemos varias opciones:

Mediante el hook phpmailer_init de la siguiente forma, introduce este snippet modificado en el archivo functions.php del tema en funcionamiento o desde un plugin de personalizaciones.

add_action( 'phpmailer_init', 'configuration_smtp' );

function configuration_smtp( PHPMailer $phpmailer ){
    $phpmailer->isSMTP(); 
    $phpmailer->Host = 'tu-servidor-smtp.com';
    $phpmailer->SMTPAuth = true;
    $phpmailer->Port = 587;
    $phpmailer->Username = 'tu-nombre-de-usuario';
    $phpmailer->Password = 'tu-contrasena';
    $phpmailer->SMTPSecure = 'ssl';
    $phpmailer->From = 'From Email';
    $phpmailer->FromName='nombre-del-remitente';
}

Otra alternativa es configurar de forma manual la conexión SMTP desde el archivo wp-config.php.

define( 'WP_MAIL_METHOD', 'smtp' ); // Definir como SMTP
define( 'WP_MAIL_HOST', 'tu-servidor-smtp.com' ); // Servidor SMTP
define( 'WP_MAIL_PORT', 587 ); // Puerto SMTP
define( 'WP_MAIL_SMTPSecure', 'tls' ); // TLS o SSL
define( 'WP_MAIL_SMTPAuth', true ); // Autenticación requerida
define( 'WP_MAIL_USERNAME', 'tu-nombre-de-usuario' ); // Nombre de usuario SMTP
define( 'WP_MAIL_PASSWORD', 'tu-contrasena' ); // Contraseña SMTP

La última opción parar configurar el SMTP sería a través de un plugin creado específicamente para ello. En el repositorio hay varios que puedes usar como:

¿Cómo se usa la función wp_mail() y qué parámetros permite?

La función admite 5 parámetros que tendremos que ir almacenando en variables. (Puedes nombrar tus variables de distinta forma que los ejemplos. solo tienes que respetar su orden dentro de la misma función).

La función devolverá True cuando no se genere un error, esto no quiere decir que el correo ha llegado al destinatario.

Haz uso de ella y actívala a través de Hooks, Templates, plugnis

// Función de WordPress con sus parámetros
wp_mail( $to, $subject, $message, $headers, $attachments );

Los siguientes parámetros se utilizan para:

  • $to => Información obligatoria del email o array de emails donde se envía la notificación.
  • $subject => Asunto del correo, obligatorio.
  • $message => Contenido del mensaje, obligatorio.
  • $headers => Encabezados adicionales de un mensaje como “FROM:” , “C.C:”, “CCO:” para especificar el email, si se desea enviar con copia o copia oculta.
  • $attachments => Archivos adjuntos que se envían con el email.

Ejemplo de como añadir contenido adicional a los encabezados a través de $headers

$headers[]= “From: Shooting Range <sample@example.com>”;
$headers[]= “Cc: <correo1@example.com>”;
$headers[]= “Bcc: <correo2@example.com>”;

El tipo de contenido predeterminado es text/plain este no permite el uso de marcado HTML.
Puedes configurar el tipo de contenido del correo electrónico utilizando el filtro wp_mail_content_type .

Con el filtro wp_mail_content_type cambiamos de texto sin formato a text/html . 

function send_email_to_finished( $test ) {
  $email = 'ejemplo@example.com';
  $title = sprintf(
    __( 'Prueba "%s" terminada', '' ),
    $test->post_title
  );
  $body = '...';
  $content_type = function() { return 'text/html'; };
  
  add_filter( 'wp_mail_content_type', $content_type );
  wp_mail( $email, $title, $body );
  remove_filter( 'wp_mail_content_type', $content_type );
}

El siguiente ejemplo muestra cómo enviar un correo a varios emails.

$multiples_recipients = [
	'ejemplo1@example.com',
	'ejemplo2@example.com'
];

add_filter( 'wp_mail_content_type', 'get_email_html_content' );

wp_mail( $multiple_recipients, 'El asunto', '<p>El Mensaje <em>HTML</em></p>' );

// Elimine el filtro de tipo de contenido para evitar posibles cambios adicionales del tipo de contenido.
remove_filter( 'wp_mail_content_type', 'get_email_html_content' );

function get_email_html_content(){
	return 'text/html';
}

¿Cómo enviar un archivo adjunto?

Algo que podemos hacer es enviar un archivo con información relevante. Desde un manual o instrucciones en PDF, un lead Magnet, una imagen, una revista interactiva

$attachments = array (WP_CONTENT_DIR.’/uploads/normativa.pdf’);

¿Cómo extender la funcionalidad wp_mail()?

Con el filtro wp_mail_charset modificaremos la codificación del email, por defecto es en UTF-8, úsalo si necesitas poner caracteres especiales para otros idiomas.

add_filter( 'wp_mail_charset', 'change_email_charset' );

function change_email_charset( $charset ) {
	return 'UTF-32';
}

Otro de los filtros que podemos usar es wp_mail_from para modificar la dirección de correo electrónico de remitente. Se puede usar junto con el filtro wp_mail_from_name para crear un remitente con nombre. Es importante para evitar que su correo electrónico se marque como SPAM

add_filter( 'wp_mail_from', function ( $email ) {
    return 'sample@example.com';
} );

add_filter( 'wp_mail_from_name', function ( $name ) {
    return 'Nombre Empresa';
} );

Con el filtro pre_wp_mail podemos ejecutar acciones o interceptar la información del email antes de que este se envíe a través de la función wp_mail().

Esto puede ser útil para propósitos de depuración, personalización, o para implementar condiciones específicas en el envío de correos.

El filtro pre_wp_mail es una herramienta poderosa para los desarrolladores que quieren tener un control fino sobre el proceso de envío de correos en WordPress.

add_filter('pre_wp_mail', 'modify_email_before_sending', 10, 2);

function modify_email_before_sending($null, $args) {
    // Aquí puedes modificar los parámetros del correo.
    $args['subject'] = '[MODIFICADO] ' . $args['subject'];
    $args['message'] .= "\n\nEste mensaje ha sido modificado.";

    // Si quieres anular el envío del correo, simplemente devuelve false
    // return false;

    // Si quieres permitir que el correo se envíe con los cambios, devuelve los argumentos modificados.
    return $args;
}

El filtro wp_mail_failed es para capturas de errores en el envío de correos. Podemos interceptar y responder a los errores que ocurren cuando wp_mail() no puede enviar un correo electrónico.

Además proporciona información sobre el error. Pasa un objeto WP_Error con la información detallada sobre el error ocurrido, lo que facilita el diagnóstico y la resolución de problemas.

add_action('wp_mail_failed', 'handle_email_sending_error', 10, 1);

function handle_email_sending_error($wp_error) {
    // Aquí puedes manejar el error como prefieras, por ejemplo, registrándolo en un archivo de log.
    $error_message = $wp_error->get_error_message();
    $error_data = $wp_error->get_error_data();
    
    // Registro del error en el archivo debug.log de WordPress
    if (defined('WP_DEBUG') && WP_DEBUG) {
        error_log('Error en el envío de correo: ' . $error_message);
        error_log('Datos adicionales: ' . print_r($error_data, true));
    }
    
    // También puedes notificar al administrador o tomar otras acciones.
}

Receta: Enviar un correo después hacer una compra donde haya un producto con una categoría específica

Después de ver muchas de las opciones que nos permite la función wp_mail() vamos a crear un pequeño tutorial para conseguir nuestro objetivo de enviar un email a los clientes que hayan comprado un producto de una categoría específica.

En primer lugar

  • Con ACF he creado un campo SELECT Multiple, y mediante la función que muestro a continuación se rellenan de forma dinámica las opciones con las categorías de producto del WooCommerce. Aquí usamos un filtro de ACF «acf/load_field/name=NOMBRE-DE-NUESTRO-CAMPO-ACF»
  • Le indicamos en ACF que muestre este campo en una página de opciones para ofrecerle al cliente la posibilidad de añadir y quitar categorías «especiales» de una forma simple. Estas categorías son las que usaremos para activar el envío del email.

Coloca el siguiente snippet en el archivo functions.php de tu tema en funcionamiento o en un plugin de personalizaciones. Solo tienes que cambiar NOMBRE-DE-NUESTRO-CAMPO-ACF por el nombre de tu campo personalizado de ACF.

function acf_product_categories_field( $field ) {
    // Obtener todas las categorías de productos
    $product_categories = get_terms( array(
        'taxonomy' => 'product_cat',
        'hide_empty' => false,
    ) );

    // Verificar si se obtuvieron las categorías y si no hay errores
    if ( !empty( $product_categories ) && !is_wp_error( $product_categories ) ) {
        // Inicializar el array de opciones
        $field['choices'] = array();

        // Loop a través de las categorías y asignarlas como opciones
        foreach ( $product_categories as $category ) {
            $field['choices'][ $category->term_id ] = $category->name;
        }
    } else {
        // Si no se encontraron categorías, muestra un mensaje de error
        $field['choices'] = array( 'error' => 'No se encontraron categorías de productos.' );
    }

    return $field;
}

add_filter( 'acf/load_field/name=NOMBRE-DE-NUESTRO-CAMPO-ACF', 'acf_product_categories_field' );

En este punto ya tenemos un lugar donde recoger un listado de Categorías de producto.

¿Necesitas una página web a medida?

Me especializo en crear sitios webs profesionales y avanzados, programando soluciones personalizadas para proyectos web. ¡No te arrepentirás!

Continuamos…

  • Ahora deberíamos crear una plantilla que será el email que vayamos a enviar. Iremos al tema en funcionamiento y crearemos la siguiente carpeta con el archivo .php de la siguiente forma: templates/email-template.php.
  • El siguiente fragmento corresponde a mi email-template.php, me he ayudado de una herramienta online como es beefree. Me ha permitido hacer un boceto y exportarlo a HTML fácilmente.
<!DOCTYPE html>
<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" lang="en">

<head>
	<title></title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0"><!--[if mso]><xml><o:OfficeDocumentSettings><o:PixelsPerInch>96</o:PixelsPerInch><o:AllowPNG/></o:OfficeDocumentSettings></xml><![endif]--><!--[if !mso]><!-->
	<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css">
	<link href="https://fonts.googleapis.com/css2?family=Bitter:wght@100;200;300;400;500;600;700;800;900" rel="stylesheet" type="text/css"><!--<![endif]-->
	<style>
		* {
			box-sizing: border-box;
		}

		body {
			margin: 0;
			padding: 0;
		}

		a[x-apple-data-detectors] {
			color: inherit !important;
			text-decoration: inherit !important;
		}

		#MessageViewBody a {
			color: inherit;
			text-decoration: none;
		}

		p {
			line-height: inherit
		}

		.desktop_hide,
		.desktop_hide table {
			mso-hide: all;
			display: none;
			max-height: 0px;
			overflow: hidden;
		}

		.image_block img+div {
			display: none;
		}

		.menu_block.desktop_hide .menu-links span {
			mso-hide: all;
		}

		@media (max-width:660px) {

			.desktop_hide table.icons-inner,
			.social_block.desktop_hide .social-table {
				display: inline-block !important;
			}

			.icons-inner {
				text-align: center;
			}

			.icons-inner td {
				margin: 0 auto;
			}

			.mobile_hide {
				display: none;
			}

			.row-content {
				width: 100% !important;
			}

			.stack .column {
				width: 100%;
				display: block;
			}

			.mobile_hide {
				min-height: 0;
				max-height: 0;
				max-width: 0;
				overflow: hidden;
				font-size: 0px;
			}

			.desktop_hide,
			.desktop_hide table {
				display: table !important;
				max-height: none !important;
			}
		}
	</style>
</head>

<body class="body" style="background-color: #252126; margin: 0; padding: 0; -webkit-text-size-adjust: none; text-size-adjust: none;">
	<table class="nl-container" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; background-color: #252126;">
		<tbody>
			<tr>
				<td>
					<table class="row row-1" align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; background-position: center top;">
						<tbody>
							<tr>
								<td>
									<table class="row-content stack" align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #000000; width: 640px; margin: 0 auto;" width="640">
										<tbody>
											<tr>
												<td class="column column-1" width="100%" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; font-weight: 400; text-align: left; padding-bottom: 40px; padding-top: 40px; vertical-align: top; border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px;">
													<table class="image_block block-1" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt;">
														<tr>
															<td class="pad" style="width:100%;padding-right:0px;padding-left:0px;">
																<div class="alignment" align="center" style="line-height:10px">
																	<div style="max-width: 128px;"><img src="https://093e4c9c26.imgdist.com/pub/bfra/eejdhl79/p0h/7hy/55y/logoSR-01-178x200.png" style="display: block; height: auto; border: 0; width: 100%;" width="128" alt="Your Logo" title="Your Logo" height="auto"></div>
																</div>
															</td>
														</tr>
													</table>
												</td>
											</tr>
										</tbody>
									</table>
								</td>
							</tr>
						</tbody>
					</table>
					<table class="row row-2" align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; background-position: center top;">
						<tbody>
							<tr>
								<td>
									<table class="row-content stack" align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #000000; width: 640px; margin: 0 auto;" width="640">
										<tbody>
											<tr>
												<td class="column column-1" width="100%" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; font-weight: 400; text-align: left; vertical-align: top; border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px;">
													<div class="spacer_block block-1" style="height:60px;line-height:60px;font-size:1px;">&#8202;</div>
													<table class="heading_block block-2" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt;">
														<tr>
															<td class="pad" style="padding-left:10px;padding-right:10px;text-align:center;width:100%;">
																<h1 style="margin: 0; color: #ffffff; direction: ltr; font-family: 'Bitter', Georgia, Times, 'Times New Roman', serif; font-size: 50px; font-weight: normal; line-height: 120%; text-align: center; margin-top: 0; margin-bottom: 0; mso-line-height-alt: 60px;"><strong>¡Gracias por tu compra!</strong></h1>
															</td>
														</tr>
													</table>
													<table class="heading_block block-3" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt;">
														<tr>
															<td class="pad" style="padding-left:10px;padding-right:10px;text-align:center;width:100%;">
																<h1 style="margin: 0; color: #ffffff; direction: ltr; font-family: 'Bitter', Georgia, Times, 'Times New Roman', serif; font-size: 50px; font-weight: normal; line-height: 120%; text-align: center; margin-top: 0; margin-bottom: 0; mso-line-height-alt: 60px;"><strong>SOOTING RANGE</strong></h1>
															</td>
														</tr>
													</table>
													<div class="spacer_block block-4" style="height:30px;line-height:30px;font-size:1px;">&#8202;</div>
													<div class="spacer_block block-5" style="height:30px;line-height:30px;font-size:1px;">&#8202;</div>
													<table class="paragraph_block block-6" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; word-break: break-word;">
														<tr>
															<td class="pad" style="padding-bottom:10px;padding-left:20px;padding-right:20px;padding-top:10px;">
																<div style="color:#393d47;font-family:'Bitter', Georgia, Times, 'Times New Roman', serif;font-size:16px;line-height:180%;text-align:center;mso-line-height-alt:28.8px;">
																	<p style="margin: 0; word-break: break-word;"><span style="color: #ffb966;">*TE RECORDAMOS QUE PARA QUE PODAMOS ENVIARTE EL PEDIDO TIENES QUE ENVIARNOS UNA COPIA DE TU DNI POR AMBAS CARAS.</span></p>
																</div>
															</td>
														</tr>
													</table>
													<table class="image_block block-7" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt;">
														<tr>
															<td class="pad" style="width:100%;">
																<div class="alignment" align="center" style="line-height:10px">
																	<div style="max-width: 500px;"><img src="https://093e4c9c26.imgdist.com/pub/bfra/eejdhl79/q0q/e8j/pmw/1000_F_262281968_7wsQfHSuCACq87tHOeYNhqJO2AjMVpfT-removebg-preview.png" style="display: block; height: auto; border: 0; width: 100%;" width="500" height="auto"></div>
																</div>
															</td>
														</tr>
													</table>
													<table class="button_block block-8" width="100%" border="0" cellpadding="10" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt;">
														<tr>
															<td class="pad">
																<div class="alignment" align="center"><!--[if mso]>
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="mailto:info@shootingzaragoza.com?subject=ENVIO%20DE%20DOCUMENTACI%C3%93N&body=" style="height:48px;width:326px;v-text-anchor:middle;" arcsize="9%" stroke="false" fillcolor="#f2bb16">
<w:anchorlock/>
<v:textbox inset="0px,0px,5px,0px">
<center dir="false" style="color:#ffffff;font-family:Georgia, 'Times New Roman', serif;font-size:19px">
<![endif]--><a href="mailto:info@shootingzaragoza.com?subject=ENVIO%20DE%20DOCUMENTACI%C3%93N&body=" target="_blank" style="background-color:#f2bb16;border-bottom:0px solid transparent;border-left:0px solid transparent;border-radius:4px;border-right:0px solid transparent;border-top:0px solid transparent;color:#ffffff;display:inline-block;font-family:'Bitter', Georgia, Times, 'Times New Roman', serif;font-size:19px;font-weight:700;mso-border-alt:none;padding-bottom:5px;padding-top:5px;text-align:center;text-decoration:none;width:auto;word-break:keep-all;"><span style="padding-left:40px;padding-right:45px;font-size:19px;display:inline-block;letter-spacing:normal;"><span style="word-break: break-word; line-height: 38px;">ENVIAR DOCUMENTACIÓN</span></span></a><!--[if mso]></center></v:textbox></v:roundrect><![endif]--></div>
															</td>
														</tr>
													</table>
													<div class="spacer_block block-9" style="height:30px;line-height:30px;font-size:1px;">&#8202;</div>
												</td>
											</tr>
										</tbody>
									</table>
								</td>
							</tr>
						</tbody>
					</table>
					<table class="row row-3" align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; background-position: top center;">
						<tbody>
							<tr>
								<td>
									<table class="row-content stack" align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #000000; width: 640px; margin: 0 auto;" width="640">
										<tbody>
											<tr>
												<td class="column column-1" width="100%" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; font-weight: 400; text-align: left; padding-bottom: 10px; padding-top: 10px; vertical-align: top; border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px;">
													<table class="image_block block-1" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt;">
														<tr>
															<td class="pad" style="width:100%;padding-right:0px;padding-left:0px;">
																<div class="alignment" align="center" style="line-height:10px">
																	<div style="max-width: 128px;"><img src="https://093e4c9c26.imgdist.com/pub/bfra/eejdhl79/p0h/7hy/55y/logoSR-01-178x200.png" style="display: block; height: auto; border: 0; width: 100%;" width="128" alt="Your Logo" title="Your Logo" height="auto"></div>
																</div>
															</td>
														</tr>
													</table>
													<div class="spacer_block block-2" style="height:25px;line-height:25px;font-size:1px;">&#8202;</div>
													<table class="paragraph_block block-3" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; word-break: break-word;">
														<tr>
															<td class="pad" style="padding-bottom:10px;padding-left:30px;padding-right:30px;padding-top:10px;">
																<div style="color:#ffffff;font-family:'Bitter', Georgia, Times, 'Times New Roman', serif;font-size:16px;line-height:180%;text-align:center;mso-line-height-alt:28.8px;">
																	<p style="margin: 0; word-break: break-word;"><span style="color: #ffffff;"><span>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. </span><span>Aenean commodo ligula eget dolor. Aenean massa.&nbsp;</span></span></p>
																</div>
															</td>
														</tr>
													</table>
													<table class="social_block block-4" width="100%" border="0" cellpadding="10" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt;">
														<tr>
															<td class="pad">
																<div class="alignment" align="center">
																	<table class="social-table" width="184px" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; display: inline-block;">
																		<tr>
																			<td style="padding:0 7px 0 7px;"><a href="https://www.facebook.com" target="_blank"><img src="https://app-rsrc.getbee.io/public/resources/social-networks-icon-sets/t-circle-white/facebook@2x.png" width="32" height="auto" alt="Facebook" title="facebook" style="display: block; height: auto; border: 0;"></a></td>
																			<td style="padding:0 7px 0 7px;"><a href="https://www.twitter.com" target="_blank"><img src="https://app-rsrc.getbee.io/public/resources/social-networks-icon-sets/t-circle-white/twitter@2x.png" width="32" height="auto" alt="Twitter" title="twitter" style="display: block; height: auto; border: 0;"></a></td>
																			<td style="padding:0 7px 0 7px;"><a href="https://www.linkedin.com" target="_blank"><img src="https://app-rsrc.getbee.io/public/resources/social-networks-icon-sets/t-circle-white/linkedin@2x.png" width="32" height="auto" alt="Linkedin" title="linkedin" style="display: block; height: auto; border: 0;"></a></td>
																			<td style="padding:0 7px 0 7px;"><a href="https://www.instagram.com" target="_blank"><img src="https://app-rsrc.getbee.io/public/resources/social-networks-icon-sets/t-circle-white/instagram@2x.png" width="32" height="auto" alt="Instagram" title="instagram" style="display: block; height: auto; border: 0;"></a></td>
																		</tr>
																	</table>
																</div>
															</td>
														</tr>
													</table>
													<table class="menu_block block-5" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt;">
														<tr>
															<td class="pad" style="color:#ffffff;font-family:'Bitter', Georgia, Times, 'Times New Roman', serif;font-size:14px;text-align:center;">
																<table width="100%" cellpadding="0" cellspacing="0" border="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt;">
																	<tr>
																		<td class="alignment" style="text-align:center;font-size:0px;">
																			<div class="menu-links"><!--[if mso]><table role="presentation" border="0" cellpadding="0" cellspacing="0" align="center" style=""><tr style="text-align:center;"><![endif]--><!--[if mso]><td style="padding-top:5px;padding-right:5px;padding-bottom:5px;padding-left:5px"><![endif]--><a href="www.example.com" target="_self" style="mso-hide:false;padding-top:5px;padding-bottom:5px;padding-left:5px;padding-right:5px;display:inline-block;color:#ffffff;font-family:'Bitter', Georgia, Times, 'Times New Roman', serif;font-size:14px;text-decoration:none;letter-spacing:normal;">Términos y condiciones</a><!--[if mso]></td><td><![endif]--><span class="sep" style="font-size:14px;font-family:'Bitter', Georgia, Times, 'Times New Roman', serif;color:#ffffff;">|</span><!--[if mso]></td><![endif]--><!--[if mso]><td style="padding-top:5px;padding-right:5px;padding-bottom:5px;padding-left:5px"><![endif]--><a href="www.example.com" target="_self" style="mso-hide:false;padding-top:5px;padding-bottom:5px;padding-left:5px;padding-right:5px;display:inline-block;color:#ffffff;font-family:'Bitter', Georgia, Times, 'Times New Roman', serif;font-size:14px;text-decoration:none;letter-spacing:normal;">Página web</a><!--[if mso]></td><![endif]--><!--[if mso]></tr></table><![endif]--></div>
																		</td>
																	</tr>
																</table>
															</td>
														</tr>
													</table>
													<div class="spacer_block block-6" style="height:40px;line-height:40px;font-size:1px;">&#8202;</div>
												</td>
											</tr>
										</tbody>
									</table>
								</td>
							</tr>
						</tbody>
					</table>
				</td>
			</tr>
		</tbody>
	</table><!-- End -->
</body>

</html>

En este punto deberías tener creado tu propio email, con imágenes, iconos, enlaces y contenidos personalizados.

El resultado es el siguiente:

Mi primer boceto de email de prueba, aún tengo que ponerle los textos originales enviados por el cliente.

Finalmente

  • Ahora toca crear la función principal, la que hace que todo se comporte como queremos.
  • Importante: Vamos a disparar nuestra función con el hook woocommerce_checkout_order_processed
  • Algunas cosas interesantes que hace la función: Comprueba si el pedido esta en estado «Pendiente» en ese caso pasan cosas. Entre ellas, obtenemos el email del comprador para luego poder enviarle nuestro correo personalizado.
  • Otra cosa que hacemos es obtener todas las categorías que hemos seleccionado en el campo de ACF.
  • Recorremos todos los productos que lleva el pedido y comparamos si sus categorías coinciden con las seleccionadas en nuestro campo ACF.
  • Si alguna coincide, entonces se activa el envío del correo.
  • Con wp_mail() enviamos el correo al comprador, con un asunto, encabezados personalizados y mandamos un email con un diseño bien desarrollado.
  • La función lleva una parte para procesar los errores que puedan surgir durante el envío.
<?php
add_action('woocommerce_order_status_changed', 'send_email_with_template', 10, 3);

function send_email_with_template($order_id, $old_status, $new_status) {
    // Verificar si el nuevo estado es 'pending'
    if ($new_status === 'pending') {
        // Obtener el pedido
        $order = wc_get_order($order_id);
        $user_email = $order->get_billing_email();
        $dni_required = false;

        // Obtener las categorías que requieren DNI desde el campo de ACF
        $categories_to_check = array();
        $categorias_email_especial_values = get_field('categorias_email_especial', 'option');
        if ($categorias_email_especial_values) {
            foreach ($categorias_email_especial_values as $categorias_email_especial_value) {
                $categories_to_check[] = esc_html($categorias_email_especial_value);
            }
        }

        // Recorrer los ítems del pedido
        foreach ($order->get_items() as $item_id => $item) {
            $product_id = $item->get_product_id();
            $product = wc_get_product($product_id);

            // Verificar si el producto pertenece a alguna de las categorías especificadas
            if (has_term($categories_to_check, 'product_cat', $product_id)) {
                $dni_required = true;
                break;
            }
        }

        // Si se requiere el DNI, enviar un correo electrónico al usuario
        if ($dni_required) {
            $subject = 'Se requiere copia de su DNI';

            // Cargar el contenido del archivo de plantilla desde el tema hijo
            ob_start();
            include get_stylesheet_directory() . '/templates/email-template.php';
            $message = ob_get_clean();

            // Establecer las cabeceras para enviar el correo en formato HTML
            $headers = array('Content-Type: text/html; charset=UTF-8');

            // Enviar el correo electrónico
            $mail_sent = wp_mail($user_email, $subject, $message, $headers);

            // Depuración: Verificar si el correo se envió correctamente
            if ($mail_sent) {
                error_log('Correo enviado exitosamente a ' . $user_email);
            } else {
                error_log('Error al enviar el correo a ' . $user_email);
            }
        } else {
            error_log('No se requiere DNI para el pedido ' . $order_id);
        }
    }
}

¿Qué más podemos hacer?

  • Controla los contenidos del código con campos personalizados, ofrece a tus clientes una forma fácil de cambiar destinatarios, mensajes, extractos, datos SMTP, etc.
  • Diseña varios boletines o emails y dale la oportunidad a tu cliente de elegir el que más se adecue a sus necesidades.
  • Ofrece también la posibilidad de personalizar estos emails, colores, tipografias, logo, imágenes… ¡Toda ayuda es buena!
  • Guarda un registro en una base de daros y programa con CROM otros envíos futuros. Crea un flujo de varios emails como hace Mailchimp o Klaviyo entre otros.

¡Enhorabuena! hemos completado una nueva funcionalidad personalizada con multitud de opciones. Fácil de extender y gestionada por nosotros mismos.

Espero que este manual te sirva de ayuda o te guíe de alguna forma en tus próximos proyectos. Si crees que le falta o le sobra algo al artículo, hazmelo saber, estaré encantado de recibir todo el feedback para mejorar.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *