Wiki Plugin Tutorial

Created by: Lee LaMont Bell Jr., Last modification: 20 May 2008 (06:12 UTC) by laetzer

Introduction

In this tutorial, I am going to try to explain what a Wiki Plugin is, how to use them, how they work, and what is needed to create or modify them.

Why should I learn this?

By creating a Wiki Plugin, an administrator or developer is adding functionality to his site. This functionality has a lot of bang for the buck because Wiki Plugins work in Wiki Pages, Articles, Blogs, and in the WikiForum (to my knowledge, Plugins are not available in PhpBB Forums at this time).

Wiki Plugins are also fairly simple and provide a good place for beginners to “play”. All that is required is a little knowledge of HTML and the PHP language or the ability to look things up.

-=
The Wiki Plugin “DIV” will be used for this tutorial
=-

So what does this Plugin do?

The DIV Plugin creates a division block so that text inside it can have a different background color, width, and alignment.

How is a Plugin used?

Our DIV Plugin (like most Plugins) operates on specific text. That text is encased in a pair of code blocks. A code block is the name of the Wiki Plugin to be used inside a pair of curly brackets “{“ and “}” like this:
{DIV} Text Inside the Block {DIV}
Please Note: the name of the Plugin has to be capitalized.

To make Plugins more functional, additional information (parameters) may be passed to them. This is done by adding parameters to the first code block in normal brackets - “(“ and “)”. Each parameter name is given – followed by the Equal and Greater-Than characters “=>” – and then a value. Each parameter must be separated from the others with a comma character “,”.

Our DIV Plugin uses 3 parameters named bg, width and align.
  • bg - is the background color and will accept a color name or HTML Hex color numbers (if proceeded with the character “#”).
  • width - is the width of the block in pixels or in a percentage of available area. A “%” character is needed for percentages (55%) or the letters “px” for pixels (55px).
  • align – is the alignment for the text inside the block. The values may be left / center / right.
Note: Because PHP is a case sensitive language, the parameters are also case sensitive. In this example, using Bg=>red or BG=>red will not work.

Some Examples:

{DIV(bg=>red,width=>25%,align=>left)} An old poem {DIV}
{DIV(bg=>red,width=>25%,align=>left)} An old poem

{DIV(bg=>cyan,width=>50%,align=>center)} Mary had a little lamb
Who’s fleece was white as snow
Everywhere that Mary went
The lamb was sure to go {DIV}
{DIV(bg=>cyan,width=>50%,align=>center)} Mary had a little lamb
Who’s fleece was white as snow
Everywhere that Mary went
The lamb was sure to go

{DIV(bg=>green,width=>25%,align=>right)} Written by:
somebody nobody remembers {DIV}
{DIV(bg=>green,width=>25%,align=>right)} Written by:
somebody nobody remembers {DIV}

Where do I find these Plugins?

The best way to become fluent with Wiki Plugins is to use them. A complete listing of Plugins can be found at the bottom of the Wiki Page Editor. Selecting Plugins will display this listing. Selecting “More details” will show all of the parameters for that Plugin as well as an example or two.
The actual files are stored in the Wiki/Plugins directory. The files use a strict file naming convention that must be adhered to. For our DIV Plugin, the filename is “wikiplugin_div.php”.

A Little History

There are 2 different kinds of Wiki Plugins. Originally, a few Plugins were imported into TikiWiki using a very simple structure. The idea was later expanded on to provide Object Oriented Plugins. The original Non-Object Oriented variety will be discussed first.

At first a Plugin only required a single function to operate - the executable function. There were only a few Plugins at the time so it wasn’t a problem. Calling {DIV} would execute the div function in the div.php file.

Later, a file / function naming standard was established. This allowed each Plugin to maintain it’s own documentation and provide an explanation of what it did – and what it needed - to the user. This was done in a catch-as-catch-can manner and most of the information was only partially available.

In the Bonnie version of bitweaver, all of the Wiki Plugins had a face-lift. The main help function was rewritten to provide a general description of the Plugin and another function was added to provide information about the parameters as well as some examples.

The File Name / Function Name Standard

Since only part of the file name is given, a routine in the wiki/wiki_lib.php file joins our {DIV} statements into a file name so that the correct Plugin is called. In this case it is “wikiplugin_div.php”. The same method is used to determine which functions are called. The naming convention is:
  1. function wikiplugin_xxxxx_help()
  2. function wikiplugin_xxxxx_extended_help()
  3. function wikiplugin_xxxxx($data, $params)
    xxxxx = the common name of the Plugin (in this case: div)

The Help Function - wikiplugin_div_help()

{CODE(in=>1)}function wikiplugin_div_help() {
$back = tra("This plugin insert a division block in the page. This allows you to control the location and background color of text with the block.\n");
$back.= tra("Syntax: ") . "
" . tra("Text Inside The Block")."
";
return $back;
}{CODE}
NOTE: The removal of an NP statement was required to allow this to code to be displayed properly
-=
When the routine is run it should look something like this
=-
DIV - This plugin insert a division block in the page. This allows you to control the location and background color of text with the block.
Syntax: {DIV(bg=> ,width=> ,align=> )} Text Inside The Block {DIV}
Please Note: Wiki Syntax is used in the Help Routines to control their appearance.

The Extended Help Function - wikiplugin_div_extended_help()

{CODE(in=>1)}function wikiplugin_div_extended_help() {
$back = tra("
Parameter Syntax: ") . "{BOX(Key=>value)} \n";
$back.= tra("
key
value
Comments

");
$back.= "
bg
" . tra("
colorname or hex color
specifies the background color. HTML colors (#RRGGBB) can be used if preceeded by the character #. Optional - there is No default.
");
$back.= "
width
" . tra("
number
can be specified by pixels or a percentage of the available area. The % character is used to define a percentage - and ") . "px" . tra(" is used to define pixels. Optional - there is No default.
");
$back.= "
align
alignment
" . tra("
the alignment of the text within the Div. Optional - there is No default.
");
$back.= tra("
Example: ") . "{DIV(bg=>#FFDDFF,align=>left)}" . tra("Text Inside The Div") . "{DIV} \n";
$back.= tra("This creates an area with a pinkish background. Because the width was not specified it will be the entire pages width. The text is left alligned.
");
$back.= tra("
Note: Plugin's are case sensitive. The Name of the plugin MUST be UPPERCASE. The Key(s) are always lowercase. Some Values are mixed-case but most require lowercase. When in doubt - look at the Example.\n");
$back.= tra("Note 2: One useful place for obtaining HTML colors is ") . "" . tra("The Color Picker II
");
return $back;
}{CODE}NOTE: The removal of 2 NP statements was required to allow this to code to display properly
-=
When the routine is run it should look something like this
=-
Parameter Syntax: BOX(Key=>value)}
key
value
Comments
bg
colorname or hex color
specifies the background color. HTML colors (#RRGGBB) can be used if preceded by the character #. Optional - there is No default.
width
number
can be specified by pixels or a percentage of the available area. The % character is used to define a percentage - and px is used to define pixels. Optional - there is No default.
align
alignment
the alignment of the text within the Div. Optional - there is No default.

Example: {DIV(bg=>#FFDDFF,align=>left)} Text Inside The Div {DIV}
This creates an area with a pinkish background. Because the width was not specified it will be the entire pages width. The text is left aligned.

Note: Plugin's are case sensitive. The Name of the plugin MUST be UPPERCASE. The Key(s) are always lowercase. Some Values are mixed-case but most require lowercase. When in doubt - look at the Example.
Note 2: One useful place for obtaining HTML colors is The Color Picker II
Please Note: Wiki Syntax is used in the Help Routines to control their appearance.

The Executed Function - wikiplugin_div($data, $params)

{CODE(in=>1)}function wikiplugin_div($data, $params) {
/* set default values for some args */
$align = "left";
extract ($params);
$w = (isset($width)) ? " width: $width;" : "";
$bg = (isset($bg)) ? " background: $bg;" : "";
$al = (isset($align) && ($align == 'right'
$align == "center")) ? " text-align: $align;" : "";
$begin = "
0 ? " style='$bg$al$w'" : "") . ">";
$end = "";
return $begin . $data . $end;
}{CODE}
-=
Lets use this as an example:
=-
{DIV(bg=>#FFDDFF,align=>center,width=>30%)} Text Inside The Block {DIV}
{DIV(bg=>#FFDDFF,align=>center,width=>30%)} Text Inside The Block {DIV}
! So how does it work?
When the function is executed, the text to be modified (the text between the code blocks – in this case ‘Text Inside The Block ’) is passed to the routine in the variable $data. The $params variable is an array containing all of the variables within the first code block.
That array is extracted to create the variables on line 4 with the statement
extract ($parmams);
So now the variables $bg, $width, and $align exist if they were defined (in this case they were) and can be used in the function.
Lines 5 & 6 the variables $width and $bg are tested to see if they exist and have a value.
Line 7 the variable $align is also tested. First to see if it exists and has a value – then to see if the value is either “right” or “center”
On all 3 lines – if they do the syntax for the HTML DIV statement is added - if not / they are set to an empty string.
Line 8 create a $begin variable and joins the others together.
Line 9 create a $end variable that is needed for the HTML code.
Line 10 joins the $begin + $data + $end together and returns it to the calling function.
So what is wrong with this?
Nothing. As far as it goes it is fine. Please notice the strlen test in Line 8 though. This Plugin only works if the variable $bg has a value. Line 3 is also a mystery to me – it doesn’t need to be there – either that or the isset test in Line 7 is redundant.
! Object Oriented Plugins
Explaining Object Oriented Programming is more than I care (or possibly could) do – but I will point out a few minor thing in the following code.
The Wiki Plugin “wikiplugins_backlinks.php” is used here as an example.
{CODE(in=>1)} <?php
/**
* Include the library {@link PluginsLib}
*/
require_once( WIKI_PKG_PATH.'plugins_lib.php' );
/**
* Backlinks plugin
* List all pages which link to specific pages (same as backlinks.php)
*
* Params:
*
*
  • info (allows multiple columns, joined by '
  • ') : hits,lastModif,user,ip,len,comment,
    * creator, version, flag, versions,links,backlinks
    *
  • exclude (allows multiple pagenames) : HomePage
  • *
  • include_self : by default, false
  • *
  • noheader : by default, false
  • *
  • page :by default, the current page.
  • *
    *
    * @package TikiWiki
    * @subpackage TikiPlugins
    * @author Claudio Bustos
    * @version $Revision: 1.3.2.5 $
    */
    class WikiPluginBackLinks extends PluginsLib {
    var $expanded_params = array("exclude", "info");
    function getDefaultArguments() {
    return array('exclude' => '',
    'include_self' => 0,
    'noheader' => 0,
    'page' => 'pagename',
    'info' => false );
    }
    function getName() {
    return "BackLinks";
    }
    function getDescription() {
    $back = tra("This plugin list all pages which contain a link to the specified pages.
    ");
    $back.= tra("Syntax: ") . "{BACKLINKS(page=> ,info=> ,exclude=> ,include_self=> ,noheader=> )}{BACKLINKS}";
    return $back;
    }
    function getBiggerDescription() {
    $back = tra("
    Parameter Syntax: ") . "{BACKLINKS(key=>value)}
    ";
    $back.= tra("
    key
    |
    value
    |
    Comments
    \n");
    $back.= "
    page
    " . tra(" |
    pagename
    | any wiki page. The default is the current page.\n");
    $back.= "
    info
    " . tra(" |
    option
    | defines what is to be displayed. Allows multiple columns if joined with the character |. Available choices are: ") . "hits, lastModif, user, ip, len, comment, creator, version, flag, versions, links, backlinks.\n";
    $back.= "
    exclude
    " . tra(" |
    pagename(s)
    | any wiki page. Allows multiple pagenames if joined with the character |. Like this: ") . "HomePage|SandBox.\n";
    $back.= "
    include_self
    " . tra(" |
    number
    | The default is ") . "False" . tra(" - use 1 to enable.\n");
    $back.= "
    noheader
    " . tra(" |
    number
    | The default is ") . "False" . tra(" - use 1 to enable.||
    ");
    $back.= tra("
    Example: ") . "{BACKLINKS(page=>MyHomePage,info=>hits|user,exclude=>HomePage|SandBox,include_self=>1,noheader=>1)}{BACKLINKS}
    ";
    $back.= tra("
    Note: Plugin's are case sensitive. The Name of the plugin MUST be UPPERCASE. The Key(s) are always lowercase. Some Values are mixed-case but most require lowercase. When in doubt - look at the Example.
    ");
    return $back;
    }
    function getVersion() {
    return preg_replace("/Revision: $/", '',
    "\$Revision: 1.3.2.5 $");
    }
    function run ($data, $params) {
    global $wikilib;
    $params = $this->getParams($params, true);
    $aInfoPreset = array_keys($this->aInfoPresetNames);
    extract ($params);
    /////////////////////////////////
    // Create a valid list for $info
    /////////////////////////////////
    //
    if ($info) {
    $info_temp = array();
    foreach($info as $sInfo) {
    if (in_array(trim($sInfo), $aInfoPreset)) {
    $info_temp[] = trim($sInfo);
    }
    $info = $info_temp?$info_temp:
    false;
    }
    }
    $sOutput = "";
    // Verify if the page exists
    if (!$wikilib->page_exists($page)) {
    return $this->error(tra("Page cannot be found")." : $page");
    }
    //
    /////////////////////////////////
    // Process backlinks
    /////////////////////////////////
    //
    $aBackRequest = array();
    $aBackLinks = $wikilib->get_backlinks($page);
    foreach($aBackLinks as $backlink) {
    if (!in_array($backlink"fromPage", $exclude)) {
    $aBackRequest[] = $backlink"fromPage";
    }
    }
    if ($include_self) {
    $aBackRequest[] = $page;
    }
    if (!$aBackRequest) {
    return tra("No pages link to")." (($page))";
    } else {
    $aPages = $this->list_pages(0, -1, 'pageName_desc', $aBackRequest);
    }
    //
    /////////////////////////////////
    // Start of Output
    /////////////////////////////////
    //
    if (!$noheader) {
    // Create header
    $count = $aPages"cant";
    if ($count == 1) {
    $sOutput .= tra("One page links to")." (($page))";
    } else {
    $sOutput = "$count ".tra("pages link to")." (($page))";
    }
    $sOutput .= "\n";
    }
    $sOutput .= PluginsLibUtil::createTable($aPages"data", $info);
    return $sOutput;
    }
    }
    function wikiplugin_backlinks($data, $params) {
    $plugin = new WikiPluginBackLinks();
    return $plugin->run($data, $params);
    }
    function wikiplugin_backlinks_help() {
    $plugin = new WikiPluginBackLinks();
    return $plugin->getDescription();
    }
    function wikiplugin_backlinks_extended_help() {
    $plugin = new WikiPluginBackLinks();
    return $plugin->getBiggerDescription();
    }
    ?>{CODE}
    First - The three functions mentioned earlier are still included at the bottom of the file on lines 121, 125, and 129.
    Second - Because this Plugin is object oriented, each of these functions first has to create an instance of the object and then call the proper method. The names of the help method can be anything at this time – as this example shows.
    Third - The methods that the two help routines call (getDescription on line 37 and getBiggerDescription on line 42) are almost identical to the non-object oriented functions.
    Forth - The executable method should always be named run. While this is not manditory, there are several other methods that are called by other routines. These include: getName on line 34 and getVersion on line 54. While these methods do not seem to be used - they are. One place where they are used is by the plugin PLUGINMANAGER. Unfortunatly, that plugin does not work all that well with non-object oriented plugins.
    Fifth - The run method in most ways is identical to a non-object oriented executable function. Converting all of the non-object oriented plugins to object oriented plugins (or vice-versa) should not be a major undertaking. The only question is - why do it at all.

    Good Luck and Happy Programming (:biggrin:)