Conecta tus Formularios de Elementor Pro con GoHighLevel

Facebook
Twitter
LinkedIn
WhatsApp

Esta guía te enseñará a crear un plugin de WordPress personalizado para enviar los datos de tus formularios de Elementor Pro directamente a tu cuenta de GoHighLevel (GHL). Esta solución es robusta, segura y te da control total sobre la información enviada.

Beneficios de este método:

  • Automatización: Envía leads y contactos a GHL sin intervención manual.
  • Seguridad: Tus claves API se almacenan de forma segura, y la integración opera dentro del entorno de WordPress.
  • Organización: El código está contenido en un plugin dedicado, separado de tu tema.
  • Flexibilidad: Fácil de adaptar para múltiples formularios y diferentes acciones en GHL (como aplicar etiquetas específicas).

Requisitos Previos:

  • WordPress con Elementor Pro instalado y activo.
  • Una cuenta de GoHighLevel con acceso a tu API Key y el Location ID donde quieres enviar los contactos.
  • Acceso a los archivos de tu servidor (vía FTP, cPanel File Manager, etc.) para crear el plugin y editar el archivo .htaccess.
  • Un editor de texto para copiar y pegar el código.

Paso 1: Configurar Variables de Entorno en .htaccess

Para mantener tus credenciales seguras, las almacenaremos fuera del código del plugin.

  1. Accede al archivo .htaccess en el directorio raíz de tu instalación de WordPress (generalmente public_html/).
  2. Añade las siguientes líneas al final del archivo:
    SetEnv GHL_API_KEY "API_KEY_DE_GOHIGHLEVEL"
    SetEnv GHL_LOCATION_ID "LOCATION_ID_DE_GOHIGHLEVEL"
  3. Reemplaza los textos en mayúsculas con tu API Key real de GoHighLevel y tu Location ID.
  4. Guarda el archivo .htaccess.

Paso 2: Crear la Estructura de Carpetas del Plugin

  • En tu computadora, crea una carpeta principal para tu plugin. Un buen nombre podría ser mi-elementor-ghl-integracion.
  • Dentro de la carpeta mi-elementor-ghl-integracion/, crea la siguiente estructura:
    • mi-elementor-ghl-integracion.php (Este será el archivo principal del plugin)includes/ (Una subcarpeta llamada includes)
      • common-ghl-functions.php (Dentro de includes/)
      form-configs/ (Una subcarpeta llamada form-configs)
      • (Aquí irán los archivos de configuración para cada formulario, ej. newsletter-form-handler.php)
    Tu estructura se verá así:
  • También necesitaremos un directorio para los logs dentro de wp-content/uploads/. El plugin intentará crearlo, pero es bueno saberlo: wp-content/uploads/me-ghl-logs/ (usaremos me-ghl- como prefijo para “Mi Elementor GHL”).

Paso 3: Código del Archivo de Funciones Comunes

Este archivo contendrá funciones reutilizables para el logging y para enviar datos a GHL.

Crea el archivo includes/common-ghl-functions.php y pega el siguiente código:

<?php
// /wp-content/plugins/mi-elementor-ghl-integracion/includes/common-ghl-functions.php

if ( ! defined( 'ABSPATH' ) ) {
    exit; // No acceso directo.
}

/**
 * Escribe un mensaje en el archivo de log del plugin.
 */
if (!function_exists('me_ghl_write_log')) {
    function me_ghl_write_log(string $message): void {
        if (!defined('ME_GHL_LOG_DIR') || !defined('ME_GHL_LOG_FILE')) {
            error_log("ME-GHL Log Error: Constantes de log no definidas. Mensaje: " . $message);
            return;
        }
        if (!is_dir(ME_GHL_LOG_DIR)) {
            if (!@wp_mkdir_p(ME_GHL_LOG_DIR)) { // Intenta crear recursivamente
                 error_log("ME-GHL Log Error: No se pudo crear dir de logs: " . ME_GHL_LOG_DIR . ". Mensaje: " . $message);
                 return;
            }
        }
        @file_put_contents(ME_GHL_LOG_FILE, "[" . date("Y-m-d H:i:s") . "] " . $message . "\n", FILE_APPEND);
    }
}

/**
 * Envía datos de contacto a la API de GoHighLevel.
 */
if (!function_exists('me_ghl_send_contact_to_ghl')) {
    function me_ghl_send_contact_to_ghl(array $contactPayloadArray, string $ghlApiKey): array {
        $result = [
            'success' => false, 'http_code' => 0, 'response_body' => '', 'error_message' => ''
        ];
        if (empty($ghlApiKey)) { 
            me_ghl_write_log("Error en me_ghl_send_contact_to_ghl: GHL API Key está vacía.");
            $result['error_message'] = "GHL API Key no proporcionada.";
            return $result;
        }
        $ghl_api_url = 'https://rest.gohighlevel.com/v1/contacts/';
        $ghl_payload_json = json_encode($contactPayloadArray);

        if (json_last_error() !== JSON_ERROR_NONE) { 
            $jsonErrorMsg = json_last_error_msg();
            me_ghl_write_log('Error: No se pudo codificar el payload para GHL. Error JSON: ' . $jsonErrorMsg . ' | Payload Array: ' . print_r($contactPayloadArray, true));
            $result['error_message'] = 'Error de codificación JSON para GHL: ' . $jsonErrorMsg;
            return $result;
        }
        
        $args = [
            'method'    => 'POST', 
            'timeout'   => 30,
            'headers'   => [
                'Content-Type'  => 'application/json; charset=utf-8',
                'Authorization' => 'Bearer ' . $ghlApiKey,
            ],
            'body'      => $ghl_payload_json,
        ];

        me_ghl_write_log("Enviando a GHL (Common Func): " . $ghl_payload_json);
        $response = wp_remote_post( $ghl_api_url, $args );

        if ( is_wp_error( $response ) ) { 
            $result['error_message'] = $response->get_error_message();
            me_ghl_write_log("Error WP_Error GHL (Common Func): " . $result['error_message']);
        } else { 
            $result['http_code'] = wp_remote_retrieve_response_code( $response );
            $result['response_body'] = wp_remote_retrieve_body( $response );
            if ( $result['http_code'] >= 200 && $result['http_code'] < 300 ) {
                $result['success'] = true;
                me_ghl_write_log("Éxito GHL (Common Func)! HTTP: " . $result['http_code'] . " | Respuesta (primeros 200c): " . substr($result['response_body'], 0, 200));
            } else {
                $result['error_message'] = "Error API GHL (" . $result['http_code'] . ")";
                me_ghl_write_log($result['error_message'] . " | Respuesta: " . $result['response_body']);
            }
        }
        return $result;
    }
}
?>

Paso 4: Código del Archivo Principal del Plugin

Este archivo inicializa el plugin, define constantes de log, incluye las funciones comunes y establece el “router” para los formularios.

Crea el archivo mi-elementor-ghl-integracion.php y pega el siguiente código:

PHP

<?php
/**
 * Plugin Name:       Mi Integración Elementor a GHL
 * Plugin URI:        https://tudominio.com/
 * Description:       Maneja los envíos de formularios de Elementor Pro para enviar datos a GoHighLevel.
 * Version:           1.0.0
 * Author:            Tu Nombre/Empresa
 * Author URI:        https://tudominio.com/
 * License:           GPL v2 or later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       me-ghl-integration
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit; // No acceso directo.
}

// --- Constantes para el Log del Plugin ---
if (!defined('ME_GHL_LOG_DIR')) { 
    define('ME_GHL_LOG_DIR', WP_CONTENT_DIR . '/uploads/me-ghl-logs/'); // Directorio para logs
}
if (!defined('ME_GHL_LOG_FILE')) {
    define('ME_GHL_LOG_FILE', ME_GHL_LOG_DIR . 'elementor_ghl_router_log.txt'); // Log principal del router
}

// --- Incluir funciones comunes PRIMERO ---
$path_to_common_functions = plugin_dir_path( __FILE__ ) . 'includes/common-ghl-functions.php';

// Diagnóstico de ruta (escribe en el error_log de PHP del servidor)
// Puedes comentar/eliminar este bloque de error_log una vez que confirmes que funciona.
error_log("---------------------------------------------------------------------");
error_log("[ME-GHL Plugin Init] Verificando common functions: " . $path_to_common_functions);
if (file_exists($path_to_common_functions)) {
    if (is_readable($path_to_common_functions)) {
        require_once $path_to_common_functions; 
        error_log("[ME-GHL Plugin Init] Archivo common functions INCLUIDO.");
    } else {
        error_log("[ME-GHL Plugin Init] ERROR: common functions existe PERO NO ES LEGIBLE. Revisa permisos.");
        return; 
    }
} else {
    error_log("[ME-GHL Plugin Init] ERROR CRÍTICO: common functions NO SE ENCONTRÓ. El plugin no funcionará. Ruta: " . $path_to_common_functions);
    return; 
}
error_log("---------------------------------------------------------------------");


/**
 * Función principal que se engancha a TODOS los envíos de formularios de Elementor Pro.
 */
function me_ghl_elementor_form_submission_router( $record, $handler ) {
    $form_name = $record->get_form_settings( 'form_name' ); 
    
    if (function_exists('me_ghl_write_log')) {
        me_ghl_write_log("Router: Nuevo envío. Formulario: " . sanitize_text_field($form_name));
    } else {
        error_log("Router ERROR CRÍTICO: me_ghl_write_log no definida. Funciones comunes no cargadas. Form: " . sanitize_text_field($form_name));
        return; 
    }

    $form_configs_path = plugin_dir_path( __FILE__ ) . 'form-configs/';

    switch ($form_name) {
        // EJEMPLO PARA UN FORMULARIO DE NEWSLETTER
        case 'mi_newsletter_form': // **REEMPLAZA** con el "Form Name" de tu formulario de newsletter en Elementor
            $handler_file = $form_configs_path . 'mi-formulario-newsletter-handler.php'; // Nombre del archivo handler
            
            me_ghl_write_log("Router: Cargando handler para 'mi_newsletter_form' desde: " . $handler_file);

            if (file_exists($handler_file)) {
                if (is_readable($handler_file)) {
                    require_once $handler_file;
                    // **REEMPLAZA** 'me_ghl_process_mi_newsletter_form' con el nombre de la función en tu handler
                    if (function_exists('me_ghl_process_mi_newsletter_form')) {
                        me_ghl_process_mi_newsletter_form( $record, $handler ); 
                    } else {
                        me_ghl_write_log("Router ERROR: Función para 'mi_newsletter_form' no definida en " . $handler_file);
                    }
                } else {
                     me_ghl_write_log("Router ERROR: Archivo handler '" . $handler_file . "' no es legible.");
                }
            } else {
                me_ghl_write_log("Router AVISO: Archivo handler para '" . sanitize_text_field($form_name) . "' no encontrado en: " . $handler_file);
            }
            break;
        
        // EJEMPLO PARA UN FORMULARIO DE CONTACTO DEL FOOTER
        case 'mi_form_footer_contacto': // **REEMPLAZA** con el "Form Name" de tu formulario de footer
            $handler_file = $form_configs_path . 'mi-formulario-footer-handler.php'; // Nombre del archivo handler
            
            me_ghl_write_log("Router: Cargando handler para 'mi_form_footer_contacto' desde: " . $handler_file);

            if (file_exists($handler_file)) {
                if (is_readable($handler_file)) {
                    require_once $handler_file;
                     // **REEMPLAZA** 'me_ghl_process_mi_footer_form' con el nombre de la función en tu handler
                    if (function_exists('me_ghl_process_mi_footer_form')) { 
                        me_ghl_process_mi_footer_form( $record, $handler ); 
                    } else {
                        me_ghl_write_log("Router ERROR: Función para 'mi_form_footer_contacto' no definida en " . $handler_file);
                    }
                } else {
                     me_ghl_write_log("Router ERROR: Archivo handler '" . $handler_file . "' no es legible.");
                }
            } else {
                me_ghl_write_log("Router AVISO: Archivo handler para '" . sanitize_text_field($form_name) . "' no encontrado en: " . $handler_file);
            }
            break;

        default:
            me_ghl_write_log("Router AVISO: Formulario '" . sanitize_text_field($form_name) . "' no tiene un 'case' configurado.");
            break;
    }
}
add_action( 'elementor_pro/forms/new_record', 'me_ghl_elementor_form_submission_router', 10, 2 );
?>

Paso 5: Código para un Manejador de Formulario Específico (Ejemplo: Newsletter)

Este archivo define la lógica particular para un formulario.

Crea el archivo form-configs/mi-formulario-newsletter-handler.php (o el nombre que coincida con tu case en el switch) y pega:

PHP

<?php
// /wp-content/plugins/mi-elementor-ghl-integracion/form-configs/mi-formulario-newsletter-handler.php

if ( ! defined( 'ABSPATH' ) ) {
    exit; // No acceso directo.
}

/**
 * Función manejadora específica para el formulario 'mi_newsletter_form'.
 * Esta es llamada por el router en el archivo principal del plugin.
 */
function me_ghl_process_mi_newsletter_form( $record, $handler ) { // **ASEGÚRATE QUE ESTE NOMBRE DE FUNCIÓN COINCIDA CON EL SWITCH**
    // Asegúrate que la función de log esté disponible
    if (!function_exists('me_ghl_write_log')) {
        error_log("Error crítico en mi-formulario-newsletter-handler.php: me_ghl_write_log no está definida.");
        return;
    }

    $form_specific_log_prefix = "Form Handler [mi_newsletter_form]: ";
    me_ghl_write_log($form_specific_log_prefix . "Iniciando procesamiento.");

    // 1. Cargar API Key de GHL 
    $ghlApiKey = getenv('GHL_API_KEY');
    if (empty($ghlApiKey)) {
        me_ghl_write_log($form_specific_log_prefix . "Error Crítico: GHL_API_KEY no disponible.");
        // $handler->add_error_message("Error de configuración del servidor."); // Opcional
        return;
    }

    // 2. Extraer y Sanitizar Datos
    $fields = $record->get_formatted_data();
    
    // **ACCIÓN REQUERIDA POR TI:** Ajusta 'id_campo_email_elementor' al ID exacto de tu campo de email en ESTE formulario de Elementor.
    $elementor_email_field_id = 'id_campo_email_elementor'; 
    $email_input = $fields[$elementor_email_field_id] ?? null;

    if (empty($email_input)) {
        me_ghl_write_log($form_specific_log_prefix . "Error: Email no encontrado con ID de campo Elementor: '" . sanitize_text_field($elementor_email_field_id) . "'. Datos recibidos: " . json_encode($fields));
        // $handler->add_error_message("El campo de email es obligatorio."); // Opcional
        return;
    }

    $email_sanitized = filter_var(trim($email_input), FILTER_SANITIZE_EMAIL);
    if (!filter_var($email_sanitized, FILTER_VALIDATE_EMAIL)) {
        me_ghl_write_log($form_specific_log_prefix . "Error: Formato de email inválido: " . htmlspecialchars($email_input));
        // $handler->add_error_message("Por favor, ingresa un email válido."); // Opcional
        return;
    }
    me_ghl_write_log($form_specific_log_prefix . "Email validado: " . $email_sanitized);
    
    $name_sanitized = '';
    // **ACCIÓN REQUERIDA POR TI (Opcional):** Si tienes un campo de nombre, ajusta 'id_campo_nombre_elementor'.
    // $elementor_name_field_id = 'id_campo_nombre_elementor'; 
    // $name_input = $fields[$elementor_name_field_id] ?? '';
    // if (!empty($name_input)) {
    //    $name_sanitized = sanitize_text_field(trim($name_input)); 
    //    me_ghl_write_log($form_specific_log_prefix . "Nombre extraído: " . htmlspecialchars($name_sanitized));
    // }

    // 3. Preparar Payload para GHL
    $ghlLocationIdFromEnv = getenv('GHL_LOCATION_ID');
    if (empty($ghlLocationIdFromEnv)) {
        me_ghl_write_log($form_specific_log_prefix . "Error Crítico: GHL_LOCATION_ID no configurada en .htaccess.");
        return; 
    }

    // **ACCIÓN REQUERIDA POR TI:** Define las etiquetas y fuente para ESTE formulario.
    $ghl_tags = ['newsletter_signup', 'mi_sitio_web']; 
    $ghl_source = 'Formulario Newsletter (Mi Sitio Web)'; 

    $ghl_payload_array = [
        'email'      => $email_sanitized,
        'source'     => $ghl_source,
        'locationId' => $ghlLocationIdFromEnv,
        'tags'       => $ghl_tags
    ];
    if (!empty($name_sanitized)) {
       $ghl_payload_array['firstName'] = $name_sanitized;
    }

    // 4. LLAMAR A LA FUNCIÓN COMÚN DE ENVÍO A GHL
    if (!function_exists('me_ghl_send_contact_to_ghl')) {
        me_ghl_write_log($form_specific_log_prefix . "Error crítico: La función me_ghl_send_contact_to_ghl no está definida.");
        // $handler->add_error_message("Error de configuración del plugin."); // Opcional
        return;
    }
    $ghl_result = me_ghl_send_contact_to_ghl($ghl_payload_array, $ghlApiKey);

    // 5. MANEJAR RESPUESTA DE GHL
    if ($ghl_result['success']) {
        me_ghl_write_log($form_specific_log_prefix . "Datos enviados exitosamente a GHL.");
        // $handler->add_success_message("¡Gracias por suscribirte!"); // Opcional
    } else {
        me_ghl_write_log($form_specific_log_prefix . "Fallo al enviar a GHL. HTTP Code: " . ($ghl_result['http_code'] ?? 'N/A') . " Error: " . ($ghl_result['error_message'] ?? 'Desconocido') . " Respuesta GHL: " . ($ghl_result['response_body'] ?? ''));
        // $handler->add_error_message("Hubo un problema al procesar tu suscripción."); // Opcional
    }
}
?>

Paso 6: Configurar Formularios en Elementor

  1. Para cada formulario que quieras integrar (ej. tu formulario de newsletter):
    • Ve a la configuración del formulario en Elementor.
    • Asegúrate de que tenga un “Nombre del Formulario” (Form Name) único. Este nombre DEBE COINCIDIR con uno de los case en el switch de tu archivo mi-elementor-ghl-integracion.php (ej. mi_newsletter_form).
    • Para cada campo (email, nombre, etc.), ve a la pestaña “Avanzado” del campo y anota o define su “ID de Campo” (Field ID). Usarás estos IDs en el archivo handler correspondiente (ej. en mi-formulario-newsletter-handler.php para $elementor_email_field_id).
  2. Importante: Con este método de plugin, NO necesitas usar la acción “Webhook” en la sección “Actions After Submit” de Elementor. El plugin se encarga de interceptar todos los envíos de Elementor Pro a través del hook elementor_pro/forms/new_record.

Paso 7: Instalar y Activar el Plugin

  1. Coloca los tres archivos (mi-elementor-ghl-integracion.php, includes/common-ghl-functions.php, y tu primer archivo handler como form-configs/mi-formulario-newsletter-handler.php) en la estructura de carpetas mi-elementor-ghl-integracion/.
  2. Comprime la carpeta mi-elementor-ghl-integracion/ en un archivo .zip.
  3. En tu panel de WordPress, ve a “Plugins” > “Añadir nuevo” > “Subir plugin”.
  4. Selecciona el archivo .zip y haz clic en “Instalar ahora”.
  5. Activa el plugin.

Paso 8: Pruebas y Depuración

  1. Envía tu formulario de Elementor configurado.
  2. Revisa primero el error_log de PHP de tu servidor. Busca las líneas de diagnóstico [ME-GHL Plugin Init] para confirmar que common-ghl-functions.php se carga.
  3. Luego, revisa el log personalizado del plugin: wp-content/uploads/me-ghl-logs/elementor_ghl_router_log.txt. Este te mostrará el flujo del router y cualquier error que las funciones de log del plugin capturen.
  4. Verifica si el contacto llega a GoHighLevel con las etiquetas y datos correctos.

Paso 9: Añadir Más Formularios

  1. En Elementor: Dale un “Form Name” único a tu nuevo formulario y anota los IDs de sus campos.
  2. Crea un nuevo archivo handler en la carpeta form-configs/ (ej. mi-otro-formulario-handler.php). Puedes copiar mi-formulario-newsletter-handler.php como plantilla.
  3. Modifica el nuevo archivo handler:
    • Cambia el nombre de la función (ej. de me_ghl_process_mi_newsletter_form a me_ghl_process_mi_otro_formulario_form).
    • Ajusta el $form_specific_log_prefix.
    • Actualiza los $elementor_..._field_id para que coincidan con los IDs de campo de tu nuevo formulario.
    • Define las $ghl_tags y $ghl_source específicas para este nuevo formulario.
  4. En el archivo principal del plugin (mi-elementor-ghl-integracion.php):
    • Añade un nuevo case al switch para el “Form Name” de tu nuevo formulario, que incluya su nuevo archivo handler y llame a su nueva función de procesamiento.

Espero que este tutorial detallado y los códigos generalizados te sirvan de guía. Recuerda reemplazar los placeholders (como “TU_API_KEY…”, “mi_newsletter_form”, “id_campo_email_elementor”) con tus valores reales.

Facebook
Twitter
LinkedIn
WhatsApp

Leave a Reply

Your email address will not be published. Required fields are marked *

Permanece actualizado con SEO Nativo

Sucribete a nuestro newsletter y obtén información actualizada de Marketing Digital.