I had a need to implement custom routing system in my WordPress theme. I’m developing a web application, not a typical theme. There is a predefined set of pages in the app and each of them has its own view (template). Ideally, the design and structure (HTML/CSS) of these templates are located in files, not in a database. They can be versioned in Git that way. Nonetheless, I still have to insert the pages with corresponding page template settings into the database. Why?
Disclaimer: Written for WordPress version 4.1.1
Request parsing and routing 101
After obtaining database and other configuration, WordPress includes a lot of files from the wp-includes folder into the memory. Primary components are included in this order:
- must-use plugins
- plugins
- theme
Main classes such as WP, WP_Rewrite, WP_Query and many more are all instantiated at this point.
Next come parsing the URL request, sending HTTP headers and querying initial posts.
Parsing a request
During this process, WordPress rewrite rules are loaded from the database and matched against the URL string. Query variables such as name of a post or search string are extracted from the URL as well. For example, if we have an URL “https://lamosty.com/contact/” and enabled pretty permalinks (rewrite rules for pages and posts), pagename
would be “contact”. WordPress will use these variables when deciding which theme file to load later on (index.php or page.php , etc).
Before finishing the parsing process, functions hooked into parse_request action hook are executed. This is an important moment and we’ll get back to it in a while.
Sending HTTP headers
Not the most important part for us. Several headers, such as Content-Type, Last-Modified (for caching) and other headers are set and send at this occasion. There is another action hook named send_headers located just before exiting the function.
Querying initial posts
If we have fully parsed request into variables, we can query some data from the database. It actually calls get_posts()
method of WP_Query object, which is also called if you do:
$query = new WP_Query( $args ); // or $posts = get_posts( $args )
in your plugins or themes.
The method is complex and I’m not going to delve into it as it has been described many times before.
The problem
If I’m working on a web application with a predefined static pages stored in files, why should I query the database?

Only to comply with the standard routing mechanism of WordPress? Wouldn’t it be better (in this case) to specify routing rules in a file which would be directly loaded just after the URL request is parsed?
Let’s look at Laravel routing:
Route::get('/', function() { return 'Hello World'; }); Route::get('user/{id}', function($id) { return 'User '.$id; });
Or Ruby on Rails:
get '/', to 'app#index' get '/user/:id', to: 'users#show'
Isn’t it beautiful? Instead of storing routes (= rewrite rules in WordPress) in the database as serialized string, store them nicely in a file. It has better performance and every developer on your team can instantly observe the routes. If the routing mechanism was like this in WordPress, we wouldn’t have to create blank pages pointing to static templates in our themes just for routing to work properly. We would simply include the templates in the matched routes and job is done.
My (failed) attempt at solving this “problem”
I attached a callback function to the parse_request action hook, after the request URL is parsed. Then I carefully inspected the query variables, loading page views (template files) according to them. Saving the code, reloading the site and… admin toolbar is missing – WTF?
Turns out I skipped a number of action and filter hooks! Oh my. Some of them:
- send_headers
- wp
- template_redirect (!!!)
A few hours of fiddling with the code and reading how to do it the “best” way, I came to a conclusion — Do you want to use WordPress for your web application? Work the WordPress way then!
I’m not complaining
Well, I’m not complaining. While I have to do some sacrifices here and there, WordPress gives me numerous benefits (described in other articles on the web). I just needed to realize and learn how to go along with it, not against the stream.

WordPress is powerful in its own ways. We should embrace them.
I have an exactly same problem. Still trying to find some way to work around.
this is the way I found recently:
https://make.wordpress.org/plugins/2012/06/07/rewrite-endpoints-api/
using rewriteRule and endpoint to avoid adding every pages in wp-admin.
Hope it could work
LikeLike
OH I am wrong. it seems it still have to add page in wp-admin. So sad.
However, I figure out some work around.
to add only one page as a router to route every page in your web application
1. add one page in wp-admin (for example, page named “router”),
2. add a template in your folder for it with wordpress template hierarchy (page-router.php)
3. add rewrite rule to make the url in your web application to redirect to “router”
4. template page-router.php take the argument passed from url.
Hope anyone have some smarter way to overcome this problem
LikeLike