Skip to content

Tudo para WordPress, desenvolvimento web — e não só

⚙️ WordPress: como definir um modelo padrão para um tipo de publicação personalizado

⚙️ WordPress: como definir um modelo padrão para um tipo de publicação personalizado

Entregou ao cliente um site em WordPress com um portefólio e, no dia seguinte, ele telefona: «Estou a adicionar uma nova entrada, mas o modelo está sempre a reverter para o predefinido com uma barra lateral. Como é que o fixo?» A situação é dolorosamente familiar: clica em «Adicionar Novo» num tipo de conteúdo personalizado e, em vez do layout de largura total que construiu, aparece uma coluna de blogue com uma barra lateral. Escolher o modelo manualmente para cada publicação é um trabalho inútil que frustra tanto o programador como o cliente. Especialmente quando «Largura Total» sem barra lateral é o que precisa quase sempre.

Por predefinição, o WordPress usa o ficheiro single.php do tema para os tipos de conteúdo personalizados (CPT). E o single.php costuma ser pensado para um blogue: título, conteúdo, barra lateral com widgets. Para portefólios, casos de estudo, testemunhos ou produtos, esse layout é um mau ajuste. A boa notícia: o WordPress oferece quatro formas de atribuir um modelo a um CPT, desde a mais simples (um ficheiro no tema, sem código nenhum) até à totalmente programática através de hooks e temas de blocos. Cada método resolve o problema de forma fiável; a única diferença é o nível de controlo e a facilidade de manutenção.

💡 Visão geral rápida:

  • Crie um ficheiro single-{post_type}.php na raiz do tema e o WordPress irá buscá-lo automaticamente através da hierarquia de modelos
  • Use o hook no filtro template_include no functions.php para atribuir um modelo programaticamente sem colocar um ficheiro físico no tema
  • Para temas de blocos, crie single-{post_type}.html na pasta templates/; pode ser editado através do Editor do Site sem código
  • Após qualquer alteração, limpe os permalinks: «Definições → Permalinks → Guardar alterações», caso contrário o WordPress não verá o novo modelo

Método 1: ficheiro de modelo através da hierarquia do WordPress

O método mais fiável e direto. Desde a versão 3.0, o WordPress suporta modelos personalizados para CPTs através da hierarquia de modelos padrão. Funciona assim: quando um visitante abre uma entrada do tipo portfolio, o WordPress procura um modelo numa ordem rigorosa, de cima para baixo, e usa o primeiro ficheiro que encontrar:

single-portfolio.phpsingle.phpsingular.phpindex.php

Precisa de criar um ficheiro com o nome single-{post_type}.php, em que {post_type} é o slug do seu tipo personalizado. Coloque-o na raiz do tema ativo:

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

A forma mais rápida de começar: copie o conteúdo de page.php ou template-fullwidth.php do seu tema e adapte o layout para o CPT específico. Se não existir nenhum ficheiro single-{post_type}.php, o WordPress recorre silenciosamente ao single.php e o cliente acaba com uma barra lateral.

A vantagem deste método: nenhum código no functions.php; o ficheiro fica simplesmente no tema e funciona. A desvantagem: o modelo fica fortemente acoplado ao tema. Se mudar de tema, o ficheiro permanece na pasta antiga e deixa de funcionar.

Método 2: programaticamente através do filtro template_include

O método baseado em ficheiros funciona desde que controle o tema. Mas se estiver a desenvolver um plugin ou um tema filho que não deve depender de um ficheiro presente na raiz, precisa do hook template_include.

O filtro é executado antes de o modelo carregar e permite-lhe apontar para um ficheiro PHP a partir de qualquer localização:

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}

O que está a acontecer aqui:

  • is_singular('portfolio') verifica se estamos numa página de entrada única do tipo portfolio
  • Se a condição for verdadeira, o WordPress carrega o modelo da pasta do plugin, ignorando a hierarquia do tema
  • A prioridade 99 garante que o filtro é executado em último lugar e não é substituído pelo tema

Esta abordagem é conveniente quando o modelo precisa de residir dentro de um plugin e sobreviver a mudanças de tema. O ficheiro templates/single-portfolio.php dentro do plugin pode usar get_header() e get_footer() do tema ativo, pelo que visualmente tudo se mantém consistente com o design do site.

Método 3: o filtro {$type}_template

O WordPress fornece um hook dinâmico {$type}_template, em que $type é single, archive ou page. Para um CPT assume a forma single-portfolio_template e permite-lhe substituir o modelo com precisão, sem verificações extra dentro da função de callback:

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}

A diferença em relação ao Método 2 é semântica: está explicitamente a dizer «altera o modelo para entradas únicas» em vez de «interceta todos os modelos». O código é ligeiramente mais limpo, mas funcionalmente ambos os hooks resolvem o problema da mesma forma.

Método 4: modelo num tema de blocos (Full Site Editing)

A partir do WordPress 5.9 e da mudança para temas de blocos, a abordagem altera-se. Nos temas FSE, os modelos são ficheiros HTML na pasta templates/, não PHP. Para um tipo de conteúdo personalizado, crie:

1/wp-content/themes/your-fse-theme/templates/single-portfolio.html

No interior, usa uma estrutura baseada em blocos. Um exemplo 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"} /-->

Pode editar este modelo diretamente no Editor do Site (Aparência → Editor) sem tocar em código. Se mudar de tema de blocos, o ficheiro permanece na pasta antiga, a mesma vulnerabilidade do Método 1.

Qual o método a escolher

Uma matriz de decisão rápida para o seu cenário:

Cenário

Método

Um tema, um CPT, sem plugins

Método 1: single-{post_type}.php

Plugin com o seu próprio modelo

Método 2: template_include

Tema filho, precisa de substituir o modelo do tema pai

Método 1 ou 3

FSE / tema de blocos (Twenty Twenty-Four e mais recentes)

Método 4: templates/single-{post_type}.html

Depois de implementar qualquer um dos métodos, não se esqueça de ir a «Definições → Permalinks» e clicar em «Guardar alterações». Isto limpa a cache das regras de reescrita e o WordPress começa a reconhecer o novo modelo.

⁉️🤔 Perguntas frequentes

O modelo não está a ser detetado. O que devo fazer?

Primeiro, limpe os permalinks («Definições → Permalinks → Guardar»). Segundo, verifique se o slug do CPT no nome do ficheiro corresponde ao slug de register_post_type(). Terceiro, se houver um plugin de cache ativo, limpe a cache. Na prática, o problema está mais frequentemente relacionado com a limpeza das regras de reescrita após registar o CPT, e não com o código do modelo em si.

Posso atribuir um modelo a vários CPTs ao mesmo tempo?

Sim. No Método 2, use um array em is_singular(): is_singular( array( 'portfolio', 'testimonials', 'team' ) ). Ou verifique in_array( $post->post_type, array('portfolio', 'team') ) dentro da função de callback. O ficheiro de modelo é um só e o layout será partilhado por todos os tipos listados.

O modelo funciona, mas o layout está quebrado (faltam estilos da barra lateral/cabeçalho).

Herdou o modelo do page.php, mas os estilos do tema dependem de classes CSS no body. Adicione um filtro body_class no functions.php para que o WordPress aplique uma classe post-type-{slug} ao <body> e os estilos serão aplicados:

1add_filter( 'body_class', function( $classes ) {
2 if ( is_singular( 'portfolio' ) ) {
3 $classes[] = 'single-portfolio';
4 }
5 return $classes;
6} );

O que acontece quando mudo de tema? O modelo desaparece.

Sim, o ficheiro single-portfolio.php permanece na pasta do tema antigo. As suas opções: mova o ficheiro manualmente para o novo tema, use um tema filho (o ficheiro sobrevive a atualizações do tema pai) ou mova o modelo para um plugin através do Método 2, que não depende do tema ativo.

E se eu precisar que TODOS os CPTs abram sem barra lateral por predefinição?

Use um filtro universal com is_singular() sem especificar um post_type em particular, mas exclua os tipos padrão post e 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 solução aplica um único modelo de largura total a todos os tipos de conteúdo personalizados de uma só vez: portefólios, testemunhos, membros da equipa, casos de estudo. As publicações e páginas padrão não são afetadas.

Vale a pena incomodar-se com o template_include quando se pode simplesmente criar um ficheiro?

Se tem um site, um tema e um CPT, crie single-{post_type}.php e esqueça o assunto. Esta é uma solução que dura anos: não se parte com atualizações do WordPress, não depende da versão do PHP e é imediatamente clara para qualquer programador que abra a pasta do tema. A manutenção resume-se a um único ficheiro que pode corrigir num instante.

Os métodos programáticos através de hooks justificam-se em dois casos. Primeiro: o modelo faz parte de um plugin distribuído e não quer obrigar os utilizadores a copiar ficheiros para o tema. Segundo: os CPTs são registados dinamicamente através de ACF, Toolset ou um plugin semelhante, e proliferar uma dúzia de ficheiros single-*.php no tema é impraticável. Para tudo o resto, a hierarquia de modelos do WordPress é o caminho mais simples e fiável, comprovado ao longo de anos.