Como crear un shortcode seguro con atributos en PHP en WordPress

Contents

Introducción

Crear shortcodes en WordPress es una forma potente de añadir contenido dinámico y reutilizable. Sin embargo, si no se programan correctamente, los shortcodes pueden introducir vulnerabilidades, sobre todo XSS (cross-site scripting) o permitir ejecución involuntaria de datos no confiables. Este artículo muestra, con todo lujo de detalles, cómo diseñar e implementar un shortcode seguro con atributos en PHP: validación de atributos, saneamiento de contenido, escape de salida y buenas prácticas.

Conceptos clave para la seguridad

  • Validar: comprobar que los atributos recibidos estén dentro de los valores esperados (listas blancas, tipos numéricos, booleanos).
  • Saneamiento: aplicar funciones de saneamiento a los datos entrantes (sanitize_text_field, esc_url_raw, absint, sanitize_html_class, etc.).
  • Escapado: cuando generes HTML de salida, escapar con las funciones apropiadas (esc_html, esc_attr, esc_url, wp_kses_post) para evitar inyección XSS.
  • Contenido: permitir solo HTML seguro para el contenido interno del shortcode mediante wp_kses_post o una lista blanca personalizada.
  • Evitar ejecución: nunca evalúes código PHP desde atributos ni incluyas archivos arbitrarios basados en valores recibidos.
  • Privilegios: si el shortcode realiza acciones sensibles (modificar base de datos, mostrar datos privados), comprueba capacidades de usuario y usa nonces si se genera un formulario.

Diseño del shortcode

Antes de programar, define claramente los atributos permitidos y su tipo. Ejemplo: un shortcode tipo card que admita atributos:

  • title: texto (string)
  • url: URL válida
  • image: URL válida
  • size: valor predefinido (smallmediumlarge)
  • align: valor predefinido (leftcenterright)
  • show_image: boolean (truefalse)
  • class: clase CSS permitida (sanitize_html_class)
  • content: contenido interno con HTML permitido (wp_kses_post)

Implementación paso a paso

  1. Registrar y establecer valores por defecto:

    Usa shortcode_atts para mezclar atributos recibidos con valores por defecto.

  2. Saneamiento inicial de atributos:

    Usa funciones como sanitize_text_field, esc_url_raw, absint, sanitize_html_class y listas blancas con in_array para valores enumerados.

  3. Saneamiento del contenido:

    Permite solo HTML seguro con wp_kses_post o wp_kses con una lista blanca personalizada. Si aceptas shortcodes anidados, ejecuta do_shortcode sobre el contenido antes de sanearlo.

  4. Escapar la salida:

    Al imprimir atributos en HTML, utiliza esc_attr, esc_html o esc_url según corresponda.

  5. Revisar privilegios y acciones sensibles:

    Si el shortcode genera formularios o acciones que cambian datos, añade nonces y comprobaciones de capacidades.

Ejemplo completo y seguro

Ejemplo práctico de un shortcode secure_card siguiendo las buenas prácticas descritas. El ejemplo registra el shortcode y muestra cómo validar, sanear y escapar correctamente.

 ,
        url        => ,
        image      => ,
        size       => medium, // allowed: smallmediumlarge
        align      => left,   // allowed: leftcenterright
        show_image => false,  // string boolean
        class      => ,
    )

    // Mezclar atributos con valores por defecto
    atts = shortcode_atts( defaults, atts, secure_card )

    // SANITIZACIÓN DE ATRIBUTOS
    title = sanitize_text_field( atts[title] )
    url   = esc_url_raw( atts[url] )
    image = esc_url_raw( atts[image] )

    // Validar enumerados con lista blanca
    size_allowed  = array( small, medium, large )
    align_allowed = array( left, center, right )

    size  = in_array( atts[size], size_allowed, true ) ? atts[size] : medium
    align = in_array( atts[align], align_allowed, true ) ? atts[align] : left

    // Booleano: convertir a boolean real
    show_image = filter_var( atts[show_image], FILTER_VALIDATE_BOOLEAN )

    // Clase CSS: usar sanitize_html_class para evitar clases inseguras
    custom_class = sanitize_html_class( atts[class] )

    // CONTENIDO: permitir shortcodes anidados, luego sanear HTML permitido
    content = do_shortcode( content )
    content = wp_kses_post( content ) // permite etiquetas seguras por WP para posts

    // CONSTRUCCIÓN DE SALIDA: escapar siempre al imprimir
    classes = array(
        secure-card,
        secure-card-- . esc_attr( size ),
        secure-card--align- . esc_attr( align ),
    )
    if ( custom_class ) {
        classes[] = esc_attr( custom_class )
    }
    class_attr = implode(  , classes )

    // Título y enlace: escapar apropiadamente
    title_html = title ?  . esc_html( title ) .  : 

    if ( url ) {
        // esc_url para salida (permite más escape para HTML)
        linked_title =  . title_html . 
    } else {
        linked_title = title_html
    }

    // Imagen (si se permite)
    image_html = 
    if ( image  show_image ) {
        image_html = .
    }

    // Montar HTML de salida
    html  = 

if ( image_html ) { html .= image_html } if ( linked_title ) { html .= linked_title } if ( content ) { html .= . content . } html .=

return html } add_shortcode( secure_card, secure_card_shortcode ) ?>

Uso de ejemplo

Ejemplo de invocación del shortcode en el editor o en un post:

// En el contenido del post:
[secure_card title=Mi tarjeta url=https://example.org image=https://example.org/imagen.jpg show_image=true size=large align=center class=destacado]Texto permitido y safe[/secure_card]

Notas sobre el ejemplo

  • Se usa esc_url_raw para sanitizar las URLs recibidas y esc_url al imprimirlas.
  • Se usa sanitize_text_field para texto plano (título) y sanitize_html_class para clases CSS.
  • Se valida size y align con listas blancas (in_array).
  • El contenido admite shortcodes anidados (do_shortcode) y luego se filtra con wp_kses_post para permitir solo HTML seguro.
  • La salida se construye escapando cada parte con esc_attr, esc_html o esc_url según corresponda.

Buenas prácticas adicionales

  • Evita ejecutar PHP o incluir archivos basados en atributos del shortcode.
  • Si el shortcode muestra datos sensibles, comprueba current_user_can antes de mostrarlos.
  • Si el shortcode genera formularios que realizan acciones, incluye wp_nonce_field y verifica el nonce en la acción.
  • Considera internacionalizar textos con __() o esc_html__() si hay textos estáticos dentro del shortcode.
  • Documenta los atributos esperados para que los usuarios no pasen valores inesperados.
  • Realiza pruebas con datos maliciosos (scripts, protocolos javascript:) para verificar que el saneamiento funciona.

Comprobaciones y pruebas recomendadas

  1. Prueba con atributos malformados: urls con javascript:, atributos con HTML o scripts, valores fuera de la lista blanca.
  2. Inserta HTML malicioso en el contenido para asegurarte de que wp_kses_post lo limpia según lo esperado.
  3. Prueba shortcodes anidados para confirmar que do_shortcode wp_kses_post no deja vectores de XSS.
  4. Revisa la salida en el inspector del navegador para verificar que los atributos están correctamente escapados.

Resumen

Un shortcode seguro se diseña definiendo claramente los atributos, validando y saneando cada valor, permitiendo solo HTML seguro en el contenido y escapando siempre la salida. Nunca confíes en los datos de entrada: valida, sanea y escapa. Siguiendo las funciones nativas de WordPress (shortcode_atts, sanitize_text_field, esc_url_raw, wp_kses_post, esc_attr, esc_html, etc.) construirás shortcodes que ofrecen funcionalidad sin introducir riesgos de seguridad.

Para ampliar, revisa la documentación oficial de WordPress sobre shortcodes y funciones de saneamiento en developer.wordpress.org.



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 *