Skip to content


Subversion checkout URL

You can clone with
Download ZIP
CakePHP2: Automagically route /:page style routes without any fuss
Branch: master
Failed to load latest commit information.
Lib/Routing/Route Fix docblock
Test/Case Initial push for a 1.0.0 release
.editorconfig Initial push for a 1.0.0 release
.semver Initial push for a 1.0.0 release
.travis.yml Initial push for a 1.0.0 release
LICENSE.txt Initial push for a 1.0.0 release
README.markdown Initial push for a 1.0.0 release
composer.json Initial push for a 1.0.0 release


Build Status Coverage Status Total Downloads Latest Stable Version

PageRoute Plugin

Forget about cluttering your routes.php with zillions of /page-style routes.


Someone in IRC was migrating tons of static pages into a fresh CakePHP install. In the webroot. I told him to move them into app/View/Pages and use routes to properly route everything. I also mentioned that rather than routing every static file one by one, it might be possible using a custom CakeRoute class, but didn't elaborate.

So a few minutes of hacking later, and here I am with this lovely PageRoute.


  • PHP 5.2+
  • CakePHP 2.x


[Using Composer]

Add the plugin to your project's composer.json - something like this:

    "require": {
        "josegonzalez/cakephp-page-route": "1.0.0"

Because this plugin has the type cakephp-plugin set in it's own composer.json, composer knows to install it inside your /Plugins directory, rather than in the usual vendors file. It is recommended that you add /Plugins/PageRoute to your .gitignore file. (Why? read this.)


[GIT Submodule]

In your app directory type:

git submodule add git:// Plugin/PageRoute
git submodule init
git submodule update

[GIT Clone]

In your plugin directory type

git clone git:// PageRoute

Enable plugin

In 2.0 you need to enable the plugin your app/Config/bootstrap.php file:


If you are already using CakePlugin::loadAll();, then this is not necessary.


Way near the bottom of your app/Config/routes.php file, add the following:

App::uses('PageRoute', 'PageRoute.Routing/Route');
Router::connect('/:page', array('controller' => 'pages', 'action' => 'display'),
    array('routeClass' => 'PageRoute')

And now you can remove all shortcuts to your /pages/display/page-name urls. Whenever you create a new .ctp file in app/View/Pages, this route will automatically detect it using a file_exists() call. Because of this, it is recommended to use this as one of the last, if not the last, route in your application, in order to minimize file-reads.

It is also possible to customize the controller/action used for this. For example, we might want to use the StaticPagesController::index() instead of PagesController::display(). In that case, our routes.php would look like the following:

App::uses('PageRoute', 'PageRoute.Routing/Route');
Router::connect('/:page', array('controller' => 'static_pages', 'action' => 'index'),
    array('routeClass' => 'PageRoute', 'controller' => 'static_pages', 'action' => 'index')

In this way, we can easily rename the PagesController to something less useful, and reuse the PagesController for something else - such as dynamic content from the database.

Reverse routing will all work the same as it does without this route class. array('controller' => 'pages', 'action' => 'display', 'about') will be automatically converted to array('controller' => 'pages', 'action' => 'display', 'page' =. 'about') for backwards compatibility Please note that by default, the regex [\/\w_-]+ is used to check the page validity, so you may need to update that regex in the Route options as follows:

App::uses('PageRoute', 'PageRoute.Routing/Route');
Router::connect('/:page', array('controller' => 'static_pages', 'action' => 'index'),
    array('routeClass' => 'PageRoute', 'page' => '[a-zA-Z]+')

Note that the . character has been disallowed in the default regex to remove the possibility of traversing the directory tree for security reasons.


  • Unit Tests
  • Allow usage of the . character in routes
  • Add caching to file_exists calls
Something went wrong with that request. Please try again.