Summary: Router allows a website's url structure to be different from PmWiki's group/page structure.
Version: 2007-12-19r12beta
Prerequisites: Tested with pmwiki-2.2.6. Should work with pmwiki-2.1.27
Status: beta
Maintainer: MagicBeanDip?
Categories: CMS Links PageNaming
Download: router.phpΔ
Discussion: Router-Talk

Questions answered by this recipe

  • How can I make PmWiki urls look different?
  • How can I make PmWiki fit into a pre-existing url structure?
  • How can I make PmWiki use dashed-lower-case urls instead of CamelCaseUrls?


Place router.phpΔ in your cookbook directory.

Add the following lines near the top of your config.php file.

  #Routing instructions go here

Router is most useful with $EnablePathInfo enabled but also works when it is disabled.

Usage Instructions

Disambiguation for link direction

  • A url link https://somesite.... is outside the wiki.
  • A wiki link Group.Page is inside the wiki.
  • Outbound = Translating from a wiki link Group.Page to a url link
  • Inbound = Translating from a URL link to a wiki link Group.Page


Router adds the page variable $GroupUrl that returns a routed URL to the base page of the current group. Instead of using <a href='{$ScriptUrl}/{$Group}'>{$Group}</a> in a template file use <a href='{$GroupUrl}'>{$Group}</a>

$aRoute - Routing Instructions

Router expects to find an array of routing instructions in the global variable $aRoute. Routing instructions are processed first to last for inbound links and last to first for outbound links. Changes made by one instruction are passed on the the next instruction.

Routing instructions can be specified in a short and long format

Short Format:


Long Format:


Both instructions do the same thing. For an outbound link, they look for a page name that begins with "MatchWiki" and substitute "MatchUrl" when a match is found. translates to a pmwiki pagename of MatchWikiGroup/MatchUrlPage

This instruction is symmetrical, so the reverse is true for an inbound link. The short instruction form uses the "BeginsWith" mode for matching.

Modes that currently exist are:

  • Symetrical Modes
    • BeginsWith
    • Contains
    • EndsWith
    • ExactMatch
  • Asymetrical Modes
    • RegReplace
  • Special Modes
    • CamelCaseToLowerCase

Symetrical Examples:


); translates to


); translates to


); translates to


); translates to

But more interestingly, Main/HomePage translates to for outbound links.

Asymetrical Modes

Asymetrical modes only work in one direction. The direction to apply the routing instruction to is specified by adding another element.

  ,'Direction'=>'Out' or

The 'Direction' element can be used with any instruction mode.

RegReplace Example


For inbound links, translates to

But this instruction is limited to only inbound links by the ,'Direction'=>'In' part of the routing instruction. It is skipped when translating pagenames to URLs for outbound links because the regex doesn't translate the URLs correctly in the reverse direction.

So a related outbound instruction is needed.


Now MatchPageGroup/MatchPagePage correctly translates to

The RegReplace instruction simply passes the values of 'Search' and 'Replace' to the php preg_replace() function. If you specify a 'Limit' element in the routing instruction, that value will also be passed to preg_replace().

Special Modes

Special modes mess with urls in an extra special way. :)

CamelCaseToLowerCase Example

The 'CamelCaseToLowerCase' mode changes the entire pmwiki url structure from CamelCaseUrls to dashed-lower-case-urls. It functions in both directions unless you specifically add a 'Direction' element to the routing instruction.

); translates to

and vice versa

When using CamelCaseToLowerCase in conjunction with the Apache mod-rewrite module, be sure to change your .htaccess to send all urls that start with lower case characters to index.php.

Create your own routing modes

Add a function named RT_ModeName to config.php before including router.php. The first parameter is the path and the second parameter is an array that contains a single routing instruction. The 'Direction' element is always present and indicates whether the path you are working on is for an inbound or outbound link. Router will add the 'Direction' element to the instruction array if it doesn't already exist. Be sure to return $path even if you don't change its value.

Values passed to the function in $aline['Direction'] are either 'In' or 'Out'. The rest of the $aline array keys are determined by your RT_ function.

The following function creates a routing mode named "Redirect"


/// Http Redirect to specified location when path matches
/// $path: page name at various stages of translation in either Wiki or Url format.
/// $aline: array containing a single routing instruction.
function RT_Redirect($path,$aline) {
  if ('In'!=$aline['Direction']) {
    return $path;
  if ($path==@$aline['In']) {
    header('Location: '.@$aline['Out'],TRUE,301);
  return $path;

Release Notes

  • 2007-12-19r12beta - Now only needs to be included from config.php
  • 2007-11-20r11alpha - initial release

If the recipe has multiple releases, then release notes can be placed here. Note that it's often easier for people to work with "release dates" instead of "version numbers".


Um... Excuse me for incompetence, but can I do something using this recipe if I want to have page names to be exactly as they are named (like "Main/Wiki sAnDbOx") or (if having spaced filenames arent possible) to substitute "_" for " " and at the same time substitute "__" for "_" (to keep underscores if they are present)?


You can have a url of match a wiki page name of Wiki.SandBox. If there are just a few pages, hard code the translations with ExactMatch mode instructions. Otherwise the CamelCaseToLowerCase mode would be an example to start from. But you would need a repeatable method to match Url names with Wiki names.


See discussion at Router-Talk

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.