...

Uso de shortcodes de WordPress en tu propio tema: tecnología, ejemplos y buenas prácticas

Te mostraré específicamente cómo registro shortcodes directamente en el tema, los entrego de forma segura y los renderizo en los lugares correctos - así es como construyo un wordpress shortcode tema con una estructura clara, código limpio y tiempos de carga rápidos. Proporciono ejemplos prácticos, explico do_shortcode en la plantilla, hablo de atributos, escapes y almacenamiento en caché y añado las mejores prácticas para temas mantenibles a largo plazo.

Puntos centrales

  • Registro mediante las funciones add_shortcode y clear callback
  • Integración en el editor, en los widgets y en las plantillas con do_shortcode
  • Seguridad mediante escapes, atributos y validación
  • Mantenimiento con tema hijo, documentación y control de versiones
  • Actuación con caché, consultas económicas e invalidación de caché

Shortcodes en el tema: registro y estructura

Coloco el registro en el tema en el funciones.php o en un pequeño plugin imprescindible si quiero separar la funcionalidad del diseño. Cada función callback devuelve una cadena y no utiliza un eco, de lo contrario la salida termina en lugares inesperados. Elijo prefijos únicos para la nomenclatura para evitar conflictos con los plugins. De esta forma mantengo el código legible y creo un orden claro, por ejemplo /inc/shortcodes.php con un require_once dirigido en functions.php. Para empezar, basta con un simple shortcode de saludo, que luego amplío paso a paso.

<?php
// /wp-content/temas/mi-tema/funciones.php
require_once get_template_directory() . '/inc/shortcodes.php';
<?php
// /wp-content/themes/my-theme/inc/shortcodes.php
función mi_shortcode_de_saludo() {
    return '¡Hola, bienvenido a mi sitio web!
}
add_shortcode('greeting', 'my_greeting_shortcode');

Utilizar shortcodes en la plantilla: do_shortcode

Llamo shortcodes en la plantilla con do_shortcode cuando integro contenidos en encabezados, pies de página o plantillas especiales. Así mantengo el editor despejado y los módulos recurrentes en una ubicación central. Documento las llamadas a plantillas en el código con un breve comentario para que otros sepan inmediatamente qué shortcode se está ejecutando aquí. Para los parámetros dinámicos, creo la cadena del shortcode en PHP y paso los valores escapados de forma segura. Este método funciona en cada archivo de plantilla como header.php, footer.php o page-templates.

<?php
// En un archivo de plantilla
echo do_shortcode('[saludo]');
echo do_shortcode('[colourbox color="green"]Bonito texto[/colorbox]');

Atributos, contenido y seguridad

Establezco atributos con vatios_código_corto y proteger los valores con esc_html, esc_attr y esc_url. Esto previene XSS y asegura HTML válido en toda la salida. Opcionalmente trato el contenido encerrado por un shortcode con wp_kses si sólo quiero permitir ciertas etiquetas. Para los colores, sólo acepto valores de la lista blanca o compruebo con regex para que no se cuele ningún script. Con estas reglas, los shortcodes siguen siendo fiables y ofrecen resultados predecibles.

<?php
function my_colorbox_shortcode($atts, $content = null) {
    $atts = shortcode_atts([
        'color' => azul',
    ], $atts, 'colourbox');

    $color = preg_match('/^#?[0-9a-fA-F]{3,6}$/', $atts['color']) ? $atts['color'] : 'azul';
    $inner = wp_kses($content, ['strong' =&gt; [], 'em' =&gt; [], 'a' =&gt; ['href' =&gt; []]]);
    $style = 'background:' . esc_attr($color) . ';padding:10px';

    return '<div style="' . $style . '">' . $inner . '</div>';
}
add_shortcode('colourbox', 'my_colorbox_shortcode');

Ejemplos prácticos: año en curso, botón y fechas

Utilizo pequeños shortcodes de ayuda para contenidos recurrentes como el actual Añobotones o listas de tipos de post personalizados. Un shortcode del año me ahorra el trabajo de mantenimiento en el pie de página o en los bloques de texto. Equipo los botones con texto, URL y color para que los editores puedan trabajar sin cambiar el código. Para la salida de datos de los CPT, limito la consulta y guardo en caché los resultados para que la página siga siendo rápida. He aquí tres breves fragmentos como base.

<?php
// Jahr
add_shortcode('current-year', function() {
    return date('Y');
});

// Button
add_shortcode('button', function($atts) {
    $atts = shortcode_atts([
        'text'  => 'haga clic ahora',
        'url' =&gt; '#',
        'color' =&gt; '#2d89ef',
    ], $atts, 'button');

    $text = esc_html($atts['text']);
    $url = esc_url($atts['url']);
    $color = esc_attr($atts['color']);

    return '<a href="/es/' . $url . '/" style="background:' . $color . ';padding:8px 18px;color:#fff;border-radius:4px;text-decoration:none">' . $text . '</a>';
});

¿Tema o plugin? Ayuda a la decisión y migración

Incluyo shortcodes en el Tema si afectan al diseño, y en un plugin si quiero seguir utilizándolos independientemente del tema. De esta forma, no pierdo funciones al cambiar de tema y mantengo clara la arquitectura. Para la documentación, creo un resumen de todos los shortcodes con parámetros para que los editores puedan encontrar rápidamente la sintaxis correcta. Más adelante, al cambiar de tema, exporto los archivos de shortcodes y sustituyo cuidadosamente las rutas necesarias. La siguiente tabla ayuda a tomar la decisión.

Utilice Tema Plugin
Vinculación al diseño Alta (por ejemplo, Hero-Box) Bajo
Riesgo de migración Mayor con cambio de tema Bajose mantiene
Mantenimiento/Actualizaciones Con el lanzamiento del tema Liberación propia, más flexible
Grupo objetivo Características del diseño Contenidos/Funciones

Uso de shortcodes en el editor y en el editor de bloques

Añado shortcodes en el editor clásico directamente como Texto y utilizar el bloque shortcode en el editor de bloques. Esta separación mantiene el contenido claro y reduce los errores al copiar. Para los editores, documento los ejemplos directamente en el backend, por ejemplo como bloque de ejemplo o nota en la plantilla. Presto atención a las diferencias entre editores en cuanto a espaciado y estilos inline, ya que los bloques a veces añaden envoltorios adicionales. Si estás pensando en la elección del editor, en la comparación encontrarás Editor de bloques vs clásico consejos útiles.

Rendimiento: almacenamiento en caché y consultas limpias

Mantengo la rapidez de los shortcodes almacenando en caché las partes de cálculo intensivo y limitando el acceso a los datos, lo que reduce el tiempo de ejecución de los shortcodes. Tiempo de carga baja. Para problemas recurrentes, utilizo Transients o WP Object Cache con una clave significativa. Limito las consultas con posts_per_page, sólo configuro los campos obligatorios y evito las costosas operaciones COUNT. Añado width/height y lazy loading a las salidas de imágenes para que la página sea visible más rápidamente. Para los componentes dinámicos, borro la caché en cuanto cambia el contenido.

<?php
add_shortcode('latest-offers', function($atts) {
    $key = 'sc_latest_offers_v1';
    $html = wp_cache_get($key);
    if ($html !== false) {
        return $html;
    }

    $q = new WP_Query([
        'post_type'      => 'angebot',
        'posts_per_page' => 5,
        'no_found_rows'  => true,
        'fields'         => 'all',
    ]);

    ob_start();
    if ($q->have_posts()) {
        echo '<ul class="offers">';
        while ($q->have_posts()) { $q->the_post();
            echo '<li>' . esc_html(get_the_title()) . '</li>';
        }
        echo '</ul>';
        wp_reset_postdata();
    }
    $html = ob_get_clean();
    wp_cache_set($key, $html, '', 600);
    return $html;
});

Encontrar y rectificar rápidamente las fuentes de error

Activo el Depurar-mode y compruebe si el shortcode está registrado correctamente. A menudo, una pantalla blanca o un texto sin formato indican que la función no se carga o utiliza echo en lugar de return. Las entradas de registro revelan tipos de datos inesperados, atributos incorrectos o escapes que faltan. En las plantillas, pruebo paso a paso: primero el texto estático, luego el shortcode, luego los parámetros. Si quieres proceder sistemáticamente, utiliza la guía del Modo depuración de WordPress.

Trabajar a prueba de actualizaciones con el tema hijo

Creo mis propios shortcodes en Tema infantil si no puedo o no quiero cambiar nada en el tema principal. De este modo, las personalizaciones se conservan durante las actualizaciones del tema y puedo controlar la secuencia de carga. Importante: registrar correctamente el tema hijo, mantener el archivo functions.php reducido e incluir sólo archivos específicos. Para proyectos estructurados, separo los shortcodes en /inc y los documento con comentarios en línea. Una guía compacta es Instrucciones del tema hijo.

Estilo, semántica y accesibilidad

Me ocupo de limpiar HTML y etiquetas semánticas para que los lectores de pantalla reconozcan correctamente el contenido. Sólo muestro botones como etiqueta con role="button" si son realmente enlaces; si no, elijo botones reales. Mantengo altos contrastes de color y establezco estilos de enfoque para que los usuarios de teclado puedan ver claramente dónde están. Reduzco los estilos en línea y traslado el diseño a un archivo CSS con clases claras. Esto mantiene los códigos cortos flexibles y accesibles al mismo tiempo.

Integración de API e integración segura de datos externos

Recupero datos externos a través de wp_remote_get y los almaceno en caché para que la página no se cuelgue durante los tiempos de espera de la API. Compruebo los códigos de estado de las respuestas, analizo JSON de forma controlada y sólo permito los campos que son realmente necesarios. En caso de fallo, muestro una salida alternativa u oculto el bloque. Para el contenido de usuario, elimino las etiquetas peligrosas y valido los enlaces minuciosamente. Esto garantiza que los shortcodes permanezcan estables, incluso si los servicios externos fluctúan.

Cargar activos sólo cuando estén en uso

Sólo cargo CSS/JS para shortcodes si realmente aparecen en la página. Esto ahorra peticiones y mantiene la ruta crítica CSS pequeña. Registro los estilos y scripts de forma centralizada y los pongo en cola en el callback o específicamente en cuanto reconozco el shortcode en el contenido. Importante: nunca escribas código duro en la cabecera sin pensar, sino que trabaja a través de las API de enqueue.

&lt;?php // functions.php – Registrar activos add_action(&#039;wp_enqueue_scripts&#039;, function() { wp_register_style(&#039;my-shortcodes&#039;, get_template_directory_uri() . &#039;/assets/shortcodes.css&#039;, [], &#039;1.0&#039;);
    wp_register_script(&#039;my-shortcodes&#039;, get_template_directory_uri() . &#039;/assets/shortcodes.js&#039;, [], &#039;1.0&#039;, true); });

// Cargar solo si está presente en el contenido add_action(&#039;wp&#039;, function() { if (is_singular() &amp;&amp; has_shortcode(get_post_field(&#039;post_content&#039;, get_queried_object_id()), &#039;button&#039;)) { wp_enqueue_style(&#039;my-shortcodes&#039;);
        wp_enqueue_script(&#039;my-shortcodes&#039;); } }); // Alternativamente, llamar directamente en la devolución de llamada del shortcode: function my_assets_example_shortcode($atts, $content = null) { wp_enqueue_style(&#039;my-shortcodes&#039;); return &#039;<div class="my-box">' . wp_kses_post($content) . '</div>';
}
add_shortcode('my-box', 'my_assets_example_shortcode');

Códigos cortos frente a llamadas directas a funciones en la plantilla

Hago una distinción consciente: para los módulos de plantilla fija, prefiero llamar a la función directamente en lugar de analizar un shortcode. Esto ahorra sobrecarga, aumenta la legibilidad y evita efectos de filtro sorprendentes. Los shortcodes están pensados para el contenido editorial; las plantillas se benefician de llamadas a funciones claras con parámetros claros.

<?php
// En lugar de:
echo do_shortcode('[saludo]');

// Mejor en la plantilla:
echo mi_saludo_shortcode();

Códigos cortos anidados y formato

Tengo en cuenta los shortcodes anidados y la inserción automática de etiquetas p y br. Si los shortcodes encierran otro contenido, continúo renderizando el contenido interno con do_shortcode, pero sólo permito etiquetas permitidas. Elimino las antiestéticas etiquetas p alrededor de los shortcodes con shortcode_unautop si, de lo contrario, se rompería el marcado.

&lt;?php function my_wrap_shortcode($atts, $content = null) { $inner = do_shortcode($content); // permitir códigos cortos anidados return &#039;<div class="wrap">' . wp_kses_post($inner) . '</div>';
}
add_shortcode('wrap', 'my_wrap_shortcode');

// Ayuda de formato opcional
add_filter('el_contenido', 'shortcode_unautop');

Internacionalización y localización

Mantengo los shortcodes aptos para varios idiomas: traduzco las cadenas de texto con el dominio de texto del tema y utilizo date_i18n para las fechas. De este modo, los módulos funcionan en entornos multilingües y mantienen la coherencia al cambiar de idioma. Localizo los textos por defecto directamente en los callbacks de los shortcodes y los escapo según el contexto.

<?php
// Tema preparado para las traducciones
add_action('after_setup_theme', function() {
    load_theme_textdomain('mi-tema', get_template_directory() . '/idiomas');
});

// Saludo localizado
function mi_saludo_hortcode() {
    return esc_html__('¡Hola, bienvenido a mi sitio web!', 'my-theme');
}

// Año localizado
add_shortcode('año-actual', function() {
    return esc_html(date_i18n('Y'));
});

Invalidación de caché, variantes y claves

Planifico las cachés de tal forma que las variantes estén separadas limpiamente y el contenido quede obsoleto rápidamente cuando se realicen cambios. Atributos como el límite o la taxonomía se incluyen en la clave. Cuando guardo los tipos de entradas relevantes, borro específicamente las claves afectadas. En configuraciones con mucho tráfico, confío en un backend de caché de objetos persistente y agrupo las claves por características para poder vaciarlas colectivamente.

<?php
add_shortcode('latest-offers', function($atts) {
    $atts  = shortcode_atts(['limit' => 5], $atts, 'latest-offers');
    $limit = max(1, (int) $atts['limit']);
    $key   = 'sc_latest_offers_v1_' . $limit;

    if (($html = wp_cache_get($key, 'mytheme')) !== false) {
        return $html;
    }

    $q = new WP_Query([
        'post_type'      => 'angebot',
        'posts_per_page' => $limit,
        'no_found_rows'  => true,
    ]);

    ob_start();
    if ($q->have_posts()) {
        echo '<ul class="offers">';
        while ($q->have_posts()) { $q->the_post();
            echo '<li>' . esc_html(get_the_title()) . '</li>';
        }
        echo '</ul>';
        wp_reset_postdata();
    }
    $html = ob_get_clean();
    wp_cache_set($key, $html, 'mytheme', 600);
    return $html;
});

// Cache invalidieren, wenn Angebote geändert werden
add_action('save_post_angebot', function() {
    foreach ([1,5,10] as $limit) {
        wp_cache_delete('sc_latest_offers_v1_' . $limit, 'mytheme');
    }
});

Profundizar en la seguridad: sanitizador, atributos permitidos y rel/target

Amplío los shortcodes con opciones sensatas pero seguras. Para los enlaces, limito el destino a _self/_blank y establezco rel="noopener noreferrer" para las pestañas nuevas. Compruebo los colores con sanitize_hex_color. Trato el contenido según el contexto, para el contenido adjunto elijo wp_kses_post o una lista de permisos más restrictiva.

<?php
add_shortcode('button', function($atts, $content = null) {
    $atts = shortcode_atts([
        'text'   => '',
        'url' =&gt; '#',
        'color' =&gt; '#2d89ef',
        'target' =&gt; '_self',
    ], $atts, 'button');

    $text = $atts['text'] !== '' ? $atts['text'] : ($content ?: esc_html__('Haz clic ahora', 'mi-tema'));
    $text = esc_html($text);
    $url = esc_url($atts['url']);
    $color = sanitise_hex_color($atts['color']) ?: '#2d89ef';
    $target = in_array($atts['target'], ['_self','_blank'], true) ? $atts['objetivo'] : '_self';
    $rel = $target === '_blank' ? 'noopener noreferrer' : '';

    $style = 'fondo:' . $colour . padding:8px 18px;color:#fff;border-radius:4px;text-decoration:none';

    return '<a class="sc-button" href="/es/' . $url . '/" style="' . esc_attr($style) . '" target="' . esc_attr($target) . '" rel="' . esc_attr($rel) . '">' . $text . '</a>';
});

Editor, widget y contextos de alimentación

Tengo en cuenta el contexto en el que se ejecuta el shortcode. Permito explícitamente los shortcodes en los widgets de texto clásicos y utilizo el bloque shortcode en el editor de widgets de bloque. En los feeds o en la búsqueda, desactivo los shortcodes especialmente complejos y los devuelvo vacíos. Además, sólo cargo activos en páginas singulares si el shortcode aparece en el contenido.

<?php
// Widgets clásicos: activar códigos cortos
add_filter('widget_text', 'do_shortcode');

// Evitar la salida cara en los feeds
add_shortcode('ultimas-ofertas-feed-seguro', function($atts) {
    if (is_feed()) {
        return '';
    }
    // ... salida regular
});

Anulación, migración a bloques y compatibilidad

Planifico el futuro de mis shortcodes: Cuando una etiqueta es reemplazada, la redirijo a la nueva durante un tiempo y anuncio el cambio en el changelog. Si confías en el editor de bloques, puedes registrar bloques del lado del servidor con render_callback y usar internamente la misma función PHP que el shortcode. De esta forma, ambos caminos coexisten limpiamente hasta que el shortcode expira.

'', 'url' => '#'], $atts, 'old-button');
    $text = $map['text'] ?: $content;
    return do_shortcode('[button text="' . esc_attr($text) . '" url="' . esc_url($map['url']) . '"]');
});

// Más tarde: eliminar completamente
// remove_shortcode('old-button');

Pruebas y control de calidad

Valido los shortcodes críticos con pruebas unitarias para que las refactorizaciones no traigan sorpresas. En las pruebas, compruebo que los atributos obligatorios estén validados, que los valores predeterminados estén establecidos y que la salida esté correctamente escapada. Para la salida HTML, elijo aserciones robustas (contains en lugar de exact match) para que los pequeños cambios de formato no rompan todas las pruebas. También compruebo casos extremos como contenido vacío, colores no válidos y textos muy largos.

assertStringContainsString('Hola', $out);
        $this->assertStringContainsString('href="#"', $out);
    }

    public function test_button_blocked_invalid_color() {
        $out = do_shortcode('[button colour="javascript:alert(1)"]');
        $this->assertStringNotContainsString('javascript:', $out);
    }
}

Por último: mi resumen práctico y compacto

Registro los shortcodes de forma clara, los entrego de forma segura y los guardo con Almacenamiento en caché rápidamente. Para el uso editorial, documento ejemplos y garantizo parámetros coherentes para que todo el mundo pueda utilizarlos con confianza. Los módulos relacionados con el diseño acaban en el tema y las funciones relacionadas con el contenido en un plugin, para que el sitio siga siendo flexible a largo plazo. Con un tema hijo, registros de depuración y una semántica limpia, el desarrollo y el mantenimiento se mantienen relajados. El resultado es un tema wordpress shortcode que se renderiza de forma fiable, es fácil de mantener y ofrece a los equipos de contenido una verdadera libertad.

Artículos de actualidad