TIP MirrorWebPlugin is not installed on Foswiki.org.


Mirror a web to another, with filtering on the topic text and fields.

Sometimes you want to share the contents of your wiki with other people, but without revealing all the contents of your topics, and without revealing all topics to everybody. Other times you want to allow free edit within a group of users, and only publish known, edited, versions of that content for public consumption.

This plugin lets you do just that. The basic idea is that your master issues web, call it "Internal", is mirrored to a slave web, call it "Public". The mirrored topics in "Public" contain data taken from the "Internal" web, but passed through filters.

For example, consider an issue tracker, where employees can see all data in all issues, but the customer must only see a subset of the data associated with their specific issues. After an initial update to populate the mirror, topics are mirrored automatically when they are saved, or an attachment is added.

Another example is where the plugin is used as part of a publishing process. Access to the "update mirror" step is restricted to certain users, so only those users can mirror the "Internal" web to the "Public" web.

  • Filter form fields, so that only selected fields get moved into the mirror topic,
  • Filter the topic text,
  • Derive access controls for the mirrored topic from form fields (and other sophisticated filtering),
  • Run automatically whenever a topic is saved in the master web, or run only when requested,
  • Update tool allows you to change the filtering criteria after mirroring has already started.


There are two main modes of operation; always mirror, where topics are mirrored every time they are saved, and mirror on demand, where mirroring is manually triggered.

To start mirroring a web to another web in either mode, create the mirror web (the copy) and set the web preference MIRRORWEBPLUGIN_MIRROR in the web that you want to mirror (the original). i.e if you want to mirror web "Internal" to web "Public", then
in Internal.WebPreferences.

Add the %UPDATEMIRROR% macro to a topic in the web - either WebPreferences or WebHome would be a good choice. This will generate a button in that topic that will update all the topics in the mirror in one go. In "always mirror" mode you usually only need to do this when mirroring an existing web for the first time. In "mirror on demand" mode, this button is how you trigger an update.

The transformation rules are defined in a topic pointed to by MIRRORWEBPLUGIN_RULES - again this should refer to the fully-qualified name of a topic (usually stored in the mirror web). This topic must contain a single verbatim block with a filter description, which is best explained using an example:
TaskTeamForm => {
    FIELD => {
        Summary => [],
        Status => []
        '.*\.gif' => []
    text => []
none => {
   text => []
other => {
   text => [ 'TEXTORCOMMENT' ]
This defines a set of filters for all topics that carry:
  1. a specific type of form, or
  2. none for topics with no form, or
  3. other for topics that have a form but it isn't explicitly listed, or if it would match 'none' but 'none' is not defined. If a topic doesn't match any of the defined rule sets, it won't be mirrored.

Each form type maps parts of the topic to another hash or to a filter; at this level the keys 'FIELD', 'FILEATTACHMENT' and 'text' can be used, relating to the individual fields in the form and the main body text respectively. 'text' is mapped direct to a filter. Under 'FIELD' and 'FILEATTACHMENT', a list of regular expressions match the full name of each entry, and map them to a list of filter names.
  • [] means the same as 'accept this without modification'.
  • Any fields/attachents not matched by any of the rules will be ignored.
  • If a name is matched by more than one set of filters, then only the first match will be applied.
  • FIELD matches the field name; FILEATTACHMENT matches the attachment name.

Thus the example defines rules for topics that (1) have the form 'TaskTeamForm', (2) have no form or (3) have a form but it isn't known. If the topic has no form, the text is just copied. If the topic has a form, but it doesn't have any rules, then the transformation is to add the text returned by the 'UNKNOWN' function before the topic text. If the topic has the 'TaskTeamForm', then the body text and the 'Summary', and 'Status' fields from the form are all copied across without modification. The filtering of 'Customer' field is used to create a group name that is then used to set the access controls on the mirror topic.

Note that if the mirror topic already exists, then as much of the topic is retained as possible. Only the fields explicitly listed in the filters will be overwritten. This allows users to interact with the mirror and (for example) add comments, attach documents etc.

The following example rules are installed with the plugin:
Rule name Description
ALLOWTOPICVIEW Limit who can view the topic to people (wiki)named in a comma-separated list
ALLOWTOPICCHANGE Limit who can change the topic to people (wiki)named in a comma-separated list
CLEARPREFERENCES Removes all META:PREFERENCE settings from the mirror topic. It's usually wise to do this prior to setting access controls.
FORMFIELD(Fieldname) Gets the value of the named formfield from the topic named in the field. See VarFORMFIELD.
MAKEGROUP Convert the field value to a group name, by converting it to a wikiword, prepending the user web name and appending "Group".
NOSET This is a 'NOP' that is used to terminate a filter chain without setting a value in the mirror topic. Use it when you want to process the value of a field, but without exporting that value to the mirror.
RESTORE Restore a previously saved value from earlier in the filter chain (see SAVE)
SAVE Save the (possibly filtered) value of the field at this point; it can be restored later in the filter chain using RESTORE. Only one value can be saved.
SUBSCRIBE Use the MailerContrib to subscribe people (wiki)named in a comma-separated list to topic change notification
TEXTORCOMMENT If the mirror topic contains text, then retain it; otherwise add %COMMENT%, The topic text from the mirrored web is discarded (use with text, not FIELD)

The filtering functions are implemented in Perl modules on the server. You can extend the set of available functions by creating a new package in lib/Foswiki/Plugins/MirrorWebPlugin/Rules/. For example, to append the current date to a field, create lib/Foswiki/Plugins/MirrorWebPlugin/Rules/ADDDATE.pm:
package Foswiki::Func::MirrorWebPlugin::Rules::ADDDATE;
use Foswiki::Time;
sub execute {
    my ($topicObject, $mirrorObject, $data) = @_;
    return unless $data;
    $data->{value} .= ' ' .
           Foswiki::Time::formatTime(time, '$year-$mo-$day');
    return $data;
All the functions useable in plugins (such as Foswiki::Func) are also available in filters. The parameters to the execute function are:
$topicObject The Foswiki::Meta object of the source topic
$mirrorObject The Foswiki::Meta object of the mirror topic
$data For a FIELD or FILEATTACHMENT, this is the structure representing the field, as stored in Foswiki::Meta. For text, it is the text of the topic.
@params Any additional parameters supplied in the rules, in brackets after the filter name (e.g for a filter MYFILTER(Master,Slave) then @params will be ('Master', 'Slave')
Filters can operate directly on these objects; any changes to the $topicObject will be discarded. Filters should return $data, which is then passed to the next filter. The return value of the final filter function is used to set the data in the mirror topic. If it is undef, then the field will not be set in the mirror topic.

If you create new filtering functions that may be useful to the Foswiki community, please attach them to Foswiki:Extensions.MirrorWebPlugin, with a comment describing what they do.

Enabling mirror-on-demand mode

If you have followed the instructions to this point, your mirror is configured in always mirror mode. You can change to mirror on demand by setting the ALLOWWEBMIRROR preference in the web preferences of the web being mirrored. This operates like the standard access controls, and if it is set to a list of names it will:
  1. Disable automatic mirroring on topic saves (for everyone),
  2. Only allow the listed people access to the %UPDATEMIRROR% button.


Obviously if a footpad were able to change the mirroring rules for a web, they could mirror content to somewhere it is not intended to go. For this reason you are recommended to finalise all the MIRRORWEBPLUGIN_ preferences, and lock down the mirror rules topic.

Installation Instructions

You do not need to install anything in the browser to use this extension. The following instructions are for the administrator who installs the extension on the server.

Open configure, and open the "Extensions" section. Use "Find More Extensions" to get a list of available extensions. Select "Install".

If you have any problems, or if the extension isn't available in configure, then you can still install manually from the command-line. See http://foswiki.org/Support/ManuallyInstallingExtensions for more help.


Another great Foswiki extension from the wikiringlogo20x20.png WikiRing - working together to improve your wiki experience!

Many thanks to the following sponsors for supporting this work:

Author(s): Crawford Currie http://c-dot.co.uk
Copyright: © 2009-2010 Rental Result
License: GPL (Gnu General Public License)
Release: 1.1.6
Version: 6207 (2010-02-02)
Change History:  
2 Feb 2010 1.1.6 Foswiki:Tasks/Item8457: fixed broken synch when invoked from save handler
21 Jan 2010 1.1.5 Foswiki:Tasks/Item8407: fixed 'none' rule
6 Jan 2010 1.1.4 Correct problem with tainted variables, and add a title attribute to META:PREFERENCEs to work around Foswiki:Tasks.Item2601
21 Dec 2009 1.1.3 Support attachment synching, and make field name matches regexes
11 Dec 2009 1.1.2 first released version
Dependencies: None
Home page: http://foswiki.org/bin/view/Extensions/MirrorWebPlugin
Support: http://foswiki.org/bin/view/Support/MirrorWebPlugin

Topic revision: r9 - 02 Feb 2010, CrawfordCurrie
The copyright of the content on this website is held by the contributing authors, except where stated elsewhere. See Copyright Statement. Creative Commons License    Legal Imprint    Privacy Policy