
🔘 Shortcode de botón en WordPress: código PHP listo para usar y CSS moderno 2026
Necesita un botón de «Descargar» en medio de un artículo, pero su tema solo muestra un enlace azul subrayado. ¿Le suena familiar? En el Editor de Bloques se añade un botón con un clic, pero en el editor clásico, en los widgets y en temas personalizados tiene que escribir HTML con clases a mano cada vez.
Copiar el marcado de una entrada a otra termina de forma predecible: olvida una clase en un sitio, pierde rel="noopener" en otro y el botón aparece de repente con un tono distinto en un tercero. Cuanto más contenido tiene su sitio, más caro resulta cada cambio de estilo.
La solución lleva unos diez minutos. A continuación encontrará un shortcode PHP [button] listo para usar, una paleta OKLCH, soporte para tema oscuro mediante light-dark() y accesibilidad WCAG 2.2. Todo ha sido probado en los navegadores actuales de 2026.
Cómo añadir un botón mediante shortcode: plan de acción
💡 Resumen rápido:
- Paso 1: Añada la función PHP del botón al archivo
functions.phpde su tema hijo - Paso 2: Registre la etiqueta
[button]conadd_shortcode()en el ganchoinit - Paso 3: Incluya el CSS con todos los estados: normal, hover, activo, foco
- Paso 4: Defina esquemas de color con una sola línea OKLCH por color
- Paso 5: Inserte
[button url="..." color="blue"]Text[/button]en una entrada y pruebe el foco por teclado
Cada paso a continuación incluye código listo para copiar. Coloque el código en un tema hijo para que actualizar el tema principal no borre sus cambios. Si aún no tiene un tema hijo, cree uno primero usando la guía oficial de WordPress sobre temas hijos; solo lleva unos minutos.
Pero antes de copiar, eche un vistazo a lo que ha cambiado en el propio estilizado de botones. En los últimos años el CSS para botones se ha reescrito casi por completo.
Qué cambió en el CSS de botones para 2026
En resumen: ya no construye botones a base de prefijos de proveedor y tres conjuntos de tonos hover elegidos a mano. Las propiedades personalizadas, el anidamiento nativo, el modelo de color OKLCH y la función light-dark() reducen un bloque de estilo típico aproximadamente a la mitad y eliminan la duplicación.
Estas técnicas se aplican a una escala enorme. Según datos de W3Techs de julio de 2026, WordPress impulsa el 41,5% de todos los sitios web y posee el 59,2% del mercado de CMS. Cualquier patrón de este artículo puede trasladarse de proyecto en proyecto durante años.
Técnica | Cómo se hacía antes | Cómo se hace en 2026 |
|---|---|---|
Color | HEX más tonos manuales para hover y activo |
|
Paleta | Nueve reglas CSS por color | Una línea sobrescribiendo |
Prefijos |
| No se necesitan: las propiedades están estandarizadas desde hace tiempo |
Anidamiento | Solo mediante Sass o Less | Anidamiento CSS nativo |
Foco |
|
|
Tema oscuro | Hoja de estilos separada |
|
Empecemos por el lado del servidor: hasta que no tengamos una función PHP, no hay nada que estilizar.
Función PHP del botón
La función acepta atributos del editor y devuelve una etiqueta <a> lista con clases, un enlace y texto. Los shortcodes aparecieron en WordPress 2.5 y siguen siendo la forma más rápida de insertar marcado arbitrario en el contenido: add_shortcode() de la referencia oficial registra la etiqueta, y una función de retrollamada ensambla el HTML.
1 /** 2 * Generates button HTML via the [button] shortcode. 3 * 4 * @param array|string $atts Shortcode attributes. 5 * @param string|null $content Text inside the paired [button]...[/button] tag. 6 * @return string Button HTML markup. 7 */ 8 function myprefix_button_shortcode( $atts, $content = null ) { 9 $atts = shortcode_atts( 10 array( 11 'url' => '', 12 'title' => '', 13 'target' => '', 14 'text' => '', 15 'color' => 'green', 16 ), 17 $atts, 18 'button' 19 ); 20 21 // Button text: text attribute takes priority, then tag content 22 $label = $atts['text'] ? $atts['text'] : $content; 23 24 // URL provided: build <a> 25 if ( $atts['url'] ) { 26 $target_attr = ( 'blank' === $atts['target'] ) ? ' target="_blank" rel="noopener noreferrer"' : ''; 27 $title_attr = $atts['title'] ? ' title="' . esc_attr( $atts['title'] ) . '"' : ''; 28 29 return sprintf( 30 '<a href="%s" class="myprefix-button color-%s"%s%s>%s</a>', 31 esc_url( $atts['url'] ), 32 esc_attr( $atts['color'] ), 33 $target_attr, 34 $title_attr, 35 do_shortcode( $label ) 36 ); 37 } 38 39 // No URL: wrap in <span> 40 return sprintf( 41 '<span class="myprefix-button color-%s">%s</span>', 42 esc_attr( $atts['color'] ), 43 do_shortcode( $label ) 44 ); 45 }
Observe tres detalles. shortcode_atts() fusiona los atributos proporcionados con los valores predeterminados, de modo que no hay extract() ni variables no declaradas en el ámbito. Todos los valores dinámicos pasan por esc_url() y esc_attr(): WordPress no escapa la salida del shortcode por usted. Y do_shortcode() dentro de la etiqueta permite anidar un shortcode dentro de otro (por ejemplo, un icono dentro del botón).
Registrar el shortcode y usarlo en el editor
El registro se engancha a init: para ese momento el núcleo está completamente cargado y otros plugins pueden sobrescribir la etiqueta mediante remove_shortcode() si es necesario.
1 add_action( 'init', 'myprefix_register_button_shortcode' ); 2 3 function myprefix_register_button_shortcode() { 4 add_shortcode( 'button', 'myprefix_button_shortcode' ); 5 }
Ahora abra una entrada e inserte la etiqueta. En el editor clásico colóquela directamente en el texto; en el Editor de Bloques use el bloque «Shortcode»:
1 [button url="https://example.com/download" target="blank" text="Download free"] 2 3 [button url="https://example.com" color="blue"]Learn more[/button]
La primera variante se cierra automáticamente con el texto en un atributo. La segunda es emparejada: la etiqueta se sitúa entre las etiquetas de apertura y cierre. El resultado es idéntico; elija la sintaxis que resulte más cómoda para sus autores.
Sin estilos, el botón sigue viéndose como un enlace normal. Sin embargo, la mecánica ya funciona: la clase myprefix-button color-green está en el marcado y solo queda estilizarlo.
Estilos base: propiedades personalizadas y anidamiento
Toda la apariencia descansa en una sola variable, --btn-bg. color-mix() calcula a partir de ella los tonos para hover y activo, de modo que ya no necesita elegir variantes más oscuras a mano. Las reglas anidadas funcionan de forma nativa, sin Sass.
1 .myprefix-button { 2 --btn-bg: oklch(58% 0.15 145); 3 --btn-fg: #fff; 4 5 display: inline-block; 6 padding: 12px 24px; 7 background: var(--btn-bg); 8 color: var(--btn-fg); 9 font-weight: 600; 10 text-decoration: none; 11 border-radius: 8px; 12 cursor: pointer; 13 transition: background 0.2s ease, translate 0.15s ease; 14 15 &:hover { 16 background: color-mix(in oklch, var(--btn-bg), black 12%); 17 color: var(--btn-fg); 18 text-decoration: none; 19 } 20 21 &:active { 22 background: color-mix(in oklch, var(--btn-bg), black 20%); 23 translate: 0 1px; 24 } 25 26 &:focus-visible { 27 outline: 3px solid color-mix(in oklch, var(--btn-bg), white 30%); 28 outline-offset: 2px; 29 } 30 }
El desplazamiento translate: 0 1px en el estado activo simula la presión de un botón físico de forma más sutil que la antigua técnica de sombra interior. transition define la suavidad y el color del texto se repite explícitamente en :hover para que los estilos del tema no lo sobrescriban.
Copie el bloque en el style.css de su tema hijo o en la sección «CSS adicional» del Personalizador. Ahora la parte divertida: los esquemas de color.
Paleta OKLCH: un color nuevo en una línea
Ahora cada esquema ocupa exactamente una línea: solo cambia la variable y todos los estados se recalculan automáticamente.
1 .myprefix-button.color-blue { --btn-bg: oklch(55% 0.17 255); } 2 .myprefix-button.color-red { --btn-bg: oklch(55% 0.19 25); } 3 .myprefix-button.color-orange { --btn-bg: oklch(68% 0.16 60); }
¿Por qué OKLCH en lugar del conocido HEX? En la descripción de oklch() en MDN, el primer parámetro es la luminosidad percibida: dos colores con el mismo primer número se ven igual de brillantes. Los botones azul y rojo de arriba son visualmente equivalentes; HEX no ofrece esa garantía. Crear nuevos esquemas es sencillo cambiando solo el tercer parámetro (tono).
El uso en el editor sigue igual: color="red" activa el esquema rojo, color="orange" el naranja. El atributo por defecto sigue siendo verde, como en la función original.

Accesibilidad: lo que más a menudo falla
La respuesta directa: un botón necesita un anillo de foco visible, un tamaño de destino suficiente y respetar las preferencias de animación. No son requisitos de casilla de verificación. Una auditoría de 17,2 millones de sitios en el Web Almanac 2025 mostró que el 67% de los sitios eliminan el contorno de foco y solo el 30% cumple los estándares de contraste de las WCAG.
El marco legal también se ha endurecido: a partir del 28 de junio de 2025 se aplica la Ley Europea de Accesibilidad y los requisitos de accesibilidad para productos digitales en la UE son ahora una norma legal, no una recomendación.
El criterio 2.5.8 Tamaño del destino (mínimo) de nivel AA de las WCAG 2.2 exige que un destino interactivo mida al menos 24 por 24 píxeles CSS o disponga de un espacio libre equivalente a su alrededor.
Nuestro botón con padding: 12px 24px supera el mínimo con holgura, pero vale la pena añadir dos reglas por separado:
1 .myprefix-button { 2 min-block-size: 44px; 3 align-content: center; 4 } 5 6 @media (prefers-reduced-motion: reduce) { 7 .myprefix-button { 8 transition: none; 9 } 10 }
La primera regla eleva la altura hasta una zona táctil cómoda en móviles, donde los toques fallidos en destinos pequeños resultan especialmente frustrantes. La segunda desactiva las animaciones para quienes lo han solicitado en los ajustes de su sistema. Ya hemos definido el anillo de foco mediante :focus-visible: aparece durante la navegación por teclado y no molesta a los usuarios de ratón.

Tema oscuro mediante light-dark()
Una sola función reemplaza toda la media query prefers-color-scheme. Usted especifica dos valores (claro y oscuro), y el navegador elige el correcto según el esquema activo. Según MDN, la función light-dark() tiene el estado Baseline Newly available desde mayo de 2024, lo que significa que funciona en todos los navegadores actuales.
1 :root { 2 color-scheme: light dark; 3 } 4 5 .myprefix-button { 6 --btn-bg: light-dark(oklch(58% 0.15 145), oklch(70% 0.13 145)); 7 --btn-fg: light-dark(#fff, oklch(22% 0.02 145)); 8 }
La línea color-scheme: light dark es obligatoria: sin ella la función no se activará. Para el esquema oscuro el fondo se aclara y el texto se oscurece: sobre un lienzo oscuro los botones oscuros saturados se hunden, un error frecuente. Un desglose detallado de la tematización con todos sus escollos está disponible en el artículo de web.dev sobre temas de color.
Si su audiencia usa navegadores corporativos antiguos, envuelva las características nuevas en @supports y mantenga HEX simple como respaldo: el botón se degrada con gracia, perdiendo solo precisión en los matices.
Seguridad: tres líneas que la gente olvida
Primero lo primero: target="_blank" sin rel="noopener noreferrer" abre una vulnerabilidad de tabnabbing. La página a la que enlaza el botón obtiene acceso a window.opener y puede reemplazar la pestaña que contiene su sitio. En nuestra función el atributo se añade automáticamente, pero es fácil perderlo durante modificaciones.
El escapado es igualmente importante. esc_url() bloquea protocolos peligrosos como javascript:, y esc_attr() previene la ruptura de un atributo. Estas llamadas nunca deben eliminarse por brevedad en ningún shortcode que acepte datos del editor.
Un último punto: $content no se pasa intencionadamente por wp_kses_post() para que los shortcodes anidados funcionen. Sin embargo, si usted permite insertar botones mediante formularios del front-end, envuelva $label en wp_kses_post() antes de la salida.
Cómo probar un botón antes de publicar
Una prueba rápida toma un par de minutos y detecta casi todos los problemas que los usuarios reportan después. Repase esta lista antes de colocar el botón en publicaciones de producción:
- Haga clic en el botón con un ratón y verifique que el enlace se abre en la pestaña correcta.
- Navegue con Tab por la página: el anillo de foco debe ser obvio a primera vista.
- Active la emulación de esquema oscuro en DevTools (panel Rendering, opción prefers-color-scheme) y compruebe ambas variantes de fondo.
- Active la emulación de prefers-reduced-motion en el mismo panel y confirme que el botón deja de animarse.
- Abra la página en modo móvil e intente tocar el botón con el pulgar.
Si todo pasa, el shortcode está listo para uso masivo. Adquiera el hábito de repasar esta lista después de cada cambio de estilo: las regresiones en estados de foco y tema oscuro son invisibles hasta que usted las busca específicamente. Las preguntas más comunes sobre el comportamiento del shortcode se recopilan a continuación.
⁉️🤔 Preguntas frecuentes
¿Este shortcode funciona en el Editor de Bloques?
Sí, completamente. Inserte un bloque "Shortcode" y escriba
[button ...]dentro. El marcado se ensambla en el servidor cuando la publicación se renderiza, así que al editor no le importa cómo llegó la etiqueta al contenido. Para elementos de uso frecuente, con el tiempo tiene sentido registrar un bloque nativo medianteregister_block_type(), pero eso es un proyecto aparte.
¿Qué pasa si el navegador de un visitante no entiende oklch() o light-dark()?
Envuelva los valores modernos en una directiva
@supportsy mantenga HEX simple como valor predeterminado. Un navegador antiguo aplicará el color de respaldo; uno nuevo usará OKLCH. El botón sigue siendo funcional en ambos casos: la degradación con gracia afecta solo a la precisión de los matices y la automatización del tema oscuro, no a la funcionalidad.
¿Por qué aparece el shortcode en la página como texto entre corchetes?
Lo más frecuente es que la función no esté registrada: verifique que
functions.phpse guardó sin errores de sintaxis y que el hookinitse disparó. Una segunda posibilidad: insertó la etiqueta en un archivo de plantilla, donde necesita una llamada explícita aecho do_shortcode( '[button ...]' ). ActiveWP_DEBUGy revise el registro de errores.
¿Cómo añado un icono dentro del botón?
La ruta más rápida: un emoji directamente en el texto, por ejemplo
text="📥 Download". Para SVG, pase la URL del archivo como un atributo separado y emita una etiqueta<img>dentro del enlace mediante el mismosprintf. El enfoque con Dashicons también funciona: un pseudoelemento::beforemásfont-family: dashiconsen una clase dedicada.
¿Siguen siendo necesarios los prefijos de proveedor para border-radius y transition en 2026?
No. Estas propiedades llevan mucho tiempo estandarizadas y funcionan en todos los navegadores actuales sin prefijos. Consulte el soporte de una característica específica en las tablas de MDN o en caniuse.com, que también muestran el estado Baseline indicando cuándo una característica puede usarse sin respaldos.
💎 Resumen y conclusiones
Para un sitio que necesita solo un par de botones estándar, un shortcode personalizado supera a cualquier plugin: control total sobre el marcado, cero scripts adicionales en la cola de carga y ninguna dependencia que mantener actualizada. Un constructor visual con docenas de estilos prefabricados se necesita menos a menudo de lo que parece, pero si realmente necesita uno, eche un vistazo a MaxButtons en el directorio de wordpress.org.
Consejo práctico: comience la implementación con la línea color-scheme: light dark en :root y variables mediante light-dark(). Esta es la forma más barata de obtener un tema oscuro adecuado, y rinde frutos para cada elemento de interfaz subsiguiente. Y un escollo para terminar: no pruebe el botón solo con un ratón. Navegue con Tab por la página y verifique que el anillo de foco sea visible; de lo contrario, algunos visitantes simplemente no encontrarán su botón.
Tome el código, péguelo en su tema hijo y pruebe el botón en su sitio hoy mismo. ¿Funcionó o encontró un conflicto con su tema? Compártalo en los comentarios y lo resolveremos juntos. Y suscríbase para recibir actualizaciones del blog: vienen más desgloses de shortcodes útiles.



