
🔧 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}.phphat - Kopieren der
single.phpIhres 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.php → single.php → singular.php → index.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 Beitragstypsingle.php, die allgemeine Einzelbeitragsvorlagesingular.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:
1 single-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 6 get_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 60 get_sidebar(); 61 get_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 vonfunctions.phpmit eineris_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:
1 add_filter( 'template_include', 'techblog_cpt_template', 99 ); 2 3 function 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:
1 add_filter( 'template_include', 'techblog_cpt_templates', 99 ); 2 3 function 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:
1 add_filter( 'template_include', 'myplugin_cpt_template', 99 ); 2 3 function 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:
1 add_action( 'init', 'techblog_register_cpt_aktsii' ); 2 3 function 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 alssingle-portfolio.php. Zweitens: Nutzen Sie dentemplate_include-Filter (Abschnitt 4): Verweisen Sie im Array$cpt_templatesverschiedene 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 gemeinsamesingle-cpt.php, prüfen Sie daringet_post_type()und binden Sie den entsprechenden Template-Teil überget_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.phpoderindex.php. Wenn der CPT'has_archive' => truehat und das Archiv unter/aktsii/geöffnet wird, aber keinearchive-aktsii.php-Datei existiert, wird die allgemeinearchive.phpverwendet. 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önnensingle-aktsii.phpin 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 |
|
Child-Theme, Sie fügen den CPT hinzu | Datei im Child-Theme, übersteht Parent-Theme-Updates |
Block-Theme (FSE), CPT über ein Plugin |
|
CPT wird als Plugin bereitgestellt | Filter + Vorlage im Plugin-Ordner |
Viele CPTs mit ähnlicher Struktur | Filter + gemeinsame |
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.



