Module Guidelines

Summary: Outline of ideas for people who want to create and maintain cookbook recipes. Version: Prerequisites: Status: Maintainer: Categories: Uncategorized

Questions answered by this recipe



Distributed recipes go in the cookbook/ subdirectory.

PmWiki's distribution has a specific file/directory structure. Pm recommends that authors of Cookbook recipes, especially those packaged into archives of some sort, place such recipes in the cookbook/ directory. If the recipe includes publicly accessible files such as images or CSS stylesheets, they should go in a subdirectory of pub/.

Archive files (i.e., 'zipfiles' or 'tarballs') should be organized in the following layout:

     COPYING.package (license info)
     README.package (install & other instructions)
         package.php (single script, loads others if necessary)
            [any skins, images, etc.]
         Package.HomePage (documentation in PmWiki format)

This way, the files can be copied recursively ("cp -r foo-0.1/* pmwiki") from within their package directory into the PmWiki top-level directory and fit into the appropriate directory. From there, WikiAdministrators? can then be told to simply add a line such as @include_once("$FarmD/cookbook/recipe.php"); to a local customization? file, and not have to worry about conflicts with other files in local/ or scripts/.

Prevent accidental execution of cookbook scripts

To prevent scripts from being run outside of the PmWiki framework, the following line should occur inside any .php files and before any other command.

<?php if (!defined('PmWiki')) exit();

Other tips

  1. Start your source files with a comment that has
    1. your copyright
    2. licensing information.
    3. JavaDoc style comments when you want a comment publicly documented (use /** comment */ style, or /// for single-line comments) so that automated documentation software packages can use your comments.
     /** \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.
  1. 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 page name in the cookbook and the version number should match the one shown on the recipe's cookbook page.
  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. The configuration variables should have reasonable default values.
  4. Use the SDV() function to assign initial values to configuration variables.
  5. Try to follow PmWiki's variable- and function-naming practices: $CamelCase for global variables, lower case for local variables
  6. 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.
  7. Use JavaDoc commenting style before functions, with \brief (skip line) full description, as outlined above (skip the \file filename portion).
  8. See DebuggingForCookbookAuthors for hints, tips & tricks about writing modules for PmWiki


Proposal for a Simpler Approach

I propose a much simpler recipe structure as follows:

      README.txt    (introduction and installation instructions)
      LICENSE.txt   (license information)
      package.php   (single script that loads others if necessary)
         bundlepages.php  (script that Adds a page storage location)
            Site.Package         (documentation or whatever)
            Site.PackageXLPage   (translatable strings)
            [any pages you want to bundle]
         [any skins, images, etc.]

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

Here are some proof-of-concept archives that should greatly speed up the process of getting a new recipe started:

Among other things, this approach would make removing a recipe as simple as deleting two directories and taking the single line out of config.php.

HaganFox August 20, 2005

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.
The Cookbook page says "feel free to add your own contributions". I can create the recipe page itself; however editing Cookbook page requires a password. Or is it up to some admins to add recipes to the list? NeARAZ

See Also


 0: 00.00 00.00 config start
 1: 00.01 00.01 config end
 2: 00.12 00.11 MarkupToHTML begin
 3: 00.12 00.11 PageStore::ls begin wiki.d/{$FullName}
 4: 00.13 00.12 PageStore::ls merge wiki.d/{$FullName}
 5: 00.13 00.12 PageStore::ls end wiki.d/{$FullName}
 6: 00.14 00.12 PageStore::ls begin $FarmD/wikilib.d/{$FullName}
 7: 00.14 00.12 PageStore::ls merge $FarmD/wikilib.d/{$FullName}
 8: 00.14 00.12 PageStore::ls end $FarmD/wikilib.d/{$FullName}
 9: 00.17 00.14 ReadApprovedUrls SiteAdmin.ApprovedUrls begin
10: 00.17 00.15 ReadApprovedUrls SiteAdmin.ApprovedUrls end
11: 00.24 00.21 MarkupToHTML end
12: 00.25 00.21 MarkupToHTML begin
13: 00.26 00.22 MarkupToHTML end
14: 00.26 00.22 MarkupToHTML begin
15: 00.27 00.23 MarkupToHTML end
16: 00.27 00.23 now
Peak memory: 5,151,664 bytes