1. Magazin
  2. /
  3. Programmierung
  4. /
  5. WordPress Custom Post Type – Einen eigenen Post Type in WordPress anlegen

WordPress Custom Post Type – Einen eigenen Post Type in WordPress anlegen

Wordpress Custom Post Type

WordPress Custom Post Type – Einen eigenen Post Type in WordPress anlegen

Was ist ein Post Type und welche Möglichkeiten bietet er mir?

Von WordPress hat mittlerweile jeder schon mal gehört und die meisten wissen auch, dass WordPress als Blog System verwendet wird. Ein einfaches Blog System ist WordPress aber schon lange nicht mehr. Seit der Software Version 1.5 („Strayhorn“) kann WordPress zu mehr verwendet werden, als lediglich dazu, Blogeinträge anzulegen, es ist nun ein CMS (Content Management System). Durch eine strikte Datenbanknormalisierung (Wikipedia – Normalisierung (Datenbank)) wurde dafür gesorgt, dass WordPress über sogenannte Post Types beliebig erweitert werden kann. Was ein Post Type ist und wie Du Deinen eigenen Custom Post Type anlegen kannst, dass erfährst Du in diesem Artikel.
Was sind nun diese Post Types? Post Types sind im Grunde die Spezifizierung von den Inhalten Deiner WordPress Seite. Alle „Inhalte“ werden in der Datenbanktabelle „wp_posts“ gespeichert. Inhalte sind beispielsweise:

  • Seiten (Post Type = „page“)
  • Blogeinträge (Post Type = „post“)
  • Medien wie: Bilder, Videos, etc. (Post Type = „attachment“)

Damit man diese Inhalte nun auseinanderhalten kann, gibt es in dieser Tabelle die Spalte „post_type“, die Aufschluss darüber gibt, was in dem jeweiligen Datensatz hinterlegt ist.
Dadurch kannst Du als Entwickler Deine eigenen Content-Typen / Post Types in WordPress hinterlegen.
Beispiele für eigene Post Types:

  • Produkte
  • Leistungen
  • Referenzen
  • Profile
  • Gegenstände / Objekte (Sofas, Tische, Häuser, Hardware)
  • etc.

Wie Du sehen kannst, sind Post Types sehr flexibel einsetzbar. Darin liegt ihre Stärke. Zudem lassen sie sich über die Tabelle „wp_post_meta“ um zusätzliche Felder erweitern, da die Tabelle „wp_posts“ lediglich über folgende Felder verfügt:
ID, post_author, post_name, post_type, post_title, post_date, post_date_gmt, post_content, post_excerpt, post_status, comment_status, ping_status, post_password, post_parent, post_modified, post_modified_gmt, comment_count, menu_order

Die Tabelle „wp_post_meta“ ist Key – Value basiert aufgebaut und direkt mit einem Post verknüpft. So kann ein Produkt bspw. folgende Post Meta Felder besitzen:

  • product_price
  • product_inventory_count
  • product_default_delivery_period
  • etc.

Leider sind den Verwendungszwecken von Post Types und ihren Meta Feldern auch Grenzen gesetzt. Welche das sind, schauen wir uns im nächsten Absatz an.

Grenzen von Post Types

Durch Post Types können wir unser WordPress Theme oder unser WordPress Plugin leicht individualisieren, wie das geht erfährst Du übrigens im nächsten Schritt, aber Post Types treffen auch irgendwann auf ihre Grenzen. Eine dieser Grenzen ist die Geschwindigkeit. Durch die strikte Normalisierung der Post und Post Meta Tabellen müssen teilweise pro Seitenaufruf im Schnitt 20 Datenbankabfragen getätigt werden. Im ungünstigsten Fall bei hunderten Website Besuchern gleichzeitig.

Gerade die Erweiterung von Post Types über Post Meta Felder ist nicht besonders schön gelöst. Jedes Post Meta Feld ist ein eigener Datensatz, was schnell dazu führen kann, dass je nach Post Type, diese Tabelle enorm wächst und Redundanzen in den Datensätzen entstehen. Ein weiterer Nachteil ist, dass die Post Meta Werte nicht im Type spezifizierbar sind. Jeder Post Meta Wert ist vom Typ „longtext“, damit Entwickler jeden Wert in die Tabelle speichern können. Dies führt wiederum dazu, dass keine Constraints für die Post Meta Werte eingerichtet werden können.

Willst Du bspw. große Datenmengen wie Statistiken und Reports mit tausenden Datensätzen in Deiner Datenbank hintelegen und diese Datensätze dann einzelnen Monaten und Nutzern zuordnet, so lässt sich dies ebenfalls nicht mit Post Types abbilden. In diesem Fall lohnt es sich bereits eigene Tabellen anzulegen (WordPress – Creating Tables with Plugins), oder WordPress gegen ein anderes PHP Framework zu tauschen.

Weiterhin ist es möglich, komplexe „wp_query“ Ergebnisse in WordPress Transients zu speichern, was leider wieder Datenbank Abfragen zur Folge hat. Ein alternative dazu ist die PHP Funktion Memcache (PHP – memcache). Mit Hilfe dieser lassen sich die „wp_query“ Ergebnisse im Zwischenspeicher ablegen.

In 4 Schritten zum eigenen Post Type

Eigene Post Types können in WordPress an vielen Stellen benötigt werden. Sie lassen sich im eigenen Theme, im Child Theme oder im eigenen Plugin integrieren. Dabei gibt es keinen Unterschied darin, wie sie integriert werden. Solltest Du Dich für die Erstellung Deines eigenen Child Themes interessieren, so kann ich Dir unseren Artikel „Wie Du in 4 Schritten Dein eigenes WordPress Child Theme erstellst“ empfehlen.

Ich helfe Dir nun dabei in nur 4 Schritten Deinen eigenen Post Type zu registrien und gebe Dir im nächsten Kapitel noch Tipps mit auf den Weg, wie Du eigene Post Meta Boxen im WordPress Backend erstellst.

Schritt 1)

Im ersten Schritt legst Du den Ordner „post_types“ in deinem Plugin oder Theme an. Danach erstellst Du in diesem Ordner eine PHP Datei mit dem Namen Deines Post Types, bspw. „product.php“. Diese Datei kannst Du nun in deinem Plugin oder Theme mit der PHP Funktion „require_once“ einbinden.

require_once( 'post_types/product.php' );

Schritt 2)

In diesem Schritt wirst Du deinen eigenen Post Type mit der WordPress Funktion „register_post_type“ registrieren. Dies funktioniert aber nur während der Aktion „init“. Wird „register_post_type“ vorher aufgerufen, wird die Registrierung fehlschlagen.
Registriere nun zuerst eine Funktion auf die „init“ Aktion in Deiner Post Type PHP Datei:

<?php
/**
* Registriert den Post Type „product“
*/
function register_product_post_type() {
    // Hier wird der Post Type registriert
}
add_action( 'init', 'register_product_post_type' );

Tipp: Versuche für Deinen Post Type einen individuellen Namen zu finden, da simple Namen für Post Types schnell von anderen Plugins oder Themes verwendet werden können. Du kannst bspw. den Namen Deines Themes oder Plugins dem Post Type voranstellen: „example_plugin_product“
Dadurch vermeidest Du von vornherein Dopplungen von Post Types und minimierst die Fehleranfälligkeit Deines Codes.

Kommen wir nun zur Registrierung. „register_post_type“ nimmt zwei Parameter entgegen. Als ersten Parameter erwartet die Funktion den Namen des Post Types und als zweiten Parameter ein Array mit Argumenten. Du kannst nun folgende Vorlage zur Vorbereitung der Registrierung innerhalb der zuvor implementierten Funktion integrieren:

Teil 1 – Die Texte vorbereiten:

   $labels = array(
        'name'                  => __( 'Produkte', TRANSLATION_CONST ),
        'singular_name'         => __( 'Produkt', TRANSLATION_CONST ),
        'add_new'               => __( 'Hinzufügen', TRANSLATION_CONST ),
        'add_new_item'          => __( 'Produkt hinzufügen', TRANSLATION_CONST ),
        'edit_item'             => __( 'Produkt bearbeiten', TRANSLATION_CONST ),
        'new_item'              => __( 'Produkt hinzufügen', TRANSLATION_CONST ),
        'view_item'             => __( 'Produkt anzeigen', TRANSLATION_CONST ),
        'view_items'            => __( 'Produkte anzeigen', TRANSLATION_CONST ),
        'search_items'          => __( 'Produkt suchen', TRANSLATION_CONST ),
        'not_found'             => __( 'Keine Produkte gefunden', TRANSLATION_CONST ),
        'not_found_in_trash'    => __( 'Keine Produkte im Papierkorb gefunden', TRANSLATION_CONST ),
        'parent_item_colon'     => __( 'Übergeordnete Produkte:', TRANSLATION_CONST ),
        'all_items'             => __( 'Alle Produkte:', TRANSLATION_CONST ),
        'archives'              => __( 'Produkt Archiv:', TRANSLATION_CONST ),
        'attributes'            => __( 'Produkt Attribute:', TRANSLATION_CONST ),
        'insert_into_item'      => __( 'Zum Produkt hinzufügen', TRANSLATION_CONST ),
        'uploaded_to_this_item' => __( 'Zum Produkt hinzugefügt', TRANSLATION_CONST ),
        'featured_image'        => __( 'Produktbild', TRANSLATION_CONST ),
        'set_featured_image'    => __( 'Produktbild setzen:', TRANSLATION_CONST ),
        'remove_featured_image' => __( 'Produktbild entfernen:', TRANSLATION_CONST ),
        'use_featured_image'    => __( 'Als Produktbild verwenden:', TRANSLATION_CONST ),
        'menu_name'             => __( 'Produkte', TRANSLATION_CONST ),
    );

In diesem Array sind nun alle wichtigen Texte für Deinen Post Type hinterlegt. Weitere Informationen dazu findest Du unter WordPress – register post type. In diesem Beispiel und in einigen folgenden Beispielen wird auch die PHP Konstante „TRANSLATION_CONST“ verwendet, die die gewünschte Text Domain (WordPress – I18n) enthält.

Teil 2 – Funktionen und Felder:

Kommen wir nun zu den Funktionen, die Dein Post Type unterstützen soll:

    $supports = array(
        'title',
        'editor', // Content Bereich
        'excerpt', // Kurzer Auszug des Contents für Archivseiten
        'author',
        'thumbnail', // featured_image / Produktbild
        //'trackbacks',
        'custom-fields',
        //'revisions',
        'page-attributes',
        'comments'
    );

Hiermit kannst Du einzelne Funktionen und Post Felder, die Dir WordPress bereitstellt aktivieren und deaktivieren. In dem Beispiel sind „trackbacks“ und „revisions“ auskommentiert, da wir sie für das Produkt nicht benötigen. Solltest Du bspw. „thumbnail“ auskommentieren, so besitzt das Produkt keine Möglichkeit ein Produktbild zu hinterlegen.

Teil 3 – Argumente zusammenstellen:

Zu guter Letzt stellen wir noch die Argumente zusammen:

    $args = array(
        'labels' => $labels,
        'hierarchical' => false,
        'description' => __( 'Produkte für mein eigenes E-Commerce Plugin', TRANSLATION_CONST ),
        'supports' => $supports,
        'public' => true,
        'show_ui' => true,
        'show_in_menu' => true,
        'menu_position' => 5, // Unterhalb der Posts
        'menu_icon' => 'dashicons-card',
        'show_in_nav_menus' => true,
        'publicly_queryable' => true,
        'exclude_from_search' => false,
        'has_archive' => true,
        'query_var' => true,
        'can_export' => true,
        'capability_type' => 'post'
    );

Die Argumente sind sehr umfangreich. Eine vollständige Liste der Funktionsdefinitionen von WordPress findest Du unter WordPress – register post type, deshalb beschreibe ich folgend nur einige der Argumente. In dieses Array von Argumenten fügen wir unter „label“ und unter „supports“ unsere zuvor definierten Arrays ein. Unter dem Punkt „hierarchical“ kannst Du festlegen, ob das Produkt auch ein übergeordnetes Produkt hat. Diese Funktion lässt sich aber nur nutzen, wenn unter „supports“ auch der Punkt „page-attributes“ aktiviert wurde.

Das Argument „capability_type“ kann in Kombination mit dem Argument „capabilities“ dazu verwendet werden, die Rechteverwaltung der Nutzer genauer zu spezifizieren. In unserm Beispiel werden die selben Rechte wie für den Post Type „post“ verwendet. Eine Auflistung der Rollen und der Zuordnung zu den Capabilities findest Du unter WordPress – Roles and Capabilities.
Über das Argument „menu_icon“ kannst Du ein Menü Icon für das WordPress Backend festlegen. Eine Übersicht aller verfügbaren Icons findest Du unter WordPress – Dashicons.

Teil 4 – Post Type registrieren:

Nun musst Du mit Hilfe der Argumente nur noch die passende WordPress Funktion „register_post_type“ aufrufen:

<?php
/**
* Registriert den Post Type „product“
*/
function register_product_post_type() {
     $labels = array(
        'name'                  => __( 'Produkte', TRANSLATION_CONST ),
        'singular_name'         => __( 'Produkt', TRANSLATION_CONST ),
        'add_new'               => __( 'Hinzufügen', TRANSLATION_CONST ),
        'add_new_item'          => __( 'Produkt hinzufügen', TRANSLATION_CONST ),
        'edit_item'             => __( 'Produkt bearbeiten', TRANSLATION_CONST ),
        'new_item'              => __( 'Produkt hinzufügen', TRANSLATION_CONST ),
        'view_item'             => __( 'Produkt anzeigen', TRANSLATION_CONST ),
        'view_items'             => __( 'Produkte anzeigen', TRANSLATION_CONST ),
        'search_items'          => __( 'Produkt suchen', TRANSLATION_CONST ),
        'not_found'             => __( 'Keine Produkte gefunden', TRANSLATION_CONST ),
        'not_found_in_trash'    => __( 'Keine Produkte im Papierkorb gefunden', TRANSLATION_CONST ),
        'parent_item_colon'     => __( 'Übergeordnete Produkte:', TRANSLATION_CONST ),
        'all_items'             => __( 'Alle Produkte:', TRANSLATION_CONST ),
        'archives'              => __( 'Produkt Archiv:', TRANSLATION_CONST ),
        'attributes'            => __( 'Produkt Attribute:', TRANSLATION_CONST ),
        'insert_into_item'      => __( 'Zum Produkt hinzufügen', TRANSLATION_CONST ),
        'uploaded_to_this_item' => __( 'Zum Produkt hinzugefügt', TRANSLATION_CONST ),
        'featured_image'        => __( 'Produktbild', TRANSLATION_CONST ),
        'set_featured_image'    => __( 'Produktbild setzen:', TRANSLATION_CONST ),
        'remove_featured_image' => __( 'Produktbild entfernen:', TRANSLATION_CONST ),
        'use_featured_image'    => __( 'Als Produktbild verwenden:', TRANSLATION_CONST ),
        'menu_name'             => __( 'Produkte', TRANSLATION_CONST ),
    );

    $supports = array(
        'title',
        'editor', // Content Bereich
        'excerpt', // Kurzer Auszug des Contents für Archivseiten
        'author',
        'thumbnail', // featured_image / Produktbild
        //'trackbacks',
        'custom-fields',
        //'revisions',
        'page-attributes',
        'comments'
    );

    $args = array(
        'labels' => $labels,
        'hierarchical' => false,
        'description' => __( 'Produkte für mein eigenes E-Commerce Plugin', TRANSLATION_CONST ),
        'supports' => $supports,
        'public' => true,
        'show_ui' => true,
        'show_in_menu' => true,
        'menu_position' => 5, // Unterhalb der Posts
        'menu_icon' => 'dashicons-card',
        'show_in_nav_menus' => true,
        'publicly_queryable' => true,
        'exclude_from_search' => false,
        'has_archive' => true,
        'query_var' => true,
        'can_export' => true,
        'capability_type' => 'post'
    );

    register_post_type( 'product', $args );
}
add_action( 'init', 'register_product_post_type' );

Schritt 3)

In diesem Schritt zeige ich Dir noch exemplarisch an Hand des Produktpreises, wie Du den zuvor registrieren Post Type um ein Post Meta Feld erweitern kannst und wie Du Deine eigene Post Meta Box im WordPress Backend hinzufügen kannst.

Für das Hinzufügen der Post Meta Box verwendest Du die WordPress Funktion „add_meta_box“. Dies Funktion nimmt eine Reihe an Parametern entgegen. In diesem Beispiel definieren wir die Parameter zuvor als Variablen, damit der Befehl nicht zu lang wird und damit Du dem Beispiel besser folgen kannst. Du kannst die Parameter auch alle direkt in die Funktion schreiben.
Um Text-Redundanzen zu vermeiden, baust Du nun zuerst eine Funktion, die für Dich die Preis Meta Box (und später vielleicht noch weitere Meta Boxen) registriert.
Jeden Code den Du in diesem Schritt implementierst, solltest Du in Deiner Post Type Datei (z.B. products.php) hinterlegen.

function add_custom_product_meta_box($meta_box_id, $meta_box_title) {
    $plugin_prefix = 'product_post_type_';

    $html_id_attribute = $plugin_prefix . $meta_box_id . '_meta_box';
    $php_callback_function = $plugin_prefix . 'build_' . $meta_box_id . '_meta_box';
    $show_me_on_post_type = 'product';
    $box_placement = 'side';
    $box_priority = 'low';

    add_meta_box(
        $html_id_attribute,
        $meta_box_title,
        $php_callback_function,
        $show_me_on_post_type,
        $box_placement,
        $box_priority
    );
}

WordPress bietet Dir nun die dynamische Aktion „add_meta_boxes_{$post_type}“ (WordPress – Add meta boxes) die Du registrieren kannst um Deine Meta Boxen zu integrieren. Dort verwendest Du dann auch die Funktion, die Du eben hinzugefügt hast.

function product_post_type_add_meta_boxes( $post ){
    add_custom_product_meta_box('price', __( 'Preis', TRANSLATION_CONST ));
    // Hier können problemlos noch weitere Meta Boxen registriert werden.
}
add_action( 'add_meta_boxes_product', 'product_post_type_add_meta_boxes' );

Nun musst Du noch drei Funktionen ergänzen. Die erste Funktion dient zum Darstellen der Post Meta Box, die zweite Funktion dient zum Speichern des Wertes, der in der Post Meta Box eingegeben wird und die dritte Funktion dient zum Ausgeben des Preises im Frontend. Die erste Funktion trägt den Namen des Callbacks, der in der Funktion „add_custom_product_meta_box“ für unser Post Meta Feld „price“ zusammengestellt wurde. Die zweite Funktion wird als Callback an die dynamische WordPress Aktion „save_post_product“ angehangen (WordPress – Save post action).

/**
 * Darstellung der "price" Meta Box
 *
 * @param object $post Das Post Objekt.
 */
function product_post_type_build_price_meta_box($post) {
    wp_nonce_field( basename( __FILE__ ), 'product_post_type_price_meta_box_nonce' );

    $current_price = get_post_meta( $post->ID, 'product_price', true );
    ?>
    <div class="inside">
        <section id="price-meta-box-container">
            <p>
                <input type="number" name="product_price" id="product-price"<?php echo ' value="'.$current_price.'"'; ?>>
            </p>
        </section>
    </div>
    <?php
}

Im ersten Teil dieser Funktion fügen wir ein „nonce“ Feld (WordPress – Nonces) ein um XSS (Cross-Site-Scripting) (WordPress – Cross site scripting) zu unterbinden. Nachfolgend ermitteln wir den aktuellen Post Meta Value mit der WordPress Funktion „get_post_meta“ (WordPress – Get post meta). Mit dieser Funktion kann auch zukünftig das Post Meta Feld immer abgerufen werden, solltest Du die Post ID kennen. Und als letztes wird noch ein wenig HTML ausgegeben, damit die Meta Box ein Eingabefeld besitzt.
Kommen wir nun zur Speicherung:

/**
 * Speicherung der "price" Meta Box Daten
 *
 * @param int $post_id Die Post ID.
 */
function product_post_type_save_price_meta_boxes_data( $post_id ){
    if ( !isset( $_POST['product_post_type_price_meta_box_nonce'] ) ||
            !wp_verify_nonce(
                $_POST['product_post_type_price_meta_box_nonce'],
                basename( __FILE__ )
            ) ){
        return;
    }

    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
        return;

    if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
        return;

    if ( !current_user_can( 'edit_post', $post_id ) )
        return;

    if ( isset( $_REQUEST['product_price'] ) ) {
        update_post_meta(
            $post_id,
            'product_price',
            sanitize_text_field( $_POST['product_price'] )
        );
    }
}
add_action( 'save_post_product', 'product_post_type_save_price_meta_boxes_data', 10, 2 );

Zu Beginn der Funktion werden einige Sicherheitsüberprüfungen durchgefüht. Es wird zuerst überprüft, ob die übergebene Nonce vorhanden und korrekt ist. Danach wird überprüft ob der aktuelle Funktionsaufruf durch eine automatische Speicherung oder durch Ajax geschieht. In beiden Fällen brechen wir den vorgang ab. Und zuletzt überprüft das Script, ob der Rang des aktuellen Nutzers über die Capability „edit_post“ verfügt.

Trifft all dies nicht zu, dann wird noch überprüft, ob „product_price“ übergeben wurde. Sollte das zutreffen, dann wird das Post Meta Feld über die WordPress Funktion „update_post_meta“ (WordPress – Update post meta) hinzugefügt oder aktuallisiert.

Nun fehlt noch die Funktion zum Ausgeben des Preises im Frontend. Hierbei orientierst Du Dich am besten an der Benamung der andern WordPress Funktionen wie „the_title“, „the_content“, oder „the_permalink“. Du könntest die Funktion bspw. „the_product_price“ nennen:

/**
 * Ausgabe des "price" Post Meta Feldes
 *
 * @param object $post Das Post Objekt.
 * @param bool $echo Sollen der Preis ausgegeben werden?
 */
function the_product_price($post = 0, $echo = true) {
    $post = get_post( $post );

    $id = isset( $post->ID ) ? $post->ID : 0;
    $value = get_post_meta( $id, 'product_price', true );

    if($echo) {
        echo sprintf(
            '<span class="product-detail--price">%s %s</span>',
            esc_html($value),
            __('€', TRANSLATION_CONST)
        );
    }
    else
        return $value;
}

In dieser letzten Funktion ermittelst Du zunächst das Post Objekt anhand der übergebenen Post Id, oder des übergeben Post Objektes. Danach wird der Wert des erfragten Post Meta Feldes ermittelt und je nach „echo“ Parameter ausgegeben oder zurückgegeben.

Schritt 4)

Dies ist der letzte Schritt, bevor Du vollends mit Deinem eigenen Post Type arbeiten kannst. In diesem Schritt wirst Du eine einfache Übersichtsseite und eine einfache Produkt Detailseite anlegen. Diese kannst Du später selber an Deine Bedürfnisse anpassen. Das Anlegen der Seite unterscheidet sich aber zwischen einem Theme und einem Plugin. In einem Theme werden diese beiden Dateien lediglich im Basisverzeichnis hinterlegt und in einem Plugin wirst Du sie im Verzeichnis „theme_files“ ablegen. Danach zeige ich dir, wie Du Dich in die notwendige Aktion einhängst, damit Deine Dateien erkannt werden.
Weiterhin ist es wichtig, dass Du Deine Permalink-Struktur in den WordPress Einstellungen aktuallisierst, nachdem Du mit allen Schritten fertig bist. Ansonsten werden die Routen zu Deiner Archivseite und zur Einzelansicht nicht erkannt.

Du beginnst zunächst mit der einfachen Archivseite für Deine Produkte. Dazu legst Du wie oben bereits beschrieben die Datei „archive-product.php“ entweder im Basisverzeichnis Deines Themes, oder im Verzeichnis „theme_files“ Deines Plugins an.

archive-product.php | Für ein Theme

<?php
/**
 * Template Name: Archive Product Template
 *
 * Description: Eine eigene Archivseite für meinen Post Type „product“
 */

get_header(); ?>

    <div class="main-wrap" role="main">

        <!-- Darstellung der Produkte -->
        <section id="product-listing">
            <?php if ( have_posts() ) : ?>
                <div class="row">
                <?php while ( have_posts() ) : the_post(); ?>
                    <div class="column"">
	       <?php get_template_part( 'template-parts/product-content', get_post_format() ); ?>
	    </div>
                <? endwhile; ?>
                </div>
            <?php endif; ?>
        </section>

    </div>

<?php get_footer();

In dieser Datei wird der WordPress Loop verwendet, um alle Produkte zu durchlaufen und auszugeben. Die genauen Inhalte werden mit der WordPress Funktion „get_template_part“ aus der Datei „product-content.php“ im Verzeichnis „template-parts“ geladen (WordPress – Get template part). Diese Funktion kann lediglich in Themes verwendet werden.
Deshalb verwendest Du in einem Plugin einen anderen Code:

archive-product.php | Für ein Plugin

<?php
/**
 * Template Name: Archive Product Template
 *
 * Description: Eine eigene Archivseite für meinen Post Type „product“
 */

get_header(); ?>

    <div class="main-wrap" role="main">

        <!-- Darstellung der Produkte -->
        <section id="product-listing">
            <?php if ( have_posts() ) : ?>
                <div class="row">
                <?php while ( have_posts() ) : the_post(); ?>
                    <div class="column"">
	       <?php require_once( 'product-content.php' ); ?>
	    </div>
                <? endwhile; ?>
                </div>
            <?php endif; ?>
        </section>

    </div>

<?php get_footer();

Der Unterschied zu der Theme-Version ist, dass die Datei „product-content.php“ nun einfach mit im Verzeichnis „theme_files“ angelegt wird. Nun erstellst Du im jeweiligen Verzeichnis die Datei „product-content.php“:

<?php
/**
 * Das Standard-Template zum Anzeigen eines Produktes
 */
?>

<div class="product-container" id="product-<?php the_ID(); ?>">
    <?php if ( has_post_thumbnail() ) : ?>
    <a href="<?php the_permalink(); ?>">
         <img src="<?php the_post_thumbnail_url( ); ?>">
    </a>
    <?php endif; ?>

    <div class="product-content-section">
        <header>
            <h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
        </header>
        <div class="entry-content">
            <?php
                the_product_price(get_the_ID());
                echo '<br />';
                the_excerpt();
            ?>
        </div>
    </div>
</div>

In der Datei kam nun auch unsere Funktion „the_product_price“ zum Einsatz. Diese gibt oberhalb des Auszugs den Preis für das Produkt aus.
Nun benötigst Du für Deine Produkte nur noch eine Detailseite. Hier gehst Du ähnlich vor wie bei der Archivseite. Die Einzelansicht / Deteilseite trägt den Dateinamen „single-product.php“ und wird bei der Integration in einem Theme in dessen Basisverzeichnis abgelegt und bei einem Plugin im Verzeichnis „theme_files“.

single-product.php

<?php get_header(); ?>

<?php while ( have_posts() ) : the_post(); ?>
<article <?php post_class() ?> id="product-<?php the_ID(); ?>">
    <div class="row column" id="product-header">
        <h1 class="entry-title"><?php the_title(); ?></h1>
    </div>

    <div class="main-wrap" role="main">
        <div class="entry-content">
            <div class="row">
                <div class="medium-6 columns">
                    <?php if(has_post_thumbnail( )) : ?>
                        <a href="<?php the_post_thumbnail_url('large'); ?>">
                                <img src="<?php the_post_thumbnail_url('large'); ?>"/>
                        </a>
                    <?php endif; ?>
                </div>
                <div class="medium-6 columns">
                    <?php the_product_price(get_the_ID()); ?>
                </div>
            </div>

            <div class="row columns">
                <?php the_content(); ?>
            </div>
        </div>

        <footer>
            <?php
                wp_link_pages(
                    array(
                        'before' => '<nav id="page-nav"><p>' . __( 'Produkte:', TRANSLATION_CONST ),
                        'after'  => '</p></nav>',
                    )
                );
            ?>
        </footer>

        <?php comments_template(); ?>

    </div>
</article>
<?php endwhile;?>

<?php get_footer();

Somit gibt es nun auch eine Detailansicht für das Produkt. Hier wird ebenfalls die Funktion „the_product_price“ des Produkt Post Types verwendet. Nun zeige ich Dir noch wie Du die „theme_files“ in einem Plugin einbinden kannst.

Hinweis: Das Beispiel zur Integratien der Dateien ist nicht auf einem objektorientieren Plugin aufgebaut. In einem objektorientierten Plugin könntest Du diese Funktionen in der Plugin Klasse hinterlegen und im Konstruktor aufrufen.

Am besten erstellst Du in Deinem Plugin ein Verzeichnis für weiteren Code, z.B. „libs“, damit Deine Plugin Datei nicht zu unübersichtlich wird. Darin erstellst Du nun die PHP Datei „register_custom_theme_files.php“:

<?php
/**
 * Verlinkt die Plugin SINGLE Post-Type Seiten
 */
function example_plugin_custom_single_theme_file_include($template) {

    global $wp;
    $requested_post_type = $wp->query_vars["post_type"];

    if($requested_post_type == 'product')
        return $template;

    $file = EXAMPLE_PLUGIN_PATH.'/theme_files/single-'.$requested_post_type.'.php';
    if(file_exists($file)) {
        $template = $file;
    }

    return $template;

}
add_filter('single_template', 'example_plugin_custom_single_theme_file_include');

/**
 * Verlinkt die Plugin ARCHIVE Post-Type Seiten
 */
function example_plugin_custom_archive_theme_file_include($template) {

    global $wp;
    $requested_post_type = $wp->query_vars["post_type"];

    if($requested_post_type == 'product')
        return $template;

    $file = EXAMPLE_PLUGIN_PATH.'/theme_files/archive-'.$requested_post_type.'.php';
    if(file_exists($file)) {
        $template = $file;
    }

    return $template;

}
add_action('archive_template', 'example_plugin_custom_archive_theme_file_include');

Die Überprüfung, ob der angefragte Post Type gleich „product“ ist, kannst Du gerne im nachhinein refaktorisieren und mit einem Array vergleichen, in dem alle registrierten Post Types Deine Plugins eingetragen sind. Weiterhin wird die Konstante „EXAMPLE_PLUGIN_PATH“ verwendet, die in der Plugin Datei wie folgt initialisiert wird:

define('EXAMPLE_PLUGIN_PATH', plugin_dir_path( __FILE__ ));

Die Datei muss nun nurnoch in der Plugin Datei mit der PHP Funktion „require_once“ integriert werden.

require_once EXAMPLE_PLUGIN_PATH.'/libs/register_custom_theme_files.php';

 

In diesem Tutorial hast Du Deinen eigenen Post Type angelegt und Ihn um Komponenten wie Post Meta Felder, eigene Post Meta Boxen, sowie die “single-{post-type}.php”, als auch die  “archive-{post-type}.php” erweitert. Nun kannst Du Deine eigenen WordPress Seiten flexibel um Inhalte erweitern und das WordPress Backend dieser Inhalte an Deine Bedürfnisse anpassen.
Solltest Du Fragen oder Anregungen haben, so zögere nicht uns ein Kommentar zu hinterlassen.

Durch unsere langjährige Arbeit und über 100 erfolgreiche Projekte, konnten wir viele Erfahrungen sammeln. Dieses Know-How im Online-Marketing gaben wir u.a. bei Vorträgen von Google, der Industrie- und Handelskammer und der Handwerkskammer weiter.

Mit Know-How, Kreativität und Leidenschaft entwickeln wir auf unsere Kunden abgestimmte Marketing-Strategien, die Sie sicher und nachhaltig zum Erfolg führen. Gemeinsam setzen wir Ihr Online-Marketing so um, dass Sie langfristig Ihren Umsatz und Return-On-Investment steigern.

Jetzt kostenlosen Beratungstermin vereinbaren   oder unter 0561 / 850 194 76 anrufen.