it-swarm.com.de

Vorlage auf verfügbaren Beitragstyp anwenden

Heute habe ich einen Client bekommen, der eine benutzerdefinierte Vorlage für jede Seite und jeden Abschnitt innerhalb wollte. Ich schlug Laravel benutzerdefinierte sh3t vor, aber er wollte WordPress, da es einfacher zu verwalten scheint ( nicht aus meiner Erfahrung ).

.. So weit, ist es gut. Ich bin da ein bisschen verwirrt.

Daher habe ich beschlossen, dass meine übergeordnete Entität Seite ist, sodass ich auf jede Seite eine andere Vorlage anwenden kann. Dann habe ich einen Abschnitt innerhalb dieser Seite, der nicht hardcored sein sollte. Der Benutzer sollte die Möglichkeit haben, das Abschnittslayout ( template ) auszuwählen und Abschnitte innerhalb der aktuellen Seite zu entfernen oder neu anzuordnen. Und schließlich habe ich Posts, da sie die kleinste Entität auf der Website sind. Posts würden als Spalten wie in Bootstrap ( col-md-2, col-lg-6 ) usw. gerendert.

Ich habe beschlossen, einen benutzerdefinierten Beitragstyp zu erstellen, um ihn als Abschnitt zu verwenden, aber dann habe ich gelesen, dass Beitragstypen keine Vorlage haben können, sondern nur Seiten. Dies beeinträchtigte meinen Plan bis jetzt und verbrachte 5 Stunden damit, nach einer Lösung zu suchen ( no exit ). Dafür brauche ich eine andere Strategie. Ich benötige Vorlagen für zwei Entitäten.

Kann jemand eine Lösung für dieses Problem vorschlagen? ( Ich kaufe dir ein Bier! )

BEARBEITEN:

Um meinen eigenen benutzerdefinierten Beitragstyp zu erstellen, verwende ich das Plugin in WordPress mit dem Namen 'Benutzerdefinierte Beitragstyp-Benutzeroberfläche' . Natürlich gibt es auch eine andere Möglichkeit, indem Sie ein kurzes Code-Snippet in Ihren einfügen. functions.php file, aber ich werde das hier nicht behandeln.

1
Dimitrov

Normalerweise würde ich einer so starken Antwort wie der von @Milo mit einem Beitrag wie diesem nicht folgen. Da ich diesen Code bereits für ein anderes Projekt geschrieben hatte, dachte ich, ich würde ihn teilen.

Der folgende Code macht alles, was @Milo in seiner Antwort zusammengefasst hat, und ich habe dies zuvor mit großem Erfolg projektübergreifend portiert.

Hier ist der Spickzettel für das, was los ist:

1) Aktivieren Sie die Aktion 'add_meta_boxes', um ein neues benutzerdefiniertes Meta-Feld auf dem Bearbeitungsbildschirm zu rendern (mit Ausnahme des systemeigenen Beitragstyps 'page').

2) Rufen Sie die Aktion 'admin_menu' auf, um das vorhandene Meta-Feld 'Seitenattribute' zu entfernen (mit Ausnahme des systemeigenen Beitragstyps 'Seite').

3) Erstellen Sie das benutzerdefinierte Meta-Feld, um die Funktionalität des nativen Meta-Felds "Seitenattribute" zu ersetzen. Dazu gehören Felder zum Definieren von PARENT, TEMPLATE und ORDER eines benutzerdefinierten Beitragstyps, den Sie initialisiert haben.

4) Aktivieren Sie die Aktion 'save_post', um Ihre Vorlagenauswahl im Post-Meta zu speichern.

5) Binden Sie sich in den Filter "single_template" ein, um Ihre benutzerdefinierte Vorlage anstelle der Standard-WordPress-Vorlage zu laden.

Hier ist das voll funktionsfähige Kopieren/Einfügen für Sie:

/** Custom Post Type Template Selector **/
function cpt_add_meta_boxes() {
    $post_types = get_post_types();
    foreach( $post_types as $ptype ) {
        if ( $ptype !== 'page') {
            add_meta_box( 'cpt-selector', 'Attributes', 'cpt_meta_box', $ptype, 'side', 'core' );
        }
    }
}
add_action( 'add_meta_boxes', 'cpt_add_meta_boxes' );

function cpt_remove_meta_boxes() {
    $post_types = get_post_types();
    foreach( $post_types as $ptype ) {
        if ( $ptype !== 'page') {
            remove_meta_box( 'pageparentdiv', $ptype, 'normal' );
        }
    }
}
add_action( 'admin_menu' , 'cpt_remove_meta_boxes' );

function cpt_meta_box( $post ) {
    $post_meta = get_post_meta( $post->ID );
    $templates = wp_get_theme()->get_page_templates();

    $post_type_object = get_post_type_object($post->post_type);
    if ( $post_type_object->hierarchical ) {
        $dropdown_args = array(
            'post_type'        => $post->post_type,
            'exclude_tree'     => $post->ID,
            'selected'         => $post->post_parent,
            'name'             => 'parent_id',
            'show_option_none' => __('(no parent)'),
            'sort_column'      => 'menu_order, post_title',
            'echo'             => 0,
        );

        $dropdown_args = apply_filters( 'page_attributes_dropdown_pages_args', $dropdown_args, $post );
        $pages = wp_dropdown_pages( $dropdown_args );

        if ( $pages ) { 
            echo "<p><strong>Parent</strong></p>";
            echo "<label class=\"screen-reader-text\" for=\"parent_id\">Parent</label>";
            echo $pages;
        }
    }

    // Template Selector
    echo "<p><strong>Template</strong></p>";
    echo "<select id=\"cpt-selector\" name=\"_wp_page_template\"><option value=\"default\">Default Template</option>";
    foreach ( $templates as $template_filename => $template_name ) {
        if ( $post->post_type == strstr( $template_filename, '-', true) ) {
            if ( isset($post_meta['_wp_page_template'][0]) && ($post_meta['_wp_page_template'][0] == $template_filename) ) {
                echo "<option value=\"$template_filename\" selected=\"selected\">$template_name</option>";
            } else {
                echo "<option value=\"$template_filename\">$template_name</option>";
            }
        }
    }
    echo "</select>";

    // Page order
    echo "<p><strong>Order</strong></p>";
    echo "<p><label class=\"screen-reader-text\" for=\"menu_order\">Order</label><input name=\"menu_order\" type=\"text\" size=\"4\" id=\"menu_order\" value=\"". esc_attr($post->menu_order) . "\" /></p>";
}

function save_cpt_template_meta_data( $post_id ) {

    if ( isset( $_REQUEST['_wp_page_template'] ) ) {
        update_post_meta( $post_id, '_wp_page_template', $_REQUEST['_wp_page_template'] );
    }
}
add_action( 'save_post' , 'save_cpt_template_meta_data' );

function custom_single_template($template) {
    global $post;

    $post_meta = ( $post ) ? get_post_meta( $post->ID ) : null;
    if ( isset($post_meta['_wp_page_template'][0]) && ( $post_meta['_wp_page_template'][0] != 'default' ) ) {
        $template = get_template_directory() . '/' . $post_meta['_wp_page_template'][0];
    }

    return $template;
}
add_filter( 'single_template', 'custom_single_template' );
/** END Custom Post Type Template Selector **/

Die einzige Annahme, die ich hier gemacht habe, ist, dass Ihre Vorlagen einer bewährten Benennungskonvention folgen:

posttype-templatename.php

Als Beispiel könnten Sie einige benutzerdefinierte Vorlagen für einen benutzerdefinierten Beitragstyp "Ereignis" definieren, indem Sie die folgende Namenskonvention in Ihrem Thema verwenden:

event-standard.php
event-allday.php
event-recurring.php

Dieser Code ist so intelligent, dass nur "Ereignis" -Vorlagen auf den Typ "Ereignisbeitrag" angewendet werden können. Mit anderen Worten, eine Vorlage mit dem Namen "section-video.php" ist für den Typ "Ereignisbeitrag" niemals sichtbar. Diese Vorlage wird stattdessen als Option im Beitragstyp "Abschnitt" angezeigt.

Um diese Funktion zu entfernen, müssen Sie lediglich die bedingte Logik aus dem obigen Code entfernen:

if ( $post->post_type == strstr( $template_filename, '-', true) ) {  }
5
dswebsme

Seit WordPress 4.7 werden benutzerdefinierte Beitragstypen für mehrere Vorlagen unterstützt.

Um eine Vorlage für Ihren benutzerdefinierten Beitragstyp verfügbar zu machen, fügen Sie diesen Header zum Meta-Teil der Vorlagendatei hinzu:

Template Post Type: post, foo, bar 

Angenommen, Ihr benutzerdefinierter Beitragstyp trägt die Bezeichnung "my_events" und Sie möchten eine Vorlage mit dem Namen "Fullwidth" sowohl für Pages als auch für Ihren benutzerdefinierten Beitragstyp verfügbar machen.

Dies:

/**
 * Template Name: Fullwidth
 * 
 * Template Description...
 **/

wird dies:

/**
 * Template Name: Fullwidth
 * Template Post Type: page, my_events
 * 
 * Template Description...
 **/

Weitere Informationen: Post Type Templates in 4.7 aus WordPress Core

13

Benutzerdefinierte Beitragstypen können wählbare Vorlagen haben. Sie müssen sie nur selbst implementieren. Die Art und Weise, wie WordPress es intern mit dem Typ des Seitenposts macht, besteht darin, einen Template-Slug in Post-Metadaten zu speichern und dann zu prüfen, ob dort ein Wert vorhanden ist, wenn das Template gemäß der Hierarchie auf das Frontend geladen wird.

Der grundlegende Vorgang besteht darin, ein Meta-Feld hinzuzufügen Ihrem benutzerdefinierten Beitragstyp hinzuzufügen, damit Benutzer eine Vorlage auswählen können (möglicherweise mithilfe von get_page_templates , um eine Liste zu erstellen).

Der zweite Schritt besteht darin, einen Filter zu single_template hinzuzufügen die ausgewählte Vorlage zu laden, wenn dieses Objekt im Frontend angezeigt wird.

Wenn Sie in die Kerndateien wp-includes/template.php und wp-includes/post-template.php schauen, können Sie den Code sehen, den WordPress verwendet (und wo der Filter angewendet wird), und ihn an Ihre Bedürfnisse anpassen. get_queried_object gibt Ihnen den post_type des Objekts im Filter sowie die ID, mit der Sie die Metadaten des Posts abrufen können.

BEARBEITEN -

Hier ist ein Beispielfilter für den Beitragstyp post, der alles lädt, was im Metaschlüssel my_template enthalten ist (wie whatever.php). Sie können dies testen, indem Sie einen neuen Beitrag erstellen und einen Dateinamen unter diesem Schlüssel in das native Metafeld Benutzerdefinierte Felder eingeben. Sie können dies für Ihren benutzerdefinierten Typ ändern ('post' ändern) und für jedes Schema, das Sie zum Speichern und Benennen von Dateien verwenden.

function wpd_post_type_template( $template ){
    $object = get_queried_object();
    if( ! empty( $object->post_type )
        && 'post' == $object->post_type
        && $slug = get_post_meta( $object->ID, 'my_template', true ) ){
        if( $custom_template = locate_template( $slug, false ) ){
            $template = $custom_template;
        }
    }
    return $template;
}
add_filter( 'single_template', 'wpd_post_type_template' ) ;
1
Milo