webfluence hat 5 von 5 Sternen bei 11 Bewertungen auf Google My Business.

WordPress Custom Post Type

Erfahre, was Custom Post Types sind und welche Vorteile sie bieten. Inklusive Code-Beispiel zum erstellen eines Eigenen

Mit Custom Post Types (CPT) kannst du die verschiedensten Inhaltsformen und Funktionen deiner Website klar voneinander trennen und somit effizient verwalten.

In diesem Artikel lernst du, was ein CPT ist, und wie du einen Eigenen anlegst. Weiterführende Infos, mit denen du eine Metabox und eigene Templates für deinen Custom Post Type erstellen kannst, gibt’s obendrauf.

Robert Rosanke

Webentwickler

Vorab-Exkurs: Was ist ein Post Type?

Einige von WordPress mitgelieferte Post Types sind:

  • post (Beitrag)
  • page (Seite)
  • attachment (Uploads in die Mediathek)

Für jeden Post Type können individuelle Einstellungen hinzugefügt werden.

Für Beiträge sind beispielsweise eigene Templates und Archivseiten gängig, um die Ausgabe im Frontend zu steuern.

Doch auch die Bearbeitungsoberfläche im Backend kann beispielsweise durch Metaboxen individualisiert werden.

Und an dieser Stelle kommen Custom Post Types ins Spiel.

Was sind Custom Post Types?

Custom Post Types sind eigens erstellte Beitragstypen, mit denen eine WordPress Installation übersichtlich erweitert werden kann.

Du kannst zum Beispiel einen eigenen Post Type erstellen, die Bearbeitungsoberfläche um ein paar Metaboxen für zusätzliche Daten erweitern, ein eigenes Template bereitstellen und ihm einen individuellen Menüpunkt namens „Produkte“ geben.

Dadurch wird die Verwaltung der Websitesinhalte deutlich vereinfacht, weil die verschiedenen Themengebiete und Inhaltsformen im Backend visuell voneinander getrennt sind und einzelne Menüpunkte und angepasste Bearbeitungsoberflächen für die verschiedenen Inhalte der Seite erhalten.

Redakteure können sich dadurch super einfach zurechtfinden und die Inhalte effizient verwalten..

(Das oben beschrieben Beispiel könnte der erste Schritt für eine Produkt-Übersichtsseite, wie in einem Online Shop oder auf einer Affiliate-Seite, sein.)

Echte-Welt Beispiele für Custom Post Types:

  • Formulare beliebter Kontaktformular-Plugins
  • Produkte in diversen Affiliate Themes oder Shop-Erweiterungen
  • Terminverwaltung für Künstler
  • Portfolios für Dienstleister
  • Immobilien-Listings in diversen Plugins und Themes

Einsatzgebiete und Grenzen

Das alles klingt auf den ersten Blick super.

Ist es auch.

Doch wie so oft, gibt es auch bei Custom Post Types irgendwann Grenzen.

Die sehe ich persönlich bei dynamischen Anwendungen, die kein Caching ermöglichen, und Daten aus vielen individuellen Metafeldern ziehen.

Denn dann wird ein Seitenaufruf alleine schon zahlreiche Datenbankabfragen zur Folge haben.

(Das ist an sich eher weniger ein Problem.)

Doch ohne Caching und mit einer hohen Zahl an gleichzeitigen Websitesbesuchern wird viel Rechenleistung benötigt, um den Content weitehrin „on the fly“ zusammenzustellen und geringe Ladezeiten bereitzustellen.

Da viele Menschen und Unternehmen aber genau beim Hosting sparen, kann das zu viel für einen leistungsschwachen Server sein und ziemlich auf die Performance drücken.

Mögliche Lösungsansätze:

  • Fragment-Caching
  • Für alle Metadaten eines Beitrags nur einen Datenbankeintrag anlegen und die Daten in einem einem JSON-(ähnlichen)-Format in einer eigenen Tabelle (engl) speichern
    • Könnte bei starkem Gebrauch von Metafeldern die Datenbankabfragen beschleunigen.
    • Bin mir aber nicht sicher, wie stark die Auswirkung davon in der Praxis wirklich wäre…
  • Framework-Wahl überdenken – es gibt mehr als nur WordPress

Meine Meinung: Solange Caching möglich ist, ist alles in Butter. Für alles mit vielen Datenabfragen ohne Caching-Möglichkeit muss ein klarer Plan her, damit die Website auch mit steigendem Besucheraufkommen effizient funktionieren kann

Custom Post Type erstellen

Im folgenden ein Beispielcode zum registrieren eines Custom Post Types.

Ziel ist es Ferienwohnungen übersichtlich zu verwalten und jedem Objekt mit Metaboxen Eingabefelder für die Kerneigenschaften bereitzustellen.

Kerneigenschaften sind beispielsweise:

  • Quadratmeter
  • Preis
  • Anzahl der Zimmer

Schritt 1: Funktion vorbereiten

Erstelle zuerst eine neue Funktion, die deinen Custom Post Type beinhaltet.

Über die init() Hook wird die Funktion, und damit auch der Custom Post Type, später ins System integriert.

function wf_register_custom_post_type_apartment() {

}
add_action( 'init', 'wf_register_custom_post_type_apartment', 0 );

wf_register_custom_post_type_apartment ist der Name der Funktion. Du kannst diesen natürlich frei anpassen.

Nutze einen aussagekräftigen Namen und stelle einen Prefix voran, um die Wahrscheinlichkeit einer Kollision mit einem anderen Plugin oder Theme zu minimieren.

Schritt 2: Beschriftungen vorbereiten

Der Custom Post Type erhält einen eigenen Menüpunkt im Backend.

Dementsprechend müssen die Label dafür vorbereitet werden.

$labels = array(
  'name'           => _x( 'Apartments', 'Post Type General Name', 'wf-apartments' ),
  'singular_name'  => _x( 'Apartment', 'Post Type Singular Name', 'wf-apartments' ),
  'menu_name'      => __( 'Apartments', 'wf-apartments' ),
  'name_admin_bar' => __( 'Apartments', 'wf-apartments' ),
  'archives'       => __( 'Apartment archives', 'wf-apartments' ),
  'all_items'      => __( 'All apartments', 'wf-apartments' ),
  'add_new_item'   => __( 'Add new apartment', 'wf-apartments' ),
  'add_new'        => __( 'Add new', 'wf-apartments' ),
  'new_item'       => __( 'New apartment', 'wf-apartments' ),
  'edit_item'      => __( 'Edit apartment', 'wf-apartments' ),
  'update_item'    => __( 'Update apartment', 'wf-apartments' ),
  'view_item'      => __( 'View apartment', 'wf-apartments' ),
  'view_items'     => __( 'View apartments', 'wf-apartments' ),
  'search_items'   => __( 'Search apartments', 'wf-apartments' ),
);

Ich habe mich dazu entschieden, nur die notwendigsten Label anzupassen, um das Tutorial kurz und verständlich zu halten. Die WordPress Ressourcen bieten eine vollständige Liste aller Post Type Label (engl).

Tipp

Falls du dich wunderst, was __() und _x() machen: Diese Funktionen markieren übersetzungsfähigen Text. Mehr dazu im Tutorial WordPress übersetzen.

Schritt 3: Editor-Ansicht vorbereiten

Nun ist es an der Zeit festzulegen, welche Funktionen in der Bearbeitungsansicht einer Ferienwohnung zu sehen sein sollen.

Ich entscheide mich für

  • den Seitentitel
  • den Editor – Classic oder Gutenberg möglich, wird gleich noch festgelegt
  • das Beitragsbild
  • Revisionen
$supports = array(
  'title',
  'editor',
  // 'excerpt',
  // 'author',
  'thumbnail',
  //'trackbacks',
  // 'custom-fields',
  'revisions',
  // 'page-attributes',
  // 'post-formats'
  // 'comments'
);

Der Vollständigkeit halber habe ich mal alle Möglichkeiten aus der Liste aller supports-Optionen (engl) aufgezeigt.

Die nicht benötigten Optionen sind auskommentiert und werden nicht im Backend angezeigt. Du kannst diese Zeilen auch einfach entfernen, um den Code übersichtlicher zu halten.

Tipp

Damit die Beitragsbild-Metabox angezeigt wird, muss das Theme post-thumbnails unterstützen. Mehr dazu: add_theme_support()

Schritt 4: Permalinks konfigurieren

Die URL-Struktur soll am Ende wie folgt aussehen:

domain.de/apartments/haus-am-strand

$rewrite = array(
  'slug'                  => 'apartments',
  'with_front'            => true,
  'pages'                 => false,
  'feeds'                 => true,
);

Code-Erklärung:

  • slug ist der Teil der URL, der den erstellten Inhalte des Custom Post Types vorangestellt werden soll. Eignet sich gut, um eine Hierarchie in die Seite zu bringen.
  • with_front entscheidet darüber, ob die vom User in den Permalink-Einstellungen festgelegte „Linkstruktur“ beibehalten werden soll. Ist ein bisschen unglücklich ausgedrückt. Darum ein Beispiel.
    • Beispiel: Permalink-Einstellungen stehen auf Benutzerdefiniert: /blog/%postname%.
    • Mit with_front' => true wird der CPT unter /blog/{slug}/%postname% angezeigt.
    • Mit with_front' => false wird der CPT unter /{slug}/%postname% angezeigt.
  • pages kann die Paginierung für Archivseiten des CPTs erlauben oder verbieten.
  • feeds gibt an, ob ein RSS-Feed-Link für den CPT erstellt werden soll.

Gut zu wissen: Aktuell ist es scheinbar nicht möglich den Slug standardmäßig übersetzungsfähig zu machen.

Mehr dazu in einem interessanten Thread auf StackExchange.

Schritt 5: Funktion vorbereiten

So. Nun wird alles zusammengeführt und die letzten Einstellungen gesetzt.

$args = array(
  'label'           => __( 'Apartments', 'wf-apartments' ),
  'description'     => __( 'Manage your apartments', 'wf-apartments' ),
  'labels'          => $labels,
  'supports'        => array( 'title', 'editor' ),
  'show_in_rest'    => true,
  'taxonomies'      => array( 'category', 'post_tag' ),
  'hierarchical'    => false,
  'public'          => true,
  'show_in_menu'    => true,
  'menu_position'   => 5,
  'menu_icon'       => 'dashicons-admin-home',
  'has_archive'     => true,
  'capability_type' => 'page',
  'rewrite'         => $rewrite,
);

Code-Erklärung:

  • label: Legt den Text für den Menüpunkt fest und überschreibt $labels[name], sofern festgelegt.
  • description: Beschreibt den Sinn und Zweck des Custom Post Types. Keine Ahnung, wo das angezeigt wird…
  • labels: Liefert die bereits oben deklarierten Beschriftungen für die Verwaltungsoberfläche.
  • supports: Legt fest, welche Funktionen in der Bearbeitungsfläche verfügbar sein werden.
    • Der oben gezeigt Code zieht die Konfiguration aus der in Schritt 3 erstellten Variable $supports.
  • show_in_rest: Legt fest, ob der Gutenberg-Editor genutzt werden darf. (Kurz und knapp erklärt aus der Praxissicht.)
  • taxonomies: Legt fest, ob dem Inhalt Kategorien (category), Schlagwörter (post_tag) oder individuelle Taxonomien (die musst du erst erstellen) zugeordnet werden dürfen.
  • hierarchical: Legt fest, ob Elternelemente festgelegt werden dürfen.
  • public: Legt fest, ob die erstellten Inhalte für Autoren und Websitesbesucher sichtbar sein dürfen.
    • true bietet sich für alles an, was ganz normal auf der Seite sichtbar sein wird. Beispielsweise die Ferienwohnungen aus dem Beispiel.
    • false bietet sich an, wenn nur Daten eingepflegt werden und diese an anderer Stelle zusammen- und ausgeführt werden.
    • public setzt anhand des zugewiesenen Wertes „Standardregeln“ für show_in_nav_menus, show_ui, exclude_from_search und publicly_queryable. Du kannst die eben genannten Argumente auch explicit setzen und das Ganze somit granularer anpassen
  • show_in_menu: Legt fest, ob der Custom Post Type einen eigenen Menüpunkt im Backend erhalten soll.
  • menu_position: Legt die Position des Menüpunkts im Backend fest. Bedingung ist natürlich, dass show_in_menu nicht false ist.
    • 5: unter Beiträge
    • 10: unter Medien
    • 20: unter Seiten
    • 25: unter Kommentare (Standard, wenn kein expliziter Wert festgelegt ist)
    • 60: unter dem ersten Trenner – also quasi über Design
    • 65: unter Plugins
    • 70: unter Benutzer
    • 75: unter Werkzeuge
    • 80: unter Einstellungen
    • 100: unter dem zweiten Trenner – also quasi über Menü einklappen
  • menu_icon: Legt fest, welches Icon dem Menüpunkt vorangestellt sein soll. Unterstützt werden die Dashicons von WordPress und eigene SVGs als inline-string (base64-codiert).
  • has_archive: Legt fest, ob die erstellten Inhalte automatisch auf einer Archivseite – ähnlich den Beiträgen – gesammelt und ausgegeben werden sollen.
    • Bei Ferienwohnungen bietet sich eine Archivseite natürlich an, weil der User so direkt die neuesten Objekte sehen kann. Mit ein paar Anpassungen könnte die Archivseite um Filterfunktionen erweitert werden, um dem User noch nützlicher zu sein.
  • capability_type: Lege fest, welche Rolle/Rechte ein Nutzer haben muss, um die Inhalte des Custom Post Types bearbeiten zu können.
  • rewrite: Legt die Permalink-Regeln fest. Kann auch weggelassen werden.
    • Wenn du rewrite setzt, dann sollte dein Plugin die Permalinks mithilfe von flush_rewrite_rules() eigenständig aktualisieren. Einmal während der Aktivierung und einmal während der Deaktivierung des Plugins.
    • Wenn die Permalinks nicht automatisch aktualisiert werden, dann muss der WordPress-User die Permalinks nach dem aktivieren und deaktivieren des Plugins manuell aktualisieren. Absolut keine Empfehlung, weil User es vergessen und dich mit Support-Anfragen überfluten werden.

Schritt 5: Post Type final registrieren

Folgende Zeile Code registriert nun den Custom Post Type.

register_post_type( 'wf_cpt_apartments', $args );

Mit der Registrierung des Custom Post Types wird der eigene Eintrag in der Menüleiste sichtbar.

Dieses Bild zeigt den neu entstandenen Menüpunkt Apartments im WordPress Backend.

Zusammenfassung

Zum Abschluss der ganze Code an einem Stück

function wf_register_custom_post_type_apartment() {
  
  $labels = array(
    'name'           => _x( 'Apartments', 'Post Type General Name', 'wf-apartments' ),
    'singular_name'  => _x( 'Apartment', 'Post Type Singular Name', 'wf-apartments' ),
    'menu_name'      => __( 'Apartments', 'wf-apartments' ),
    'name_admin_bar' => __( 'Apartments', 'wf-apartments' ),
    'archives'       => __( 'Apartment archives', 'wf-apartments' ),
    'all_items'      => __( 'All apartments', 'wf-apartments' ),
    'add_new_item'   => __( 'Add new apartment', 'wf-apartments' ),
    'add_new'        => __( 'Add new', 'wf-apartments' ),
    'new_item'       => __( 'New apartment', 'wf-apartments' ),
    'edit_item'      => __( 'Edit apartment', 'wf-apartments' ),
    'update_item'    => __( 'Update apartment', 'wf-apartments' ),
    'view_item'      => __( 'View apartment', 'wf-apartments' ),
    'view_items'     => __( 'View apartments', 'wf-apartments' ),
    'search_items'   => __( 'Search apartments', 'wf-apartments' ),
  );
  
  $supports = array(
    'title',
    'editor',
    // 'excerpt',
    // 'author',
    'thumbnail',
    //'trackbacks',
    // 'custom-fields',
    'revisions',
    // 'page-attributes',
    // 'post-formats'
    // 'comments'
  );
  
  $rewrite = array(
    'slug'       => 'apartments',
    'with_front' => true,
    'pages'      => false,
    'feeds'      => true,
  );
  
  $args = array(
    'label'           => __( 'Apartment', 'wf-apartments' ),
    'description'     => __( 'Manage your apartments', 'wf-apartments' ),
    'labels'          => $labels,
    'supports'        => array( 'title', 'editor' ),
    'show_in_rest'    => true,
    'taxonomies'      => array( 'category', 'post_tag' ),
    'hierarchical'    => false,
    'public'          => true,
    'show_in_menu'    => true,
    'menu_position'   => 5,
    'menu_icon'       => 'dashicons-admin-home',
    'has_archive'     => true,
    'capability_type' => 'page',
    'rewrite'         => $rewrite,
  );
  
  register_post_type( 'wf_cpt_apartments', $args );
  
}
add_action( 'init', 'wf_register_custom_post_type_apartment', 0 );

Metabox für deinen Custom Post Type erstellen

Sobald der Custom Post Type registriert ist, geht es daran das Backend entsprechend zu erweitern.

Dazu eignen sich Metaboxen wunderbar.

Für eine Ferienwohnung könnten beispielsweise die Anzahl der Zimmer, die Wohnfläche in m² oder auch der Preis pro Nacht in Metaboxen festgehalten werden.

Zu Demonstrationszwecken erstelle ich ein einfaches Eingabefeld für den Titel des Hauses.

So kann der User seine interne Bezeichnung für das Haus von der für den Websitesbesucher sichtbaren Bezeichnung trennen.

Das macht zum Beispiel Sinn, wenn der User die Objekte intern mit Immobilien-IDs als Titel anlegen will und dem Websitesbesucher gleichzeitig eine attraktive h1-Überschrift angezeigt werden soll.

Schritt 1: Metabox „registrieren“ und mit CPT verknüpfen

Kurz vorab: Eine Metabox kann mehrere Eingabefelder haben. Für viele Einsatzzwecke reicht es also aus, eine zu registrieren.

function wf_add_apartment_metabox() {
  add_meta_box(
    'wf_apartment_metabox',
    _x( 'Apartment features', 'Backend: Title for Metabox panel' , 'wf-apartments' ),
    'wf_display_apartment_metabox',
    array( 'wf_cpt_apartments' ),
    'normal',
    'default'
	);
}

Code-Erklärung:

  • wf_apartment_metabox ist die ID der Metabox. Wert darf individuell bennant werden und sollte einmalig sein.
  • _x(...) gibt der Metabox einen Namen. Wird beispielsweise als Screenreader-Text für den einblenden/ausblenden Button des Panels genutzt.
  • wf_display_apartment_metabox ist die Callback-Funktion. In dieser ist das HTML-Gerüst der Metabox hinterlegt.
  • array( 'wf_cpt_apartments' ) gibt an, für welche Post Types die Metaboxen angezeigt werden sollen.
  • normal ist Anzeigeposition im Backend.
    • normal und advanced zeigen die Metabox unter dem Editor an – kein Unterschied im Gutenberg erkennbar.
    • side verlagert die Metabox in die Seitenleiste mit den Dokument-Einstellungen
  • default beschreibt die Priorität der Metabox. Hat beispielsweise eine Auswirkung auf die Reihenfolge, wenn mehrere Metaboxen die selbe Position in Anspruch nehmen wollen.
    • mögliche werte: default, low, high, core

Teile dem Custom Post Type anschließend noch mit, dass er eine eigene Metabox hat.

Erweitere dazu $args um folgende Zeile:

'register_meta_box_cb' => 'wf_add_apartment_metabox',

Code Erklärung

  • wf_add_apartment_metabox ist der Funktionsname, der deine Metabox hinzufügt.

Schritt 2: HTML-Gerüst der Metabox festlegen

Die bei der Registrierung der Metabox hinterlegte Callback-Funktion trägt das HTML-Gerüst.

Da es diese Funktion nicht gibt, musst du sie noch erstellen.

function wf_display_apartment_metabox( $post ) {
  wp_nonce_field( basename( __FILE__ ), 'wf_apartments_metabox_nonce' );

  $html = '<p><label>' . esc_html( 'Apartment title' , 'wf-apartments' ) . ' <input type="text" aria-describedby="title-description" name="wf_apartment_title" value="' . esc_attr( get_post_meta($post->ID, 'wf_apartment_title',true) )  . '" /></label></p>';
	$html .= '<p class="description" id="title-description">' . esc_html( 'This title will be shown to your website visitors.' , 'wf-apartments' ) . '</p>';

  echo $html;
}

Die Funktion besteht einfach aus dem nonce-Feld und deinem HTML.

Das nonce-Feld ist ein verstecktes Formularfeld, das zur Absicherung der Eingaben eingesetzt wird. Mehr dazu: wp_nonce_field()

Das HTML kann nun die Eingabefelder beinhalten, die du für deine Metabox benötigst.

Wichtig:

  • Gib allen Eingabefeldern ein name-Attribut mit einem einmaligen Wert, damit WordPress weiß unter welchem „Bezeichner“ der vom User eingegebene Inhalt in der Datenbank gespeichert werden soll.
  • Nutze den „Bezeichner“, um mithilfe von get_post_meta() den gespeicherten Wert aus der Datenbank auszulesen und als Inhalt im Eingabefeld anzuzeigen. (Sonst wird der vom User gesetzte Inhalt nicht im Backend angezeigt, wenn er den Beitrag erneut bearbeitet.)
    • Setze dafür beispielsweise ein value-Attribut bei Textfeldern und ordne diesem als Wert den aus der Datenbank ausgelesenen Inhalt zu.
    • Oder setze das checked-Attribut bei einer Checkbox, wenn der ausgelesene Wert 1 ist.

Schritt 3: Speichern der Daten erlauben

Da das HTML-Gerüst steht, kann es schon im Backend angezeigt werden.

Doch damit die Werte beim speichern des Beitrags an die Datenbank gesendet werden, ist noch eine letzte Funktion notwendig.

Kurze Erklärung, was die Funktion machen soll:

  • Allgemeiner Sicherheits-Check: Prüfen, ob das nonce-Feld den im HTML-Gerüst festgelegten Wert hat
  • Benutzerrechte-Check: Festlegen und sicherstellen, dass der User die entsprechenden Rechte hat, um die Merkmale der Ferienwohnung zu bearbeiten.
  • Frontend absichern: Verhindern, dass die automatische Zwischenspeicherung Inhalte in der Datenbank überschreibt und damit die Frontend-Ausgabe der Live-Version verändert.
  • Wenn alle Checks erfolgreich bestanden sind, dann werden die Daten an die Datenbank gesendet und gespeichert.

Erstelle dafür eine neue Funktion, die über die save_post()-Hook geladen wird.

function wf_save_apartments_post_meta( $post_id, $post ) {
  //...
  return $post_id;
}

add_action( 'save_post_wf_cpt_apartments', 'wf_save_apartments_post_meta', 10, 2 );

Tipp

Um Ressourcen zu sparen, kannst du save_post_[cpt_name]() anstatt der einfachen save_post()-Hook verwenden. Dann wird das Script nur beim festgelegten Custom Post Type ausgeführt.

Nun wird die Funktion mit Inhalt gefüllt

nonce-Feld prüfen

if ( !isset( $_POST['wf_apartments_metabox_nonce'] ) || !wp_verify_nonce( $_POST['wf_apartments_metabox_nonce'], basename( __FILE__ ) ) ) {
  return $post_id;
}

Benutzerrechte prüfen

Wenn der Nutzer keine Beiträge bearbeiten darf, dann wird auch nichts gespeichert.

$post_type = get_post_type_object( $post->post_type );
if ( !current_user_can( $post_type->cap->edit_post, $post_id ) ) {
  return $post_id;
}

Automatisches Datenüberschreiben verhindern

Wenn der Speichervorgang eine automatische Speicherung ist, dann werden die Metadaten nicht überschrieben, damit der User die volle Kontrolle darüber hat, wann er die Daten veröffentlicht.

if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) {
return $post_id;
}

Eingaben an die Datenbank senden

Wenn bis jetzt noch nicht abgebrochen wurde, und der richtige Post Type bearbeitet wird, dann kann gespeichert werden.

if ($post->post_type == 'wf_cpt_apartments') {
  update_post_meta($post_id, 'wf_apartment_title', sanitize_text_field( $_POST['wf_apartment_title'] ) );
}

Tipp

Wenn du mehr als nur ein Eingabefeld benötigst, dann kannst du einfach das HTML-Grundgerüst erweitern und weitere Zeilen mit update_post_meta() in die if-Bedingung des Snippets einfügen.

Zusammenfassung: Speicherfunktion auf einen Blick

function wf_save_apartments_post_meta( $post_id, $post ) {

  // security: check nonce field
  if ( !isset( $_POST['wf_apartments_metabox_nonce'] )	|| !wp_verify_nonce( $_POST['wf_apartments_metabox_nonce'], basename( __FILE__ ) ) ) {
    return $post_id;
  }

  // security: check user permissions
  $post_type = get_post_type_object( $post->post_type );
  if ( !current_user_can( $post_type->cap->edit_post, $post_id ) ) {
    return $post_id;
}

  // prevent updating post meta on autosave
  if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) {
    return $post_id;
}

  // update post meta
  if ($post->post_type == 'wf_cpt_apartments') {
    update_post_meta($post_id, 'wf_apartment_title', sanitize_text_field( $_POST['wf_apartment_title'] ) );
  }

  return $post_id;
}

add_action( 'save_post_wf_cpt_apartments', 'wf_save_apartments_post_meta', 10, 2 );

Eigene Templates für deinen CPT anlegen

WordPress durchsucht standardmäßig das aktive Theme nach Templates.

Das betrifft sowohl die Basis-Templates, wie beispielsweise archive.php und single.php aber auch individuelle Templates, die von Themes bereitgestellt werden.

Theme Autoren können zur Template-Erstellung einfach eine PHP-Datei mit (fast) beliebigen Namen im Theme-Ordner hinterlegen und diese mit einer einfachen Info als Template kenntlich machen.

Fast beliebiger Name, weil WordPress einige Dateinamen für gängige Templates (engl) nutzt/reserviert. Diese zu verwenden, könnte für Probleme sorgen.

<?php
/**
* Template Name: Apartment
* Template Post Type: wf_cpt_apartments
*/

Code-Erklärung

  • Template Name darf frei gewählt werden und ist automatisch – also auch ohne ohne __() – übersetzungsfähig.
  • Template Post Type ist optional und erlaubt es festzulegen, für welche Beitragsarten das Template genutzt werden darf.

Tipp

Template-Infos können einfach in einem Kommentar hinterlegt werden. Ähnlich einem Plugin Header.

So. Nun habe ich über Themes gesprochen. Plugins durchsucht WordPress standardmäßig nicht nach Template-Dateien.

Für den Fall, dass du deinen Custom Post Type in einem Plugin hältst, kannst du eine Funktion schreiben, die folgendes macht:

  1. Dateinamen für deine CPT Template-Dateien festlegen. Zum Beispiel wf-apartment-single.php und wf-apartment-archive.php.
  2. Prüfen, ob das aktive Theme die Dateien besitzt.
    1. Wenn ja, dann diese Template-Dateien zur Ausgabe verwenden.
    2. Wenn nein, dann die im Plugin mitgelieferten Dateien nutzen.

Mit diesem Ansatz erlaubst du den Usern deines Plugins die Ausgabe zu steuern, weil sie deine Template-Dateien aus dem Plugin kopieren, anpassen, in ihr Theme laden, und die Ausgabe einfach anpassen können.

Einen Beispielcode dafür gibt es auf Pixelbar: Templates in Plugins

Die Daten der Metaboxen kannst du dann mit get_post_meta() erhalten und ganz einfach im Template verwenden:

<php
$price_per_night = get_post_meta( $post_id, $meta_key, true);
// more meta data...
?>

Die Ausgabe könnte wie folgt aussehen:

<p class="wf_apartment_data__pricing">
  <span class="wf_apartment_data__label"><php _e( 'Price per night' , 'wf-apartments' ); ?></span>
  <span class="wf_apartment_data__value"><php esc_html_e( $price_per_night ); ?></span>
</p>

Diesen Artikel in sozialen Netzwerken teilen: