Como escapar salidas con esc_html, esc_attr y esc_url en WordPress

Contents

Introducción: por qué escapar salidas en WordPress

Escapar salidas es una práctica fundamental de seguridad y calidad en cualquier tema o plugin de WordPress. Cuando muestras datos que vienen de usuarios, de la base de datos o de fuentes externas, debes transformarlos para que no contengan código ejecutable no deseado (XSS), HTML malicioso ni protocolos peligrosos en enlaces. WordPress proporciona funciones específicas para cada contexto: esc_html, esc_attr y esc_url. Cada una está diseñada para un uso concreto: contenido HTML, atributos HTML y URLs respectivamente.

Escapar vs Sanear vs Validar

Es importante distinguir tres pasos distintos:

  • Validar: comprobar que los datos cumplen un formato esperado (ej. que un email tenga formato correcto).
  • Saniar (sanitize): limpiar los datos al guardarlos en la base de datos. Ej.: sanitize_text_field(), sanitize_email().
  • Escapar (escape): transformar datos justo antes de mostrarlos en HTML para evitar ejecución de código. Ej.: esc_html(), esc_attr(), esc_url().

Regla práctica: sanear al guardar, escapar al mostrar.

Resumen rápido de las funciones

  • esc_html( text ): escapa caracteres especiales para mostrar contenido dentro del flujo HTML (entre etiquetas). Convierte < a lt y gt etc.
  • esc_attr( text ): escapa cadenas para incluir en atributos HTML (value=, title=, alt=, data-, etc.).
  • esc_url( url ): limpia y escapa URLs para atributos href, src, action, etc. Elimina protocolos peligrosos (como javascript:) y devuelve una URL segura o una cadena vacía si no es válida.

Cuándo usar cada una: ejemplos prácticos

1) Contenido dentro de etiquetas (esc_html)

Usa esc_html cuando vas a imprimir texto entre etiquetas HTML. Ideal para títulos, descripciones o contenido corto que no debe interpretar HTML.

lt?php
title = get_the_title() // viene de la BD
// Correcto: escapar antes de mostrar en el flujo HTML
echo lth3gt . esc_html( title ) . lt/h3gt
?gt

Evita insertar directamente title sin escapar: si contiene ltscriptgt podrías introducir XSS.

2) Valores de atributos (esc_attr)

Para atributos como value, title, placeholder, alt o data-, utiliza esc_attr.

lt?php
placeholder = get_post_meta( post->ID, _mi_placeholder, true )
?gt
ltinput type=text name=mi_input value=lt?php echo esc_attr( valor_guardado ) ?gt placeholder=lt?php echo esc_attr( placeholder ) ?gtgt

Si el atributo contiene comillas o saltos de línea, esc_attr las escapará correctamente para mantener la integridad del HTML.

3) Enlaces y URLs (esc_url)

Para href, src y cualquier URL use esc_url. Esta función además de escapar, valida protocolos seguros y normaliza la URL.

lt?php
profile_url = get_user_meta( user_id, profile_url, true )
// Correcto: limpiar y escapar la URL antes de insertarla en href
echo lta href=quot . esc_url( profile_url ) . quotgtPerfillt/agt
?gt

esc_url elimina protocolos como javascript: y devuelve string vacío si la URL no es segura. Para guardar URLs en la BD normalmente usarías sanitize_text_field() o esc_url_raw() al guardar esc_url es para salida.

Casos concretos y patrones comunes

Salida internacionalizada con printf/esc_html__

lt?php
// Texto traducible con placeholders: escapar cada argumento según su contexto
printf(
    esc_html__( Artículo publicado por %s el %s, mi-textdomain ),
    esc_html( author_name ),
    esc_html( publish_date )
)
?gt

Nunca pongas cadenas traducibles sin escapar: usa las funciones esc_html__ o esc_attr__ según el contexto.

Atributos data- con contenido complejo

Para atributos data que contienen JSON o contenido con comillas, serializa y escapa con esc_attr. Si necesitas JSON seguro para JavaScript, usa wp_json_encode combinado con esc_attr o esc_js según cómo lo vayas a inyectar.

lt?php
data = array( id =gt 123, name =gt OReilly )
json = wp_json_encode( data ) // codifica correctamente
?gt
ltdiv data-info=lt?php echo esc_attr( json ) ?gtgtlt/divgt

srcset y múltiples URLs

Si tienes una lista de URLs (por ejemplo srcset), escapa cada URL con esc_url y luego el conjunto con esc_attr:

lt?php
parts = array(
    esc_url( url_1 ) .  300w,
    esc_url( url_2 ) .  768w,
)
echo ltimg src=quot . esc_url( url_1 ) . quot srcset=quot . esc_attr( implode( , , parts ) ) . quot alt=quot . esc_attr( alt ) . quotgt
?gt

Errores comunes y cómo evitarlos

  • Doble escape: no escapar varias veces en la misma salida (ej. esc_html( esc_html( x ) )). Escapar una vez en el momento de salida es suficiente.
  • No escapar: imprimir directamente datos del usuario o meta sin escapar expone a XSS.
  • Usar la función equivocada: usar esc_url en texto plano o esc_html en atributos puede dejar caracteres sin escapar correctamente. Elije según el contexto: contenido, atributo o URL.
  • Escapar al guardar: mucho cuidado en sanear para la DB versus escapar para salida. Escapar débiles al guardar puede alterar datos que necesiten HTML legítimo preferible sanear al guardar y escapar siempre al mostrar.

Funciones relacionadas útiles

  • esc_html_e(), esc_attr_e(): versiones que imprimen directamente cadenas traducibles y escapadas.
  • esc_html__(), esc_attr__(): devuelven la cadena traducida ya lista para escapa (usar luego con printf/echo).
  • wp_kses(): si quieres permitir un conjunto limitado de etiquetas HTML, wp_kses filtra permitiendo solo etiquetas y atributos permitidos.
  • esc_url_raw(): para limpiar URLs al guardar en la base de datos a diferencia de esc_url, no aplica el mismo filtrado para salida.

Ejemplos de malas prácticas y correcciones

Mal: URL sin escapar

lt?php
url = get_post_meta( id, _link, true )
echo lta href=quot . url . quotgtAbrir enlacelt/agt // inseguro
?gt

Bien: usar esc_url

lt?php
url = get_post_meta( id, _link, true )
echo lta href=quot . esc_url( url ) . quotgtAbrir enlacelt/agt
?gt

Mal: imprimir descripción de usuario sin escapar

lt?php
bio = get_user_meta( user_id, description, true )
echo ltdiv class=quotbioquotgt . bio . lt/divgt // puede contener scripts
?gt

Bien: usar esc_html o wp_kses si se permiten etiquetas

lt?php
bio = get_user_meta( user_id, description, true )
// Mostrar texto plano:
echo ltdiv class=quotbioquotgt . esc_html( bio ) . lt/divgt
// O si quieres permitir etiquetas limitadas:
allowed = array(
  a =gt array( href =gt true, title =gt true ),
  strong =gt array(),
  em =gt array(),
)
echo ltdiv class=quotbioquotgt . wp_kses( bio, allowed ) . lt/divgt
?gt

Checklist rápida antes de publicar salida

  1. ¿Es una URL? Usa esc_url para href/src.
  2. ¿Va dentro de un atributo HTML? Usa esc_attr.
  3. ¿Es texto dentro del HTML (contenido)? Usa esc_html.
  4. ¿Necesitas permitir algunas etiquetas HTML? Usa wp_kses con una lista blanca.
  5. ¿Los datos provienen de usuario? Sanitiza al guardar y siempre escapa al mostrar.

Aplicando estas reglas básicas y utilizando consistentemente esc_html, esc_attr y esc_url evitarás la mayoría de problemas de XSS y mantendrás tu tema o plugin robusto y seguro. Escapar no es opcional: es obligatorio cada vez que muestres datos que no controlas completamente.



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Deja una respuesta

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