在插件中为自定义帖子类型创建自定义存档页面


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_headerget_sidebarget_footer功能,但应该是什么内容的ID <div>是什么?每个主题都不同。

我想做的是用我自己的内容替换内容本身,并用它代替存档页面作为我的自定义帖子类型。

Answers:


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

有关Codex的更多信息,


这仍然只是替换主题的模板文件,对吗?我在插件的archive-lesson.php文件中放什么?处理每个主题都需要有所不同。甚至默认的“二十”主题也不同意围绕内容的div / section容器。
本·米勒

7

您可以archive_template通过以下方案使用该钩子来处理主题的存档模板的内容,但是显然,您只能处理其中一部分主题,因为模板基本上可以包含任何旧内容。 。

该方案是将模板加载到过滤器中的字符串($tpl_str)中archive_template,替换您的内容,包括该字符串(使用技巧eval( '?>' . $tpl_str );),然后返回一个空白文件,以便include在“ wp-includes / template-loader.php”中成为空手。

以下是我在插件中使用的经过修改的代码版本,该代码版本针对使用的“经典”模板,get_template_part并且与存档相比更关注处理单个模板,但应该可以帮助您入门。设置是插件有一个名为“模板”的子目录,该子目录包含一个空白文件(“ 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创建一个页面,其名称为发布类型,内容为简码。

您可以在简码中提供选项以用于其他样式注意事项,或者将类添加到帖子容器中以匹配特定于主题或自定义样式。用户还可以通过编辑页面在循环之前/之后添加其他内容。


尽管我不是OP,但我一直在寻找解决同一问题的方法。我已经遵循了您的假设性解决方案,现在我可以确认它也可以在实践中使用。
路西欧·克鲁斯卡

嘿,太好了!很高兴这对某人有用。我完全忘记了这一点。
SkyShab '16

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,但我认为这对我想做的不起作用。我已经用更多信息编辑了我的问题。
本·米勒
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.