Crea una pagina di archivio personalizzata per un custom post type in un plugin

27 set 2013, 22:04:49
Visualizzazioni: 18.3K
Voti: 16

Sto scrivendo un plugin che crea un custom post type chiamato "my_plugin_lesson":

$args = array (
    'public' => true,
    'has_archive' => true,
    'rewrite' => array('slug' => 'lessons', 'with_front' => false)
);
register_post_type ('my_plugin_lesson', $args);

Il custom post type ha un archivio, e l'URL dell'archivio è:

http://example.com/lessons

Voglio personalizzare l'aspetto di questo archivio; voglio elencare i post in formato tabella, invece del classico archivio blog di WordPress. Capisco che si potrebbe creare un template di archivio personalizzato nel tema creando il file archive-my_plugin_lesson.php; tuttavia, vorrei che il plugin funzioni con qualsiasi tema.

Come posso modificare il contenuto della pagina di archivio senza aggiungere o modificare file del tema?

Modifica: Capisco che potrei usare l'hook filter archive_template. Tuttavia, tutto ciò che fa è sostituire il template del tema, che deve comunque essere specifico per il tema. Ad esempio, quasi tutti i template del tema avranno bisogno delle funzioni get_header, get_sidebar, e get_footer, ma quale dovrebbe essere l'id del <div> del contenuto? Questo è diverso in ogni tema.

Quello che vorrei fare è sostituire il contenuto stesso con il mio contenuto, e usarlo al posto della pagina di archivio per il mio custom post type.

0
Tutte le risposte alla domanda 4
1
17

Quello di cui hai bisogno è agganciare il filtro template_include e caricare selettivamente il tuo template all'interno del plugin.

Come buona pratica, se intendi distribuire il tuo plugin, dovresti verificare se archive-my_plugin_lesson.php (o magari myplugin/archive-lesson.php) esiste nel tema, altrimenti usa la versione del plugin.

In questo modo è facile per gli utenti sostituire il template tramite il tema (o child theme) senza modificare il codice del plugin.

Questo è il metodo utilizzato da plugin popolari, ad esempio WooCommerce, giusto per citare un nome.

add_filter('template_include', 'lessons_template');

function lessons_template( $template ) {
  if ( is_post_type_archive('my_plugin_lesson') ) {
    $theme_files = array('archive-my_plugin_lesson.php', 'myplugin/archive-lesson.php');
    $exists_in_theme = locate_template($theme_files, false);
    if ( $exists_in_theme != '' ) {
      return $exists_in_theme;
    } else {
      return plugin_dir_path(__FILE__) . 'archive-lesson.php';
    }
  }
  return $template;
}

Maggiori informazioni sul Codex per

28 set 2013 14:38:19
Commenti

Questo sostituisce ancora solo il file template del tema, giusto? Cosa devo inserire nel file archive-lesson.php del mio plugin? Dovrebbe essere diverso per funzionare con ogni tema. Anche i temi predefiniti "Twenty" non sono d'accordo su quali siano i contenitori div/section che circondano il contenuto.

Ben Miller Ben Miller
29 set 2013 07:35:37
0

Puoi utilizzare l'hook archive_template per elaborare il contenuto del template di archivio di un tema, utilizzando lo schema seguente. Tuttavia, riuscirai a elaborare solo una frazione dei temi esistenti, dato che un template può contenere praticamente qualsiasi cosa.

Lo schema consiste nel caricare il template in una stringa ($tpl_str) nel filtro archive_template, sostituire il tuo contenuto, includere la stringa (utilizzando il trucco eval( '?>' . $tpl_str );) e poi restituire un file vuoto in modo che l'include in "wp-includes/template-loader.php" diventi un'operazione nulla.

Di seguito trovi una versione modificata del codice che utilizzo in un plugin, che si rivolge ai template "classici" che usano get_template_part ed è più orientato all'elaborazione di template singoli piuttosto che di archivio, ma può aiutarti a iniziare. L'impostazione prevede che il plugin abbia una sottodirectory chiamata "templates" che contiene un file vuoto ("null.php") e template di contenuto (ad esempio "content-single-posttype1.php", "content-archive-postype1.php"), oltre a un template di fallback "single.php" per il caso singolo, e utilizza una versione personalizzata di get_template_part che cerca in questa directory.

define( 'MYPLUGIN_FOLDER', dirname( __FILE__ ) . '/' );
define( 'MYPLUGIN_BASENAME', basename( MYPLUGIN_FOLDER ) );

add_filter( 'single_template', 'myplugin_single_template' );
add_filter( 'archive_template', 'myplugin_archive_template' );

function myplugin_single_template( $template ) {
    static $using_null = array();

    // Modifica con i tuoi custom post type.
    $post_types = array( 'posttype1', );

    if ( is_single() || is_archive() ) {
        $template_basename = basename( $template );
        // Questo controllo può essere rimosso.
        if ( $template == '' || substr( $template_basename, 0, 4 ) == 'sing' || substr( $template_basename, 0, 4 ) == 'arch' ) {
            $post_type = get_post_type();
            $slug = is_archive() ? 'archive' : 'single';
            if ( in_array( $post_type, $post_types ) ) {
                // Permetti all'utente di sovrascrivere.
                if ( $single_template = myplugin_get_template( $slug, $post_type ) ) {
                    $template = $single_template;
                } else {
                    // Se non hai già passato tutto questo...
                    if ( empty( $using_null[$slug][$post_type] ) ) {
                        if ( $template && ( $content_template = myplugin_get_template( 'content-' . $slug, $post_type ) ) ) {
                            $tpl_str = file_get_contents( $template );
                            // Dovrai adattare queste regex al tuo caso - buona fortuna!
                            if ( preg_match( '/get_template_part\s*\(\s*\'content\'\s*,\s*\'' . $slug . '\'\s*\)/', $tpl_str, $matches, PREG_OFFSET_CAPTURE )
                            || preg_match( '/get_template_part\s*\(\s*\'content\'\s*,\s*get_post_format\s*\(\s*\)\s*\)/', $tpl_str, $matches, PREG_OFFSET_CAPTURE )
                            || preg_match( '/get_template_part\s*\(\s*\'content\'\s*\)/', $tpl_str, $matches, PREG_OFFSET_CAPTURE )
                            || preg_match( '/get_template_part\s*\(\s*\'[^\']+\'\s*,\s*\'' . $slug . '\'\s*\)/', $tpl_str, $matches, PREG_OFFSET_CAPTURE ) ) {
                                $using_null[$slug][$post_type] = true;
                                $tpl_str = substr( $tpl_str, 0, $matches[0][1] ) . 'include \'' . $content_template . '\'' . substr( $tpl_str, $matches[0][1] + strlen( $matches[0][0] ) );
                                // Questo trucco include la $tpl_str.
                                eval( '?>' . $tpl_str );
                            }
                        }
                    }
                    if ( empty( $using_null[$slug][$post_type] ) ) {
                        // Parsing fallito - cerca un template di fallback.
                        if ( file_exists( MYPLUGIN_FOLDER . 'templates/' . $slug . '.php' ) ) {
                            $template = MYPLUGIN_FOLDER . 'templates/' . $slug . '.php';
                        }
                    } else {
                        // Successo! "null.php" è semplicemente un file vuoto di zero byte.
                        $template = MYPLUGIN_FOLDER . 'templates/null.php';
                    }
                }
            }
        }
    }
    return $template;
}

function myplugin_archive_template( $template ) {
    return myplugin_single_template( $template );
}

La versione personalizzata di get_template_part:

/*
 * Versione di WP get_template_part() che cerca nel tema, poi nel tema genitore e infine nella directory dei template del plugin (sottodirectory "templates").
 * Cerca inizialmente anche nella sottodirectory "myplugin" se presente nelle directory del tema e del tema genitore, in modo che i template del plugin possano essere mantenuti separati.
 */
function myplugin_get_template( $slug, $part = '' ) {
    $template = $slug . ( $part ? '-' . $part : '' ) . '.php';

    $dirs = array();

    if ( is_child_theme() ) {
        $child_dir = get_stylesheet_directory() . '/';
        $dirs[] = $child_dir . MYPLUGIN_BASENAME . '/';
        $dirs[] = $child_dir;
    }

    $template_dir = get_template_directory() . '/';
    $dirs[] = $template_dir . MYPLUGIN_BASENAME . '/';
    $dirs[] = $template_dir;
    $dirs[] = MYPLUGIN_FOLDER . 'templates/';

    foreach ( $dirs as $dir ) {
        if ( file_exists( $dir . $template ) ) {
            return $dir . $template;
        }
    }
    return false;
}

Per completezza, ecco il template di fallback "single.php", che utilizza la versione personalizzata di get_template_part:

<?php
get_header(); ?>

    <div id="primary" class="content-area">
        <div id="content" class="clearfix">
            <?php while ( have_posts() ) : the_post(); ?>

            <?php if ( $template = myplugin_get_template( 'content-single', get_post_type() ) ) include $template; else get_template_part( 'content', 'single' ); ?>

                <?php
                    // Se i commenti sono aperti o abbiamo almeno un commento, carica il template dei commenti
                    if ( comments_open() || '0' != get_comments_number() ) :
                        comments_template();
                    endif;
                ?>

            <?php endwhile; ?>

        </div><!-- #content -->
    </div><!-- #primary -->

<?php get_sidebar(); ?>
<?php get_footer(); ?>
11 set 2014 19:35:11
2

Mi sono posto la stessa domanda e questa è la soluzione ipotetica a cui sono arrivato:

  • All'interno del plugin, crea uno shortcode che generi il tuo loop di archivio nel modo che desideri.
  • Quando crei il custom post type, non abilitare l'opzione 'archive'.
  • Aggiungi un foglio di stile che controlli tutti gli stili dei contenuti del tuo loop.

All'attivazione del plugin, crea una pagina usando wp_insert_post con il nome corrispondente al post type e il contenuto che sarà lo shortcode.

Puoi fornire opzioni nello shortcode per considerazioni stilistiche aggiuntive, oppure aggiungere classi al contenitore del post per adattarsi a stili specifici del tema o personalizzati. L'utente può anche aggiungere contenuti aggiuntivi prima/dopo il loop modificando la pagina.

30 mag 2015 22:32:43
Commenti

Anche se non sono l'autore del post originale, stavo cercando una soluzione allo stesso problema. Ho seguito la tua soluzione ipotetica e posso confermare che funziona anche nella pratica.

Lucio Crusca Lucio Crusca
6 gen 2016 16:21:01

Fantastico! Sono contento che sia stato utile per qualcuno. Avevo completamente dimenticato questo post.

SkyShab SkyShab
6 gen 2016 17:50:20
1

Puoi utilizzare il filtro single_template. Un esempio base preso dal Codex:

function get_custom_post_type_template($single_template) {
     global $post;

     if ($post->post_type == 'my_post_type') {
          $single_template = dirname( __FILE__ ) . '/post-type-template.php';
     }
     return $single_template;
}

add_filter( "single_template", "get_custom_post_type_template" );
27 set 2013 22:18:41
Commenti

Penso che l'hook del filtro per un template di archivio sia archive_template, ma non credo che funzionerà per quello che sto cercando di fare. Ho modificato la mia domanda con maggiori informazioni.

Ben Miller Ben Miller
28 set 2013 07:49:09