Tutorial - Syntax Plugin Development

This tutorial will deliver a brief description how to develop a simple DokuWiki Plugin to extend DokuWikis syntax.

This tutorial targets to beginner level but assumes that you have a bit knowledge about development in php, experience in html and understanding of DokuWiki itself. That are prerequisite condition to follow-up the descriptions within this article.


Introduction

DokuWiki comes up with a huge set of functions. It might occur that for your customized purpose the right feature is not implemented and not available as already developed plug-in (or you just have fun to develop a plug-in and support the wide community). There are a few plugin types where syntax plug-in is the most popular followed by action- and admin plug-ins. Please keep in mind that a published plug-in will be used also if the users do not providing feedback. Therefore it is good to place valuable comments within your scripts that the community is able to follow-up your code and help supporting it.

For “spare-time” developers it might be good to have valuable language descriptions and tools at hand. We propose the following (but you may use others):

The following puristic php code skeleton filled and explained by this tutorial:

plugin_skeleton.php
<?php
/******************************************************************************/
/* Plugin skeleton: provides smallest set of functions for plugin development */
/* @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)                   */
/* @author                                                                    */     
/******************************************************************************/
 
if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'syntax.php');  
 
/*----------------------------------------------------------------------------*/
/* All DokuWiki plugins to extend the parser/rendering mechanism              */
/* need to inherit from this class                                            */
/*----------------------------------------------------------------------------*/
class syntax_plugin_my-plugin extends DokuWiki_Syntax_Plugin {
 
/*----------------------------------------------------------------------------*/
/* return some info (for compatibility with aged DokuWiki versions)           */
/*----------------------------------------------------------------------------*/
    function getInfo(){ return confToHash(dirname(__FILE__).'/plugin.info.txt'); }
 
/*----------------------------------------------------------------------------*/
/* set basic behaviour of the plugin                                          */
/*----------------------------------------------------------------------------*/
    function getType(){ return 'substition';} // Returns the type of syntax this plugin defines 
    function getPType(){ return 'block';}     // Defines how this syntax is handled regarding paragraphs
    function getSort(){ return 999;}          // Returns a number used to determine in which order modes are added
 
/******************************************************************************/
/* Connect pattern to lexer                                                   */   
/*----------------------------------------------------------------------------*/
    function connectTo($mode){
        $this->Lexer->addSpecialPattern('\{\(my-plugin>[^}]*\)\}',$mode,'plugin_my-plugin');
    }
 
/*----------------------------------------------------------------------------*/
/* handle the match                                                           */   
/*----------------------------------------------------------------------------*/
    function handle($match, $state, $pos, &$handler) {        
        //strip markup from start and end
        $match = substr($match,strlen('{(my-plugin>'),-2); 
 
        //split parameter string
        $params = array();
        $params = explode(",",$match);    
        return $params;       
     }
 
/*----------------------------------------------------------------------------*/
/* render output                                                              */   
/*----------------------------------------------------------------------------*/
    function render($mode, &$renderer, $params) {
    // enter the main function code in here and call further functions if needed
    // finally add your html-formatted output to the DokuWiki renderer
       $renderer->doc .= $code_block;
    }
}
?>

1. The Plugin Directory

DokuWiki owns a Plugin directory ([dokuwiki_root]/lib/plugins) to host all plugins and offer them to the DokuWiki core system for dynamic use. The plugin directory is to be named as the plugin and contains usually following files:

  1. The core script of a syntax plugin is named syntax.php Files and Folders
  2. To provide basic information about the plugin a plugin.info.txt file should be existent.
    This file content will be used each time the plugin info is asked (e.g. Plugin Management).
  3. You may provide a readme file to briefly explain how the plugin is to be used and what it does.

All these files will be used automatically by DokuWiki plugin feature. Let us assume you want to develop a plugin named SimpleSnipper then you would have a folder structure and files similar to the picture beside.

Info

     Do not use special characters like underline within plugin names. That may conflict future version of DokuWiki.






In the event you want to develop a more complex plugin you may have further folders and files within the specific plugin directory:

  • To define the output styles of classes a style.css file is used.
  • conf directory containing defaults and definitions, used by Configuration Manager
    • default.php to specify parameters and initial values (description see lang/settings.php)
    • metadata.php to define the configuration management controls
  • lang directory does contain further folders, one for each language but at least one for English as default
    • Eache language folder has to be named according the 2-digit ISO 639-1 codes.
    • a folder en to hold all translations needed for a language. It is good practice to start develop with English text first in the event you develop a language supported plugin due to it is default and fall back if a language specific parameter in e.g. DE is missing.
      • the settings.php to be used to map the configuration parameter and short description, which are provided within Configuration Manager
      • the lang.php contains all text of controls and messages to be finally showed to the user
    • To add further languages you should copy the files from English folder to secure translation of all strings.

SECTION RESULT


     You should have created a folder named simplesnipper within your plugin directory.







2. The Code Skeleton

This chapters of this section handle the code skeleton of a syntax plugin. You will see the main code blocks and get a bunch of descriptions explaining most of the code (except php/html basics). We will follow up developing a plugin named SimpleSnipper during this tutorial.

2.1 Intro

You may already have noticed, we are developing a php-script. For sake of clarity, the code examples provided on this page are rendered by an extended, more complex version of SimpleSnipper (==> xsSnipper).

Info

     To work on php scripts you may use PSPad, a freeware tool delivering a wide range of functionality
     but still easy to handle.






2.2 Main code structure of syntax.php

You may think of a a plugin code file of a little document containing 3 chapters.

  1. Header
  2. Class definition
  3. Output rendering
  4. Supporting functions

Our tutorial covering points 1 to 3 due to coding of supporting functions is related to usual php-development only.

Header:
Beside the introducing php syntax:

  • your header should contain some comments about the plugin, homepage for further description and contact information of yourself
  • we need some necessary DokuWiki standard scripts, which have to be referenced or included. We are skipping the functional details and descriptions here due to they are described within DokuWiki.org.

Your code should look like following:

syntax.php
*/ if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); if(!defined('DOKU_DATA')) define('DOKU_DATA',DOKU_INC.'data/pages/'); require_once(DOKU_PLUGIN.'syntax.php'); require_once(DOKU_INC.'inc/parser/xhtml.php');
  1. <?php
  2.  
  3. /**
  4.  * Plugin simplesnipper: provides rendered code snippeds from files to be displayed in a code block
  5.  *
  6.  * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
  7.  * @author     Taggic <taggic@t-online.de>
  8.  */
  9.  
  10. if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
  11. if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
  12. if(!defined('DOKU_DATA')) define('DOKU_DATA',DOKU_INC.'data/pages/');
  13. require_once(DOKU_PLUGIN.'syntax.php');  
  14. require_once(DOKU_INC.'inc/parser/xhtml.php');
  15.  

Info

     Move your mouse pointer over the red-coloured php commands. They are directly linked to their php.net descriptions.






Class definition:
First we want to show you the code and add some comments and links to good description.

syntax.php
/** * All DokuWiki plugins to extend the parser/rendering mechanism * need to inherit from this class */ class syntax_plugin_simplesnipper extends DokuWiki_Syntax_Plugin { /******************************************************************************/ /* return some info */ function getInfo(){ return confToHash(dirname(__FILE__).'/plugin.info.txt'); } function getType(){ return 'substition';} // Returns the type of syntax this plugin defines function getPType(){ return 'block';} // Defines how this syntax is handled regarding paragraphs function getSort(){ return 999;} // Returns a number used to determine in which order modes are added /******************************************************************************/ /* Connect pattern to lexer */ function connectTo($mode){ $this->Lexer->addSpecialPattern('\{\(simplesnipper>[^}]*\)\}',$mode,'plugin_simplesnipper');
  1. /**
  2.  * All DokuWiki plugins to extend the parser/rendering mechanism
  3.  * need to inherit from this class
  4.  */
  5. class syntax_plugin_simplesnipper extends DokuWiki_Syntax_Plugin {
  6.  
  7. /******************************************************************************/
  8. /* return some info
  9. */
  10.     function getInfo(){
  11.         return confToHash(dirname(__FILE__).'/plugin.info.txt');
  12.     }
  13.  
  14.     function getType(){ return 'substition';} // Returns the type of syntax this plugin defines
  15.     function getPType(){ return 'block';}     // Defines how this syntax is handled regarding paragraphs
  16.     function getSort(){ return 999;}          // Returns a number used to determine in which order modes are added
  17.    
  18. /******************************************************************************/
  19. /* Connect pattern to lexer
  20. */  
  21.     function connectTo($mode){
  22.         $this->Lexer->addSpecialPattern('\{\(simplesnipper>[^}]*\)\}',$mode,'plugin_simplesnipper');
  23.  

- Line 25: function getInfo() -
This function is for compatibility issue to older DokuWiki versions. It makes use of plugin.info.txt, which is automatically used by newer DokuWiki versions. That delivers the advantage to provide this information only once and prevents inconsistencies. Please read (later) Content of plugin.info.txt section for the purpose of our tutorial.

- Line 36: function connectTo() -
This function is used to register the regular expressions needed to match your syntax on a DokuWiki page..

Info

     Much more details can be found on Synopsis
     For this plugin development jump start it is not mandatory to step into a deeper level but
     consider also the comments provided within the code above.







SECTION RESULT


     You should have created a syntax.php file within the plugin/simplesnipper folder containing the code explained above.








3. Feature Code and Output

SimpleSnipper adding the possibility to show a snippet of code out of a given file. It reuses the code block feature of DokuWiki to render the output. Therefore the plugin needs path and file information, begin and end line to be displayed additionally to DokuWikis code block syntax requirements.

The plugin syntax to be used on your DokuWiki page will be following: {(simplesnipper>[path],[begin],[end],[type] [file])}

Parameter Necessity Meaning
[path] mandatory specifies the file where content to be picked up
[begin] optional defines the first line to be displayed, if empty it will be set to zero; if further parameter will be given at least the colon separator to be written
[end] optional defines the last line to be displayed, if empty it will be set to end of file; if further parameter will be given at least the colon separator to be written
[type] optional tells code block/GeSHi what language file to be used for colouring, file extension of the [path] parameter will be used if empty
[file] optional enables the download cod blocks feature and specifies the file name, if empty no downloadable code block provided

3.1 Retrive the Syntax Pparameter Values

The following code shows how to detect single parameters fom the syntax call.

  1. At the beginning $match contains the whole syntax line. We have to strip the opening and closing tags of the plugin to extract the pure parameter string (code line 45).
  2. Next we split the parameter string per parameter and get a parameter array (code line 49).
  3. In the event that no parameter was given within the syntax line an error message will be displayed. (code lines 59 - 61).
  4. Finally we store the parameter values into a descriptive array for a better usage.
  5. Last step is to handover the result to DokuWikis output rendering, close the function and class by curled brackets and finally put the php closing to the end.
syntax.php
/******************************************************************************/ /* handle the match */ function handle($match, $state, $pos, &$handler) { $match = substr($match,strlen('{(simplesnipper>'),-2); //strip markup from start and end //split parameter string $params = explode(",",$match); /******************************************************************************/ /* parameters can be: {(simplesnipper>[file path],[from line],[to line],[type] [file])} [file path] ... path to the file (either it is in DokuWiki media directory or windows fileshare, etc.) [from line] ... the first line, which should be displayed [to line] ... the last line, which should be displayed [type] ... the type of content to tell the renderer how to interprete and set colors [file] ... if download block should get a different name as source file /******************************************************************************/ if (!$params) { msg('Syntax of simplesnipper detected but an unknown parameter was attached.', -1); } else { // Values $simplesnipper = array(); $simplesnipper['filepath'] = $params[0]; $simplesnipper['from'] = $params[1]; $simplesnipper['until'] = $params[2]; $alpha = explode(' ',$params[3]); $simplesnipper['type'] = $alpha[0]; $simplesnipper['file'] = $alpha[1]; return $simplesnipper; } }
  1. /******************************************************************************/
  2. /* handle the match
  3. */  
  4.     function handle($match, $state, $pos, &$handler) {
  5.  
  6.         $match = substr($match,strlen('{(simplesnipper>'),-2); //strip markup from start and end
  7.  
  8.         //split parameter string
  9.         $params = explode(",",$match);
  10.     /******************************************************************************/
  11.     /*      parameters can be:
  12.             {(simplesnipper>[file path],[from line],[to line],[type] [file])}
  13.             [file path] ... path to the file (either it is in DokuWiki media directory or windows fileshare, etc.)
  14.             [from line] ... the first line, which should be displayed
  15.             [to line]   ... the last line, which should be displayed
  16.             [type]      ... the type of content to tell the renderer how to interprete and set colors
  17.             [file]      ... if download block should get a different name as source file
  18.     /******************************************************************************/
  19.         if (!$params) {
  20.           msg('Syntax of simplesnipper detected but an unknown parameter was attached.', -1);          
  21.         }
  22.         else {
  23.           // Values
  24.           $simplesnipper                = array();
  25.           $simplesnipper['filepath']    = $params[0];
  26.           $simplesnipper['from']        = $params[1];
  27.           $simplesnipper['until']       = $params[2];
  28.           $alpha                        = explode(' ',$params[3]);
  29.           $simplesnipper['type']        = $alpha[0];
  30.           $simplesnipper['file']        = $alpha[1];
  31.           return $simplesnipper;
  32.         }        
  33.      }
  34.  

3.2 Content Preparation and Output

The following code shows how to load the specified file content and preparing the output. You will see also the SimpleSnipper wraps around code block of DokuWiki due to the code block handling of the content will be initiated and the result is further processed.

  1. Initially we check if the file is available/can be reached and displaying an error message if not (code line 80 - 83).
  2. Next we store the file content into $records variable for further processing (code line 85).
  3. Third step is to check if all parameters own a value or to set them to a default. Here we need to check [type], [file] and [until] (code lines 88 - 91).
    If [start] parameter is empty it is used as code line 0.
  4. Now we loop through the records to assemble the wanted lines to a string named $code_lines.
  5. To use DokuWikis code block handling we need to wrap around our $code_lines string the related DokuWiki code syntax. Then we call the p_get+p_get_instructions functions to let DokuWiki do the code block analysis and conversion to html + styling.
syntax.php
/******************************************************************************/ /* render output * @author Taggic */ function render($mode, &$renderer, $simplesnipper) { // 1. check if file exist, else error message if(!file_exists($simplesnipper['filepath'])) { msg('file '.$simplesnipper['filepath'].' not found',-1); return false; } // 2. load the raw file content into $records $records = file($simplesnipper['filepath']); // 3. check parameters and set to default if empty if(!$simplesnipper['type']) $simplesnipper['type'] ='txt'; if(!$simplesnipper['file']) $simplesnipper['file'] = basename($simplesnipper['filepath']); if(!$simplesnipper['file']) $simplesnipper['file'] ='snippet.'.$simplesnipper['type']; if(!$simplesnipper['until']) $simplesnipper['until'] = count($records); // 4. retrive specified lines of file foreach ($records as $line_num => $line) { if(($line_num>=$simplesnipper['from']-1) && ($line_num<=$simplesnipper['until']-1)) $code_lines .= $line; } // 5. prepare string and execute the code block formatting and html conversion by DokuWiki feature $info = array(); $code_block = '' . $code_lines . ''; $code_block = p_render('xhtml',p_get_instructions($code_block),$info); // 6. add your html-formatted output to the DokuWiki renderer $renderer->doc .= $code_block; } } ?>
  1. /******************************************************************************/
  2. /* render output
  3. * @author Taggic <taggic@t-online.de>
  4. */  
  5.     function render($mode, &$renderer, $simplesnipper) {
  6.     // 1. check if file exist, else error message
  7.        if(!file_exists($simplesnipper['filepath'])) {
  8.           msg('file '.$simplesnipper['filepath'].' not found',-1);
  9.           return false;
  10.        }
  11.  
  12.     // 2. load the raw file content into $records      
  13.        $records    = file($simplesnipper['filepath']);
  14.    
  15.     // 3. check parameters and set to default if empty
  16.         if(!$simplesnipper['type'])  $simplesnipper['type']  ='txt';
  17.         if(!$simplesnipper['file'])  $simplesnipper['file']  = basename($simplesnipper['filepath']);
  18.         if(!$simplesnipper['file'])  $simplesnipper['file']  ='snippet.'.$simplesnipper['type'];
  19.         if(!$simplesnipper['until']) $simplesnipper['until'] = count($records);    
  20.        
  21.     // 4. retrive specified lines of file
  22.         foreach ($records as $line_num => $line) {
  23.             if(($line_num>=$simplesnipper['from']-1) && ($line_num<=$simplesnipper['until']-1))
  24.             $code_lines .= $line;
  25.         }
  26.    
  27.     // 5. prepare string and execute the code block formatting and html conversion by DokuWiki feature
  28.        $info = array();
  29.        $code_block = '<code ' . $simplesnipper['type'] . '>' . $code_lines . '</code>';      
  30.        $code_block = p_render('xhtml',p_get_instructions($code_block),$info);
  31.  
  32.     // 6. add your html-formatted output to the DokuWiki renderer
  33.        $renderer->doc .= $code_block;
  34.     }
  35. }
  36. ?>

Other functions of your plugin you may need for more complex functionality have to be invoked by a function call !

SECTION RESULT


     You should have extended syntax.php file by the code explained above in paragraph 3.1 and 3.2.
     The php development of the plugin is finished.








4 Further Files

4.1 Content of plugin.info.txt

plugin.info.txt
# PLUGIN INFO - DO NOT EDIT! base xssnipper author Taggic email taggic@t-online.de date 2012-01-18 name simplesnipper desc provides syntax plugin to retrieve code snippeds from files url http://www.dokuwiki.org/plugin:simplesnipper
  1. # PLUGIN INFO - DO NOT EDIT!
  2.  
  3. base    xssnipper
  4. author  Taggic
  5. email   taggic@t-online.de
  6. date    2012-01-18
  7. name    simplesnipper
  8. desc    provides syntax plugin to retrieve code snippeds from files
  9. url     http://www.dokuwiki.org/plugin:simplesnipper
  10.  

4.2 Plugin zip-file

The folder including the files of this tutorial can be downloaded here: simplesnipper.zip


see also

tips/tips_plugindev.txt · Last modified: 2014/04/30 09:36 (external edit)

This Wiki is hosted and ruled by Policies of Frister Consultancy Services.
By using this wiki you accept these rules. -> Impressum