Skip to content

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

🔧 Como criar um modelo para um tipo de publicação personalizado no WordPress

🔧 Como criar um modelo para um tipo de publicação personalizado no WordPress

Adicionou um tipo de publicação personalizado ao seu site, por exemplo «Promoções», «Portefólio» ou «Testemunhos». Tudo funciona: as publicações são criadas, os campos meta são preenchidos. Mas quando abre uma dessas publicações no front-end, ela parece uma publicação de blogue normal. O mesmo layout, as mesmas barras laterais, nenhuma diferença. No entanto, criou um tipo de publicação personalizado precisamente para que o conteúdo fosse apresentado de forma diferente.

O problema é que o WordPress renderiza qualquer publicação personalizada através do single.php por predefinição, o modelo universal para todas as publicações individuais. Para obter um layout único para um tipo específico, precisa do seu próprio ficheiro de modelo. E acaba por ser surpreendentemente fácil.

Abaixo está uma análise passo a passo: desde a hierarquia de modelos até dois métodos de criação (via um ficheiro de tema e via o filtro template_include), com exemplos de código funcionais.

💡 Visão geral rápida:

  • Compreender como o WordPress procura um modelo para um tipo de publicação personalizado e a prioridade do single-{post_type}.php
  • Copiar o single.php do seu tema, renomeá-lo para o seu CPT e personalizá-lo
  • Explorar um método alternativo via o filtro template_include (útil se não quiser mexer no tema)
  • Criar o próprio tipo de publicação personalizado usando o plugin Custom Post Type UI, de forma rápida e sem código

1. Como o WordPress escolhe um modelo para um tipo de publicação personalizado

A hierarquia de modelos do WordPress é uma cadeia de ficheiros que o núcleo verifica para encontrar o modelo certo para renderizar uma página. Para publicações padrão, a cadeia é longa: single-post.phpsingle.phpsingular.phpindex.php. Para tipos de publicação personalizados é mais curta, mas a lógica é a mesma.

Quando um visitante abre uma publicação personalizada do tipo aktsii, o WordPress verifica os ficheiros por esta ordem:

  • single-aktsii.php, o modelo específico para este tipo de publicação personalizado
  • single.php, o modelo genérico de publicação individual
  • singular.php, o modelo para qualquer conteúdo singular (publicação, página, CPT)
  • index.php, o recurso final de contingência

O primeiro ficheiro encontrado na cadeia é o usado para a renderização. Se o single-aktsii.php existir, o WordPress seleciona-o e para. Se não for encontrado, o núcleo avança para o single.php. É exatamente por isso que o seu tipo de publicação personalizado se parece com uma publicação normal: não existe um ficheiro single-aktsii.php, por isso o núcleo recorre ao single.php genérico.

A solução decorre diretamente daqui: crie o single-{post_type}.php e o WordPress seleciona-o automaticamente.

2. Criar um ficheiro de modelo: copiar o single.php e renomeá-lo

Esta é a abordagem mais simples e fiável. Funciona com qualquer tema clássico e não requer plugins nem filtros.

Passo 1: encontre o single.php do seu tema. Ele está na raiz da pasta do tema: /wp-content/themes/your-theme/single.php. Se o tema usar FSE (Full Site Editing) e for construído em blocos, este ficheiro pode não existir e o método do filtro (template_include) será mais conveniente (secção 4).

Passo 2: copie e renomeie. Copie o single.php e nomeie-o seguindo o padrão single-{slug}.php: substitua {slug} pelo slug do seu tipo de publicação personalizado (o especificado durante o registo, em caracteres latinos). Por exemplo, para um tipo com o slug aktsii:

1single-aktsii.php

Para um tipo com o slug portfolio, o ficheiro chamar-se-ia single-portfolio.php. Para testimonials torna-se single-testimonials.php. Importante: o slug deve corresponder ao especificado no parâmetro 'rewrite' => array('slug' => '...') durante o registo.

Passo 3: coloque o ficheiro de volta na pasta do tema. O WordPress irá selecioná-lo automaticamente para todas as publicações deste tipo. Não é necessária configuração adicional; a hierarquia de modelos trata disso automaticamente.

Passo 4: verifique. Abra qualquer publicação do tipo personalizado no front-end. Se vir a mesma página de antes, verifique o nome do ficheiro (maiúsculas/minúsculas, hífens em vez de underscores) e limpe a cache. Se o ficheiro foi criado num tema filho e o tema pai também contiver single-{post_type}.php, o tema filho tem prioridade.

3. Personalizar o conteúdo do modelo

O single.php copiado ainda é idêntico ao original; simplesmente renderiza o mesmo layout genérico. Agora preenchemo-lo com conteúdo específico do tipo de publicação personalizado.

3.1. Estrutura básica: exibir campos personalizados

Suponha que o tipo de publicação personalizado aktsii tem os campos aktsiya_data_start, aktsiya_data_end e aktsiya_skidka (criados via ACF, Meta Box ou manualmente). Aqui está um modelo mínimo que os exibe:

1<?php
2/**
3 * Template for custom type "Promotions" (single-aktsii.php)
4 */
5
6get_header();
7?>
8
9<main id="main" class="site-main" role="main">
10
11 <?php while ( have_posts() ) : the_post(); ?>
12
13 <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
14
15 <header class="entry-header">
16 <?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
17 </header>
18
19 <?php if ( has_post_thumbnail() ) : ?>
20 <div class="post-thumbnail">
21 <?php the_post_thumbnail( 'large' ); ?>
22 </div>
23 <?php endif; ?>
24
25 <div class="entry-content">
26 <?php the_content(); ?>
27
28 <div class="custom-fields">
29 <?php
30 $data_start = get_post_meta( get_the_ID(), 'aktsiya_data_start', true );
31 $data_end = get_post_meta( get_the_ID(), 'aktsiya_data_end', true );
32 $skidka = get_post_meta( get_the_ID(), 'aktsiya_skidka', true );
33
34 if ( $data_start ) {
35 echo '<p><strong>Start Date:</strong> ' . esc_html( $data_start ) . '</p>';
36 }
37 if ( $data_end ) {
38 echo '<p><strong>End Date:</strong> ' . esc_html( $data_end ) . '</p>';
39 }
40 if ( $skidka ) {
41 echo '<p><strong>Discount:</strong> ' . esc_html( $skidka ) . '%</p>';
42 }
43 ?>
44 </div>
45 </div>
46
47 </article>
48
49 <?php
50 if ( comments_open() || get_comments_number() ) :
51 comments_template();
52 endif;
53 ?>
54
55 <?php endwhile; ?>
56
57</main>
58
59<?php
60get_sidebar();
61get_footer();

Este é um modelo totalmente funcional que pode colocar no seu tema tal como está. Exibe o título, a imagem destacada, o conteúdo e três campos personalizados num bloco separado.

3.2. O que mais pode fazer com o modelo

A partir daqui, as possibilidades de personalização são virtualmente ilimitadas:

  • Remover a barra lateral: simplesmente remova a chamada get_sidebar().
  • Alterar o wrapper HTML: substitua <article> por uma <div> com a classe de que precisa, adicione a sua própria grelha.
  • Chamar uma parte de modelo específica: por exemplo, get_template_part( 'template-parts/content', 'aktsii' ) e mantenha a lógica num ficheiro separado.
  • Carregar estilos personalizados: via wp_enqueue_style() dentro do functions.php com uma verificação is_singular( 'aktsii' ).

Uma nota importante: se o tema for atualizado, um ficheiro no tema pai pode ser sobrescrito. Portanto, trabalhe num tema filho ou use o método do filtro da próxima secção.

4. Abordagem alternativa: o filtro template_include

Se preferir não modificar ficheiros do tema (ou se o tema for baseado em blocos e não tiver um single.php clássico), pode atribuir um modelo via o hook template_include. Ele é acionado antes de o WordPress incluir o ficheiro de modelo e permite-lhe substituir o caminho.

Desvantagem: terá de armazenar o ficheiro de modelo num plugin ou num tema filho, e o código deve apontar para o caminho correto. Vantagem: a lógica não se perde quando o tema pai é atualizado.

4.1. Exemplo: um CPT, um modelo

Adicione isto ao functions.php do tema filho (ou a um MU-plugin):

1add_filter( 'template_include', 'techblog_cpt_template', 99 );
2
3function techblog_cpt_template( $template ) {
4 if ( is_singular( 'aktsii' ) ) {
5 $custom_template = get_stylesheet_directory() . '/single-aktsii.php';
6 if ( file_exists( $custom_template ) ) {
7 return $custom_template;
8 }
9 }
10 return $template;
11}

O código verifica se a página atual pertence ao tipo de publicação personalizado aktsii. Se sim, procura o ficheiro single-aktsii.php na pasta do tema filho (get_stylesheet_directory()) e devolve-o. Se o ficheiro não for encontrado, devolve o $template predefinido inalterado.

4.2. Exemplo: vários CPTs com um único manipulador

Se tiver vários tipos de publicação personalizados, é conveniente consolidar a lógica num só filtro:

1add_filter( 'template_include', 'techblog_cpt_templates', 99 );
2
3function techblog_cpt_templates( $template ) {
4 $cpt_templates = array(
5 'aktsii' => 'single-aktsii.php',
6 'portfolio' => 'single-portfolio.php',
7 'testimonials' => 'single-testimonials.php',
8 );
9
10 foreach ( $cpt_templates as $cpt => $template_file ) {
11 if ( is_singular( $cpt ) ) {
12 $custom_template = get_stylesheet_directory() . '/' . $template_file;
13 if ( file_exists( $custom_template ) ) {
14 return $custom_template;
15 }
16 }
17 }
18
19 return $template;
20}

Agora cada CPT recebe o seu próprio modelo e toda a lógica reside numa única função.

4.3. Armazenar modelos num plugin

Se distribuir o tipo de publicação personalizado como um plugin (em vez de como parte de um tema), faz sentido armazenar o modelo na pasta do plugin. Nesse caso, especifique o caminho via plugin_dir_path( __FILE__ ):

1add_filter( 'template_include', 'myplugin_cpt_template', 99 );
2
3function myplugin_cpt_template( $template ) {
4 if ( is_singular( 'aktsii' ) ) {
5 $custom_template = plugin_dir_path( __FILE__ ) . 'templates/single-aktsii.php';
6 if ( file_exists( $custom_template ) ) {
7 return $custom_template;
8 }
9 }
10 return $template;
11}

Este padrão é usado por muitos plugins populares (WooCommerce, Easy Digital Downloads, The Events Calendar): eles incluem modelos internamente e carregam-nos via o filtro.

5. Criar o tipo de publicação personalizado

Temos o modelo pronto, mas para sermos completos, algumas palavras sobre de onde vem o próprio tipo de publicação personalizado.

5.1. Registo via código

Um registo mínimo de CPT no functions.php ou num MU-plugin:

1add_action( 'init', 'techblog_register_cpt_aktsii' );
2
3function techblog_register_cpt_aktsii() {
4 $labels = array(
5 'name' => 'Promotions',
6 'singular_name' => 'Promotion',
7 'menu_name' => 'Promotions',
8 );
9
10 $args = array(
11 'labels' => $labels,
12 'public' => true,
13 'has_archive' => true,
14 'supports' => array( 'title', 'editor', 'thumbnail' ),
15 'rewrite' => array( 'slug' => 'aktsii' ),
16 'show_in_rest' => true,
17 );
18
19 register_post_type( 'aktsii', $args );
20}

O detalhe chave aqui é que o parâmetro 'rewrite' => array( 'slug' => 'aktsii' ) define o slug usado tanto no URL como no nome do ficheiro de modelo. Se o slug for aktsii, o ficheiro de modelo deve chamar-se single-aktsii.php.

5.2. Usar o plugin Custom Post Type UI

Se preferir não editar o functions.php, pode criar um CPT visualmente usando o plugin gratuito Custom Post Type UI no WordPress.org. Após a instalação:

  • No painel de administração, vá a CPT UI → Add/Edit Post Types
  • Preencha os campos: Post Type Slug (caracteres latinos), Plural Label, Singular Label
  • No separador Settings, selecione as funcionalidades do editor de que precisa (título, editor, miniatura)
  • Clique em Add Post Type

O plugin gera o código PHP de registo, que pode exportar e colar no functions.php. Isto é conveniente se mais tarde quiser remover a dependência do plugin. O slug que especificou no CPT UI é o mesmo que vai para o nome do ficheiro de modelo.

⁉️🤔 Perguntas frequentes

O que devo fazer se o modelo não for selecionado após criar o ficheiro?

Reconstrua os permalinks: vá a Settings → Permalinks e clique em «Save Changes» (não precisa de alterar nada). O WordPress reconstruirá as suas regras de roteamento. Se isso não ajudar, verifique o nome do ficheiro: o slug do tipo de publicação personalizado e o nome do ficheiro devem corresponder (maiúsculas/minúsculas, hífens e underscores). Como terceiro passo, limpe a cache do seu plugin de cache, se tiver um instalado. Os permalinks devem ser reconstruídos após registar qualquer novo tipo de publicação personalizado, não apenas quando encontra problemas de modelo. Esta é uma prática padrão: vá a Settings → Permalinks → Save e os novos URLs começam a funcionar imediatamente.

Posso usar um modelo para vários tipos de publicação personalizados?

Sim, de duas formas. Primeiro, crie um ficheiro físico single-aktsii.php e, para o segundo tipo (digamos, portfolio), copie-o como single-portfolio.php. Segundo, use o filtro template_include (secção 4): no array $cpt_templates, aponte tipos diferentes para o mesmo ficheiro de modelo. Na prática, porém, CPTs diferentes quase sempre têm layouts diferentes; copiar e editar é mais simples do que construir lógica condicional dentro de um único modelo. Se tiver realmente muitos tipos com lógica idêntica, crie um single-cpt.php partilhado, verifique get_post_type() dentro dele e inclua a parte de modelo correspondente via get_template_part( 'template-parts/content', get_post_type() ). Esta é uma abordagem limpa e escalável.

Preciso de criar o archive-{post_type}.php** para a página de arquivo?**

É recomendado, mas não obrigatório. Sem ele, o WordPress usa o archive.php ou o index.php. Se o CPT tiver 'has_archive' => true e o arquivo abrir em /aktsii/, mas não existir um ficheiro archive-aktsii.php, será usado o archive.php genérico. Criar um modelo de arquivo separado faz sentido quando a grelha de publicações, o layout de colunas ou a barra lateral devem diferir do arquivo do blogue.

Isto funciona com temas de blocos (FSE)?

Em temas de blocos, os ficheiros de modelo PHP clássicos não são a abordagem principal. No entanto, o filtro template_include (secção 4) funciona também no FSE: pode colocar o single-aktsii.php num tema filho ou plugin e incluí-lo via o filtro. Alternativamente, no Editor de Site pode criar um modelo para um tipo de publicação personalizado específico através da interface: Appearance → Editor → Templates → Add New Template → Single Item: Aktsii. O WordPress irá guardá-lo como um modelo HTML na base de dados e funcionará sem quaisquer ficheiros no tema.

O que escolher em 2026: ficheiro ou filtro?

Uma matriz de decisão rápida para escolher a abordagem:

Cenário

O que usar

Tema clássico, um ou dois CPTs

Ficheiro single-{post_type}.php, código mínimo, seleção automática

Tema filho, está a adicionar o CPT

Ficheiro no tema filho, sobrevive a atualizações do tema pai

Tema de blocos (FSE), CPT via um plugin

Filtro template_include, independente da estrutura do tema

CPT distribuído como um plugin

Filtro + modelo dentro da pasta do plugin

Muitos CPTs com uma estrutura semelhante

Filtro + single-cpt.php partilhado + partes de modelo

Na prática, no techblog.sdstudio.top usamos mais frequentemente uma combinação: registamos o CPT via código num MU-plugin e colocamos os modelos como ficheiros num tema filho. Isto proporciona seleção automática sem filtros extra e as atualizações do tema pai não quebram nada.

Se está a começar a aprender sobre tipos de publicação personalizados, comece com o ficheiro single-{post_type}.php. Demora cinco minutos e produz resultados instantâneos. Quando sentir que a abordagem baseada em ficheiros já não é suficiente (precisa de carregar modelos de um plugin ou trocá-los dinamicamente), mude para o template_include. Ambos os métodos são totalmente legítimos e suportados pelo núcleo do WordPress.