
⚙️ WordPress: cómo establecer una plantilla predeterminada para un tipo de contenido personalizado
Le entregó al cliente un sitio en WordPress con un portafolio, y al día siguiente le llaman: «Estoy añadiendo una nueva entrada, pero la plantilla sigue volviendo a la predeterminada con barra lateral. ¿Cómo la fijo?». La situación es dolorosamente familiar: hace clic en «Añadir nuevo» en un tipo de contenido personalizado y, en lugar del diseño a ancho completo que usted construyó, aparece una columna de blog con barra lateral. Elegir la plantilla manualmente para cada entrada es una tarea repetitiva sin sentido que frustra tanto a usted como al cliente. Sobre todo cuando «Ancho completo» sin barra lateral es lo que necesita casi siempre.
Por defecto, WordPress usa single.php del tema para los tipos de contenido personalizado (CPT). Y single.php suele estar pensado para un blog: título, contenido, barra lateral con widgets. Para portafolios, casos de estudio, testimonios o productos, ese diseño no encaja bien. La buena noticia: WordPress ofrece cuatro maneras de asignar una plantilla a un CPT, desde la más simple (un archivo en el tema, sin nada de código) hasta la completamente programática mediante hooks y temas de bloques. Cada método cumple el objetivo de forma fiable; la única diferencia es el nivel de control y la facilidad de mantenimiento.
💡 Resumen rápido:
- Cree un archivo
single-{post_type}.phpen la raíz del tema, y WordPress lo detectará automáticamente mediante la jerarquía de plantillas - Enganche el filtro
template_includeenfunctions.phppara asignar una plantilla programáticamente sin colocar un archivo físico en el tema - Para temas de bloques, cree
single-{post_type}.htmlen la carpetatemplates/; se puede editar a través del Editor del sitio sin código - Después de cualquier cambio, regenere los enlaces permanentes: «Ajustes → Enlaces permanentes → Guardar cambios», de lo contrario WordPress no verá la nueva plantilla
Método 1: archivo de plantilla mediante la jerarquía de WordPress
El método más fiable y directo. Desde la versión 3.0, WordPress admite plantillas personalizadas para CPT a través de la jerarquía de plantillas estándar. Funciona así: cuando un visitante abre una entrada del tipo portfolio, WordPress busca una plantilla en un orden estricto, de arriba abajo, y usa el primer archivo que encuentra:
single-portfolio.php → single.php → singular.php → index.php
Necesita crear un archivo llamado single-{post_type}.php, donde {post_type} es el slug de su tipo personalizado. Colóquelo en la raíz del tema activo:
1 /* File: /wp-content/themes/your-theme/single-portfolio.php */ 2 3 <?php get_header(); ?> 4 5 <div class="full-width-content"> 6 <?php while ( have_posts() ) : the_post(); ?> 7 <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> 8 <h1><?php the_title(); ?></h1> 9 <div class="entry-content"> 10 <?php the_content(); ?> 11 </div> 12 </article> 13 <?php endwhile; ?> 14 </div> 15 16 <?php get_footer(); ?> 17
La forma más rápida de empezar: copie el contenido de page.php o template-fullwidth.php de su tema y adapte el diseño para el CPT específico. Si no existe un archivo single-{post_type}.php, WordPress recurre silenciosamente a single.php, y el cliente termina con una barra lateral.
La ventaja de este método: nada de código en functions.php; el archivo simplemente está en el tema y funciona. La desventaja: la plantilla está fuertemente acoplada al tema. Si cambia de tema, el archivo se queda en la carpeta antigua y deja de funcionar.
Método 2: programáticamente mediante el filtro template_include
El método basado en archivos funciona mientras usted controle el tema. Pero si está desarrollando un plugin o un tema hijo que no debería depender de que un archivo esté presente en la raíz, necesita el hook template_include.
El filtro se ejecuta antes de que se cargue la plantilla y le permite apuntar a un archivo PHP desde cualquier ubicación:
1 /* File: functions.php (theme) or main plugin file */ 2 3 add_filter( 'template_include', 'sd_cpt_default_template', 99 ); 4 5 function sd_cpt_default_template( $template ) { 6 if ( is_singular( 'portfolio' ) ) { 7 $custom_template = plugin_dir_path( __FILE__ ) . 'templates/single-portfolio.php'; 8 if ( file_exists( $custom_template ) ) { 9 return $custom_template; 10 } 11 } 12 return $template; 13 }
Lo que sucede aquí:
is_singular('portfolio')comprueba si estamos en una página de entrada individual del tipoportfolio- Si la condición es verdadera, WordPress carga la plantilla desde la carpeta del plugin, omitiendo la jerarquía del tema
- La prioridad 99 asegura que el filtro se ejecute al final y no sea anulado por el tema
Este enfoque es conveniente cuando la plantilla necesita residir dentro de un plugin y sobrevivir a los cambios de tema. El archivo templates/single-portfolio.php dentro del plugin puede usar get_header() y get_footer() del tema activo, por lo que visualmente todo se mantiene coherente con el diseño del sitio.
Método 3: el filtro {$type}_template
WordPress proporciona un hook dinámico {$type}_template, donde $type es single, archive o page. Para un CPT toma la forma single-portfolio_template y le permite anular la plantilla de forma precisa, sin comprobaciones adicionales dentro de la función de retorno:
1 add_filter( 'single_template', 'sd_cpt_template_by_type' ); 2 3 function sd_cpt_template_by_type( $single_template ) { 4 global $post; 5 6 if ( 'portfolio' === $post->post_type ) { 7 $custom_template = get_stylesheet_directory() . '/single-portfolio.php'; 8 if ( file_exists( $custom_template ) ) { 9 return $custom_template; 10 } 11 } 12 return $single_template; 13 }
La diferencia con el Método 2 es semántica: usted dice explícitamente «cambiar la plantilla para entradas individuales» en lugar de «interceptar todas las plantillas». El código es ligeramente más limpio, pero funcionalmente ambos hooks resuelven el problema de la misma manera.
Método 4: plantilla en un tema de bloques (Full Site Editing)
A partir de WordPress 5.9 y el cambio hacia los temas de bloques, el enfoque cambia. En los temas FSE, las plantillas son archivos HTML en la carpeta templates/, no PHP. Para un tipo de contenido personalizado, cree:
1 /wp-content/themes/your-fse-theme/templates/single-portfolio.html
Dentro, se usa una estructura basada en bloques. Un ejemplo mínimo:
1 <!-- wp:template-part {"slug":"header","theme":"your-fse-theme"} /--> 2 3 <!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} --> 4 <main class="wp-block-group"> 5 <!-- wp:post-title {"level":1} /--> 6 <!-- wp:post-featured-image /--> 7 <!-- wp:post-content {"layout":{"type":"constrained"}} /--> 8 </main> 9 <!-- /wp:group --> 10 11 <!-- wp:template-part {"slug":"footer","theme":"your-fse-theme"} /-->
Puede editar esta plantilla directamente en el Editor del sitio (Apariencia → Editor) sin tocar nada de código. Si cambia de tema de bloques, el archivo se queda en la carpeta antigua, la misma vulnerabilidad que el Método 1.
Qué método elegir
Una matriz rápida de decisión para su escenario:
Escenario | Método |
|---|---|
Un tema, un CPT, sin plugins | Método 1: |
Plugin con su propia plantilla | Método 2: |
Tema hijo, necesita anular la plantilla del padre | Método 1 o 3 |
FSE / tema de bloques (Twenty Twenty-Four y más recientes) | Método 4: |
Después de implementar cualquiera de los métodos, asegúrese de ir a «Ajustes → Enlaces permanentes» y hacer clic en «Guardar cambios». Esto vacía la caché de reglas de reescritura, y WordPress empieza a reconocer la nueva plantilla.
⁉️🤔 Preguntas frecuentes
La plantilla no se está detectando. ¿Qué debo hacer?
Primero, regenere los enlaces permanentes («Ajustes → Enlaces permanentes → Guardar»). Segundo, verifique que el slug del CPT en el nombre del archivo coincida con el slug de
register_post_type(). Tercero, si hay un plugin de caché activo, limpie la caché. En la práctica, el problema suele deberse a no haber regenerado las reglas de reescritura después de registrar el CPT, no al código de la plantilla en sí.
¿Puedo asignar una plantilla a varios CPT a la vez?
Sí. En el Método 2, use un array en
is_singular():is_singular( array( 'portfolio', 'testimonials', 'team' ) ). O compruebein_array( $post->post_type, array('portfolio', 'team') )dentro de la función de retorno. El archivo de plantilla es uno, y el diseño se compartirá entre todos los tipos listados.
La plantilla funciona, pero el diseño está roto (faltan estilos de barra lateral/cabecera).
Heredó la plantilla de
page.php, pero los estilos del tema dependen de clases CSS enbody. Añada un filtrobody_classenfunctions.phppara que WordPress aplique una clasepost-type-{slug}a<body>, y los estilos se aplicarán:
1 add_filter( 'body_class', function( $classes ) { 2 if ( is_singular( 'portfolio' ) ) { 3 $classes[] = 'single-portfolio'; 4 } 5 return $classes; 6 } );
¿Qué pasa cuando cambio de tema? La plantilla desaparece.
Sí, el archivo
single-portfolio.phpse queda en la carpeta del tema antiguo. Sus opciones: mover el archivo al nuevo tema manualmente, usar un tema hijo (el archivo sobrevive a las actualizaciones del tema padre) o mover la plantilla a un plugin mediante el Método 2, que no depende del tema activo.
¿Y si necesito que TODOS los CPT se abran sin barra lateral por defecto?
Use un filtro universal con
is_singular()sin especificar un post_type concreto, pero excluya los estándarpostypage:
1 add_filter( 'template_include', function( $template ) { 2 if ( is_singular() && ! is_singular( array( 'post', 'page' ) ) ) { 3 $fullwidth = get_stylesheet_directory() . '/template-fullwidth.php'; 4 if ( file_exists( $fullwidth ) ) { 5 return $fullwidth; 6 } 7 } 8 return $template; 9 }, 99 );
Esta solución aplica una única plantilla a ancho completo a todos los tipos de contenido personalizado a la vez: portafolios, testimonios, miembros del equipo, casos de estudio. Las entradas y páginas estándar no se ven afectadas.
¿Vale la pena molestarse con template_include cuando se puede simplemente crear un archivo?
Si tiene un sitio, un tema y un CPT, cree single-{post_type}.php y olvídese. Esta es una solución que dura años: no se rompe con las actualizaciones de WordPress, no depende de la versión de PHP y resulta inmediatamente clara para cualquier desarrollador que abra la carpeta del tema. El mantenimiento se reduce a un solo archivo que puede arreglar en un momento.
Los métodos programáticos mediante hooks se justifican en dos casos. Primero: la plantilla es parte de un plugin distribuido, y no quiere obligar a los usuarios a copiar archivos en el tema. Segundo: los CPT se registran dinámicamente a través de ACF, Toolset o un plugin similar, y proliferar una docena de archivos single-*.php en el tema no es práctico. Para todo lo demás, la jerarquía de plantillas de WordPress es el camino más simple y fiable, probado durante años.



