Cómo medir fuente y medio para Ninja Forms 📊

Aquí puedes empezar con una breve explicación de por qué es importante medir la fuente y el medio de los envíos de formularios. Menciona los beneficios, como entender de dónde vienen tus leads y optimizar tus campañas de marketing. Puedes incluir una frase como “Si alguna vez te has preguntado de dónde provienen los envíos de tus formularios de Ninja Forms, ¡este tutorial es para ti!”.

ninja forms

¿Qué son la fuente (source) y el medio (medium)? 🤔

Es crucial aclarar estos conceptos antes de ir a lo técnico.

  • Fuente (source): Es el origen de donde vino la visita, por ejemplo, Google, Facebook, un correo electrónico, etc.

  • Medio (medium): Es la categoría general de la fuente, como “orgánico”, “pago” (CPC), “social”, “email”, etc.

1) JavaScript (first-touch + autollenado)

Pega tal cual en el footer del theme (o en un HTML widget global), una sola vez:

javascript
<script>
(function () {
  var COOKIE = "rkz_attrib";
  var DAYS = 90;

  function cookieDomain(){
    var h = location.hostname.split('.');
    return (h.length >= 2) ? "."+h.slice(-2).join('.') : location.hostname;
  }
  function setCookie(name, value, days){
    var d = new Date(); d.setTime(d.getTime()+days*864e5);
    document.cookie = name+"="+encodeURIComponent(JSON.stringify(value))+
      "; expires="+d.toUTCString()+"; path=/; domain="+cookieDomain()+"; SameSite=Lax";
  }
  function getCookie(name){
    var m = document.cookie.match(new RegExp('(^| )'+name+'=([^;]+)'));
    if (!m) return null;
    try { return JSON.parse(decodeURIComponent(m[2])); } catch(e){ return null; }
  }

  var p   = new URLSearchParams(location.search);
  var ref = document.referrer || "";
  var hasUTM   = ["utm_source","utm_medium","utm_campaign","utm_term","utm_content"].some(k => p.has(k));
  var hasAdsId = p.has("gclid") || p.has("fbclid") || p.has("msclkid");

  function classify(){
    var src  = (p.get("utm_source") || "").toLowerCase();
    var med  = (p.get("utm_medium") || "").toLowerCase();
    var camp = (p.get("utm_campaign") || "").toLowerCase();
    var r    = ref.toLowerCase();

    var channel = "Directo";
    if (hasAdsId || ["cpc","ppc","paid","sem"].includes(med)) channel = "Paid Search";
    else if (r.includes("google.") || r.includes("bing.") || r.includes("yahoo.") || r.includes("duckduckgo")) channel = "Orgánico";
    else if (r.includes("facebook") || r.includes("instagram") || r.includes("t.co") || r.includes("x.com") || r.includes("linkedin")) channel = "Social";
    else if (ref) channel = "Referido";

    var source = src || (ref ? (new URL(ref)).hostname.replace(/^www\./,"") : "direct");
    var medium = med || (channel==="Orgánico" ? "organic" : channel==="Social" ? "social" : channel==="Paid Search" ? "cpc" : "direct");
    return { source, medium, campaign: camp, channel };
  }

  // Set first-touch once, or refresh if llega con nuevas UTM/IDs
  var attrib = getCookie(COOKIE);
  if (!attrib || hasUTM || hasAdsId) {
    var c = classify();
    attrib = { source:c.source, medium:c.medium, campaign:c.campaign, channel:c.channel,
               landing: location.href, referrer: ref, ts: new Date().toISOString() };
    setCookie(COOKIE, attrib, DAYS);
  }

  function fill(){
    var a = getCookie(COOKIE) || {};
    var value = [a.source, a.medium, a.campaign].filter(Boolean).join(" / ");
    document.querySelectorAll("input.js-medio").forEach(function(el){
      if (!el.value) el.value = value || "Desconocido";
    });
  }
  document.addEventListener("DOMContentLoaded", fill);
  document.addEventListener("nfFormReady", fill);
})();
</script>
  

2) PHP (respaldo server-side)

Deja solo este snippet en functions.php de tu child theme (

php
<?php
// Rellena el campo 'medio' al enviar (server-side)
add_filter('ninja_forms_submit_data', function($form_data){

  // 1) Intenta desde cookie (first-touch)
  $value = '';
  if (!empty($_COOKIE['rkz_attrib'])) {
    $json = json_decode(stripslashes($_COOKIE['rkz_attrib']), true);
    if (is_array($json)) {
      $src = sanitize_text_field($json['source'] ?? '');
      $med = sanitize_text_field($json['medium'] ?? '');
      $cmp = sanitize_text_field($json['campaign'] ?? '');
      $value = trim(implode(' / ', array_filter([$src, $med, $cmp])));
    }
  }

  // 2) Fallback: UTM o referrer
  if ($value === '') {
    $utm_source   = sanitize_text_field($_GET['utm_source']   ?? '');
    $utm_medium   = sanitize_text_field($_GET['utm_medium']   ?? '');
    $utm_campaign = sanitize_text_field($_GET['utm_campaign'] ?? '');
    if ($utm_source || $utm_medium || $utm_campaign) {
      $value = implode(' / ', array_filter([$utm_source, $utm_medium, $utm_campaign]));
    } else {
      $ref = strtolower(sanitize_text_field($_SERVER['HTTP_REFERER'] ?? ''));
      if (!$ref) $value = 'Directo';
      elseif (strpos($ref,'google')!==false || strpos($ref,'bing')!==false || strpos($ref,'yahoo')!==false || strpos($ref,'duckduckgo')!==false) $value='Orgánico';
      elseif (strpos($ref,'facebook')!==false || strpos($ref,'instagram')!==false || strpos($ref,'x.com')!==false || strpos($ref,'t.co')!==false || strpos($ref,'linkedin')!==false) $value='Social';
      else $value='Referido';
    }
  }

  // 3) Escribe en el campo key = 'medio' si está vacío
  if (!empty($form_data['fields']) && is_array($form_data['fields'])) {
    foreach ($form_data['fields'] as &$field) {
      if (($field['key'] ?? '') === 'medio' && empty($field['value'])) {
        $field['value'] = $value ?: 'Desconocido';
      }
    }
  }

  return $form_data;
}, 999);
?>

Pruebas (rápidas)

  1. UTM: abre la página del formulario con
    ?utm_source=google&utm_medium=cpc&utm_campaign=prueba
    → envía → el envío debe mostrar google / cpc / prueba en medio.

  2. Orgánico: entra desde una búsqueda de Google sin UTM → Orgánico.

  3. Social: entra desde un enlace en Facebook/Instagram → Social.

  4. Directo: escribe la URL a mano → Directo.