Jump to content

Routing system, aka. "Where to put page actions in ProcessWire"


Recommended Posts


this feature wish came up while I was working on my first bigger project with ProcessWire. While almost all of the CMS is very well thought out there was one thing that always kept me thinking "where should I put this?": simple page actions.

What I mean is code snippets that belong to a page and should be run when a certain action is taken. E.g. when a user submits the form on my contact page (that has the contact template) I somewhere have to validate the form and then send it somewhere. So far I see two options to do that.

  1. Write a module that hooks into some methods and checks if the post data is set and if the page is my contact page
    This aproach is clean but it's usually a lot of overhead to write a module just for that
  2. Write the code in my contact.php template
    This aproach is fast but feels really dirty. It does not help to separate the logic from the design which I fear in a long term could lead to some Wordpressish code structure


Now since I don't have so much experience with ProcessWire there might be a chance I missed something, but then it's probably not documented obvious enough. So I thought how you improve on this problem and came to a solution, that's again really close to the syntax that jQuery provides. If we had some kind of routing system we could register those actions in any file, for example the templates _func.php

// execute this action when a post request is sent to /contact
// the parameters given to the callback function probably should be different
wire('request')->on('post', '/contact', function($request, $input) {
	// do an action

// do the action for any post request                    
wire('request')->on('post', function($request, $input) {
	// do an action

// do the action for get requests on contact pages                    
wire('request')->on('get', 'template=contact', function($request, $input) {
	// do an action

// do the action on ajax-GET requests                     
wire('request')->on('get.ajax', '/contact', function($request, $input) {
	// do an action


Is that something that could improve the work with ProcessWire? What's your honest opinion about it? If that's a useful suggestion I would like to help with the implementation.




Link to comment
Share on other sites

@MrSnoozles Why not put the code in _func.php and use if statements?

if($page->name == "page-name" && $input->post->submit) {
	// code to run on a specific page when form is submited

if($page->template->name == "template-name" && $input->post->submit) {
	// code to run on a specific template when form is submited

if($page->template->name == "template-name") {
	// code to run on a specific template


  • Like 3
Link to comment
Share on other sites

ProcessWire does have an router, even though it does look vastly different to what you're talking about. It's routing requests by the page template to the corresponding template.php file. What you proposed does not correspond very well with that core routing strategy, because neither urls nor the http methods are the identifying factor here. It's the pages template and the existence in the page tree.

If you're looking for a more traditional mvc routing layer, you can set an alternative template file for your templates (by hook or in the backend). Just point all of them to e.g. a router.php file and use whatever router package your like to route requests to wherever the action should be handled. 

And about the core routing of processwire. Always keep in mind that mvc frameworks do not have something like the page tree, which is why they need a router to work on the url of the request. ProcessWire does not need that with it's approach.

  • Like 10
Link to comment
Share on other sites

Hello MrSnoozles,

in Processwire template files are not actually templates and You can actually use them as controllers (see the "delayed approach" in pw tutorials). In template files You can manage the request ($input), build forms (InputfieldForm module instances) and assign variables which are later used in the included view file(s). (btw, I use the ".phtml" extension for my views/partials  to distinguish them from template/controller files ".php").

If you ever worked with Silverstripe you can actually think of template files code as Silverstripe's Page_Controller classes ' method code. You can leverage pw's urlSegment feature to add sub-routes for the current page/template. If you have a contact-page template (/contact-us/) You can use a "submit" segment ($input->urlSegment(1)) and use "/contact-us/submit" as the form action, the same way You can add any route segment in a Silverstripe (Page_)Controller class. 

I don't find it useful to add code used only by the "contact-page" template in a global function inside (_func.php).

As in Silverstripe cmf the segment approach has the advantage that it continues to work even if you change the url (name) of the page using that template.

Think of template files as controllers: while in other frameworks you have to assign controllers to routes, in PW  a route (Page path/url) is automatically linked to a peculiar controller (template) by the fact that the Page with that route is using that template.

kind regards,

maks feltrin

  • Like 5
Link to comment
Share on other sites

Agreed - you can take the MVC approach using template-files. If you really wanted to use a router like that, you could always create a Process module to use as a fallback to non-existing routes. Jumplinks 2 will use this methodology on the 404 event, where it collects routes from the database and applies a single action. You could do something similar where the module sets up the router (in the case of Jumplinks 2, it is FastRoute), and then have it include a routing file. From there, you'd have access to the global scope and do pretty much whatever you want to do.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Similar Content

    • By wumbo
      I'm about to implement a multisite project with PW3 (which is great btw!!!).
      Because of "reasons" I need to implement my own routing. To do this I implemented a little module the hooks ProcessPageView::execute(). I reviewed its code and found out, that the actual logic to look-up the requested page from the request is placed in a protected method ProcessPageView::getPage(). And because this method is currently not hookable, I needed to do a dirty hack (overriding the GET.it parameter that is inspected by ProcessPageView::getPage()).
      I suggest making ProcessPageView::getPage() hookable and pass the arguments for the page look-up via method arguments instead of inspecting the GET scope within the method.
    • By haibogu
      Hi all,
      I'm experimenting building a content site based on AngularJS and Processwire.
      I‘ve turned on the html5Mode in angularjs, everything works so far re agularjs routing, but when I try to refresh a page, only loads a page without header (thus no js/style). This to me seems a classic problem with server setup ( http://stackoverflow.com/questions/16569841/reloading-the-page-gives-wrong-get-request-with-angularjs-html5-mode/16570533#16570533 ), which requires htaccess setup (I'm on Apache server).
      But not quite sure how to set up the htaccess? Attached is my htaccess, with below are some routing settings of angular:
      scotchApp.config(function($routeProvider,$locationProvider) {     $routeProvider         .when('/news', {             templateUrl : 'news',             controller  : 'mainController'         })         .when('/about', {             templateUrl : 'about',             controller  : 'aboutController'         })         .otherwise({             templateUrl : 'news',             controller  : 'mainController'         });     $locationProvider.html5Mode(true); });  
      THANKS advance for all your help!
    • By Chris
      short story:
      think of a radio button mechanic in the background, but ui-wise you present images with captions as "buttons".
      for instance i whant to be able to let admins change some visual themes of a single page, with different background and formating for each, i could place screenshots thumbs with a short caption. so the admins are able to se a preview image and know better what this setting does.
      therefore it would be needed to define images for an input field, during the field creation. maybe someone likes the idea and is able to do it? 
    • By dev_panther
      I downloaded an existing processwire project to my mac, modified it a bit, and tried to upload it to a new "GoDaddy" server. The home page is loaded fine, and links to pages on that server that doesn't use the processwire system also works, but all the links that use the processwire system leads to "404 not found" error. No matter if try to get to them as links, or to type the address manually. 
      It's like the server doesn't recognise that "www.MySite/newPage" should look for the "newPage" in the processwire directory, and it's trying to find a file names "newPage", in the root directory, that obviously doesn't exist. 
      (Another point - running the project on MAMP server on my mac works fine).
      Any suggestions? 
    • By Oliver
      I just wanted to vote for making Template class’ filenameExists method hookable. Would become handy as soon as you don’t want to work with native template files the usual way without all pages being marked as not viewable.
      BTW: As the hook method viewable provided by PagePermissions is the main problem here, it would be good to know if it were possible to override existing hooks of other modules somehow. Just a thought.
  • Create New...