来自插件文件夹的自定义帖子类型模板?


57

我想提供自定义帖子类型作为插件,以便人们可以使用它而无需触摸主题文件夹。但是自定义帖子类型模板(例如single-movies.php)位于主题文件夹中。有没有办法让WP检查插件文件夹中的single-movies.php?将函数挂接到Filer层次结构中?或get_template_directory(); ?

Answers:


90

您可以使用single_template过滤器挂钩。

/* Filter the single_template with our custom function*/
add_filter('single_template', 'my_custom_template');

function my_custom_template($single) {

    global $post;

    /* Checks for single template by post type */
    if ( $post->post_type == 'POST TYPE NAME' ) {
        if ( file_exists( PLUGIN_PATH . '/Custom_File.php' ) ) {
            return PLUGIN_PATH . '/Custom_File.php';
        }
    }

    return $single;

}

很棒的答案。请分享我是否可以获取所有模板可用的钩子,例如single_template。
Gowri

6
@gowri过滤器由get_query_template()函数调用。这是一个变量钩子,因此第一部分{$type}_template根据传递给该函数的参数而变化。参见wp-includes / template.php了解一些常见的内容
Shea,

本教程介绍了single_template挂钩,并提供了很好的解释。一旦理解了这些钩子,@shea的注释就建议使用一种比@Bainternet的答案更简单的方法,add_filter( 'single-movies_template', 'my_custom_template' );如链接教程中所述。(此问题仅适用于新答案,因此我不能
单独

2
您可以替换PLUGIN_PATHplugin_dir_path( __FILE__ ),然后从文件名中删除第一个斜杠。完整路径如下所示:return plugin_dir_path( __FILE__ ) . 'Custom_File.php';
Frits

1
PLUGIN_PATH扔了一个错误,这里是一个伟大的职位,显示了如何做到这一点,它为我工作开箱:wpsites.net/free-tutorials/...
弥敦道

22

更新的答案

更干净,更短的版本。

function load_movie_template( $template ) {
    global $post;

    if ( 'movie' === $post->post_type && locate_template( array( 'single-movie.php' ) ) !== $template ) {
        /*
         * This is a 'movie' post
         * AND a 'single movie template' is not found on
         * theme or child theme directories, so load it
         * from our plugin directory.
         */
        return plugin_dir_path( __FILE__ ) . 'single-movie.php';
    }

    return $template;
}

add_filter( 'single_template', 'load_movie_template' );

旧答案

在主题文件夹中的@Brainternet答案中添加了对自定义帖子类型特定模板的检查。

function load_cpt_template($template) {
    global $post;

    // Is this a "my-custom-post-type" post?
    if ($post->post_type == "my-custom-post-type"){

        //Your plugin path 
        $plugin_path = plugin_dir_path( __FILE__ );

        // The name of custom post type single template
        $template_name = 'single-my-custom-post-type.php';

        // A specific single template for my custom post type exists in theme folder? Or it also doesn't exist in my plugin?
        if($template === get_stylesheet_directory() . '/' . $template_name
            || !file_exists($plugin_path . $template_name)) {

            //Then return "single.php" or "single-my-custom-post-type.php" from theme directory.
            return $template;
        }

        // If not, return my plugin custom post type template.
        return $plugin_path . $template_name;
    }

    //This is not my custom post type, do nothing with $template
    return $template;
}
add_filter('single_template', 'load_cpt_template');

现在,您可以让插件用户将模板从插件复制到其主题以覆盖它。

在此示例中,模板必须位于插件和主题的根目录中。


1
在我看来,使用locate_template而不是get_stylesheet_directory听起来更干净的选项(请参见:code.tutsplus.com/tutorials/…)。
菲利克斯(Felix)2016年

1
更新的答案无效,接受的答案(或您的旧答案)有效。
爱德华

2
你是对的,@ Edward,那是可怕的更新。我根据Felix的建议再次对其进行了更新。也是这次,我在发布代码之前测试了代码:)
campsjos 18'Apr

4

我想指出的是,当您使用过滤器方法时,对过滤器进行优先级排序非常重要,如下所示:

add_filter('single_template', 'my_custom_template', 99);

如果您不这样做,则有时WP会尝试在此过滤器之后重新检查。正因为如此,将我的头发拉了大约2个小时。


0

我正在为插件使用一种更好的方法。

正如@campsjos 在这里提到的那样,您可以检查locate_template将要签入主题覆盖模板文件的文件,而不是检查文件是否存在。这是很明显的。

function my_plugin_templates() {
    if (is_singular('movie')) {
        if (file_exists($this->template_dir . 'single-movie.php')) {
            return $this->template_dir . 'single-movie.php';
        }
    }
}

使用template_include筛选器挂钩加载以上代码。

add_filter('template_include' , 'my_plugin_templates');

0

感谢此页面,我能够为我解决相同的问题。

供参考,这就是我最终得到的:

function pluginName_myposttype_single_template($single_template) {
  $myposttype_template = PLUGIN_DIR . 'templates/single-myposttype.php';
  return get_post_type() === 'myposttype' && file_exists($myposttype_template) ? $myposttype_template : $single_template;
}
add_filter('single_template', 'pluginName_myposttype_single_template');

{$ type} _template过滤器挂钩对我不起作用

function pluginName_myposttype_single_template($single_template) {
  $myposttype_template = PLUGIN_DIR . 'templates/single-myposttype.php';

  if ( file_exists($myposttype_template) ) {
    $single_template = $myposttype_template;
  }
  return $single_template;
}
add_filter('single-myposttype_template', 'pluginName_myposttype_single_template');

-2

上面是一个很好的答案,但是检查$ single var允许模板覆盖由主题/子主题提供的模板。

/* Filter the single_template with our custom function*/
add_filter('single_template', 'your_cpt_custom_template');

function your_cpt_custom_template( $single ) {
    global $wp_query, $post;
    /* Checks for single template by post type */
    if ( !$single && $post->post_type == 'cpt' ) {
        if( file_exists( plugin_dir_path( __FILE__ ) . 'single-cpt.php' ) )
            return plugin_dir_path( __FILE__ ) . 'single-cpt.php';
    }
    return $single;
}

1
这不会检查在子级或主题中是否存在single-cpt.php。它仅检查将始终出现在任何主题中的single.php。
newpxsn

没错,当我写这篇文章时,我使用的是一个纯粹的主题,必须有更好的方法!
DigitalDesignDj
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.