Skip to content

Alles für WordPress, Webentwicklung — und mehr

🔧 So erstellst du eine Vorlage für einen benutzerdefinierten Beitragstyp in WordPress

🔧 So erstellst du eine Vorlage für einen benutzerdefinierten Beitragstyp in WordPress

Sie haben einen benutzerdefinierten Beitragstyp zu Ihrer Website hinzugefügt, zum Beispiel „Promotions", „Portfolio" oder „Testimonials". Alles funktioniert: Beiträge werden erstellt, Meta-Felder werden befüllt. Doch wenn Sie einen dieser Beiträge im Frontend öffnen, sieht er aus wie ein gewöhnlicher Blogbeitrag. Gleiches Layout, gleiche Seitenleisten, keinerlei Unterschied. Dabei haben Sie den benutzerdefinierten Beitragstyp doch genau deshalb angelegt, damit die Inhalte anders dargestellt werden.

Das Problem ist, dass WordPress jeden benutzerdefinierten Beitrag standardmäßig über single.php rendert, die universelle Vorlage für alle Einzelbeiträge. Um ein eigenes Layout für einen bestimmten Typ zu erhalten, benötigen Sie eine eigene Template-Datei. Und das erweist sich als überraschend einfach.

Nachfolgend eine Schritt-für-Schritt-Anleitung: von der Template-Hierarchie bis zu zwei Erstellungsmethoden (über eine Theme-Datei und über den template_include-Filter), mit funktionierenden Codebeispielen.

💡 Kurzüberblick:

  • Verstehen, wie WordPress nach einer Vorlage für einen benutzerdefinierten Beitragstyp sucht und welche Priorität single-{post_type}.php hat
  • Kopieren der single.php Ihres Themes, Umbenennen für Ihren CPT und Anpassen
  • Erkunden einer alternativen Methode über den template_include-Filter (praktisch, wenn Sie das Theme nicht anfassen möchten)
  • Erstellen des benutzerdefinierten Beitragstyps selbst mit dem Plugin Custom Post Type UI, schnell und ohne Code

1. Wie WordPress eine Vorlage für einen benutzerdefinierten Beitragstyp auswählt

Die WordPress-Template-Hierarchie ist eine Kette von Dateien, die der Core durchläuft, um die richtige Vorlage für die Darstellung einer Seite zu finden. Für Standardbeiträge ist die Kette lang: single-post.phpsingle.phpsingular.phpindex.php. Für benutzerdefinierte Beitragstypen ist sie kürzer, aber die Logik ist dieselbe.

Wenn ein Besucher einen benutzerdefinierten Beitrag vom Typ aktsii öffnet, prüft WordPress die Dateien in dieser Reihenfolge:

  • single-aktsii.php, die Vorlage speziell für diesen benutzerdefinierten Beitragstyp
  • single.php, die allgemeine Einzelbeitragsvorlage
  • singular.php, die Vorlage für jeglichen singulären Inhalt (Beitrag, Seite, CPT)
  • index.php, die letzte Rückfallebene

Die erste in der Kette gefundene Datei wird für die Darstellung verwendet. Wenn single-aktsii.php existiert, greift WordPress darauf zu und hört auf. Wird sie nicht gefunden, geht der Core zu single.php über. Genau deshalb sieht Ihr benutzerdefinierter Beitragstyp wie ein normaler Beitrag aus: Es gibt keine single-aktsii.php-Datei, also greift der Core auf die allgemeine single.php zurück.

Die Lösung ergibt sich direkt daraus: Erstellen Sie single-{post_type}.php, und WordPress greift automatisch darauf zu.

2. Erstellen einer Template-Datei: single.php kopieren und umbenennen

Dies ist der einfachste und zuverlässigste Ansatz. Er funktioniert mit jedem klassischen Theme und erfordert keine Plugins oder Filter.

Schritt 1: Finden Sie die single.php Ihres Themes. Sie befindet sich im Wurzelverzeichnis des Theme-Ordners: /wp-content/themes/your-theme/single.php. Wenn das Theme FSE (Full Site Editing) nutzt und auf Blöcken aufbaut, existiert diese Datei möglicherweise nicht, und die Filter-Methode (template_include) ist bequemer (Abschnitt 4).

Schritt 2: Kopieren und umbenennen. Kopieren Sie single.php und benennen Sie sie nach dem Muster single-{slug}.php: Ersetzen Sie {slug} durch den Slug Ihres benutzerdefinierten Beitragstyps (der bei der Registrierung angegebene, in lateinischen Zeichen). Zum Beispiel für einen Typ mit dem Slug aktsii:

1single-aktsii.php

Für einen Typ mit dem Slug portfolio würde die Datei single-portfolio.php heißen. Für testimonials wird daraus single-testimonials.php. Wichtig: Der Slug muss mit dem übereinstimmen, der im Parameter 'rewrite' => array('slug' => '...') bei der Registrierung angegeben wurde.

Schritt 3: Legen Sie die Datei zurück in den Theme-Ordner. WordPress wird sie automatisch für alle Beiträge dieses Typs verwenden. Es ist keine weitere Konfiguration nötig; die Template-Hierarchie erledigt das automatisch.

Schritt 4: Überprüfen. Öffnen Sie einen beliebigen Beitrag des benutzerdefinierten Typs im Frontend. Wenn Sie dieselbe Seite wie zuvor sehen, überprüfen Sie den Dateinamen (Groß-/Kleinschreibung, Bindestriche statt Unterstriche) und leeren Sie den Cache. Wenn die Datei in einem Child-Theme erstellt wurde und das Parent-Theme ebenfalls single-{post_type}.php enthält, hat das Child-Theme Vorrang.

3. Anpassen des Template-Inhalts

Die kopierte single.php ist noch identisch mit dem Original; sie rendert einfach dasselbe allgemeine Layout. Nun befüllen wir sie mit Inhalten, die spezifisch für den benutzerdefinierten Beitragstyp sind.

3.1. Grundstruktur: Ausgabe benutzerdefinierter Felder

Angenommen, der benutzerdefinierte Beitragstyp aktsii hat die Felder aktsiya_data_start, aktsiya_data_end und aktsiya_skidka (erstellt über ACF, Meta Box oder manuell). Hier ist eine minimale Vorlage, die diese ausgibt:

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();

Dies ist eine voll funktionsfähige Vorlage, die Sie unverändert in Ihr Theme übernehmen können. Sie gibt den Titel, das Beitragsbild, den Inhalt und drei benutzerdefinierte Felder in einem separaten Block aus.

3.2. Was Sie mit der Vorlage sonst noch tun können

Von hier aus sind die Möglichkeiten zur Anpassung praktisch unbegrenzt:

  • Seitenleiste entfernen: Entfernen Sie einfach den Aufruf get_sidebar().
  • HTML-Wrapper ändern: Ersetzen Sie <article> durch ein <div> mit der von Ihnen benötigten Klasse, fügen Sie Ihr eigenes Grid hinzu.
  • Einen bestimmten Template-Teil aufrufen: zum Beispiel get_template_part( 'template-parts/content', 'aktsii' ) und die Logik in einer separaten Datei halten.
  • Eigene Styles einbinden: über wp_enqueue_style() innerhalb von functions.php mit einer is_singular( 'aktsii' )-Prüfung.

Ein wichtiger Hinweis: Wenn das Theme aktualisiert wird, kann eine Datei im Parent-Theme überschrieben werden. Arbeiten Sie daher entweder in einem Child-Theme oder nutzen Sie die Filter-Methode aus dem nächsten Abschnitt.

4. Alternativer Ansatz: der template_include-Filter

Wenn Sie Theme-Dateien lieber nicht verändern möchten (oder das Theme blockbasiert ist und keine klassische single.php besitzt), können Sie eine Vorlage über den template_include-Hook zuweisen. Er wird ausgelöst, bevor WordPress die Template-Datei einbindet, und ermöglicht es Ihnen, den Pfad zu überschreiben.

Nachteil: Sie müssen die Template-Datei entweder in einem Plugin oder in einem Child-Theme ablegen, und der Code muss auf den korrekten Pfad verweisen. Vorteil: Die Logik geht bei einem Update des Parent-Themes nicht verloren.

4.1. Beispiel: ein CPT, eine Vorlage

Fügen Sie dies der functions.php des Child-Themes (oder einem MU-Plugin) hinzu:

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}

Der Code prüft, ob die aktuelle Seite zum benutzerdefinierten Beitragstyp aktsii gehört. Wenn ja, sucht er im Child-Theme-Ordner (get_stylesheet_directory()) nach der Datei single-aktsii.php und gibt sie zurück. Wird die Datei nicht gefunden, gibt er das standardmäßige $template unverändert zurück.

4.2. Beispiel: mehrere CPTs mit einem einzigen Handler

Wenn Sie mehrere benutzerdefinierte Beitragstypen haben, ist es praktisch, die Logik in einem Filter zu bündeln:

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}

Nun erhält jeder CPT seine eigene Vorlage, und die gesamte Logik befindet sich in einer einzigen Funktion.

4.3. Vorlagen in einem Plugin ablegen

Wenn Sie den benutzerdefinierten Beitragstyp als Plugin bereitstellen (und nicht als Teil eines Themes), ist es sinnvoll, die Vorlage im Plugin-Ordner abzulegen. Geben Sie in diesem Fall den Pfad über plugin_dir_path( __FILE__ ) an:

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}

Dieses Muster wird von vielen bekannten Plugins verwendet (WooCommerce, Easy Digital Downloads, The Events Calendar): Sie liefern Vorlagen intern mit und binden sie über den Filter ein.

5. Erstellen des benutzerdefinierten Beitragstyps

Die Vorlage ist fertig, aber der Vollständigkeit halber ein paar Worte dazu, woher der benutzerdefinierte Beitragstyp selbst stammt.

5.1. Registrierung per Code

Eine minimale CPT-Registrierung in functions.php oder einem 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}

Das entscheidende Detail hier ist, dass der Parameter 'rewrite' => array( 'slug' => 'aktsii' ) den Slug festlegt, der sowohl in der URL als auch im Dateinamen der Vorlage verwendet wird. Wenn der Slug aktsii lautet, muss die Template-Datei single-aktsii.php heißen.

5.2. Verwendung des Plugins Custom Post Type UI

Wenn Sie die functions.php lieber nicht bearbeiten möchten, können Sie einen CPT visuell mit dem kostenlosen Custom Post Type UI Plugin auf WordPress.org erstellen. Nach der Installation:

  • Gehen Sie im Admin-Panel zu CPT UI → Add/Edit Post Types
  • Füllen Sie die Felder aus: Post Type Slug (lateinische Zeichen), Plural Label, Singular Label
  • Wählen Sie auf der Registerkarte Settings aus, welche Editor-Funktionen Sie benötigen (Titel, Editor, Beitragsbild)
  • Klicken Sie auf Add Post Type

Das Plugin generiert den PHP-Registrierungscode, den Sie exportieren und in die functions.php einfügen können. Das ist praktisch, wenn Sie später die Plugin-Abhängigkeit entfernen möchten. Der Slug, den Sie in CPT UI angegeben haben, ist derselbe, der in den Dateinamen der Vorlage einfließt.

⁉️🤔 Häufig gestellte Fragen

Was soll ich tun, wenn die Vorlage nach dem Erstellen der Datei nicht übernommen wird?

Leeren Sie die Permalinks: Gehen Sie zu Einstellungen → Permalinks und klicken Sie auf „Änderungen speichern" (Sie müssen nichts ändern). WordPress wird seine Routing-Regeln neu aufbauen. Wenn das nicht hilft, überprüfen Sie den Dateinamen: Der Slug des benutzerdefinierten Beitragstyps und der Dateiname müssen übereinstimmen (Groß-/Kleinschreibung, Bindestriche und Unterstriche). Leeren Sie als dritten Schritt den Cache Ihres Caching-Plugins, falls eines installiert ist. Permalinks sollten nach der Registrierung jedes neuen benutzerdefinierten Beitragstyps geleert werden, nicht nur, wenn Sie auf Vorlagenprobleme stoßen. Dies ist gängige Praxis: Gehen Sie zu Einstellungen → Permalinks → Speichern, und die neuen URLs funktionieren sofort.

Kann ich eine Vorlage für mehrere benutzerdefinierte Beitragstypen verwenden?

Ja, auf zwei Arten. Erstens: Erstellen Sie eine physische Datei single-aktsii.php, und für den zweiten Typ (z. B. portfolio) kopieren Sie diese als single-portfolio.php. Zweitens: Nutzen Sie den template_include-Filter (Abschnitt 4): Verweisen Sie im Array $cpt_templates verschiedene Typen auf dieselbe Template-Datei. In der Praxis haben verschiedene CPTs jedoch fast immer unterschiedliche Layouts; Kopieren und Bearbeiten ist einfacher, als bedingte Logik innerhalb einer einzigen Vorlage aufzubauen. Wenn Sie wirklich viele Typen mit identischer Logik haben, erstellen Sie eine gemeinsame single-cpt.php, prüfen Sie darin get_post_type() und binden Sie den entsprechenden Template-Teil über get_template_part( 'template-parts/content', get_post_type() ) ein. Das ist ein sauberer und skalierbarer Ansatz.

Muss ich archive-{post_type}.php** für die Archivseite erstellen?**

Es wird empfohlen, ist aber nicht zwingend erforderlich. Ohne sie verwendet WordPress archive.php oder index.php. Wenn der CPT 'has_archive' => true hat und das Archiv unter /aktsii/ geöffnet wird, aber keine archive-aktsii.php-Datei existiert, wird die allgemeine archive.php verwendet. Eine separate Archivvorlage zu erstellen ist sinnvoll, wenn sich das Beitragsraster, das Spaltenlayout oder die Seitenleiste vom Blog-Archiv unterscheiden sollen.

Funktioniert das mit Block-Themes (FSE)?

In Block-Themes sind klassische PHP-Template-Dateien nicht der primäre Ansatz. Der template_include-Filter (Abschnitt 4) funktioniert jedoch auch in FSE: Sie können single-aktsii.php in einem Child-Theme oder Plugin ablegen und über den Filter einbinden. Alternativ können Sie im Site-Editor eine Vorlage für einen bestimmten benutzerdefinierten Beitragstyp über die Oberfläche erstellen: Design → Editor → Vorlagen → Neue Vorlage hinzufügen → Einzeleintrag: Aktsii. WordPress speichert sie als HTML-Vorlage in der Datenbank, und sie funktioniert ohne jegliche Dateien im Theme.

Was wählt man 2026: Datei oder Filter?

Eine kurze Entscheidungsmatrix für die Wahl des Ansatzes:

Szenario

Was verwenden

Klassisches Theme, ein oder zwei CPTs

single-{post_type}.php-Datei, minimaler Code, automatische Übernahme

Child-Theme, Sie fügen den CPT hinzu

Datei im Child-Theme, übersteht Parent-Theme-Updates

Block-Theme (FSE), CPT über ein Plugin

template_include-Filter, unabhängig von der Theme-Struktur

CPT wird als Plugin bereitgestellt

Filter + Vorlage im Plugin-Ordner

Viele CPTs mit ähnlicher Struktur

Filter + gemeinsame single-cpt.php + Template-Teile

In der Praxis verwenden wir bei techblog.sdstudio.top meist eine Kombination: Registrieren des CPT per Code in einem MU-Plugin und Ablegen der Vorlagen als Dateien in einem Child-Theme. Das ermöglicht die automatische Übernahme ohne zusätzliche Filter, und Parent-Theme-Updates zerstören nichts.

Wenn Sie gerade erst anfangen, sich mit benutzerdefinierten Beitragstypen zu beschäftigen, beginnen Sie mit der single-{post_type}.php-Datei. Es dauert fünf Minuten und liefert sofortige Ergebnisse. Wenn Sie feststellen, dass der dateibasierte Ansatz nicht mehr ausreicht (Sie müssen Vorlagen aus einem Plugin laden oder spontan austauschen), wechseln Sie zu template_include. Beide Methoden sind vollkommen legitim und werden vom WordPress-Core unterstützt.