]> sipb.mit.edu Git - ikiwiki.git/blobdiff - doc/plugins/write.mdwn
Merge branch 'master' into autotag
[ikiwiki.git] / doc / plugins / write.mdwn
index 17c54ffc7a39e8f138c685cf1441b54ddc48d213..404c3b44f3ace0123194a29c14c5ede32d2be3dc 100644 (file)
@@ -3,8 +3,84 @@ written to extend ikiwiki in many ways. Despite the length of this page,
 it's not really hard. This page is a complete reference to everything a
 plugin might want to do. There is also a quick [[tutorial]].
 
 it's not really hard. This page is a complete reference to everything a
 plugin might want to do. There is also a quick [[tutorial]].
 
+[[!template id="note" text="""
+Ikiwiki is a compiler
+
+One thing to keep in mind when writing a plugin is that ikiwiki is a wiki
+*compiler*. So plugins influence pages when they are built, not when they
+are loaded. A plugin that inserts the current time into a page, for
+example, will insert the build time.
+
+Also, as a compiler, ikiwiki avoids rebuilding pages unless they have
+changed, so a plugin that prints some random or changing thing on a page
+will generate a static page that won't change until ikiwiki rebuilds the
+page for some other reason, like the page being edited.
+
+The [[tutorial]] has some other examples of ways that ikiwiki being a
+compiler may trip up the unwary.
+"""]]
+
 [[!toc levels=2]]
 
 [[!toc levels=2]]
 
+## Highlevel view of ikiwiki
+
+Ikiwiki mostly has two modes of operation. It can either be running
+as a compiler, building or updating a wiki; or as a cgi program, providing
+user interface for editing pages, etc. Almost everything ikiwiki does
+is accomplished by calling various hooks provided by plugins.
+
+### compiler
+
+As a compiler, ikiwiki starts by calling the `refresh` hook. Then it checks
+the wiki's source to find new or changed pages. The `needsbuild` hook is
+then called to allow manipulation of the list of pages that need to be
+built. 
+
+Now that it knows what pages it needs to build, ikiwiki runs two
+compile passes. First, it runs `scan` hooks, which collect metadata about
+the pages. Then it runs a page rendering pipeline, by calling in turn these
+hooks: `filter`, `preprocess`, `linkify`, `htmlize`, `postscan`,
+`pagetemplate`, `sanitize`, `format`.
+
+After all necessary pages are built, it calls the `change` hook. Finally,
+if a page is was deleted, the `delete` hook is called, and the files that
+page had previously produced are removed.
+
+### cgi
+
+The flow between hooks when ikiwiki is run as a cgi is best illustrated by
+an example.
+
+Alice browses to a page and clicks Edit.
+
+* Ikiwiki is run as a cgi. It assigns Alice a session cookie, and,
+  by calling the `auth` hooks, sees that she is not yet logged in.
+* The `sessioncgi` hooks are then called, and one of them,
+  from the [[editpage]] plugin, notices that the cgi has been told "do=edit".
+* The [[editpage]] plugin calls the `canedit` hook to check if this
+  page edit is allowed. The [[signinedit]] plugin has a hook that says not:
+  Alice is not signed in.
+* The [[signinedit]] plugin then launches the signin process. A signin
+  page is built by calling the `formbuilder_setup` hook.
+
+Alice signs in with her openid.
+
+* The [[openid]] plugin's `formbuilder` hook sees that an openid was
+  entered in the signin form, and redirects to Alice's openid provider.
+* Alice's openid provider calls back to ikiwiki. The [[openid]] plugin
+  has an `auth` hook that finishes the openid signin process.
+* Signin complete, ikiwiki returns to what Alice was doing before; editing
+  a page.
+* Now all the `canedit` hooks are happy. The [[editpage]] plugin calls
+  `formbuilder_setup` to display the page editing form.
+
+Alice saves her change to the page.
+
+* The [[editpage]] plugin's `formbuilder` hook sees that the Save button
+  was pressed, and calls the `checkcontent` and `editcontent` hooks.
+  Then it saves the page to disk, and branches into the compiler part
+  of ikiwiki to refresh the wiki.
+
 ## Types of plugins
 
 Most ikiwiki [[plugins]] are written in perl, like ikiwiki. This gives the
 ## Types of plugins
 
 Most ikiwiki [[plugins]] are written in perl, like ikiwiki. This gives the
@@ -31,18 +107,6 @@ they're the same as far as how they hook into ikiwiki. This document will
 explain how to write both sorts of plugins, albeit with an emphasis on perl
 plugins.
 
 explain how to write both sorts of plugins, albeit with an emphasis on perl
 plugins.
 
-## Remember: Ikiwiki is a compiler
-
-One thing to keep in mind when writing a plugin is that ikiwiki is a wiki
-*compiler*. So plugins influence pages when they are built, not when they
-are loaded. A plugin that inserts the current time into a page, for
-example, will insert the build time. Also, as a compiler, ikiwiki avoids
-rebuilding pages unless they have changed, so a plugin that prints some
-random or changing thing on a page will generate a static page that won't
-change until ikiwiki rebuilds the page for some other reason, like the page
-being edited. The [[tutorial]] has some other examples of ways that ikiwiki
-being a compiler may trip up the unwary.
-
 ## Plugin interface
 
 To import the ikiwiki plugin interface:
 ## Plugin interface
 
 To import the ikiwiki plugin interface:
@@ -472,7 +536,7 @@ The data returned is a list of `%config` options, followed by a hash
 describing the option. There can also be an item named "plugin", which
 describes the plugin as a whole. For example:
 
 describing the option. There can also be an item named "plugin", which
 describes the plugin as a whole. For example:
 
-                return
+               return
                        plugin => {
                                description => "description of this plugin",
                                safe => 1,
                        plugin => {
                                description => "description of this plugin",
                                safe => 1,
@@ -528,13 +592,13 @@ function of the ikiwiki wrapper when it is being generated.
 
 Several variables are exported to your plugin when you `use IkiWiki;`
 
 
 Several variables are exported to your plugin when you `use IkiWiki;`
 
-### %config
+### `%config`
 
 A plugin can access the wiki's configuration via the `%config`
 hash. The best way to understand the contents of the hash is to look at
 your ikiwiki setup file, which sets the hash content to configure the wiki.
 
 
 A plugin can access the wiki's configuration via the `%config`
 hash. The best way to understand the contents of the hash is to look at
 your ikiwiki setup file, which sets the hash content to configure the wiki.
 
-### %pagestate
+### `%pagestate`
 
 The `%pagestate` hash can be used by plugins to save state that they will need
 next time ikiwiki is run. The hash holds per-page state, so to set a value,
 
 The `%pagestate` hash can be used by plugins to save state that they will need
 next time ikiwiki is run. The hash holds per-page state, so to set a value,
@@ -552,7 +616,7 @@ When pages are deleted, ikiwiki automatically deletes their pagestate too.
 Note that page state does not persist across wiki rebuilds, only across
 wiki updates.
 
 Note that page state does not persist across wiki rebuilds, only across
 wiki updates.
 
-### %wikistate
+### `%wikistate`
 
 The `%wikistate` hash can be used by a plugin to store persistant state
 that is not bound to any one page. To set a value, use
 
 The `%wikistate` hash can be used by a plugin to store persistant state
 that is not bound to any one page. To set a value, use
@@ -561,28 +625,52 @@ serialize, `$key` is any string you like, and `$id` must be the same as the
 "id" parameter passed to `hook()` when registering the plugin, so that the
 state can be dropped if the plugin is no longer used.
 
 "id" parameter passed to `hook()` when registering the plugin, so that the
 state can be dropped if the plugin is no longer used.
 
-### %links
+### `%links`
 
 The `%links` hash can be used to look up the names of each page that
 a page links to. The name of the page is the key; the value is an array
 reference. Do not modify this hash directly; call `add_link()`.
 
 
 The `%links` hash can be used to look up the names of each page that
 a page links to. The name of the page is the key; the value is an array
 reference. Do not modify this hash directly; call `add_link()`.
 
-### %destsources
+       $links{"foo"} = ["bar", "baz"];
 
 
-The `%destsources` hash records the name of the source file used to
-create each destination file. The key is the output filename (ie,
-"foo/index.html"), and the value is the source filename that it was built
-from (eg, "foo.mdwn"). Note that a single source file may create multiple
-destination files. Do not modify this hash directly; call `will_render()`.
+### `%typedlinks`
+
+The `%typedlinks` hash records links of specific types. Do not modify this
+hash directly; call `add_link()`. The keys are page names, and the values
+are hash references. In each page's hash reference, the keys are link types
+defined by plugins, and the values are hash references with link targets
+as keys, and 1 as a dummy value, something like this:
+
+       $typedlinks{"foo"} = {
+               tag => { short_word => 1, metasyntactic_variable => 1 },
+               next_page => { bar => 1 },
+       };
+
+Ordinary [[WikiLinks|ikiwiki/WikiLink]] appear in `%links`, but not in
+`%typedlinks`.
 
 
-### %pagesources
+### `%pagesources`
 
 The `%pagesources` has can be used to look up the source filename
 of a page. So the key is the page name, and the value is the source
 filename. Do not modify this hash.
 
 
 The `%pagesources` has can be used to look up the source filename
 of a page. So the key is the page name, and the value is the source
 filename. Do not modify this hash.
 
+       $pagesources{"foo"} = "foo.mdwn";
+
+### `%destsources`
+
+The `%destsources` hash records the name of the source file used to
+create each destination file. The key is the output filename (ie,
+"foo/index.html"), and the value is the source filename that it was built
+from (eg, "foo.mdwn"). Note that a single source file may create multiple
+destination files. Do not modify this hash directly; call `will_render()`.
+       
+       $destsources{"foo/index.html"} = "foo.mdwn";
+
 ## Library functions
 
 ## Library functions
 
+Several functions are exported to your plugin when you `use IkiWiki;`
+
 ### `hook(@)`
 
 Hook into ikiwiki's processing. See the discussion of hooks above.
 ### `hook(@)`
 
 Hook into ikiwiki's processing. See the discussion of hooks above.
@@ -646,7 +734,10 @@ Additional named parameters can be specified:
 * `filter` is a reference to a function, that is called and passed a page,
   and returns true if the page should be filtered out of the list.
 * `sort` specifies a sort order for the list. See
 * `filter` is a reference to a function, that is called and passed a page,
   and returns true if the page should be filtered out of the list.
 * `sort` specifies a sort order for the list. See
-  [[ikiwiki/PageSpec/sorting]] for the avilable sort methods.
+  [[ikiwiki/PageSpec/sorting]] for the avilable sort methods. Note that
+  if a sort method is specified that depends on the
+  page content (such as 'meta(foo)'), the deptype needs to be set to
+  a content dependency.
 * `reverse` if true, sorts in reverse.
 * `num` if nonzero, specifies the maximum number of matching pages that
   will be returned.
 * `reverse` if true, sorts in reverse.
 * `num` if nonzero, specifies the maximum number of matching pages that
   will be returned.
@@ -664,7 +755,7 @@ By default, dependencies are full content dependencies, meaning that the
 page will be updated whenever anything matching the PageSpec is modified.
 This can be overridden by passing a `deptype` value as the third parameter.
 
 page will be updated whenever anything matching the PageSpec is modified.
 This can be overridden by passing a `deptype` value as the third parameter.
 
-#### `pagespec_match($$;@)`
+### `pagespec_match($$;@)`
 
 Passed a page name, and [[ikiwiki/PageSpec]], returns a true value if the
 [[ikiwiki/PageSpec]] matches the page.
 
 Passed a page name, and [[ikiwiki/PageSpec]], returns a true value if the
 [[ikiwiki/PageSpec]] matches the page.
@@ -694,7 +785,7 @@ dependency type from one or more of these keywords:
 
 If multiple types are specified, they are combined.
 
 
 If multiple types are specified, they are combined.
 
-#### `bestlink($$)`
+### `bestlink($$)`
 
 Given a page and the text of a link on the page, determine which
 existing page that link best points to. Prefers pages under a
 
 Given a page and the text of a link on the page, determine which
 existing page that link best points to. Prefers pages under a
@@ -702,7 +793,7 @@ subdirectory with the same name as the source page, failing that
 goes down the directory tree to the base looking for matching
 pages, as described in [[ikiwiki/SubPage/LinkingRules]].
 
 goes down the directory tree to the base looking for matching
 pages, as described in [[ikiwiki/SubPage/LinkingRules]].
 
-#### `htmllink($$$;@)`
+### `htmllink($$$;@)`
 
 Many plugins need to generate html links and add them to a page. This is
 done by using the `htmllink` function. The usual way to call
 
 Many plugins need to generate html links and add them to a page. This is
 done by using the `htmllink` function. The usual way to call
@@ -839,6 +930,10 @@ time.
 
 This is the standard gettext function, although slightly optimised.
 
 
 This is the standard gettext function, although slightly optimised.
 
+### `ngettext`
+
+This is the standard ngettext function, although slightly optimised.
+
 ### `urlto($$;$)`
 
 Construct a relative url to the first parameter from the page named by the
 ### `urlto($$;$)`
 
 Construct a relative url to the first parameter from the page named by the
@@ -863,11 +958,31 @@ Optionally, a third parameter can be passed, to specify the preferred
 filename of the page. For example, `targetpage("foo", "rss", "feed")`
 will yield something like `foo/feed.rss`.
 
 filename of the page. For example, `targetpage("foo", "rss", "feed")`
 will yield something like `foo/feed.rss`.
 
-### `add_link($$)`
+### `add_link($$;$)`
 
 This adds a link to `%links`, ensuring that duplicate links are not
 added. Pass it the page that contains the link, and the link text.
 
 
 This adds a link to `%links`, ensuring that duplicate links are not
 added. Pass it the page that contains the link, and the link text.
 
+An optional third parameter sets the link type. If not specified,
+it is an ordinary [[ikiwiki/WikiLink]].
+
+### `add_autofile($$$)`
+
+Sometimes you may want to add a file to the `srcdir` as a result of content
+of other pages. For example, [[plugins/tag]] pages can be automatically
+created as needed. This function can be used to do that. 
+
+The three parameters are the filename to create (relative to the `srcdir`),
+the name of the plugin, and a callback function. The callback will be
+called if it is appropriate to automatically add the file, and should then
+take care of creating it, and doing anything else it needs to (such as
+checking it into revision control). Note that the callback may not always
+be called. For example, if an automatically added file is deleted by the
+user, ikiwiki will avoid re-adding it again.
+
+This function needs to be called during the scan hook, or earlier in the
+build process, in order to add the file early enough for it to be built.
+
 ## Miscellaneous
 
 ### Internal use pages
 ## Miscellaneous
 
 ### Internal use pages
@@ -987,6 +1102,17 @@ it up in the history.
 
 It's ok if this is not implemented, and throws an error.
 
 
 It's ok if this is not implemented, and throws an error.
 
+If the RCS cannot determine a ctime for the file, return 0.
+
+#### `rcs_getmtime($)`
+
+This is used to get the page modification time for a file from the RCS, by
+looking it up in the history.
+
+It's ok if this is not implemented, and throws an error.
+
+If the RCS cannot determine a mtime for the file, return 0.
+
 #### `rcs_receive()`
 
 This is called when ikiwiki is running as a pre-receive hook (or
 #### `rcs_receive()`
 
 This is called when ikiwiki is running as a pre-receive hook (or
@@ -1034,6 +1160,24 @@ For example, "backlink(foo)" is influenced by the contents of page foo;
 they match; "created_before(foo)" is influenced by the metadata of foo;
 while "glob(*)" is not influenced by the contents of any page.
 
 they match; "created_before(foo)" is influenced by the metadata of foo;
 while "glob(*)" is not influenced by the contents of any page.
 
+### Sorting plugins
+
+Similarly, it's possible to write plugins that add new functions as
+[[ikiwiki/pagespec/sorting]] methods. To achieve this, add a function to
+the IkiWiki::SortSpec package named `cmp_foo`, which will be used when sorting
+by `foo` or `foo(...)` is requested.
+
+The names of pages to be compared are in the global variables `$a` and `$b`
+in the IkiWiki::SortSpec package. The function should return the same thing
+as Perl's `cmp` and `<=>` operators: negative if `$a` is less than `$b`,
+positive if `$a` is greater, or zero if they are considered equal. It may
+also raise an error using `error`, for instance if it needs a parameter but
+one isn't provided.
+
+The function will also be passed one or more parameters. The first is
+`undef` if invoked as `foo`, or the parameter `"bar"` if invoked as `foo(bar)`;
+it may also be passed additional, named parameters.
+
 ### Setup plugins
 
 The ikiwiki setup file is loaded using a pluggable mechanism. If you look
 ### Setup plugins
 
 The ikiwiki setup file is loaded using a pluggable mechanism. If you look