Report abuse

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
sub load_tmpl {
    my $self = shift;
    my $app = MT->instance;
=item

    ### SUMMARY 

    My plugin-created MT::App::CMS subclass requires the use of the 
    Transformer callbacks in order to modify the left nav of the system
    menu and they work perfectly well for any mode served by MT::App::CMS.
    However, any modes served by my plugin app do not exhibit the
    Transformations.
    
    Why?  Because plugin modes are generated using the load_tmpl method in
    MT::Plugin which, for some reason, lacks the Transformer callbacks found
    in MT::App::load_tmpl. (Actually, I am guessing the reason is because
    most plugins bootstrap their own apps instead of subclassing an MT::App
    and masquerading as that app, adding methods and using the apps
    templates.)
    
    Unfortunately, plugins can not easily use MT::App::load_tmpl because that
    function doesn't register the tmpl directory in the plugin envelope like
    MT::Plugin's version.  What's more, there's no way to pass in a paramter
    to MT::App::load_tmpl to add the directory to the search path.


    ### QUESTIONS

      * Why doesn't MT::Plugin->load_tmpl allow for Transformer callbacks
        when my plugin is an MT::App::CMS subclass?

      * Why doesn't MT::App->load_tmpl allow prepending of tmpl paths onto
        its search array?


    ### MAKING MT::App::load_tmpl FIND THE PLUGIN'S TMPL DIRECTORY
    
    So I found an awesome hack in the HTML::Template POD docs to take care
    of the problem of MT::App::load_tmpl not finding the plugin tmpl
    directory: the HTML_TEMPLATE_ROOT environment variable.  
    
    The value of HTML_TEMPLATE_ROOT is recognized by HTML::Template's
    internal methods and **prepended to the search paths array** giving it
    priority over the MT::App::CMS templates in the fallback order.

        my $tmpl;
        {
            local $ENV{HTML_TEMPLATE_ROOT} = 
                File::Spec->catdir($app->mt_dir,
                                   $plugin->envelope, 
                                   'tmpl');
            $tmpl = $app->load_tmpl(@_);
        }

    Benefits:
    
        * Can be lexically scoped so as not to interfere with the template
          loading of identically named templates by other plugins or the app
          itself.
        * No code hacking necessary
        * Native, documented functionality of HTML::Template

    Problems:
    
        * In some environments, this variable may not be settable or may be 
          purposefully set to another value.
        * The default template parameters in MT::App are specific to the
          MT::App's and often less correct than those in MT::Plugin, even
          when the plugin app is a subclass of MT::App::CMS.
    
    ### ENABLING TRANSFORMER CALLBACKS IN MT::Plugin

    After staring at the code long enough, I saw that it was actually quite 
    simple to enable the Transformer callbacks in plugin-created modes with
    templates loaded by MT::Plugin::load_tmpl.

    To do so, you simply add the same filter param that can be found in
    MT::App::load_tmpl to the load_tmpl arguments, like so:
    
=cut
    push(@_, filter => sub {
            my $fname = $HTML::Template::this_file;
            if ($fname) {
                $fname = File::Basename::basename($fname);
                $fname =~ s/\.tmpl$//;
                $app->run_callbacks(ref($app) . "::AppTemplateSource.$fname",
                                    $app, $_[0]);
            } else {
                $app->run_callbacks(ref($app)."::AppTemplateSource",
                                    $app, $_[0]);
            }
            $_[0];
        });

    # At this point, we can now call MT::Plugin (the superclass) and 
    # have our callback triggered.
    my $tmpl = $self->SUPER::load_tmpl(@_);

=item
    Benefits:

        * Uses MT's own functions and should be consistent in all environments
        * Could be switched on and off on a per page basis if you liked
        * Plugin now inherits all of MT::Plugin's default template params

    Problems:

        * Can't see any at the moment.

=cut

    # Add any parameters necessary for this plugin. e.g.
    #   $tmpl->param(add_showhidejs => 1) if $MT::VERSION == '3.2';

    $tmpl;
}