如何从插件向页面模板列表中添加选项?


10

在过去的几个小时中,我一直在寻找一种从插件中创建自定义页面模板的方法,但是还没有运气。

我专门想做的是在编辑页面时将选项添加到可用页面模板列表中,而不使用其他方法,例如if( is_page( 'page-slug' ) ) { /* etc */ }

是否可以修改全局变量来执行此操作?

编辑:

我目前正在使用此代码,基于@ m0r7if3r在评论中给我的链接,问题是它将在查看页面时运行此功能,但在编辑页面时不运行(用页面模板填充下拉列表) :

class JW_SiteGrader {

    private static $instance;

    private function __construct() {


        add_action( 'template_redirect', array( &$this, 'sitegrader_template_redirect' ), 20 );

    }

    public static function getInstance() {

        // Return the class data in a Singleton fashion
        if (self::$instance == null)
            self::$instance = new JW_SiteGrader();
        return self::$instance;

    }

    public function sitegrader_template_redirect() {

        add_filter( 'page_template', array( &$this, 'sitegrader_page_template' ), 10, 1 );

    }

    public function locate_plugin_template( $template_names, $load = false, $require_once = true ) {

        if ( !is_array( $template_names ) )
            return '';

        $located = '';

        $this_plugin_dir = WP_PLUGIN_DIR . '/' . str_replace( basename( __FILE__ ), '', plugin_basename( __FILE__ ) );

        foreach ( $template_names as $template_name ) {

            if ( !$template_name )
                continue;

            if ( file_exists( STYLESHEETPATH . '/' . $template_name ) ) {

                $located = STYLESHEETPATH . '/' . $template_name;
                break;

            } else if ( file_exists( TEMPLATEPATH . '/' . $template_name ) ) {

                $located = TEMPLATEPATH . '/' . $template_name;
                break;

            } else if ( file_exists( $this_plugin_dir .  $template_name ) ) {

                $located =  $this_plugin_dir . $template_name;
                break;

            }

        }

        if ( $load && '' != $located )
            load_template( $located, $require_once );

        return $located;
    }

    public function sitegrader_page_template( $template ) {

        $object = get_queried_object();

        if ( 'page' == $object->post_type ) {

            // New 
            $templates[] = "page-sitegrader.php";
            // Like in core
            $templates[] = "page-{$object->post_type}.php";
            $templates[] = "page.php";

            return locate_template( $templates );  

        }

        // return apply_filters('page_template', $template);
        return $template;
    }

}

编辑2:

似乎该功能将在将来的更新中发布,我阅读了许多有关此问题的跟踪记录,并且进行了一些讨论,但没有真正的答案(希望获得3.4)。稍后将在此列出追踪票的URL。

编辑3:

上面的代码有效,但是,这时我唯一遇到的问题是在编辑/添加新页面时,没有模板被添加到下拉列表中。我正在尝试一些事情,很快就会更新我的问题。


2
您是否尝试过类似这样
mor7ifer 2012年

@ m0r7if3r(如果您尝试这样做,请留言如何解决-谢谢!)
kaiser 2012年

@kaiser我尝试了他推荐的代码,唯一缺少的链接是让meta框将模板添加到下拉列表中(据我所知!)。
贾里德

@Jared请看对这个答案的回答,该答案类似于a底部的类似Q和相关的追踪票。给您的代码添加广告)如果未在每个页面上都显示该代码,则说明您使用了错误的钩子来运行实例。您正在使用哪个挂钩?
kaiser

@kaiser我正在使用该page_template钩子,上面编辑中的代码是当前正在使用的代码。我是否需要使用template_redirect挂钩,然后page_template在其中添加过滤器?
贾里德

Answers:


4

过滤器?任何人?

那里没有过滤器可以帮助您:page_template_dropdown($template);用于构建下拉列表,并且不可过滤。

潜入模板数组?

要构建下拉菜单内容,核心meta框使用get_page_templates()。从内部看,该函数如下所示:

$themes = get_themes();
$theme = get_current_theme();
$templates = $themes[$theme]['Template Files'];

但是当调查时get_themes();,接缝不可能拦截模板列表。此外,我们还有一个问题,那就是没有机会从主题目录之外获取模板…

...假装主题!

理论及其弊端……

您可以register_theme_directory()用来添加其他主题目录,您可以在其中放置模板。因此,最简单的方法就是将您的插件也注册为主题文件夹:

// Register during init hook:
register_theme_directory( plugin_dir_path( __FILE__ ).'templates' );

注意:这是我不确定是否可以使用的地方

在插件激活期间: 然后,您应该在style.css.php文件templates夹中放置一个文件。这将允许您将变量添加到文件中。然后,此变量将成为父主题。父主题应该只是当前活动的主题。然后将您的活动主题更新为插件。

缺点2: 关于»Appearance«UI ...也许要注意,该“ Theme”不是要用作实际主题。我将剩下的“避免激活此主题”内容留给您自己的想象。无论如何:它应该起作用。

缺点2:技巧将成功避免出现子主题。您可以有一个父主题。而已。


因此,我猜测没有任何实际方法可以使用任何非活动主题的自定义页面模板,对吗?我可以注册一个主题目录,但是除非该主题处于活动状态,否则无法使用这些模板。
贾里德

1
并不是的。只是不应该如此,因此缺乏核心。您是否尝试过以上指向ipstenu的链接?我已经尝试过这条路线,但是以另一种方法失败了。最好的选择是跟随票证,无论您身在何处都可以推入并链接它们。:/
kaiser 2012年

2

作为可能的解决方法的建议,您是否考虑过使用WordPress文件系统将页面模板文件从插件写入当前的活动主题目录?根据您希望对该过程进行多少控制,可以让您的插件在激活时写入文件,并在卸载时将其删除。或者,您可以使用格式传递某些值(例如将显示在后期编辑屏幕的下拉框中的页面模板名称),从插件UI中动态创建页面模板文件。从理论上讲,您也可以单击按钮从插件UI内删除页面模板,并类似地添加多个模板以实现不同的目的。Otto的博客上有一篇关于使用文件系统的好文章。我现在没有链接,但您可以搜索它。

我希望他们在下一个核心版本中通过钩子发布您打算做的事情。


1
我以前有一种完全像这样的方法,但是尝试时又遇到了很多问题,因为当用户切换主题时,它不会删除模板文件,并且如果他们要复制其活动主题并将其放在另一个站点上,他们将冒上传无法使用的自定义模板文件的风险。我知道有几种解决方法,但是我真的希望这是自动的。+1的建议。
杰瑞德

1
嗨,Jared,我也担心同一问题。我唯一想进一步扩展此替代方法的解决方案是,在激活插件时获得当前主题的名称,然后,如果用户停用/切换主题,则可以从该主题删除模板文件并将其重写为新激活的模板文件。主题。看一下此链接,他在那里创建了自己的激活/停用钩子以检查主题。加上一些额外的代码,我觉得这是可行的。
亚当

绝对,我认为这可能有效。我会尝试一下并将结果发布在我的问题中。感谢您的链接,它会有所帮助!
杰瑞德(Jared)

1

我浏览了源代码,令人震惊的是,似乎没有办法做到这一点!我建议的技巧是添加带有主题覆盖/第二个主题下拉列表的第二个meta框。然后挂接到此过滤器中:

# wp-includes/theme.php line 751 in 3.3.1:
return apply_filters( "{$type}_template", locate_template( $templates ) );

返回您的主题文件(如果已被覆盖)。当然,如果只需要add_filter,则只需要它即可。

如果您想花哨的话,可以将原始包装箱刮掉并重新创建(当然可以通过过滤器,而无需修改核心代码)。

我还建议添加一个要求该功能的追踪票(如果那里尚无此)。


1
同意w /建议这样做。
helgatheviking 2012年

它似乎已经在跟踪中
Jared

1
我只是针对单篇文章类型模板调查了另一个问题。您可以在答案的末尾找到Trac门票。我们希望有3.4。
kaiser 2012年

1

过去,我已经通过删除默认的页面模板metabox并添加自己的metabox来实现了这一目标。我让新的metabox使用内置的get_page_templates,然后以编程方式添加了我需要的其他metabox。在保存时,它可以像wordpress一样更新页面模板。


您介意显示完整代码吗?目前,这只是一个粗糙的概念。谢谢。
kaiser 2012年


-2

使用DuckDuckGo的搜索结果添加了一个wordpress页面模板,在名为WordPress自定义页面模板教程的wpmu.org页面上为我找到了答案。

本质上,在主题目录wp-content / themes / your-theme中,将现有页面模板复制到您选择的新php文件名中。编辑新文件,请注意在文件顶部的注释中更改神奇的“模板名称:”属性值。

这就是全部。这可能是使问题过时的功能。我正在使用带有二十一十一主题的WP 3.5。

也可能有更干净的方法来扩展主题。这样的编辑可能会被主题更新覆盖。Mea Culpa。


我需要一种解决方案,将模板从插件(而不是主题)添加到下拉列表中。:(
贾里德
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.