Создайте пользовательскую страницу архива для пользовательского типа сообщения в плагине

11

Я пишу плагин, который создает пользовательский тип записи с именем "my_plugin_lesson":

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

Пользовательский тип записи имеет архив, а URL-адрес архива:

http://example.com/lessons

Я хочу настроить внешний вид этого архива; Я хочу перечислить сообщения в табличном формате, а не в стандартном архиве сообщений блога WordPress. Я понимаю, что пользовательский шаблон архива может быть создан в теме путем создания archive-my_plugin_lesson.phpфайла; Тем не менее, я хотел бы, чтобы плагин работал с любой темой.

Как я могу изменить содержимое страницы архива без добавления или изменения файлов темы?

Изменить: я понимаю, что я мог бы использовать archive_templateфильтр крючок. Однако все, что это делает, это заменяет шаблон темы, который все еще должен быть специфичным для темы. Например, почти каждому шаблону темы потребуются функции get_header, get_sidebarи get_footer, но каким должен быть идентификатор контента <div>? Это отличается в каждой теме.

То, что я хотел бы сделать, это заменить сам контент своим собственным контентом и использовать его вместо страницы архива для моего пользовательского типа поста.

Бен Миллер - Помни Монику
источник

Ответы:

12

Что вам нужно, это подключить template_includeфильтр и выборочно загрузить ваш шаблон внутри плагина.

В качестве хорошей практики, если вы планируете распространять свой плагин, вы должны проверить, существует ли archive-my_plugin_lesson.php(или, возможно, myplugin/archive-lesson.php) в теме, если не использовать версию плагина.

Таким образом, пользователи могут легко заменить шаблон через тему (или дочернюю тему) без редактирования кода плагина.

Это метод, используемый популярными плагинами, например, WooCommmerce, просто чтобы сказать одно имя.

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

Больше информации о Кодексе для

Gmazzap
источник
Это по-прежнему просто заменяет файл шаблона темы, верно? Что я помещаю в файл archive-lesson.php моего плагина? Это должно быть по-разному, чтобы работать с каждой темой. Даже стандартные темы «Двадцать» не согласны с тем, какие контейнеры div / section окружают контент.
Бен Миллер - Помните, Моника
7

Вы можете использовать archive_templateловушку для обработки содержимого архивного шаблона темы, используя схему ниже, но очевидно, что вы когда-либо сможете обработать только часть тем, учитывая, что шаблон может в основном содержать любую старую вещь. ,

Схема состоит в том, чтобы загрузить шаблон в строку ( $tpl_str) в archive_templateфильтре, заменить ваш контент, включить строку (используя трюк eval( '?>' . $tpl_str );), а затем вернуть пустой файл, чтобы includeв «wp-includes / template-loader.php» становится неоперативным.

Ниже приведена взломанная версия кода, которую я использую в плагине, который нацелен на «классические» шаблоны, которые используют get_template_partи больше занимается обработкой отдельных шаблонов, чем архивом, но должен помочь вам начать работу. Настройка заключается в том, что плагин имеет подкаталог с именем «templates», в котором содержится пустой файл («null.php») и шаблоны содержимого (например, «content-single-posttype1.php», «content-archive-postype1.php»). а также запасной шаблон "single.php" для отдельного случая и использует пользовательскую версию, get_template_partкоторая выглядит в этом каталоге.

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

Обычай 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;
}

Для полноты вот запасной вариант "single.php", который использует кастом 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(); ?>
Бонгер
источник
1

Я размышлял над тем же вопросом, и вот гипотетическое решение, которое я нашел:

  • Внутри плагина создайте шорткод, который выводит ваш архивный цикл так, как вы хотите.
  • При создании пользовательского типа записи не включайте опцию «архив».
  • Добавьте таблицу стилей, которая управляет всеми стилями содержимого вашего цикла.

После активации плагина создайте страницу, используя wp_insert_post с именем, являющимся типом поста, а контентом - шорткодом.

Вы можете предоставить опции в шорткоде для дополнительных стилевых соображений или добавить классы в почтовый контейнер, чтобы соответствовать конкретным или пользовательским стилям темы. Пользователь также может добавить дополнительный контент до / после цикла, отредактировав страницу.

SkyShab
источник
Несмотря на то, что я не ОП, я искал решение той же проблемы. Я следовал вашему гипотетическому решению и теперь могу подтвердить, что оно работает на практике.
Лусио Круска
Эй, отлично! Рад, что это было полезно для кого-то. Я полностью забыл об этом.
SkyShab
0

Вы можете использовать фильтр single_template. Основной пример взят из Кодекса :

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" );
Эяль
источник
Я думаю, что фильтр-фильтр для архивного шаблона есть archive_template, но я не думаю, что это сработает для того, что я пытаюсь сделать. Я отредактировал свой вопрос с дополнительной информацией.
Бен Миллер - Помните, Моника