====== Template Extension for Command Plugin ======
---- plugin ----
description: Render a data set from a template.
author : Spider Joe
email : http://www.spiderjoe.com
type :
lastupdate : 2005-09-09
compatible :
depends : command
conflicts :
similar :
tags : extension, command, template
----
===== Overview =====
The **Template Command** renders a data set from a template. The data set is just a [[DokuWiki]] page containing a series of lists representing records ([[http://www.spiderjoe.com/spiders/calendar?do=edit|example]]). The template is a PHP file in ''lib/tpl/'' that generates either HTML or DokuWiki [[syntax]] for inclusion at the place of the template command ([[http://www.spiderjoe.com/spiders/calendar|example]]). The command is an extension of the [[plugin:command|Command Plugin]], requiring that plugin and implementing a command of that plugin.
This command is useful for...
* Representing data in [[DokuWiki]] separately from its formatting.
* Applying repetitive formatting to each of multiple data items.
* Generating rich HTML for inclusion in a [[DokuWiki]] page.
* Expressing [[DokuWiki]]-maintained data in rich HTML.
The command defines a kind of page called a //data page//. A data page is just a series of DokuWiki [[syntax#lists|lists]] delimited by horizontal rules. Each list represents a record, and each item in a list represents a field of the record.
A template command takes optional parameters, a template file name, and the name of a data page. Here are some example uses:
#template(news.php|health:news updates)#
#template?category=health(news.php|news:records)#
#template(mla.php|article references)#
#template(calendar.php|calendar:events)#
#template?from=2004-1-1&to=2005-1-1(calendar.php|calendar:events)#
#template?_cache(calendar.php|calendar:events)#
The parameters are handed to the template file, allowing for parameterized templates. The template file may produce either HTML or DokuWiki [[syntax]] that is in turn translated to HTML --- which ever is easiest for the template writer.
Here are two demo pages that are generated by this command:
* [[http://www.spiderjoe.com/spiders/calendar|Spider Calendar]]
* [[http://www.spiderjoe.com/spiders/oak-hill|Spiders of Oak Hill]]
===== Modification History =====
* 2005/08/30 --- Created. [[http://www.spiderjoe.com|Spider Joe]]
* 2005/08/31 --- Was breaking RSS feed, which couldn't output headers. To fix, I now use PHP's built-in output buffer nesting. [[http://www.spiderjoe.com|Spider Joe]]
* 2005/09/09 --- Added the ability to put the data set directly in the command. [[http://www.spiderjoe.com|Spider Joe]]
* 2005/09/09 --- Fixed another problem with RSS. template() was not available. [[http://www.spiderjoe.com|Spider Joe]]
===== Installation =====
To install this command, first make sure you have a recent version of the [[plugin:command|Command Plugin]] installed. Then save the provided [[#source]] file with filename ''template.php'' in the following directory:
/lib/plugins/command/ext/
You now need to create a template file and a data file, and then you're ready to try the command.
====== Syntax =====
The Template command conforms to the [[plugin:command|Command Plugin]] syntax. In particular, it takes one of the following forms:
* ''%%#template(template.php|data page)#%%''
* ''%%#template?_cache(template.php|data page)#%%''
* ''%%#template?parameters(template.php|data page)#%%''
* ''%%#template?_cache¶meters(template.php|data page)#%%''
* ''%%#template(template.php|... Your data set goes here)#%%''
As described in the [[plugin:command|Command Plugin]], the command name 'template' is not case sensitive, and the above syntax places the generated HTML outside of paragraphs, while ''%% %template()% %%'' syntax embeds the generated HTML in a paragraph (the current paragraph). The ''%'' notation is called //inline embedding// and the ''#'' notation is called //block embedding//.
==== Command Name ====
Each extension of the [[plugin:command|Command Plugin]] has a unique command name. This command takes the name **TEMPLATE**.
==== Parameters ====
The values that may follow the ''?'' in a [[plugin:command|Command Plugin]] command are called parameters. This command accepts optional parameters. Only one parameter affects the behavior of the command, independently of the template:
* ''_cache'' (optional): Cache the page that contains the command. When present, the containing pages won't reflect data page changes until it is resaved. When absent, the containing page is never cached, so that the page automatically remains accurate. The server does more work per page access when caching is off.
All additional parameters are passed straight to the template file. This allows a template file to be designed so that each use of the template command can uniquely filter or format the data of a data page.
==== Content ====
The text that the user inserts between the opening ''('' and closiing '')'' parentheses of a [[plugin:command|Command Plugin]] is called the //content//. For example, in ''%% %template(format.php|ns:data)% %%'', the content is ''%%format.php|ns:data%%''. The content of the template command must have one of the following two formats:
template_file|data_page
template_file|... data_set
* ''template_file'' --- The name of the PHP template file. This file typically has extension ''.php''. The extension must be included. The command looks for the template file in the active ''lib/tpl/'' directory (e.g. ''lib/tpl/default/''); ''template_file'' is a path relative to this directory. The characters "''..''" may not be included in the path name.
* ''data_page'' --- The name of the data page. This name must be namespace-qualified if the data page resides within a namespace.
* ''data_set'' --- The data set to use. Instead of putting the data set in a separate page, you may put '%%...%%' into the command and follow it with the actual data set that would otherwise go in a separate data page.
===== Data Page Format =====
A data page is a page that represents a set of records. Each record is a DokuWiki [[syntax#lists|list]], and each item of the list provides a field of the record. Multiple records are delimited with the horizontal rule, denoted in the DokuWiki [[syntax]] by "''%%----%%''".
Here is an example data page:
Any text you put before the first list item of record is ignored. This is a good place to describe the data page or to describe the next record.
* date: 2005-7-31
* category: DokuWiki
* page: [[http://www.meganews.com?id=12345|DokuWiki has done it again!]]
* abstract: The amazing **Andi Gohr** has produced a [[plugin:gallery|gallery plugin]] to die for.
----
* date: 2005-8-30
* category: Spiders
* page: [[http://www.spiderjoe.com/spiders/oak-hill/mrs-featherlegged|Mrs. Fanged Featherlegged]]
* abstract:
Of the 900 or so species of spiders living in Texas, only seven lack poison glands. One of these spiders raised a family beside the dog house in my back yard.
* follow up:
----
Again, text you put before the first list item is ignored, so you can describe the record.
* date: 2000-1-1
* #category: Warnings --- the # comments out a field
* category: Catastrophies
* page: [[http://www.meganews.com?id=666|Armageddon finally occurs]]
* abstract:
We'd been waiting for it for centuries and now it has finally happened. **Armageddon** has finally occurred.
Read all about it from the comfort of your home, at your fancy multimedia computer.
* follow up: The world was reborn, minds were erased, and we were given another shot. Next Armaggedon: Year 2100. Click [[http://runwithfear.com/go|here]] to run with fear.
----
Empty records are ignored.
This example isn't exactly pretty, as it's meant to demonstrate the variety of formatting that the template command will accept.
Each list item represents a field and has the following format:
* field_name: field_value
multi_para_value
* ''field_name'' --- The name of the field. It may contain any character other than the colon. If preceded by a ''#'', the field and its value is ignored, even if the value is given by a ''multi_para_value''.
* ''field_value'' (optional) --- The value of the field, expressed in a single line. If neither a ''field_value'' nor a ''multi_para_value'' is provided, the field value is an empty string.
* ''multi_para_value'' (optional) --- A long representation of the field value, allowing it to include multiple paragraphs. Generally, one should only provide either a ''field_value'' or a ''multi_para_value'', but not both.
Text that appears before the first list item of a record is ignored and may be used to comment the page or the record. Note that DokuWiki needs a blank line before each horizontal rule. Records not containing any list items are ignored and are not handed to the template. This happens when two horizontal rules appear back-to-back or when one appears at the start or end of the file.
Note that the ''field_value'' and ''multi_para_value'' representations need not be equivalent. In an HTML template, each paragraph of a ''multi_para_value'' is wrapped in
tags, while in a DokuWiki [[syntax]] template, there are no
tags, but any blank lines present will be included. Whitespace preceding or trailing each ''field_value'' or ''multi_field_value'' is trimmed and so is not significant. ===== Template Files ====== A template file is a file that uses PHP to generate HTML or DokuWiki [[syntax]] from a data set. The file is placed in the active ''lib/tpl/'' directory or in some subdirectory thereof. (The default active template directory is ''lib/tpl/default/''.) How a template file works can be summarized in a few points: - Think of the file as a regular HTML or DokuWiki [[syntax]] file that may contain embedded PHP. Everything outside of the PHP tags and all output echoed by PHP becomes part of the generated result. - The PHP in the file runs within an outer, invisible PHP function. All this means is that you must declare any globals you want to use. - The ''$TEMPLATECOMMAND_SOURCE'' variable is available to the PHP code. This variable contains an object from which the code gets its source data. ''$TEMPLATECOMMAND_SOURCE'' contains an object of class ''TemplateCommandSource''. You need only be aware of three methods of this class: * ''getParamHash()'' --- Returns an assoociative array of all the parameters that the user provided to the template command. The [[plugin:command|Command Plugin]] allows parameters to be assigned via an "''=''". When a parameter is so assigned, the value to the left of the "''=''" is a key of the array, and the value to the right is the value at that key. When a parameter is included without an "''=''", the parameter provided becomes the key and the value at that key is the empty string. For example, "''#template?1&1&2&a&b=&c=3&d=4&d=5(format.php|data)#''" produces array('1'=>'', '2'=>'', 'a'=>'', 'b'=>'', 'c'=>'3', 'd'=>'5'). * ''getTextRecords()'' --- Returns an array of records, ordered according to their order of appearance within the data page. Each record is an associative array mapping the ''field_name'' to its ''field_value'' or ''multi_para_value''. The field values will be the raw text that appears within the data page, as seen when editing the data page; DokuWiki [[syntax]] will not have been translated to HTML. Calling this method informs the template command that the template is generating DokuWiki [[syntax]]. The command will subsequently translate it to HTML. * ''getHtmlRecords()'' --- Returns an array of records, ordered according to their order of appearance within the data page. Each record is an associative array mapping the ''field_name'' to its ''field_value'' or ''multi_para_value''. The field values will already have their DokuWiki [[syntax]] translated to HTML. Calling this method informs the template command that the template is generating the HTML to be displayed. All field values are reported with preceding and trailing whitespace trimmed. Note that in records retrieved via ''getHtmlRecords()'', each paragraph of a ''multi_para_value'' field value will be wrapped in
tags, as we expect DokuWiki to do.
===== Source (template.php) =====
';
if(isset($record['image']))
{
$imageID = idfilter(cleanID($record['image']));
$imageURL = $conf['basedir'].'_media/'.$imageID.'?cache=cache';
$imageWidth = '';
if(isset($record['image-width']))
{
$imageWidth = $record['image-width'];
$imageURL .= "&w=$imageWidth&h=";
}
echo "
*
* Modification History:
*
* 2005/08/30 - Created. JTL
* 2005/08/31 - Now uses ob nesting so RSS can write its headers. JTL
* 2005/09/09 - Added ability to include data set in command. JTL
* 2005/09/09 - template() was not available from within RSS. JTL
*/
define('TEMPLATECOMMAND_CONTENT_ERROR', '_INVALID_TEMPLATE_CONTENT_');
define('TEMPLATECOMMAND_DATA_NOT_FOUND', '_DATA_SET_NOT_FOUND_');
define('TEMPLATECOMMAND_TEMPLATE_NOT_FOUND', '_TEMPLATE_NOT_FOUND_');
class CommandPluginExtension_template extends CommandPluginExtension
{
function getCachedData($embedding, $params, $paramHash, $content,
&$errorMessage) // STATIC
{
// Extract the template file name and data set ID.
$barPos = strpos($content, '|');
if($barPos === false)
{
$errorMessage = TEMPLATECOMMAND_CONTENT_ERROR;
return;
}
/* next lines work even if get empty strings */
$templateName = trim(substr($content, 0, $barPos));
$dataSet = trim(substr($content, $barPos + 1));
if($templateName == '' || $dataSet == '')
{
$errorMessage = TEMPLATECOMMAND_CONTENT_ERROR;
return;
}
$templateFN = CommandPluginExtension_template::template($templateName);
if(strlen($dataSet) >= 3 && substr($dataSet, 0, 3) == '...')
{
$dataSetType = 'text';
$dataSet = substr($dataSet, 3);
}
else
$dataSetType = 'id';
// Cache the page if caller allows it.
if(isset($paramHash['_cache']))
{
$errorMessage = CommandPluginExtension_template::resolve(
$templateFN, $dataSetType, $dataSet);
if($errorMessage)
return;
return CommandPluginExtension_template::generate(
$templateFN, $dataSetType, $dataSet, $paramHash);
}
// Cache info needed to dynamically load page.
return array($templateFN, $dataSetType, $dataSet, $paramHash);
}
function runCommand($embedding, $cachedData, &$renderer,
&$errorMessage) // STATIC
{
if(is_string($cachedData))
return $cachedData;
list($templateFN, $dataSetType, $dataSet, $paramHash) = $cachedData;
$errorMessage = CommandPluginExtension_template::resolve(
$templateFN, $dataSetType, $dataSet);
if($errorMessage)
return;
$renderer->info['cache'] = false;
return CommandPluginExtension_template::generate(
$templateFN, $dataSetType, $dataSet, $paramHash);
}
function resolve($templateFN, $dataSetType, &$dataSet) // STATIC
{
global $ID;
if(strpos($templateFN, '..') !== false ||
!@file_exists($templateFN)) // PHP caches the results
return TEMPLATECOMMAND_TEMPLATE_NOT_FOUND;
if($dataSetType == 'id')
{
$exists = false;
resolve_pageid(getNS($ID), $dataSet, $exists);
if(!$exists || auth_quickaclcheck($dataSet) < AUTH_READ)
return TEMPLATECOMMAND_DATA_NOT_FOUND;
}
return null;
}
function generate($templateFN, $dataSetType, $dataSet, $paramHash) // STATIC
{
// Generate HTML or text from the template.
$source = new TemplateCommandSource($templateFN, $dataSetType,
$dataSet, $paramHash);
ob_start();
CommandPluginExtension_template::runTemplate($source);
$outString = ob_get_contents();
ob_end_clean();
// If the template generated text, translate into HTML.
if(!$source->isHTML)
{
$instructs = p_get_instructions($outString);
$info = array();
$outString = p_render('xhtml', $instructs, $info);
}
return $outString; // return generated HTML
}
function runTemplate(&$TEMPLATECOMMAND_SOURCE)
{
// Isolate template in its own function because it has access to
// the function variables. Template writes to standard out.
include($TEMPLATECOMMAND_SOURCE->templateFN);
}
/**
* This is a duplicate of its namesake in template.php, since the
* namesake is not available in an RSS feed.
*
* @author Andreas Gohr
===== Examples =====
Bear in mind that, although the following examples generate HTML, the template file may instead generate DokuWiki [[syntax]] by calling ''$TEMPLATECOMMAND_SOURCE->getTextRecords()'' instead of ''$TEMPLATECOMMAND_SOURCE->getHtmlRecords()''. I just don't have a live example to show you. You might want to generate DokuWiki syntax if it's easier than generating the HTML, as it usually will be. Also, these examples used to use a separate data page. I have since moved the data directly into the command using the new '%%...%%' syntax.
* The [[http://www.spiderjoe.com/spiders/calendar|Spider Calendar]] page is generated via [[http://www.spiderjoe.com/spiders/calendar?do=edit|this command]] using the following template:
s and
');
if($endOutline !== false)
{
// next line works even if nothing follows or
$multiline = trim(substr($fieldSplit, $endOutline + 5));
if($multiline != '')
$fieldValue .= $multiline;
}
// Record the extracted field.
$record[$fieldName] = $fieldValue;
}
}
?>s
$outline = preg_replace('/<[ou]l(\s.*?)?>/', '', $outline);
//
');
if($endOutline === false)
$endOutline = strpos($fieldSplit, '
s delimit records
$recordSplits = preg_split('/
/', $outline);
foreach($recordSplits as $recordSplit)
{
$fieldSplits = preg_split('/
* The [[http://www.spiderjoe.com/spiders/calendar|Oak Hill]] page is generated via a data set included in a template command [[http://www.spiderjoe.com/spiders/oak-hill?do=edit|on this page]] using the following template:
getHtmlRecords();
foreach($records as $record)
{
if(isset($record['month']))
{
?>
","
getHtmlRecords();
$side = 'left';
foreach($records as $record)
{
$pageURL = $conf['basedir'].idfilter(cleanID($record['page']));
$title = $record['title'];
echo '
> Note that the JavaScript function "svchk()" no longer exists (and is now unnecessary) in Dokuwiki, and does cause JavaScript errors, so references should be removed.
>-- [[todd@rollerorgans.com]] 2007-02-26
===== Discussion =====
* The template command allows the user to name any file in the [[DokuWiki]] ''%%lib/tpl/%%'' templates directory. The command specifically does not allow the filename to include '%%..%%', but there are no other constraints. Is there a potential security problem I need to handle? Thanks! --- [[http://www.spiderjoe.com|Spider Joe]]
* The example links (http://www.spiderjoe.com/spiders/calendar) do not work. -- [[wonko@wonkology.org|Wonko]] 2006-07-01
* ";
}
echo "";
echo $title;
echo '. ';
echo $record['abstract'];
echo "
[[DokuWiki]] syntax is not processed if I simple make the template ''echo'' it. Please give an example. Thanks!. Ok, I read more carefully and found that it depended in which function was called to get the records. I modified the page a bit to make it more explicitly to those of us who just skim through the instructions :D. 2006-09-05