Cómo crear un formulario de contacto en WordPress y recibir los mensajes con Brevo

Conecta un formulario de WordPress con Brevo por API: dominio autenticado, listas por sección y correos que no caen en spam. Código completo.

Formulario de contacto con Brevo

Un formulario de contacto normal te avisa por correo cuando alguien te escribe, y ahí termina todo. Pero si conectas tu formulario con Brevo, cada persona que deja su correo pasa a formar parte de una lista con la que puedes comunicarte después: enviarle novedades, nuevas convocatorias, un curso o tus últimos artículos. Es la base para construir una comunidad propia que no depende de las redes sociales.

En este tutorial te explico por qué elijo Brevo, cómo configurar tu dominio para que tus correos no caigan en spam, cómo conectar un formulario de WordPress con Brevo mediante su API (con el código completo), cómo organizar los contactos según la sección de tu web y con qué frecuencia enviar.

¿Por qué debes usar Brevo para el envio de mensajes?

Desde mi experiencia, Brevo es una de las plataformas más completas para empezar con el email marketing. Tiene muchas funciones (listas, plantillas de correo, automatizaciones, envío de correos desde tu web) y, sobre todo, un plan gratuito generoso: permite enviar hasta 300 correos al día sin pagar.

Si estás empezando y tu lista tiene 50, 100 o 200 personas, puedes enviarles un correo a todas sin gastar nada. Cuando tu lista crezca y necesites enviar más, pasas a un plan de pago que elimina el límite diario.

Los límites y precios de los planes cambian con el tiempo, así que revísalos en la web de Brevo antes de empezar.

Planes de brevo
Brevo tiene una sección gratuita que te permite mandar hasta 300 correos en un solo día.

Antes de conectar nada: configura tu dominio

Este es el paso que más gente se salta, y es el responsable de que muchos correos terminen en la carpeta de spam. Si envías correos desde una dirección genérica o sin autenticar tu dominio, Gmail y otros proveedores desconfían.

1. Usa un correo con tu propio dominio

Envía siempre desde una dirección como hola@tudominio.com, no desde una cuenta gratuita de Gmail. En mi caso uso Google Workspace, que me permite crear correos con mi dominio (@juniorolivares.com) y añadir usuarios para mi equipo.

Ahora mira, esto depende de dónde tengas tu dominio principal. Si lo compraste en otras plataformas, por ejemplo GoDaddy, AWS de Amazon o Hostinger, tendrías que configurar los DNS para que tu dominio apunte a la plataforma donde vas a configurar tu correo electrónico, en este caso Google Workspace.

Bien, entonces depende mucho de la plataforma donde hayas comprado tu dominio, porque sí o sí tendrías que usar los DNS. Hay algunos registros que tienes que crear. Por ejemplo, aquí te voy a mostrar algunos de los registros que tengo yo, considerando que mi dominio juniorolivares.com lo tengo en la consola de AWS, dentro de Route 53. Aquí vas a poder ver los diferentes registros que tengo para conectar mi dominio con Google Workspace. De esta manera, Google puede confirmar que yo soy el propietario de ese dominio y, a partir de ahí, puedo crear diferentes correos electrónicos con mi dominio.

Sección en Route 53 de AWS Console.

Ahora, Brevo sirve solo para el tema de marketing, es decir, para el envío de correos electrónicos. Brevo tiene funciones que te permiten crear una plantilla y subir tu lista de contactos, es decir, la lista de correos electrónicos, para luego enviarles el correo con un solo clic. En su versión gratuita puedes enviar hasta 300 correos electrónicos al día.

2. Autentica tu dominio en Brevo

En Brevo, en la sección de remitentes y dominios, añades tu dominio. Brevo te da unos registros que tienes que copiar en el panel DNS de tu proveedor de dominio:

  • Código de verificación de Brevo: demuestra que el dominio es tuyo.
  • DKIM: una firma digital que prueba que el correo salió de ti y no fue alterado.
  • SPF: autoriza a Brevo a enviar correos en nombre de tu dominio. Si ya usas Google Workspace, no crees un segundo registro SPF: añade Brevo al que ya tienes.
  • DMARC: le dice a los proveedores de correo qué hacer con los mensajes que no pasan las comprobaciones.

Los cambios en las DNS pueden tardar desde unos minutos hasta unas horas en activarse. Cuando Brevo marque todo en verde, tu dominio está listo. Si no sabes cómo hacer este paso en tu proveedor de dominio, la IA te puede guiar pantalla por pantalla.

Mira, cuando estés en Brevo, inicia sesión con tu cuenta de correo electrónico, por ejemplo con tu Gmail. Luego dirígete a la sección Configuración (o Settings, en inglés) y después a Configuración de la organización. Ahí hay una opción llamada Remitentes, dominios e IP, y ahí van a aparecer los registros DNS para que puedas autenticar tu dominio.

Mensaje de conexión correcta en los DNS con Brevo
Mensaje de conexión correcta en los DNS con Brevo

Hay diferentes tipos de registros de autenticación. Por ejemplo:

  • El código de Brevo, de tipo TXT.
  • El registro DKIM 1, de tipo CNAME.
  • El registro DKIM 2, también de tipo CNAME.
  • El registro DMARC, de tipo TXT. Su nombre suele ser _dmarc y el valor es el que te da Brevo.
  • El registro de marca, de tipo CNAME.
  • El registro de redireccionamiento, también de tipo CNAME, cuyo nombre suele ser r.mail.
  • El registro de redireccionamiento de imágenes, de tipo CNAME, cuyo nombre es img.mail.

Esos son la mayoría, por no decir todos, los registros DNS que tiene que tener tu dominio para que puedas autenticarlo en Brevo. Esto lo puedes hacer en la plataforma donde tengas tu dominio, ya sea GoDaddy o la consola de AWS de Amazon.

Cuando termines de configurar estos registros, puedes verificar y tras hacerlo, tendrás mensajes el verde.

3. Crea tus listas y tu clave API

  • Listas: en Contactos > Listas, crea una lista para cada grupo de personas. Cada lista tiene un número (ID) que usaremos en el formulario.
  • Clave API: en la configuración de tu cuenta, en la sección de claves API, genera una clave nueva. Es como una contraseña que permite a tu web hablar con Brevo. Nunca la publiques ni la compartas: quien la tenga puede usar tu cuenta.

Tres formas de conectar tu web con Brevo

Con el plugin oficial de Brevo. Es lo más rápido si no quieres tocar código, pero añade otro plugin a tu web con funciones que quizá no uses. lo encuentras directamente en la tienda en WordPress.

Con un plugin propio que use la API de Brevo. Es lo que hago yo. Mi plugin tiene una sección de configuración donde pego la clave de Brevo, y el formulario envía cada contacto directamente a la lista correcta. Más abajo encontrarás el paso a paso de como puedes armar un plugin similar

Así se ve el plugin de conexión de Brevo, un plugin personalizado creado por nosotros.
Así se ve el plugin de conexión de Brevo, un plugin personalizado creado por nosotros.

Fuera de WordPress. Si tu proyecto está hecho con otra tecnología, como Next.js con Supabase, puedes guardar los correos en tu base de datos, exportarlos a una hoja de cálculo e importarlos en Brevo a mano. No es automático, pero funciona.

En este tutorial usamos la segunda opción, un plugin que usa la API de brevo.

¿Cómo crear el plugin que conecte Brevo con tu página web hecha en WordPress?

Crea la carpeta formulario-brevo en wp-content/plugins y un archivo formulario-brevo.php.

1. Ajustes: tu clave API

<?php
/**
 * Plugin Name: Formulario Brevo
 * Description: Formulario de suscripción que envía los contactos a listas de Brevo.
 * Version: 1.0
 */
if ( ! defined( 'ABSPATH' ) ) exit;

add_action( 'admin_menu', function () {
  add_options_page( 'Brevo', 'Brevo', 'manage_options', 'formulario-brevo', 'fb_ajustes' );
} );
add_action( 'admin_init', function () {
  register_setting( 'fb_grupo', 'fb_api_key', array( 'sanitize_callback' => 'sanitize_text_field' ) );
  register_setting( 'fb_grupo', 'fb_listas', array( 'sanitize_callback' => 'sanitize_text_field' ) );
} );
function fb_ajustes() { ?>
  <div class="wrap"><h1>Conexión con Brevo</h1>
  <form method="post" action="options.php">
    <?php settings_fields( 'fb_grupo' ); ?>
    <p><label>Clave API<br><input type="password" class="regular-text" name="fb_api_key" value="<?php echo esc_attr( get_option( 'fb_api_key' ) ); ?>"></label></p>
    <p><label>IDs de listas permitidas (separados por comas)<br><input type="text" name="fb_listas" value="<?php echo esc_attr( get_option( 'fb_listas' ) ); ?>"></label></p>
    <?php submit_button(); ?>
  </form></div>
<?php }

Esto crea Ajustes > Brevo, donde pegas tu clave API y los números de las listas que tu web puede usar. La clave se muestra como contraseña para que nadie la lea por encima de tu hombro.

2. El formulario, con una lista distinta según la sección

add_shortcode( 'formulario_brevo', function ( $atts ) {
  $atts = shortcode_atts( array( 'lista' => '' ), $atts );
  ob_start();
  if ( isset( $_GET['suscrito'] ) ) {
    echo '<p class="fb-ok">¡Listo! Ya estás en la lista.</p>';
  }
  ?>
  <form class="fb-form" method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
    <input type="hidden" name="action" value="fb_suscribir">
    <input type="hidden" name="fb_lista" value="<?php echo esc_attr( $atts['lista'] ); ?>">
    <?php wp_nonce_field( 'fb_suscribir', 'fb_nonce' ); ?>
    <input type="text" name="fb_nombre" placeholder="Tu nombre" required>
    <input type="email" name="fb_correo" placeholder="Tu correo" required>
    <label><input type="checkbox" required> Acepto la política de privacidad</label>
    <button type="submit">Suscribirme</button>
  </form>
  <?php
  return ob_get_clean();
} );

El shortcode acepta un atributo lista. Así puedes poner [ formulario_brevo lista="3" ] en una sección y [ formulario_brevo lista="4" ] en otra, y cada contacto va a la lista correcta.

3. Enviar el contacto a Brevo

function fb_suscribir() {
  if ( ! isset( $_POST['fb_nonce'] ) || ! wp_verify_nonce( $_POST['fb_nonce'], 'fb_suscribir' ) ) wp_die( 'Solicitud no válida.' );
  $nombre = sanitize_text_field( wp_unslash( $_POST['fb_nombre'] ?? '' ) );
  $correo = sanitize_email( wp_unslash( $_POST['fb_correo'] ?? '' ) );
  $lista  = absint( $_POST['fb_lista'] ?? 0 );
  $permitidas = array_map( 'absint', explode( ',', (string) get_option( 'fb_listas' ) ) );
  if ( ! is_email( $correo ) || ! in_array( $lista, $permitidas, true ) ) wp_die( 'Datos no válidos.' );

  $respuesta = wp_remote_post( 'https://api.brevo.com/v3/contacts', array(
    'timeout' => 15,
    'headers' => array(
      'api-key'      => get_option( 'fb_api_key' ),
      'Content-Type' => 'application/json',
      'Accept'       => 'application/json',
    ),
    'body' => wp_json_encode( array(
      'email'         => $correo,
      'attributes'    => array( 'FIRSTNAME' => $nombre ),
      'listIds'       => array( $lista ),
      'updateEnabled' => true,
    ) ),
  ) );
  if ( is_wp_error( $respuesta ) || wp_remote_retrieve_response_code( $respuesta ) >= 300 ) {
    wp_die( 'No pudimos registrarte. Inténtalo de nuevo más tarde.' );
  }
  $volver = wp_get_referer() ? wp_get_referer() : home_url();
  wp_safe_redirect( add_query_arg( 'suscrito', '1', $volver ) );
  exit;
}
add_action( 'admin_post_nopriv_fb_suscribir', 'fb_suscribir' );
add_action( 'admin_post_fb_suscribir', 'fb_suscribir' );

¿Qué hace esta función?

  1. Comprueba el nonce y limpia el nombre y el correo.
  2. Verifica que la lista esté entre las permitidas en los ajustes. Sin esto, alguien podría cambiar el número de lista desde el navegador y meter contactos en una lista que no corresponde.
  3. Envía el contacto a la API de Brevo con wp_remote_post. La opción updateEnabled hace que, si el correo ya existía, se actualice y se añada a la nueva lista en lugar de dar error.
  4. Si Brevo responde con un error, muestra un mensaje amable. Si todo sale bien, devuelve al usuario a la misma página con un mensaje de confirmación.

¿Cómo organiza tus contactos según la sección de tu web?

Aquí está el verdadero valor de esta técnica. El lugar donde alguien deja su correo te dice qué le interesa.

Por ejemplo, en una web de convocatorias de trabajo:

  • Quien se suscribe en la página de empleos de administración quiere recibir convocatorias de administración.
  • Quien se suscribe en la página de prácticas preprofesionales y profesionales quiere recibir prácticas.

Si usas una lista distinta para cada sección, cuando envíes un correo le llegará a cada persona solo lo que le interesa. Eso aumenta las aperturas, reduce las bajas y evita que te marquen como spam. Poco a poco, cada formulario alimenta tu base de datos de contactos segmentada.

Ejemplo de uso en una web de Convocatorias de Trabajo

Ahora, siguiendo con este mismo tema de las convocatorias de trabajo: cuando publicas convocatorias de empleo, hay diferentes tipos de búsqueda que un usuario podría hacer al entrar a tu página web hecha en WordPress.

Por ejemplo, mira, cuando yo comencé a publicar muchos videos sobre convocatorias de trabajo en la página El Paisano Trabajos o El Paisano Convocatorias, en TikTok y en diferentes redes sociales, las personas entraban a mi página web, donde había un buscador, y comenzaban a buscar: prácticas, trabajos en salud, trabajos en universidades, trabajos para practicantes, trabajos sin experiencia, trabajos para bachilleres, prácticas preprofesionales y profesionales, o trabajos en el sector minero. Entonces, las palabras, las frases o keywords que los usuarios escriben en el buscador son muy variadas.

Esto es muy importante, porque puedes tener páginas principales, por ejemplo, “Trabajos en minería”, y ahí colocar tu buscador, mostrar las convocatorias vigentes y, a un costado, mostrar el formulario para que el usuario deje su correo electrónico si le interesan esas convocatorias. Esto, como te mencioné antes en este mismo contenido, te permite tener tu propia lista de personas interesadas en diferentes trabajos, y con este plugin también puedes segmentarla.

Hay una gran diferencia en tener un plugin personalizado para alimentar a tu lista de contactos a tener un canal de WhatsApp, porque en el plugin con el lista brevo hace que tu tengas más control sobre las personas interesadas. En un canal de WhatsApp las personas se suscriben, pero realmente no tienes ningún contacto directo con ellas. Ahora, en cambio, tienes una fuente propia, digamos una base de datos, que te permite ya no depender de la cantidad de personas que entran a tu página web ni de cuántas visualizaciones te da el algoritmo de alguna red social.

Con este nuevo plugin de conexción tu la lista de correos electrónicos se vuelve tu fuente de tráfico. Podrías tener 1000, 5000 o 10 000 correos electrónicos y, cada semana, ir enviando las convocatorias activas y vigentes que se van publicando, según el interés de cada persona. Y también podrías segmentar.

Podrías ofrecer, por ejemplo, cómo crear un buen CV en Perú, cómo responder a las preguntas más comunes que te hacen en una entrevista de trabajo, y así muchas otras opciones. Todo lo relacionado con el empleo: conseguir el primer trabajo, el currículum vitae y todo lo que sume.

También podrías ofrecer cursos de Excel, de inglés, de administración o de inteligencia artificial enfocados en cada rubro o profesión. Todo eso suma, porque ahora muchas personas quieren aprender estas cosas. Y si ya tienes la lista de correos electrónicos, además de compartir por correo una oportunidad laboral, podrías acompañar esa información con cursos nuevos relacionados con esa convocatoria.

¿Con qué frecuencia enviar un mensaje en Brevo? Mi recomendación

Tener una lista de 1.000, 2.000 o 5.000 correos no significa que debas escribirles todos los días. Si envías demasiados correos, la gente deja de abrirlos, empieza a marcarlos como spam, y Gmail y otros proveedores empiezan a mandar tus mensajes directamente a la carpeta de correo no deseado.

Lo recomendable es tener una estrategia: por ejemplo, un correo a la semana, con contenido útil. Para una web de empleos, un resumen semanal de las mejores convocatorias de cada sector funciona muy bien.

Recuerda también el límite de tu plan: con el gratuito, si tu lista supera los 300 contactos, tendrás que repartir el envío en varios días o pasar a un plan de pago. Incluso el plan básico te sirve para hacer envíos de prueba, así poder testear tus mensajes enviados.

Y no todo termina ahí, porque también hay pagos adicionales que probablemente no estés contemplando. Para tener un correo electrónico con tu dominio, a ver, tienes que evaluar cuántos correos necesitas en realidad: el correo de contacto, tal vez el de compras y ventas, el de marketing. Entonces evalúas cuántos usuarios de tu página web van a tener un correo electrónico con tu dominio principal, porque cada usuario que registras en Google Workspace tiene un costo: un pago mensual que tienes que hacer. Así funciona.

Por ejemplo, actualmente yo tengo solo un correo, que es contacto@juniorolivares.com. Lo tengo a raíz de un proyecto que creé en juniorolivares.com, donde hablo de herramientas de monetización y ofrezco cursos educativos. Es muy importante considerar eso.

En cuanto al límite, quiero que entiendas esto: Google Workspace solo te ayuda a configurar y tener tu lista de usuarios con su correo electrónico. Pero si quieres enviar mensajes con plantillas personalizadas, con diseños en HTML y demás, usas Brevo. Brevo tiene un plan gratuito, pero probablemente, a medida que tu lista de contactos crezca (1000, 2000 o 5000 correos electrónicos), tengas que pasarte a un plan de pago dentro de Brevo.

Pero también tienes que tener en cuenta los pagos mensuales que te va a facturar Google Workspace y que tienes que pagar a fin de mes, porque se paga por cada usuario. Entonces también tienes que evaluar eso y qué proveedor puedes escoger. Por ejemplo, GoDaddy también te da el servicio de enviar correos electrónicos.

Termino dándote el código completo del plugin para su instalación

Tienes que seguir estos pasos para instalar este plugin. Mira, aquí abajo te dejo el código completo, en un solo archivo. El nombre lo puedes cambiar, pero te recomiendo que le pongas formulario-brevo.php.

Como vas a poder ver, si lo analizas bien, antes de instalarlo tienes que guardarlo como archivo .php. Luego, una vez guardado, tienes que comprimirlo en un archivo .zip con el mismo nombre.

En el código vas a poder ver las diferentes secciones que te mostré en la imagen anterior y que tienes que llenar, como por ejemplo la clave API de Brevo. También vas a ver el campo de los ID de las listas permitidas, separados por comas, y un pequeño tutorial de cómo usarlo, con los shortcodes que se van a generar.

Ese es el código completo, así que guárdalo, comprímelo, súbelo en la sección de Plugins de WordPress e instálalo.

<?php
/**
 * Plugin Name:       Formulario Brevo
 * Description:       Formulario de suscripción que envía cada contacto a una lista de Brevo. Usa el shortcode [formulario_brevo lista="3"].
 * Version:           1.1.0
 * Requires at least: 5.6
 * Requires PHP:      7.4
 * Author:            Junior Olivares
 * License:           GPL-2.0-or-later
 * Text Domain:       formulario-brevo
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

define( 'FB_VERSION', '1.1.0' );

/* -------------------------------------------------------------------------
 * 1. Ajustes: clave API y listas permitidas
 * ---------------------------------------------------------------------- */

add_action( 'admin_menu', function () {
	add_options_page( 'Brevo', 'Brevo', 'manage_options', 'formulario-brevo', 'fb_pagina_ajustes' );
} );

add_action( 'admin_init', function () {
	register_setting( 'fb_grupo', 'fb_api_key', array(
		'type'              => 'string',
		'sanitize_callback' => 'fb_sanitizar_api_key',
		'default'           => '',
	) );
	register_setting( 'fb_grupo', 'fb_listas', array(
		'type'              => 'string',
		'sanitize_callback' => 'fb_sanitizar_listas',
		'default'           => '',
	) );
	register_setting( 'fb_grupo', 'fb_url_privacidad', array(
		'type'              => 'string',
		'sanitize_callback' => 'esc_url_raw',
		'default'           => '',
	) );
} );

/**
 * Si el campo de la clave se deja vacío, se conserva la clave guardada
 * (así no hace falta volver a pegarla cada vez que se guardan los ajustes).
 */
function fb_sanitizar_api_key( $valor ) {
	$valor = trim( sanitize_text_field( (string) $valor ) );
	return '' === $valor ? (string) get_option( 'fb_api_key', '' ) : $valor;
}

/** Deja solo números separados por comas: "3, 4,abc,5" -> "3,4,5". */
function fb_sanitizar_listas( $valor ) {
	$ids = array_filter( array_map( 'absint', explode( ',', (string) $valor ) ) );
	return implode( ',', array_unique( $ids ) );
}

function fb_pagina_ajustes() {
	if ( ! current_user_can( 'manage_options' ) ) {
		return;
	}
	$hay_clave = '' !== (string) get_option( 'fb_api_key', '' );
	?>
	<div class="wrap">
		<h1>Conexión con Brevo</h1>
		<form method="post" action="options.php">
			<?php settings_fields( 'fb_grupo' ); ?>
			<table class="form-table" role="presentation">
				<tr>
					<th scope="row"><label for="fb_api_key">Clave API de Brevo</label></th>
					<td>
						<input type="password" id="fb_api_key" name="fb_api_key" class="regular-text" value="" autocomplete="off"
							placeholder="<?php echo $hay_clave ? '•••••••• (guardada)' : 'xkeysib-...'; ?>">
						<p class="description">
							<?php echo $hay_clave
								? 'Ya hay una clave guardada. Déjalo vacío para mantenerla o pega una nueva para reemplazarla.'
								: 'Pégala desde Brevo → Configuración → Claves API. No la compartas con nadie.'; ?>
						</p>
					</td>
				</tr>
				<tr>
					<th scope="row"><label for="fb_listas">IDs de listas permitidas</label></th>
					<td>
						<input type="text" id="fb_listas" name="fb_listas" class="regular-text"
							value="<?php echo esc_attr( get_option( 'fb_listas' ) ); ?>" placeholder="3,4,5">
						<p class="description">Números de lista separados por comas (Brevo → Contactos → Listas).</p>
					</td>
				</tr>
				<tr>
					<th scope="row"><label for="fb_url_privacidad">Página de política de privacidad</label></th>
					<td>
						<input type="url" id="fb_url_privacidad" name="fb_url_privacidad" class="regular-text"
							value="<?php echo esc_attr( get_option( 'fb_url_privacidad', get_privacy_policy_url() ) ); ?>">
						<p class="description">Opcional. Se enlaza en la casilla de aceptación del formulario.</p>
					</td>
				</tr>
			</table>
			<?php submit_button(); ?>
		</form>

		<h2>Cómo usarlo</h2>
		<p>Inserta el shortcode en cualquier página, entrada o widget, indicando el ID de la lista:</p>
		<p><code>[formulario_brevo lista="3"]</code></p>
		<p>Opcionalmente puedes cambiar el texto del botón: <code>[formulario_brevo lista="4" boton="Quiero recibir prácticas"]</code></p>
	</div>
	<?php
}

/* Enlace "Ajustes" en la lista de plugins. */
add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), function ( $enlaces ) {
	array_unshift( $enlaces, '<a href="' . esc_url( admin_url( 'options-general.php?page=formulario-brevo' ) ) . '">Ajustes</a>' );
	return $enlaces;
} );

/* -------------------------------------------------------------------------
 * 2. Formulario (shortcode) con una lista distinta según la sección
 * ---------------------------------------------------------------------- */

add_shortcode( 'formulario_brevo', function ( $atts ) {
	$atts = shortcode_atts( array(
		'lista' => '',
		'boton' => 'Suscribirme',
	), $atts, 'formulario_brevo' );

	$lista = absint( $atts['lista'] );
	if ( ! $lista ) {
		return current_user_can( 'manage_options' )
			? '<p class="fb-aviso fb-error">Formulario Brevo: falta el atributo <code>lista</code> en el shortcode.</p>'
			: '';
	}

	wp_enqueue_style( 'formulario-brevo' );

	// Mensaje solo para el formulario de la misma lista que se envió.
	$mensaje = '';
	if ( isset( $_GET['fb_estado'], $_GET['fb_lista'] ) && absint( $_GET['fb_lista'] ) === $lista ) {
		$estado = sanitize_key( wp_unslash( $_GET['fb_estado'] ) );
		if ( 'ok' === $estado ) {
			$mensaje = '<p class="fb-aviso fb-ok" role="status">¡Listo! Ya estás en la lista.</p>';
		} elseif ( 'datos' === $estado ) {
			$mensaje = '<p class="fb-aviso fb-error" role="alert">Revisa tu nombre y correo, y acepta la política de privacidad.</p>';
		} elseif ( 'error' === $estado ) {
			$mensaje = '<p class="fb-aviso fb-error" role="alert">No pudimos registrarte. Inténtalo de nuevo más tarde.</p>';
		}
	}

	$url_privacidad = (string) get_option( 'fb_url_privacidad', get_privacy_policy_url() );
	$texto_privacidad = $url_privacidad
		? 'Acepto la <a href="' . esc_url( $url_privacidad ) . '" target="_blank" rel="noopener">política de privacidad</a>'
		: 'Acepto la política de privacidad';

	$id = 'fb-form-' . $lista;

	ob_start();
	?>
	<div class="fb-contenedor" id="<?php echo esc_attr( $id ); ?>">
		<?php echo $mensaje; // phpcs:ignore WordPress.Security.EscapeOutput -- HTML fijo definido arriba. ?>
		<form class="fb-form" method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
			<input type="hidden" name="action" value="fb_suscribir">
			<input type="hidden" name="fb_lista" value="<?php echo esc_attr( $lista ); ?>">
			<?php wp_nonce_field( 'fb_suscribir', 'fb_nonce' ); ?>

			<!-- Campo trampa contra bots: las personas no lo ven. -->
			<div class="fb-trampa" aria-hidden="true">
				<label>No llenar <input type="text" name="fb_web" tabindex="-1" autocomplete="off"></label>
			</div>

			<input type="text" name="fb_nombre" placeholder="Tu nombre" required maxlength="100" autocomplete="given-name">
			<input type="email" name="fb_correo" placeholder="Tu correo" required maxlength="190" autocomplete="email">
			<label class="fb-privacidad">
				<input type="checkbox" name="fb_privacidad" value="1" required>
				<?php echo wp_kses( $texto_privacidad, array( 'a' => array( 'href' => array(), 'target' => array(), 'rel' => array() ) ) ); ?>
			</label>
			<button type="submit"><?php echo esc_html( $atts['boton'] ); ?></button>
		</form>
	</div>
	<?php
	return ob_get_clean();
} );

/* Estilos mínimos (se cargan solo en páginas con el formulario). */
add_action( 'wp_enqueue_scripts', function () {
	wp_register_style( 'formulario-brevo', false, array(), FB_VERSION );
	wp_add_inline_style( 'formulario-brevo', '
		.fb-form{display:flex;flex-direction:column;gap:.6em;max-width:420px}
		.fb-form input[type=text],.fb-form input[type=email]{padding:.6em .8em;border:1px solid #ccc;border-radius:6px;width:100%;box-sizing:border-box}
		.fb-form button{padding:.7em 1em;border:0;border-radius:6px;cursor:pointer}
		.fb-privacidad{font-size:.9em}
		.fb-trampa{position:absolute!important;left:-9999px!important;width:1px;height:1px;overflow:hidden}
		.fb-aviso{padding:.6em .8em;border-radius:6px;max-width:420px}
		.fb-ok{background:#e7f6ec;color:#1e6b34}
		.fb-error{background:#fdecec;color:#8a1f1f}
	' );
} );

/* -------------------------------------------------------------------------
 * 3. Enviar el contacto a Brevo
 * ---------------------------------------------------------------------- */

function fb_suscribir() {
	$lista  = absint( $_POST['fb_lista'] ?? 0 );
	$volver = wp_get_referer() ? wp_get_referer() : home_url( '/' );
	$volver = remove_query_arg( array( 'fb_estado', 'fb_lista' ), $volver );

	$redirigir = function ( $estado ) use ( $volver, $lista ) {
		$url = add_query_arg( array( 'fb_estado' => $estado, 'fb_lista' => $lista ), $volver );
		wp_safe_redirect( $url . '#fb-form-' . $lista );
		exit;
	};

	if ( ! isset( $_POST['fb_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['fb_nonce'] ) ), 'fb_suscribir' ) ) {
		$redirigir( 'error' );
	}

	// Si un bot llenó el campo trampa, fingimos éxito y no enviamos nada.
	if ( ! empty( $_POST['fb_web'] ) ) {
		$redirigir( 'ok' );
	}

	$nombre     = sanitize_text_field( wp_unslash( $_POST['fb_nombre'] ?? '' ) );
	$correo     = sanitize_email( wp_unslash( $_POST['fb_correo'] ?? '' ) );
	$privacidad = ! empty( $_POST['fb_privacidad'] );
	$permitidas = array_filter( array_map( 'absint', explode( ',', (string) get_option( 'fb_listas' ) ) ) );

	if ( '' === $nombre || ! is_email( $correo ) || ! $privacidad ) {
		$redirigir( 'datos' );
	}

	// Evita que alguien cambie el número de lista desde el navegador.
	if ( ! in_array( $lista, $permitidas, true ) ) {
		$redirigir( 'error' );
	}

	$api_key = (string) get_option( 'fb_api_key' );
	if ( '' === $api_key ) {
		$redirigir( 'error' );
	}

	$respuesta = wp_remote_post( 'https://api.brevo.com/v3/contacts', array(
		'timeout' => 15,
		'headers' => array(
			'api-key'      => $api_key,
			'Content-Type' => 'application/json',
			'Accept'       => 'application/json',
		),
		'body'    => wp_json_encode( array(
			'email'         => $correo,
			'attributes'    => array( 'FIRSTNAME' => $nombre ),
			'listIds'       => array( $lista ),
			'updateEnabled' => true, // Si el correo ya existe, se actualiza y se añade a la lista.
		) ),
	) );

	$codigo = is_wp_error( $respuesta ) ? 0 : (int) wp_remote_retrieve_response_code( $respuesta );
	if ( $codigo < 200 || $codigo >= 300 ) {
		if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
			error_log( 'Formulario Brevo: error ' . ( is_wp_error( $respuesta ) ? $respuesta->get_error_message() : $codigo . ' ' . wp_remote_retrieve_body( $respuesta ) ) );
		}
		$redirigir( 'error' );
	}

	$redirigir( 'ok' );
}
add_action( 'admin_post_nopriv_fb_suscribir', 'fb_suscribir' );
add_action( 'admin_post_fb_suscribir', 'fb_suscribir' );

Junior Olivares

Soy Junior Olivares, ingeniero de procesos peruano que lleva más de 6 años viviendo de internet. Creo webs, herramientas con una programación limpia y herramientas de IA.

Go up