Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I'm using the Custom Post Type UI plugin to create my custom taxonomies. I have a portfolio that is made up of projects (custom post type) with 2 custom taxonomies of technologies and clients. The clients taxonomy has a custom rewrite slug of portfolio/clients/, while the technologies taxonomy has a custom rewrite slug of portfolio/

Rewrites:
portfolio/html <- page displays all projects using HTML
portfolio/clients/client-a <- page displays all projects for client A

Now when I try to make a landing page for clients that has a url slug of /portfolio/clients I get the 404 page. I'm pretty sure this is because of conflicting url rewrites of the technologies taxonomy. I'm guessing as it searches for it in the technology taxonomy, it doesn't exist then it spits out the 404 page. So how do I get the url rewrite slug to work so that when I hit /portfolio/clients, it doesn't send back the 404 page and it uses the correct page template?

share|improve this question

1 Answer 1

up vote 12 down vote accepted

You seem to need "partial verbose rewrite rules". Verbose rewrite rules means all the pages are put on top because WordPress can't figure out the difference between a page and a post. Here it thinks it can, because all URLs of the form portfolio/([^/]+)/ are from your portfolio taxonomy, except this one portfolio/clients/. You will have to put that one on top of the rewrite rules, so it matches before the more generic portfolio taxonomy. You could probably also force all of the rewrite rules to be verbose, but that will impact the performance if you have lots of pages.

This answer is written with my just-gained understanding of rewrite rules, so I hope it is a good way to do it and the example code doesn't contain too many errors.

A page does not generate just one rewrite rule, it generates a group:

  • (pagename)/trackback/?$
  • (pagename)/feed/(feed|rdf|rss|rss2|atom)/?$
  • (pagename)/(feed|rdf|rss|rss2|atom)/?$
  • (pagename)/page/?([0-9]{1,})/?$
  • (pagename)/comment-page-([0-9]{1,})/?$
  • (pagename)(/[0-9]+)?/?$

You don't have to create these yourself, you can re-use the power of WP_Rewrite. Look at its page_rewrite_rules() method: if we are in verbose mode, it gets a list of all pages (via page_uri_index()) and their attachments, overwrites the %pagename% rewrite tag, and generates the rewrite rules for this page. We can do this too:

// We only generate them for this page
$page_uri = 'portfolio/clients';
// Returns site root + '%pagename%'
$page_structure = $wp_rewrite->get_page_permastruct();
// Everywhere you see %pagename% in the structure used to generate rules
// in the next step, replace it with our fixed page name
$wp_rewrite->add_rewrite_tag('%pagename%', "({$page_uri})", 'pagename=');
// This generates the group given above
$page_rewrite_rules = $wp_rewrite->generate_rewrite_rules($page_structure, EP_PAGES);

This will give us the rules for the pages, but not yet for attachments used in the page. If you also want them, you repeat the step for each attachment, but with add_rewrite_tag('%pagename%', "({$attachment_uri})", 'attachment=') (see page_rewrite_rules() for more details).

Good, we got the rules, but now you need to add them to the complete rewrite structure in some way. You could do this with add_rewrite_rule(), but you must call it for every rule generated in the $page_rewrite_rules array. For this reason, many people hook into the rewrite_rules_array filter, since you can just modify the array there.

add_filter('rewrite_rules_array', 'add_verbose_portfolio_clients_page');
function add_verbose_portfolio_clients_page($rewrite_rules)
{
    global $wp_rewrite;

    // The previous code snippet comes here, where we generate $page_rewrite_rules

    // Our rules have priority, they should be on top
    $rewrite_rules = array_merge($page_rewrite_rules, $rewrite_rules);

    return $rewrite_rules;
}

After you included this filter, you should flush the rewrite rules (once, not one every page load, as it is quite heavy). You can do this by calling flush_rewrite_rules(), or by visiting the "Permalinks" settings page.

share|improve this answer
    
Excellent! Thanks Jan! This worked. I couldn't have received a better explanation. –  jaysonp Nov 16 '10 at 8:27

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.