Some background on rewrite rules
The WP Rewrite system looks complicated, but in fact it’s not that hard to understand how it works. It is used to parse pretty URLs (/designers/
) as if they were non-pretty (/index.php?pagename=designers
). The basic idea is that you have a list of rewrite rules, regular expressions that can match the incoming URLs, and rewrite them into other URLs, mostly in the form of index.php
with some query variables. These variables are set to parts of the regular expression that matched the URL. The rules are evaluated top to bottom, so if two rules might match, the first one “wins”.
These rewrite rules are stored in the database by calling flush_rewrite_rules()
, but because generating and writing these rules is an expensive operation, you should not do it on every init
. Instead, you only do it when you change the rules: probably on plugin activation (using register_activation_hook()
), or manually by visiting the Permalinks settings page (because it’s hard to do this automatically on theme activation). If you don’t flush the rules, calling add_rewrite_rule()
has no effect. It is no problem to call add_rewrite_rule()
on every init
, even after you flushed the rules.
There are many ways to add your rewrite rules, and if you only want to add one rule, you can do this with add_rewrite_rule()
. Because the rules for posts, pages, taxonomies, … result in multiple rules, they are created with high level functions like add_rewrite_tag()
, add_permastruct()
, … But these are not needed for the simple case we have here.
There are also some filters, so you can also add your rules using the generate_rewrite_rules
or generate_rewrite_rules_array
hooks. These give you very detailed control over the complete rules, but again, add_rewrite_rule()
is enough if you just want to add one rule.
I created a little plugin that allows you to analyze the current rewrite rules, and (of course) I recommend you use it when you try to change anything.
Getting your extra info from the URL
Let’s build on the example you gave. You have the designer brand Batlak og Selvig
, with the numberic ID (bid
) 9
. You don’t want this ID in the URL, but only the name. We call the URL-friendly version of the name (without spaces or special characters) the slug: Batlak-og-Selvig
.
In general, the URL should contain all info to identify the content you want to show on the page. You can use cookies or POST requests to store the actual designer ID you want to display, but this will break down if anyone shares the link, by sending it via mail, Facebook, Twitter, or just reading it out loud over the phone. If you don’t want to use the numeric ID in your URL, you should make sure the slug is unique: then you first do a lookup of the ID based on the slug, and continue as you did before.
So what we have learned now is that we want to add a rewrite rule for the pattern “/designers/
followed by anything up to the next /
“, and save that “anything” in the designer_slug
query variable. In your case I believe you also want to use the page with the slug designers
as the general page content, so we’ll tell WordPress that too.
add_action( 'init', 'wpa5413_init' );
function wpa5413_init()
{
// Remember to flush the rules once manually after you added this code!
add_rewrite_rule(
// The regex to match the incoming URL
'designers/([^/]+)/?',
// The resulting internal URL: `index.php` because we still use WordPress
// `pagename` because we use this WordPress page
// `designer_slug` because we assign the first captured regex part to this variable
'index.php?pagename=designers&designer_slug=$matches[1]',
// This is a rather specific URL, so we add it to the top of the list
// Otherwise, the "catch-all" rules at the bottom (for pages and attachments) will "win"
'top' );
}
The only thing left to do is to tell WordPress to also keep the designer_slug
in the query variables, so you can access it later. WordPress uses a whitelist of allowed query variables, to prevent people from modifying every parameter of the posts query via the URL. Everything not on this list is ignored. Just hook into the query_vars
hook and add your extra variable:
add_filter( 'query_vars', 'wpa5413_query_vars' );
function wpa5413_query_vars( $query_vars )
{
$query_vars[] = 'designer_slug';
return $query_vars;
}
As you can see, this answer is basically the same as my previous answer, but without the rule flushing in the code (so you can use it in your theme’s functions.php
instead of a plugin), and with a bit more certainty and explanation because I learned a lot about rewrite rules since (and because of) answering your first question.
Chat room discussion
We cleared up final issues for this question in the chat room. In the end, Steven used the generate_rewrite_rules
hook, because the add_rewrite_rule()
function did not seem to work for him.