/mt-plugin-template-callback

Adding Template Callbacks feature - proof of concept

Primary LanguageJavaScript

Movable Type Plugin: Template Callbacks
---------------------------------------

This is a proof-of-concept plugin. It tries to re-define the relations between
templates, plugins and themes. 

1. It defines the concept of 'Callbacks' inside a template
2. let the theme declare 'theme variables', that are added to the templates on build
3. Opens the ability for content-plugins

The theme variables can be set under the Design->Appearance menu

It works for Static Publishing and Dynamic Publishing

-------------------------------------------------------------------------------
-------------------------------------------------------------------------------

Plugin Template Init
--------------------

For initializing the plugin, put in the head of each published template 
(either index or archive) the following tag:

<$mt:InitTemplateCallback screen="screen_name"$>

At the start of the template, please add these lines:

The screen name specifies in which page we are now. 
typlically is "main_index", or "entry" and so on

Without this tag, the callback tags will be ignored, and the theme variables won't
be added to the template variables

-------------------------------------------------------------------------------
-------------------------------------------------------------------------------

TAGS
----

If offers three tags:

<$mt:TemplateCallback name="callback name" [priority="5"] $>

This runs all the callbacks for the given name.
Examples for names: "verytop", "siderbar_primary sidebar_secondary".
Priority: can be either a number, (i.e. "5") or a range ("3..7"). 
Will execute only the callback with these priorities. If no priority is given, 
will execute all the callbacks for this callback name.

<mt:SetTemplateCallback name="callback name" [priority="5"] $>
   ... template code ...
</mt:SetTemplateCallback>

This set a callback for a given name, and priority. 
If no priority was given, 5 is the default.

<mt:AreCallbacksRegistred name="callback name">
</mt:AreCallbacksRegistred>

A conditional block, running only if any callback was registered for this name.

Callback Names
--------------

A typical callback name is: "publish.verytop.index".
It goes from the application, to the position, and to the specific page name.
In this case, callbacks registered to the following names will be run:
"publish", "publish.verytop" and "publish.verytop.index".

So callback registred to "publish.verytop" will appear in the very top 
of all the pages.

Registering a global Callback
-----------------------------

In your plugin directory, create directory: "tmpl/callbacks".

In this directory, the files sould be named "<cb_name>.<priority>.tmpl". i.e.

  publish.sidebar_primary.2.tmpl

Will register a callback for all blogs, callback name "publish.sidebar_primary",
priority "2".

Another example:

  publish.banner.entry.5.tmpl

Will be added to the banner only in the entry pages, with priority "5".

Registering a Callback on the DB
--------------------------------

Create and save a template object, with the following parameters:

  my $tmpl = $app->model('template')->new();
  $tmpl->type('t_callback');
  $tmpl->name('verytop.entry');
  $tmpl->blog_id(0);
  $tmpl->text('<h1>this is a callback</h1>');
  $tmpl->build_interval(5);
  $tmpl->identifier('publish');
  $tmpl->save() or die "failed to save tmpl";

Notes: 
* Name can also be "plugin_id::verytop.entry", which will be activated only if the plugin is installed.
* "blog_id" can be "0" or a specific blog number.
* The identifier specify for which application this callback is directed. currently, only 'publish' exists.

If this callback is setting-dependent, you can do it on setting-saving, in the following callbacks:

callbacks:
    MT::PluginData::pre_save: $Plugin::Module::plugin_data_pre_save
    save_config_filter.Plugin_Id: $Plugin::Module::register_callbacks

Where the first callback will work for older MT installations, and the second is prefered for new MT versions.

Widgets
-------

The widgets are automatically loaded into these callbacks: 
"publish.sidebar_primary" and "publish.sidebar_secondary", 
with priorities from "3" to "7". If there is only one sidebar, 
they will be mixed together, ordered by priority.

Note: this is the only case of callbacks with non-integer priority. oops.

The "mt:widgets" tag has another attribute: "callback". It is the name of the callback to load the widgets
on, and to excecute. If there are more then one callback in the attribute, the widgets will be loaded
on the first callback, and all the callbacks will be excecuted. Examples:

  <$mt:WidgetSet 
    name="<__trans phrase="3-column layout - Primary Sidebar">" 
    callback="sidebar_primary"$>
  <$mt:WidgetSet 
    name="<__trans phrase="2-column layout - Sidebar">" 
    callback="sidebar_primary sidebar_secondary"$>

If a callback attribute is not present, the widgets will be displayed normally, and no callback
will be called.

-------------------------------------------------------------------------------
-------------------------------------------------------------------------------

Declaring Theme Variables
-------------------------

In the theme.yaml file, under the 'elements' key, add the following lines:

elements:
    variables:
        component: TemplateCallback
        importer: theme_variables
        data:
            background_color:
                order: 100
                label: Background Color
                type: color
                default: red

This defines one variable, of type 'color', with label and default. All these keys are required.
(order, label, type and default) there might be other types that need / can accept more keys.

Declaring Color Theme variable
------------------------------

Good for: background color, banner color, font color, and so on

            background_color:
                order: 100
                label: Background Color
                type: color
                default: red

the default can be either a CSS color name, or in hex format, i.e. #330099

Declaring Image Theme variable
------------------------------

Good for: banner image, user picture

            banner_image:
                order: 200
                label: Banner Image
                type: image
                default: '%ss/banner.jpg'
                size: 'w:940 h:198'

The default image should be part of the theme, and must be of the expected size
If it is under the 'static' directory, it should start with "%ss/". If it is under
the 'blog_static' directory, it should start with "%bs/"

If the user supplies an image that does not fit the expected size, it will be scaled
to the requied size. (TODO: make something more advanced then that)

Declaring Checkbox Theme variable
---------------------------------

Good for: yes/no questions

            is_up:
                order: 300
                label: Is Up?
                type: checkbox
                default: 1

the default should be 1 or 0

Declaring Radio button / Dropdown Theme variable
------------------------------------------------

Good for: multiple options, such as in which side to put the widgets, different layouts
and so on.

            which_side:
                order: 400
                label: Which side
                type: dropdown
                default: up
                choices:
                    up: Up
                    down: Down
                    left: left
                    right: Right

the default should be one of the choices. 
In the choices, the user is displayed the values, and the theme variable contains the key. 
So in this case, the user will select 'Down', and the 'which_side' variable will contain 'down'.

putting 'radio' instead of 'dropdown' will create radio buttons.

-------------------------------------------------------------------------------
-------------------------------------------------------------------------------

Content Plugins
---------------

This gives plugins the ability to have plugin-data inside the body of an entry,
that will be inflated to true HTML code when the entry is published (on static
publishing) or viewed (on Dynamic Publishing)

For this to work, the plugin needs to add to the body the following HTML code:

  <div class="mtplugin mtplugin_<plugin name>">
    <div class="plugin_internal_data" ...attributes...>
      ...plugin data...
    </div>
  </div>

Anything that is inside the mtplugin div, but outside the plugin_internal_data
div is considered edit-time information and will be discard on save.
So you can add controls and previews, that will not be showed on the published 
entry.

For registering the publish-time replacement, add in your config.yaml file:

tags:
  content:
    <plugin name>: $Plugin::Perl::Module::handler

If a matching div is found in the entry one publish, this handler will be called
using these parameters:

  $str = handler($app, $ctx, $plugin_name, $content, \@args)

Where $content includes whatever was inside the plugin_internal_data div, and 
@args contains pairs of [key, value] of the attributes of the same div

The whole mtplugin div will be replaced with the output of the handler function.
If there is no such handler function registered, the div will be deleted.

Controling the plugin divs replacement
--------------------------------------

By default, these plugins will be only active for the EntryBody, EntryMore tags
and their Page equivalents. However, you can turn this on for other tags as well
using this modifier:

  content_plugins="1"

Also, for the EntryBody/More tags, setting it to zero will disable the plugin
operation:

  content_plugins="0"

-------------------------------------------------------------------------------
-------------------------------------------------------------------------------

Included Themes
---------------

The attached themes are a copy of the "classic blog" and "website" themes supplied by
default with Movable Type. They were modified to support callbacks.

The following callbacks are used:
before_content, after_content, above_footer, footer, verybottom, 
verytop, banner, below_banner, htmlhead, between_content.entry_summary,
sidebar_secondary, sidebar_primary, after_content, before_content

The following screen-names are used:
archive_index, category_entry_listing, comment_preview, comment_response, dynamic_error, 
entry, main_index, monthly_entry_listing, page search_results.

-------------------------------------------------------------------------------
-------------------------------------------------------------------------------

TODO
----

In Dynamic Publishing, add support for ignoring callbacks from plugins that were uninstalled or deactivated.