Skip to content

Todo para WordPress, el desarrollo web — y mucho más

⚙️ WordPress: cómo establecer una plantilla predeterminada para un tipo de contenido personalizado

⚙️ 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}.php en la raíz del tema, y WordPress lo detectará automáticamente mediante la jerarquía de plantillas
  • Enganche el filtro template_include en functions.php para asignar una plantilla programáticamente sin colocar un archivo físico en el tema
  • Para temas de bloques, cree single-{post_type}.html en la carpeta templates/; 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.phpsingle.phpsingular.phpindex.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
3add_filter( 'template_include', 'sd_cpt_default_template', 99 );
4
5function 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 tipo portfolio
  • 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:

1add_filter( 'single_template', 'sd_cpt_template_by_type' );
2
3function 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: single-{post_type}.php

Plugin con su propia plantilla

Método 2: template_include

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: templates/single-{post_type}.html

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 compruebe in_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 en body. Añada un filtro body_class en functions.php para que WordPress aplique una clase post-type-{slug} a <body>, y los estilos se aplicarán:

1add_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.php se 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ándar post y page:

1add_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.