X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/c4ebdd6f467f3361b1f444d9462e10acdbcf9322..36c3c518f3c8d591a39c16e99435c4cd6296858e:/doc/plugins/write.mdwn
diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn
index e60314485..c3f531b66 100644
--- a/doc/plugins/write.mdwn
+++ b/doc/plugins/write.mdwn
@@ -31,20 +31,26 @@ 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`, `indexhtml`,
-`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.
+As a compiler, ikiwiki starts by calling the
+[[`refresh`|plugins/write#refresh]] hook. Then it checks the wiki's source to
+find new or changed pages. The [[`needsbuild`|plugins/write#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`|plugins/write#scan]] hooks, which collect
+metadata about the pages. Then it runs a page rendering pipeline, by calling
+in turn these hooks: [[`filter`|plugins/write#filter]],
+[[`preprocess`|plugins/write#preprocess]],
+[[`linkify`|plugins/write#linkify]], [[`htmlize`|plugins/write#htmlize]],
+[[`indexhtml`|plugins/write#indexhtml]],
+[[`pagetemplate`|plugins/write#pagetemplate]],
+[[`sanitize`|plugins/write#sanitize]], [[`format`|plugins/write#format]].
+
+After all necessary pages are built, it calls the
+[[`changes`|plugins/write#changes]] hook. Finally, if a page was deleted, the
+[[`delete`|plugins/write#delete]] hook is called, and the files that page had
+previously produced are removed.
### cgi
@@ -53,33 +59,39 @@ 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.
+* Ikiwiki is run as a cgi. It assigns Alice a session cookie, and, by calling
+ the [[`auth`|plugins/write#auth]] hooks, sees that she is not yet logged in.
+* The [[`sessioncgi`|plugins/write#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`|plugins/write#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`|plugins/write#formbuilder]]
+ 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.
+* The [[openid]] plugin's [[`formbuilder`|plugins/write#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`|plugins/write#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.
+* Now all the [[`canedit`|plugins/write#canedit]] hooks are happy. The
+ [[editpage]] plugin calls
+ [[`formbuilder_setup`|plugins/write#formbuilder]] 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.
+* The [[editpage]] plugin's [[`formbuilder`|plugins/write#formbuilder]] hook
+ sees that the Save button was pressed, and calls the
+ [[`checkcontent`|plugins/write#checkcontent]] and
+ [[`editcontent`|plugins/write#editcontent]] hooks. Then it saves the page
+ to disk, and branches into the compiler part of ikiwiki to refresh the wiki.
## Types of plugins
@@ -165,7 +177,7 @@ is populated at this point, but other state has not yet been loaded.
The function is passed no values. It's ok for the function to call
`error()` if something isn't configured right.
-### refresh
+### refresh
hook(type => "refresh", id => "foo", call => \&refresh);
@@ -173,7 +185,7 @@ This hook is called just before ikiwiki scans the wiki for changed files.
It's useful for plugins that need to create or modify a source page. The
function is passed no values.
-### needsbuild
+### needsbuild
hook(type => "needsbuild", id => "foo", call => \&needsbuild);
@@ -187,7 +199,7 @@ modified version of its input. It can add or remove files from it.
The second parameter passed to the function is a reference to an array of
files that have been deleted.
-### scan
+### scan
hook(type => "scan", id => "foo", call => \&scan);
@@ -199,7 +211,30 @@ them to `%links`. Present in IkiWiki 2.40 and later.
The function is passed named parameters "page" and "content". Its return
value is ignored.
-### filter
+### readtemplate
+
+ hook(type => "readtemplate", id => "foo", call => \&readtemplate);
+
+Runs on the raw source of a page or `*.tmpl` file that is being
+used as a template, before it is parsed by [[!cpan HTML::Template]].
+For instance, the [[plugins/templatebody]] plugin uses this to return
+the content of the [[ikiwiki/directive/templatebody]] directive (if there
+is one) instead of the page's full content.
+
+The function is passed named parameters:
+
+* `id`: the name under which the template was looked up,
+ such as `page.tmpl` or `note`
+* `page`: the name of the template as a page or attachment in the wiki,
+ such as `templates/note`, or `undef` if it's outside the wiki (e.g. in
+ `/usr/share/ikiwiki/templates`)
+* `content`: the content of the corresponding file
+* `untrusted`: true if the template was loaded from the wiki or an underlay,
+ false if it was loaded from a trusted location
+
+It should return the replacement content.
+
+### filter
hook(type => "filter", id => "foo", call => \&filter);
@@ -207,7 +242,7 @@ Runs on the full raw source of a page, before anything else touches it, and
can make arbitrary changes. The function is passed named parameters "page",
"destpage", and "content". It should return the filtered content.
-### preprocess
+### preprocess
Adding a preprocessor [[ikiwiki/directive]] is probably the most common use
of a plugin.
@@ -250,7 +285,7 @@ format at preprocessor time. Text output by a preprocessor directive will
be linkified and passed through markdown (or whatever engine is used to
htmlize the page) along with the rest of the page.
-### linkify
+### linkify
hook(type => "linkify", id => "foo", call => \&linkify);
@@ -263,7 +298,7 @@ Plugins that implement linkify must also implement a scan hook, that scans
for the links on the page and adds them to `%links` (typically by calling
`add_link`).
-### htmlize
+### htmlize
hook(type => "htmlize", id => "ext", call => \&htmlize);
@@ -287,7 +322,7 @@ like `Makefile` that have no extension.
If `hook` is passed an optional "longname" parameter, this value is used
when prompting a user to choose a page type on the edit page form.
-### indexhtml
+### indexhtml
hook(type => "indexhtml", id => "foo", call => \&indexhtml);
@@ -298,7 +333,7 @@ update search indexes. Added in ikiwiki 2.54.
The function is passed named parameters "page", "destpage", and "content".
Its return value is ignored.
-### pagetemplate
+### pagetemplate
hook(type => "pagetemplate", id => "foo", call => \&pagetemplate);
@@ -333,7 +368,7 @@ page (next to Edit, RecentChanges, etc). The hook is passed a "page"
parameter, and can return a list of html fragments to add to the action
bar.
-### sanitize
+### sanitize
hook(type => "sanitize", id => "foo", call => \&sanitize);
@@ -343,7 +378,7 @@ modify the body of a page after it has been fully converted to html.
The function is passed named parameters: "page", "destpage", and "content",
and should return the sanitized content.
-### format
+### format
hook(type => "format", id => "foo", call => \&format);
@@ -356,21 +391,48 @@ when the page is being previewed.)
The function is passed named parameters: "page" and "content", and
should return the formatted content.
-### delete
+### build_affected
+
+ hook(type => "build_affected", id => "foo", call => \&build_affected);
+
+This hook is called after the directly changed pages have been built,
+and can cause extra pages to be built. If links and backlinks were provided
+by a plugin, this would be where that plugin would rebuild pages whose
+backlinks have changed, for instance. The [[trail]] plugin uses this hook
+to rebuild pages whose next or previous page has changed.
+
+The function should currently ignore its parameters. It returns a list with
+an even number of items (a hash in list context), where the first item of
+each pair is a page name to be rebuilt (if it was not already rebuilt), and
+the second is a log message resembling
+`building plugins/write because the phase of the moon has changed`.
+
+### delete
hook(type => "delete", id => "foo", call => \&delete);
-Each time a page or pages is removed from the wiki, the referenced function
+After a page or pages is removed from the wiki, the referenced function
is called, and passed the names of the source files that were removed.
-### change
+### rendered
- hook(type => "change", id => "foo", call => \&render);
+ hook(type => "rendered", id => "foo", call => \&rendered);
-Each time ikiwiki renders a change or addition (but not deletion) to the
+After ikiwiki renders a change or addition (but not deletion) to the
wiki, the referenced function is called, and passed the names of the
source files that were rendered.
+(This hook used to be called "change", but that was not accurate.
+For now, plugins using the old hook name will still work.)
+
+### changes
+
+ hook(type => "changes", id => "foo", call => \&changes);
+
+After ikiwiki renders changes to the wiki, the referenced function is
+called, and passed the names of the source files that were added, modified,
+or deleted.
+
### cgi
hook(type => "cgi", id => "foo", call => \&cgi);
@@ -383,7 +445,7 @@ parameters, and if it will handle this CGI request, output a page
Note that cgi hooks are called as early as possible, before any ikiwiki
state is loaded, and with no session information.
-### auth
+### auth
hook(type => "auth", id => "foo", call => \&auth);
@@ -396,7 +458,7 @@ object's "name" parameter to the authenticated user's name. Note that
if the name is set to the name of a user who is not registered,
a basic registration of the user will be automatically performed.
-### sessioncgi
+### sessioncgi
hook(type => "sessioncgi", id => "foo", call => \&sessioncgi);
@@ -405,7 +467,7 @@ is only run once a session object is available. It is passed both a CGI
object and a session object. To check if the user is in fact signed in, you
can check if the session object has a "name" parameter set.
-### canedit
+### canedit
hook(type => "canedit", id => "foo", call => \&canedit);
@@ -445,7 +507,7 @@ bypass it). It works exactly like the `canedit` hook,
but is passed the named parameters `cgi` (a CGI object), `session` (a
session object), `src`, `srcfile`, `dest` and `destfile`.
-### checkcontent
+### checkcontent
hook(type => "checkcontent", id => "foo", call => \&checkcontent);
@@ -466,7 +528,7 @@ should return a message stating what the problem is, or a function
that can be run to perform whatever action is necessary to allow the user
to post the content.
-### editcontent
+### editcontent
hook(type => "editcontent", id => "foo", call => \&editcontent);
@@ -477,7 +539,7 @@ user, the page name, a `CGI` object, and the user's `CGI::Session`.
It can modify the content as desired, and should return the content.
-### formbuilder
+### formbuilder
hook(type => "formbuilder_setup", id => "foo", call => \&formbuilder_setup);
hook(type => "formbuilder", id => "foo", call => \&formbuilder);
@@ -580,6 +642,7 @@ describes the plugin as a whole. For example:
* `description` is a short description of the option.
* `link` is a link to further information about the option. This can either
be a [[ikiwiki/WikiLink]], or an url.
+* `htmldescription` is displayed instead of the description by websetup.
* `advanced` can be set to true if the option is more suitable for advanced
users.
* `safe` should be false if the option should not be displayed in unsafe
@@ -593,7 +656,7 @@ describes the plugin as a whole. For example:
strictly required.
* `section` can optionally specify which section in the config file
the plugin fits in. The convention is to name the sections the
- same as the tags used for [[plugins|plugin]] on this wiki.
+ same as the tags used for [[plugins]] on this wiki.
### genwrapper
@@ -644,7 +707,7 @@ wiki updates.
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
-`$wikistate{$id}{$key}=$value, where `$value` is anything Storable can
+`$wikistate{$id}{$key}=$value`, where `$value` is anything Storable can
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.
@@ -679,17 +742,24 @@ 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.
+Attachments also appear in this hash, with the same key and value.
+
$pagesources{"foo"} = "foo.mdwn";
+ $pagesources{"logo/ikiwiki.png"} = "logo/ikiwiki.png";
+
### `%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
+"foo/index.html"), and the value is the name of the page that it was built
+from (eg, "foo"). 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";
+
+Attachments also appear in this hash, with the same key and value.
+
+ $destsources{"foo/index.html"} = "foo";
+ $destsources{"logo/ikiwiki.png"} = "logo/ikiwiki.png";
## Library functions
@@ -740,6 +810,8 @@ with no ".tmpl" extension. Template pages are normally looked for in
the templates/ directory. If the page name starts with "/", a page
elsewhere in the wiki can be used.
+If the template is not found, or contains a syntax error, an error is thrown.
+
### `template_depends($$;@)`
Use this instead of `template()` if the content of a template is being
@@ -980,14 +1052,22 @@ This is the standard gettext function, although slightly optimised.
This is the standard ngettext function, although slightly optimised.
-### `urlto($$;$)`
+### `urlto($;$$)`
Construct a relative url to the first parameter from the page named by the
second. The first parameter can be either a page name, or some other
destination file, as registered by `will_render`.
-If the third parameter is passed and is true, an absolute url will be
-constructed instead of the default relative url.
+Provide a second parameter whenever possible, since this leads to better
+behaviour for the [[plugins/po]] plugin and `file:///` URLs.
+
+If the second parameter is not specified (or `undef`), the URL will be
+valid from any page on the wiki, or from the CGI; if possible it'll
+be a path starting with `/`, but an absolute URL will be used if
+the wiki and the CGI are on different domains.
+
+If the third parameter is passed and is true, the url will be a fully
+absolute url. This is useful when generating an url to publish elsewhere.
### `newpagefile($$)`
@@ -1099,9 +1179,7 @@ to version control; the subdir can be added if so.
Remove a file. The filename is relative to the root of the srcdir.
Note that this should not commit the removal, it should only prepare for it
-to be committed when `rcs_commit` (or `rcs_commit_staged`) is called. Note
-that the new file may be in a new subdir that is not yet in version
-control; the subdir can be added if so.
+to be committed when `rcs_commit` (or `rcs_commit_staged`) is called.
#### `rcs_rename($$)`
@@ -1141,19 +1219,19 @@ The data structure returned for each change is:
],
}
-#### `rcs_diff($)`
+#### `rcs_diff($;$)`
+
+The first parameter is the rev from `rcs_recentchanges`.
+The optional second parameter is how many lines to return (default: all).
-The parameter is the rev from `rcs_recentchanges`.
Should return a list of lines of the diff (including \n) in list
-context, and the whole diff in scalar context.
+context, and a string containing the whole diff in scalar context.
#### `rcs_getctime($)`
This is used to get the page creation 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 ctime for the file, return 0.
#### `rcs_getmtime($)`
@@ -1174,9 +1252,9 @@ sense to implement for all RCSs.
It should examine the incoming changes, and do any sanity
checks that are appropriate for the RCS to limit changes to safe file adds,
-removes, and changes. If something bad is found, it should exit
-nonzero, to abort the push. Otherwise, it should return a list of
-files that were changed, in the form:
+removes, and changes. If something bad is found, it should die, to abort
+the push. Otherwise, it should return a list of files that were changed,
+in the form:
{
file => # name of file that was changed
@@ -1189,6 +1267,42 @@ files that were changed, in the form:
The list will then be checked to make sure that each change is one that
is allowed to be made via the web interface.
+#### `rcs_preprevert($)`
+
+This is called by the revert web interface. It is passed a RCS-specific
+change ID, and should determine what the effects would be of reverting
+that change, and return the same data structure as `rcs_receive`.
+
+Like `rcs_receive`, it should do whatever sanity checks are appropriate
+for the RCS to limit changes to safe changes, and die if a change would
+be unsafe to revert.
+
+#### `rcs_revert($)`
+
+This is called by the revert web interface. It is passed a named
+parameter rev that is the RCS-specific change ID to revert.
+
+It should try to revert the specified rev, and leave the reversion staged
+so `rcs_commit_staged` will complete it. It should return undef on _success_
+and an error message on failure.
+
+This hook and `rcs_preprevert` are optional, if not implemented, no revert
+web interface will be available.
+
+### `rcs_find_changes($)`
+
+Finds changes committed since the passed RCS-specific rev. Returns
+a hash of the files changed, a hash of the files deleted, and the
+current rev.
+
+This hook is optional.
+
+### `rcs_get_current_rev()`
+
+Gets a RCS-specific rev, which can later be passed to `rcs_find_changes`.
+
+This hook is optional.
+
### PageSpec plugins
It's also possible to write plugins that add new functions to