Cum să creezi o pagină de arhivă personalizată pentru un post type custom într-un plugin WordPress
Scriu un plugin care creează un post type custom numit "my_plugin_lesson":
$args = array (
'public' => true,
'has_archive' => true,
'rewrite' => array('slug' => 'lessons', 'with_front' => false)
);
register_post_type ('my_plugin_lesson', $args);
Post type-ul custom are o arhivă, iar URL-ul arhivei este:
http://example.com/lessons
Doresc să personalizez aspectul acestei arhive; vreau să afișez postările într-un format tabelar, în locul arhivei standard WordPress. Înțeleg că se poate crea un șablon personalizat în temă prin fișierul archive-my_plugin_lesson.php
; totuși, aș dori ca plugin-ul să funcționeze cu orice temă.
Cum pot modifica conținutul paginii de arhivă fără a adăuga sau modifica fișierele temei?
Edit:
Înțeleg că pot folosi hook-ul archive_template
. Totuși, acesta doar înlocuiește șablonul temei, care în continuare trebuie să fie specific temei. De exemplu, aproape orice șablon de temă va avea nevoie de funcțiile get_header
, get_sidebar
și get_footer
, dar care ar trebui să fie id-ul div-ului de conținut? Acesta diferă în fiecare temă.
Ceea ce aș dori să fac este să înlocuiesc conținutul în sine cu propriul meu conținut și să-l folosesc în locul paginii de arhivă pentru post type-ul meu custom.

Ceea ce aveți nevoie este să utilizați filtrul template_include
și să încărcați selectiv șablonul din interiorul plugin-ului.
Ca o bună practică, dacă intenționați să distribuiți plugin-ul, ar trebui să verificați dacă archive-my_plugin_lesson.php
(sau poate myplugin/archive-lesson.php
) există în tema, iar dacă nu, să folosiți versiunea din plugin.
În acest fel, utilizatorii pot înlocui cu ușurință șablonul prin intermediul temei (sau a temei copil) fără a modifica codul plugin-ului.
Aceasta este metoda folosită de plugin-uri populare, de exemplu WooCommerce, doar ca să menționăm un nume.
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;
}
Mai multe informații în Codex pentru

Acest lucru înlocuiește doar fișierul șablon al temei, nu? Ce ar trebui să pun în fișierul archive-lesson.php al pluginului meu? Ar trebui să fie diferit pentru a funcționa cu fiecare temă. Chiar și temele implicite "Twenty" nu sunt de acord asupra div-urilor/secțiunilor de container care înconjoară conținutul.

Puteți folosi hook-ul archive_template
pentru a procesa conținutul unui șablon de arhivă al temei, folosind schema de mai jos, dar evident veți putea procesa doar o fracțiune din temele existente, având în vedere că un șablon poate conține orice.
Schema constă în încărcarea șablonului într-un string ($tpl_str
) în cadrul filtrului archive_template
, înlocuirea conținutului dumneavoastră, includerea string-ului (folosind trucul eval( '?>' . $tpl_str );
), și returnarea unui fișier gol astfel încât include
-ul din "wp-includes/template-loader.php" să devină un no-op.
Mai jos este o versiune modificată a codului pe care îl folosesc într-un plugin, care se adresează șabloanelor "clasice" ce folosesc get_template_part
și este mai preocupat de procesarea șabloanelor individuale decât de cele de arhivă, dar vă poate ajuta să începeți. Configurația este următoarea: plugin-ul are un subdirector numit "templates" care conține un fișier gol ("null.php") și șabloane de conținut (de ex. "content-single-posttype1.php", "content-archive-postype1.php"), precum și un șablon de rezervă "single.php" pentru cazurile individuale, și utilizează o versiune personalizată a get_template_part
care caută în acest director.
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();
// Ajustați cu tipurile dumneavoastră de postări personalizate.
$post_types = array( 'posttype1', );
if ( is_single() || is_archive() ) {
$template_basename = basename( $template );
// Această verificare poate fi eliminată.
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 ) ) {
// Permiteți utilizatorului să suprascrie.
if ( $single_template = myplugin_get_template( $slug, $post_type ) ) {
$template = $single_template;
} else {
// Dacă nu ați trecut prin toate acestea înainte...
if ( empty( $using_null[$slug][$post_type] ) ) {
if ( $template && ( $content_template = myplugin_get_template( 'content-' . $slug, $post_type ) ) ) {
$tpl_str = file_get_contents( $template );
// Va trebui să ajustați aceste regex-uri pentru cazul dumneavoastră - mult noroc!
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] ) );
// Acest truc include $tpl_str.
eval( '?>' . $tpl_str );
}
}
}
if ( empty( $using_null[$slug][$post_type] ) ) {
// Nu s-a putut analiza - căutați șablonul de rezervă.
if ( file_exists( MYPLUGIN_FOLDER . 'templates/' . $slug . '.php' ) ) {
$template = MYPLUGIN_FOLDER . 'templates/' . $slug . '.php';
}
} else {
// Succes! "null.php" este doar un fișier gol cu zero biți.
$template = MYPLUGIN_FOLDER . 'templates/null.php';
}
}
}
}
}
return $template;
}
function myplugin_archive_template( $template ) {
return myplugin_single_template( $template );
}
Versiunea personalizată a get_template_part
:
/*
* Versiunea WP get_template_part() care caută în tema, apoi în tema părinte, și în final în directorul de șabloane al plugin-ului (subdirectorul "templates").
* De asemenea, caută inițial în subdirectorul "myplugin" dacă există în directoarele temei și temei părinte, astfel încât șabloanele plugin-ului să poată fi păstrate separate.
*/
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;
}
Pentru completitudine, iată șablonul de rezervă "single.php", care folosește versiunea personalizată a 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
// Dacă comentariile sunt deschise sau avem cel puțin un comentariu, încărcăm șablonul de comentarii
if ( comments_open() || '0' != get_comments_number() ) :
comments_template();
endif;
?>
<?php endwhile; ?>
</div><!-- #content -->
</div><!-- #primary -->
<?php get_sidebar(); ?>
<?php get_footer(); ?>

M-am tot gândit la aceeași întrebare, și iată soluția ipotetică la care am ajuns:
- În cadrul plugin-ului, creează un shortcode care afișează bucla de arhivă așa cum dorești.
- Când creezi tipul de postare personalizată, nu activa opțiunea 'archive'.
- Adaugă o foaie de stiluri care controlează toate stilurile conținutului buclei tale.
La activarea plugin-ului, creează o pagină folosind wp_insert_post cu numele fiind tipul de postare și conținutul fiind shortcode-ul.
Poți oferi opțiuni în shortcode pentru considerații suplimentare de stil, sau poți adăuga clase containerului de postare pentru a se potrivi cu stilurile specifice temei sau stilurilor personalizate. Utilizatorul poate adăuga și conținut suplimentar înainte/după buclă prin editarea paginii.

Deși nu sunt cel care a postat inițial, căutam o soluție la aceeași problemă. Am urmat soluția ta ipotetică și acum pot confirma că funcționează și în practică.

Puteți utiliza filtrul single_template
. Un exemplu de bază preluat din 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" );
