Utwórz niestandardową stronę archiwum dla niestandardowego typu postu we wtyczce

11

Piszę wtyczkę, która tworzy niestandardowy typ postu o nazwie „my_plugin_lesson”:

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

Niestandardowy typ postu ma archiwum, a adres URL archiwum to:

http://example.com/lessons

Chcę dostosować wygląd tego archiwum; Chcę wyświetlić listę postów w formacie tabeli, a nie w standardowym archiwum postów na blogu WordPress. Rozumiem, że niestandardowy szablon archiwum można utworzyć w kompozycji, tworząc archive-my_plugin_lesson.phpplik; Chciałbym jednak, aby wtyczka działała z dowolnym motywem.

Jak mogę zmienić zawartość strony archiwum bez dodawania lub modyfikowania plików motywu?

Edycja: Rozumiem, że mógłbym użyć archive_templatehaka filtra. Wszystko to jednak polega na zastąpieniu szablonu motywu, który wciąż musi być specyficzny dla motywu. Na przykład, prawie każdy szablon tematem będzie potrzebne get_header, get_sidebaroraz get_footerfunkcje, ale co powinno id zawartości <div>być? W każdym temacie jest inaczej.

Chciałbym zastąpić samą treść własną treścią i użyć jej zamiast strony archiwum dla mojego niestandardowego typu postu.

Ben Miller - Pamiętaj Monikę
źródło

Odpowiedzi:

12

To, czego potrzebujesz, to przechwycenie template_includefiltra i selektywne załadowanie szablonu do wtyczki.

Jako dobrą praktykę, jeśli planujesz dystrybuować swoją wtyczkę, powinieneś sprawdzić, czy archive-my_plugin_lesson.php(a może myplugin/archive-lesson.php) istnieje w motywie, jeśli nie, użyj wersji wtyczki.

W ten sposób użytkownicy mogą łatwo zastąpić szablon motywem (lub motywem potomnym) bez edycji kodu wtyczki.

Jest to metoda używana przez popularne wtyczki, np. WooCommmerce, żeby powiedzieć tylko jedną nazwę.

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;
}

Więcej informacji na temat Codex dla

gmazzap
źródło
To wciąż zastępuje plik szablonu motywu, prawda? Co mam umieścić w pliku archive-lesson.php mojej wtyczki? Praca z każdym motywem musiałaby być inna. Nawet domyślne motywy „dwadzieścia” nie zgadzają się co do tego, jakie kontenery div / section otaczają treść.
Ben Miller - Pamiętaj Monikę
7

Możesz użyć archive_templatehaka do przetworzenia zawartości szablonu archiwum motywu, korzystając z poniższego schematu, ale oczywiście będziesz w stanie przetworzyć tylko ułamek motywów, biorąc pod uwagę, że szablon może zasadniczo zawierać dowolną starą rzecz .

Schemat polega na załadowaniu szablonu do ciągu ( $tpl_str) w archive_templatefiltrze, podstawieniu treści, dołączeniu ciągu (przy użyciu lewy eval( '?>' . $tpl_str );), a następnie zwróceniu pustego pliku, tak aby includew pliku „wp-include / template-loader.php” staje się zakazem.

Poniżej znajduje się zhakowana wersja kodu, którego używam we wtyczce, która jest skierowana do „klasycznych” szablonów, które używają get_template_parti bardziej dotyczy przetwarzania pojedynczych szablonów niż archiwizacji, ale powinna pomóc ci zacząć. Konfiguracja polega na tym, że wtyczka ma podkatalog o nazwie „szablony”, który zawiera pusty plik („null.php”) i szablony treści (np. „Content-single-posttype1.php”, „content-archive-postype1.php”) jak również szablon rezerwowy „single.php” dla pojedynczego przypadku i wykorzystuje niestandardową wersję tego, get_template_partktóry wygląda w tym katalogu.

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();

    // Adjust with your custom post types.
    $post_types = array( 'posttype1', );

    if ( is_single() || is_archive() ) {
        $template_basename = basename( $template );
        // This check can be removed.
        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 ) ) {
                // Allow user to override.
                if ( $single_template = myplugin_get_template( $slug, $post_type ) ) {
                    $template = $single_template;
                } else {
                    // If haven't gone through all this before...
                    if ( empty( $using_null[$slug][$post_type] ) ) {
                        if ( $template && ( $content_template = myplugin_get_template( 'content-' . $slug, $post_type ) ) ) {
                            $tpl_str = file_get_contents( $template );
                            // You'll have to adjust these regexs to your own case - good luck!
                            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] ) );
                                // This trick includes the $tpl_str.
                                eval( '?>' . $tpl_str );
                            }
                        }
                    }
                    if ( empty( $using_null[$slug][$post_type] ) ) {
                        // Failed to parse - look for fall back template.
                        if ( file_exists( MYPLUGIN_FOLDER . 'templates/' . $slug . '.php' ) ) {
                            $template = MYPLUGIN_FOLDER . 'templates/' . $slug . '.php';
                        }
                    } else {
                        // Success! "null.php" is just a blank zero-byte file.
                        $template = MYPLUGIN_FOLDER . 'templates/null.php';
                    }
                }
            }
        }
    }
    return $template;
}

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

Zwyczaj get_template_part:

/*
 * Version of WP get_template_part() that looks in theme, then parent theme, and finally in plugin template directory (sub-directory "templates").
 * Also looks initially in "myplugin" sub-directory if any in theme and parent theme directories so that plugin templates can be kept 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;
}

Dla kompletności oto cofnięty „single.php”, który używa niestandardowego 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
                    // If comments are open or we have at least one comment, load up the comment template
                    if ( comments_open() || '0' != get_comments_number() ) :
                        comments_template();
                    endif;
                ?>

            <?php endwhile; ?>

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

<?php get_sidebar(); ?>
<?php get_footer(); ?>
bonger
źródło
1

Zastanawiam się nad tym samym pytaniem i oto hipotetyczne rozwiązanie, które wymyśliłem:

  • Wewnątrz wtyczki utwórz krótki kod, który wyświetli pętlę archiwum zgodnie z oczekiwaniami.
  • Podczas tworzenia niestandardowego typu postu nie włączaj opcji „archiwizuj”.
  • Dodaj arkusz stylów, który kontroluje wszystkie style zawartości pętli.

Po aktywacji wtyczki utwórz stronę za pomocą wp_insert_post z nazwą typu posta i treścią shortcode.

Możesz podać opcje w krótkim kodzie dla dodatkowych rozważań dotyczących stylu lub dodać klasy do kontenera pocztowego, aby dopasować style specyficzne lub niestandardowe. Użytkownik może również dodawać dodatkową zawartość przed / po pętli, edytując stronę.

SkyShab
źródło
Mimo że nie jestem OP, szukałem rozwiązania tego samego problemu. Śledziłem twoje hipotetyczne rozwiązanie i mogę teraz potwierdzić, że działa również w praktyce.
Lucio Crusca
Hej, świetnie! Cieszę się, że było to przydatne dla kogoś. Zupełnie o tym zapomniałem.
SkyShab
0

Możesz użyć filtra single_template. Podstawowy przykład zaczerpnięty z Kodeksu :

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" );
Eyal
źródło
Myślę, że haczyk filtrujący dla szablonu archiwum jest archive_template, ale nie sądzę, że zadziała to, co próbuję zrobić. Zredagowałem swoje pytanie, podając więcej informacji.
Ben Miller - Pamiętaj Monikę