Questions answered by this recipe
- How do I create a recipe script for the PmWiki Cookbook?
- If my recipe has multiple files, how should I bundle them together for easy installation and maintenance?
PmWiki is distributed with a specific file and directory structure that provides a
cookbook/ directory for add-on scripts (recipe scripts).
Some (most?) recipes consist of a single PHP script that goes in the
The simplest add-on recipes are just a single PHP script with an obvious name (recipename.php). It's helpful for your script to include a line to prevent accidental execution of the script and, if it's appropriate, a single line to define the recipe's name and version so a WikiAdministrator can easily check for an update.
Your script can be uploaded and attached to the recipe's page in the Cookbook. Your recipe's Summary and category link(s) at the top of the recipe's page will automatically add it to the appropriate Cookbook index page(s).
If your recipe includes more than just one php script file, then you are encouraged to upload an archive file (i.e., 'zip file' or 'tarball'). The following structure is recommended:
Installing and upgrading become similar to upgrading PmWiki, for example using "
cp -a package-0.1/. pmwiki" or some similar method to recursively copy the structure into the PmWiki top-level directory. One file and one directory (e.g. the
package.php script and
package/ directory) will end up in the PmWiki's
cookbook/ directory and one directory (e.g.
package/) will end up in PmWiki's
The recipe can be activated in the same way as a single-script recipe, where the WikiAdministrator simply adds a line such as
@include_once("$FarmD/cookbook/package.php"); to a local customization file.
A recipe with this structure may be easily removed, too. The administrator can simply take the single line out of config.php and delete one script file and two directories to completely remove the recipe.
<?php if (!defined('PmWiki')) exit(); // Add a custom wikipage storage location for bundles pages. global $WikiLibDirs; $PageStorePath = dirname(__FILE__)."/wikilib.d/\$FullName"; $where = count($WikiLibDirs); if ($where>1) $where--; array_splice($WikiLibDirs, $where, 0, array(new PageStore($PageStorePath)));
Simpler Packaging Method
A simpler method of packaging the recipe forgoes the top-level "package-0.01" directory and assumes that packages are unpacking directly into the pmwiki root:
cookbook/ |- package.php `- package/ |- README.txt |- LICENSE.txt ...etc... pub/ `- package/ |- package.js |- package.jpg ...etc...
For example, the recipe author can easily create such an archive from a command line (on a *nix system):
zip -r package.zip cookbook/package.php cookbook/package pub/package
 (note for Windows desktop software users goes here)
Prevent accidental execution
To prevent scripts from being run outside of the PmWiki framework, any .php file should begin with the following line:
<?php if (!defined('PmWiki')) exit();
Omit the closing ?> php tag
It is recommended to omit the closing ?> tag. The tag is not required, and omitting it avoids problems with unnoticed spaces or blank lines at the end of the file. Also, some file transfer protocols may change the newline character(s) in the file, which can also cause problems. See also the Instruction separation page in the PHP manual.
Set a recipe name and version
In the first couple of lines of your extension, set the recipe+version for your extension so other code can tell that it's loaded.
$RecipeInfo['RecipeName']['Version'] = '2006-10-25';
The recipe name should match the recipe's CamelCase page name in the Cookbook and the version number should match the one shown on the recipe's cookbook page. This way your recipe will be compatible with automated update-checking. (See Cookbook:RecipeCheck .)
PmWiki and recipes follow a convention that variables acting as "flags" should generally begin with "$Enable...". As a corollary to this, PmWiki never has variables that begin with "$Disable...", so that admins don't have to remember which to use.
Use the SDV() ("set default value") function to assign initial values to configuration variables and give them reasonable default values.
If recipe authors include PmWiki documentation pages (a good idea if the module adds new markup),
- call them Cookbook.RecipeName -- this makes it easy for an administrator to provide a list of installed modules
- include a link to the recipe page on pmwiki.org
- include a link to a place where readers can see the recipe in action and (if appropriate) practice in a sandbox
- include a recipe category or category of skin
- assume that the primary readership are end users, not site administrators
- either place them in a recipe/wikilib.d directory (the preferred method if the recipe includes a bundlepages.php script)
- or advise the user to place them in the wiki.d or wikilib.d directory (with a warning that they may be over-written by subsequent updates)
- Start your source files with a comment that has your copyright, licensing information, and perhaps a brief description. (ExampleΔ) If your script is based on or contains code from other authors, be sure to mention their names.
- To avoid function collisions, any function not meant to override another should have the name of the package prepended. Thus "
ListToText()" should be "
PackageListToText()." Do this also for global variables. For example, don't use a variable
- Try to follow PmWiki's variable- and function-naming practices: $CamelCase for global variables, lower case for local variables
This advice seems too specific to include in the guidelines page.
# Insert any styles needed via a
$HTMLStylesFmt definition, or if you use a lot and want to call a separate stylesheet use
, but if this is used inside a function called by markup, then first create an empty entry with
at the beginning of the script. This will ensure the loading of the stylesheet at the right place in the sequence of css loading. Otherwise it will load last of all, possibly overwriting admin and skin style settings.
Automated documentation software packages can use your comments if you use JavaDoc style comments (specially formatted C-style comments using /** and */ for comment blocks and // for single-line comments). You start your script with the following
<?php if (!defined('PmWiki')) exit(); /** \file filename * \brief A brief, one-line module description * * A see-also line with a full URL to the Cookbook * (or other) page where the documentation is kept. * A longer description of your file, usage, etc. */ // This recipe's name and version $RecipeInfo['RecipeName']['Version'] = '2007-04-15';
You can also also use JavaDoc commenting style before functions, with \brief (skip line) full description, as outlined above (skip the \file filename portion).
Here are some archives that will greatly speed up the process of creating a brand new recipe:
It would be nice to add a guideline how to prepare your recipe for localization. It seems that most are without. Could that be added to the guidelines? Kenneth, 28 feb 2006.
See Discussion at ModuleGuidelines-Talk
Documenting large/complex recipes
If you have created a recipe that requires more than one page to document it well, just create a separate group for this purpose. So if you have created the recipe
you can create a separate group called e.g.
Cookbook-Votes or simply
where you then place the pages that document this recipe. You don't have to add
Cookbook-, but it might be useful if the name of the recipe is common.
- Debugging for cookbook authors - with some more tips