Module Guidelines

Summary: Guidelines for creating, distributing, and maintaining a recipe for the Cookbook.
Version: 2007-04-14
Prerequisites:
Status:
Maintainer:

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?

Description

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 cookbook/ directory, while others are multiple scripts and / or servable content such as CSS stylesheets, JavaScript files, and images that are bundled together as a package. You can also include wiki pages as part of your recipe.

Simple recipes

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).

Complex recipes

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:

package-0.01/
|- cookbook/
|  |- package.php              A single recipe script
|  `- package/                 A single directory
|     |- README.txt            Introduction and instructions
|     |- LICENSE.txt           License information (e.g. GNU GPL)
|     |- bundlepages.php       A script to add a page storage location
|     |- foo.php               Extra scripts include()ed by the recipe
|     `- wikilib.d             Custom page storage location
|        `-- Site.BundledPage  Any Bundled pages
`- pub/
   `- package/                 A single directory for "servable" files
      |- some-image.png        Image files
      |- recipe.js             JavaScript files
      `- recipe.css            CSS stylesheets

Installing and upgrading become similar to upgrading PmWiki, for example using "cp -a package-0.1/. pmwiki"[1] 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 pub/ directory.

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.

Here's bundlepages.php:

<?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

or drag and drop folders from Windows Explorer into Peazip or 7-Zip.

Notes

[1] (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 .)

Configuration variables

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.

Documentation guidelines

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)

Other tips

  1. 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.
  2. 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 $Count; use $FooCount instead.
  3. 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 $HTMLHeaderFmt['myrecipe']="<link ..../>";, but if this is used inside a function called by markup, then first create an empty entry with $HTMLHeaderFmt['myrecipe']=''; 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.

JavaDoc-style comments

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).

Comments

Here are some archives that will greatly speed up the process of creating a brand new recipe:

--HaganFox

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

Votes

you can create a separate group called e.g. Cookbook-Votes or simply Votes where you then place the pages that document this recipe. You don't have to add the prefix Cookbook-, but it might be useful if the name of the recipe is common.

See Also

Contributors

User notes? : If you use, used or reviewed this recipe, you can add your name. These statistics appear in the Cookbook listings and will help newcomers browsing through the wiki.