Table of Contents
Tips for programming plugins
Please write down tips you've discovered making it easier for others tomake plugins.I actually had to sit down and fgrep myself to this info, and I hope that it will help others
On this page are some tips (see ToC right). Useful resources elsewhere in the wiki are:
- Pluginfile structure andname conventions
Customized Section editing
When you like to change only small pieces of the wiki text via your plugin, it is recommended to look for section editing. This let you provide your interface elements that can edit a specific marked piece of wiki text.
Please refer tosection editor for details on the implementation in your plugin.
User lists and info
You can access user-lists/info and more for internal use by declaring the following in a function that needs it:
global$auth;if($auth->canDo('getUsers')){// is this feature available?$auth->retrieveUsers(0,0,$filter);}
Where$filter
is an array with one or more of the following keysuser
,name
,mail
, orgrps
.Several values in each using|
as a separator.
For example, to retrieve all users in the group 'admin', one would use:
$filter['grps']='admin';$array_of_matches=$auth->retrieveUsers(0,0,$filter);
Be aware that the authentication plugin needs to implement this function. Otherwise it returns always an empty array.
See alsoauthentication plugins mention ofretrieveUsers()
and other functions.
DokuWiki Global Variables
DokuWiki uses a number ofglobal variables to hold information about the current page, current user and the actions being performed.
Details of these can be found on theenvironment page.
Making your plugins more secure
Clean all input and output
Be aware that every one can do 'requests' on your forms and pages with all data they think off. People can send the same kind of data as a brave one using your form, without using your form itself. So everything can be included. So check always whether the given data is that whatyou allowed.
And when you output data, especially in theHTML of your interface, your plugin should ensure any data output has allHTML special characters converted toHTML entities using thehtmlspecialchars() function. DokuWiki provides a convenient shortcut calledhsc() for the function. URLs values should be escaped usingrawurlencode(). This makes sure input is always outputted as text and not as executable code. Malicious users could otherwise introduce what ever JavaScript andHTML code they want on your site and can manipulate and change everything.
Protect forms and action urls
If you use forms in your plugins or urls that initiate actions, you should include a hidden form field with the session-based security token. In the current version of DokuWiki you can generate this field by calling the functionformSecurityToken(). Before you process the form input, callcheckSecurityToken(). This function checks if the sent security token is correct.
Scenario If you wonder, why this will make your plugins more secure, consider the following scenario:
You have written a plugin that displays a form to delete several pages at once.
An attacker knows you regularly log in to your wiki and you use a site that is under his control.
He places an images tag on his page that links to your doku.php and has all the form parameters for deleting pages in theURL.
Each time you see the page form the attacker, your browser requests the image from your DokuWiki installation, thereby deleting pages.
This attack is calledCross Site Request forgery.
Other security tips are listed and explainedon the dedicated page.
Use correct regular expressions
Use correct regular expressions for syntax search patterns. If the search pattern is incorrect, it can produce unwanted effects in combination with other plugins.
Use reasonable tag names to avoid conflicts with other plugins. For example don't use a name liketest
butpluginname_test
instead. Maybe check existing search patterns heresyntax, but don't use them as example because many of them are incorrect regular expressions.
Correct regular expression
<tag\b.*?>.*?</tag><tag\b[^>\r\n]*?>.*?</tag><tag\b[^>\r\n]*?>[^\r\n]*?</tag><tag\b.*?>(?:.*?</tag>)<tag\b(?:\s+(?:par1|par2)="[^">\r\n]*")*\s*>(?:.*?</tag>)
~~tag\b.*?~~~~tag>.+?~~~~tag>[^\r\n]+?~~
False regular expression
Example 1:
<tag.*>.*?</tag><tag ?.*>.*?</tag><tag *.*>.*?</tag>
Start tag is not a word, the end-of-word marker\b
is missing, any pattern for example tagmore or taged is found too.
This produces a wrong result in this case:
<tagmore>Text</tagmore><tag>Text</tag>
Example 2:
<tag\b.*>.*?</tag><tag\b.*?>.*</tag>
The search pattern is “greedy”, the not-greedy marker?
is missing, to long pieces are included in one search match.
This produces a wrong result in this case:
<tag>Text</tag><tag>Text</tag>
Spam prevention
When you offer a form in your plugin and this can be also used by public users of a wiki, it's recommended to use CAPTCHA to defeat spambots. There is already aCAPTCHA plugin available, which provides different formats, visible and invisible CAPTCHAs.
See the plugin page for description of theintegration and theconfiguration options.
Example implementation
TheBureaucracy plugin supports this plugin. The CAPTCHA is integrated in the submit button, seesubmit.php.
Adding JavaScript
Modify your wiki via local JavaScripts
If you need to enhance DokuWiki's capabilities, you can consider JavaScript beside creating a new plugin.
Just put the JavaScript code intoconf/userscript.js
(create this file if it doesn't exists).
Examples JavaScripts additions:wordcounter orcopy_section_link
Distribute JavaScript and CSS files by pseudo plugins
If you want to add some JavaScript andCSS at the same time and make it easier to distribute, you can create a'pseudo' plugin. Create a new folder and add ascript.js
and/or astyle.css
file to it. Add this folder tolib/plugins/
and complete it by adding theplugin.info.txt
.
Examples pseudo plugins:searchjump oripa
More aboutJavaScript andCSS styles in plugins.
Using cookies
When you like to store some preferences, you can add to and retrieve of DokuWikis preferences cookie by:
- in PHP:
- set a value
set_doku_pref($pref, $value)
- delete an entry
set_doku_pref($pref, false)
- and retrieve its value with
get_doku_pref($pref, $default)
- and in #"https://codesearch.dokuwiki.org/search?project=dokuwiki&defs=&path=lib%20scripts%20cookie.js" title="unknown definition">DokuCookie.setValue(pref, value)
- and retrieve value
DokuCookie.getValue(pref)
For other usages you use a separated cookie. Next snippet shows how you set cookies with the correct path in DokuWiki.
In PHP:
global$conf;$cookieDir=empty($conf['cookiedir']) ? DOKU_REL:$conf['cookiedir'];setCookie("yourCookieName",$value,$expire,$cookieDir,'',($conf['securecookie']&& is_ssl()));
and in #"/faq:cookies" title="faq:cookies" data-wiki-id="faq:cookies">DokuWiki's cookies,cookiedir config,securecookie config.
Handle JSON ajax request
An action plugin that register theAJAX_CALL_UNKNOWN event, you can handle your own ajax requests. Here a sample how you can return JSON to your javascript. Plugin name isexample
.
Create anAction Plugin which should contain:
- lib/plugin/example/action.php
use dokuwiki\Extension\ActionPlugin;use dokuwiki\Extension\EventHandler;use dokuwiki\Extension\Event; class action_plugin_exampleextends ActionPlugin{ /** * plugin should use this method to register its handlers * with the dokuwiki's event controller */publicfunction register(EventHandler$controller){$controller->register_hook('AJAX_CALL_UNKNOWN','BEFORE',$this,'ajaxCall');} /** * handle ajax requests */publicfunction ajaxCall(Event$event){if($event->data!=='plugin_example'){return;}//no other ajax call handlers needed$event->stopPropagation();$event->preventDefault(); //e.g. access additional request variablesglobal$INPUT;$name=$INPUT->str('name'); //data$data=[]; //set content typeheader('Content-Type: application/json');echojson_encode($data);}}
You can request the data in javascript, for example:
- lib/plugins/example/script.js
jQuery.post( DOKU_BASE+'lib/exe/ajax.php',{ call:'plugin_example', name:'local'},function(data){ alert('Received response');// data is array you returned with action.php},'json');
Checking user-input text against the DokuWiki blacklist
You have some user input you want to validate using the internal blacklist (e.g. as an anti-spam measure for comments or anything like that).
Make a temporary backup of the current content of the internal$TEXT
variable (which usually contains the wiki text of the displayed page), then put your text into$TEXT
. A call tocheckwordblock()
should then yield a result oftrue
if the processed text contains any blocked words, andfalse
otherwise. Don't forget to restore the original content of$TEXT
after you are done checking your user input by copying it back from the backup you made.
Example:
// backup and reset the current $TEXT variable$backupText=$TEXT;$TEXT=$userinput; if(checkwordblock()){// text contains blocked words ...} // restore $TEXT$TEXT=$backupText;
Disabling syntax plugins in user comments
You have written a syntax plugin which will be used in a restricted environment where anonymous users are not allowed to edit pages but allowed to comment using thediscussion plugin. You do not want to disable wiki syntax in comments completely, but want to disable the syntax provided by your plugin as it can become a risk in the wrong hands.
In your plugin'shandle
method, check whether$_REQUEST['comment']
is set – this indicates that the parsing process is working on a discussion comment.
Example:
global$INPUT; // we are parsing a submitted comment...if($INPUT->has('comment')){returnfalse;}
Sending popularity data
Since release 2015-08-10 “Detritus”
As a plugin developer, beware: since popularity data is public, you must not send sensitive information with this feature.
Thepopularity plugin already gather the number of time a plugin is installed on an instance of Dokuwiki.
It also let the possibility to developers, to send more data about usage. It can be used by plugins developers to know if a given obsolete feature is still used. To do it, you need to subscribe to thePLUGIN_POPULARITY_DATA_SETUP event. This event contains a key-value array. You should add a key which is the name of your plugin. The value should be either a string, or a key-value array itself (in this latter case, the data will be sent with the key<plugin-name>_<key>
)
Example:
- action.php
use dokuwiki\Extension\ActionPlugin;use dokuwiki\Extension\EventHandler;use dokuwiki\Extension\Event; class action_plugin_exampleextends ActionPlugin{publicfunction register(EventHandler$controller){$controller->register_hook('PLUGIN_POPULARITY_DATA_SETUP','AFTER',$this,'usageData');} publicfunction usageData(Event$event){$event->data['my_plugin_name']='my usage data'; /* or: $event->data['my_plugin_name'] = [ 'k1' => 'v1', 'k2' => 'v2' ]; */}}
A plugin which uses this feature is thenspages Plugin.