Is it possible to have a template page in WordPress, that could be used for different pages dynamically?
For example, I have a page template cars.php
and I would like to use it for subpages of different types of cars e.g.:
limousine,
coupe,
suv,
van.
I would like to have this hierarchy of pages:
cars ─┬─limousine │ ├─coupe │ ├─suv │ └─van
with this links:
example.com/cars/limousine/ example.com/cars/coupe/ example.com/cars/suv/ example.com/cars/van/
These types of cars come from a database where we could add cars of a new type, say spider.
I know how to do that manually, i.e. making pages limousine, coupe, suv, van and spider creating them using WordPress editor where I would choose car.php as a template.
So in my cars.php page template I would get data of, say, limousine type if a user clicked on example.com/cars/limousine/
link. How should I use my cars.php
page template so that I could get this page with the specified hierarchy? How would WordPress recognise the link if I didn’t explicitly created each of pages (limousine, coupe, suv, van and spider), how could that info about certain page be passed to cars.php
?
Best regards,
Igor
Advertisement
Answer
Edited post
I’ve removed my original response since it was getting in the way.
The way that WordPress (and many/most modern CMSs) work, is that they tell the server such as Apache, Nginx or IIS to do their normal stuff, but if the server results in an effective 404, pass that result into the CMS at a known point (index.php) for further processing.
Server level
The first place that you could hook into would be at the server level using something like an .htaccess file. You could have a rule that maps /cars/*
onto just /cars/?car_type=*
. Not redirect, just map. The map should result in an effective 404 at the server level which means WordPress kicks in with a known URL and a query string that it can just ignore. (I’m 95% certain this would work, but I don’t have an Apache server available to test with right now.) You could register the query parameter, or you could just use $_GET
and perform logic.
But I’m not a big fan of editing server config files, especially if this needs to be more dynamic, or be manageable by people that are comfortable with doing that.
WordPress level
So the next stop is to handle things somehow in WordPress. The bad news is that no matter what you do, WordPress is going to consider this a 404. The good news is, however, you can reroute the 404 as you need.
I’m going to keep going with the /cars/limo
path, but you can adapt as necessary.
The first two steps are optional but are closer to the “official” way of doing things and I would encourage you to do them, but I’ll explain later how you can skip them.
First, we need to register a pattern with WordPress that we’re interested in. The first parameter is a regex, the second is a mapping, and the last says that we basically want to trump other rules. One you add this code, or make any changes to it, you need to flush your WordPress permalinks. Also, if you are developing locally and don’t have rewrites enabled at all, you’ll need to turn them on.
add_action( 'init', static function () { add_rewrite_rule('cars/(.+)[/]?$', 'index.php?car_type=$matches[1]', 'top'); } );
The previous thing didn’t do a whole lot, however, so we also need to tell WordPress that we’re interested in certain query strings. This query string should be the same between the previous and following functions.
add_filter( 'query_vars', static function ($query_vars) { $query_vars[] = 'car_type'; return $query_vars; } );
The last step is to use the magic template_include
filter along with get_query_var
. This filter is called on every non-admin page, so be careful with it and make sure you only change the return if you are guaranteed to be in your specific scenario. The get_query_var
is able to pluck out our query string that we registered in the second step.
add_filter( 'template_include', static function ($template) { $car_type = get_query_var('car_type'); if ($car_type) { // The path must be absolute return __DIR__ . '/cars.php'; } return $template; } );
For the if
logic, you might want to perform additional things such as checking an array to see if it is in the collection of known types. You really should avoid making a database call here if at all possible, because remember, this is called on every page.
Skipping the first two steps
If did say that you could skip the first two steps, and although I don’t recommend it, I want to show you how you can do it. We’re still going to use the template_include
hook, but now we’re just going to look at the URL manually and do things with it. This isn’t guaranteed to survive across different server environments, and you could run into some funky scenarios, so I say skip it. I’m also not going to include logic for figuring out the page itself, that should be pretty easy, too.
add_filter( 'template_include', static function ($template) { $url = wp_parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); if( YOUR LOGIC FOR PARSING URL HERE ){ return 'cars.php'; } return $template; } );