Custom URL for each tab on a page

(cfx) #1

I have a Page Template, page-services.php, which displays content in various tabs. The page’s URI is currently

I want each tab to have its own permalink so that visiting a URI like displays the Services page with “Tab 1” automatically active (instead of exposing a URI parameter like which is just fugly).

I’ve accomplished this so far by (1) adding a rewrite rule for any Services Page Template, (2) adding a custom rewrite tag, and (3) using the rewrite tag (query var) in the page template to set the active tab accordingly.

Here are my rewrite customizations:


function custom_tab_rewrites_and_tag() {
  add_rewrite_tag('%service_tab%', '([^&]+)');

  $services_pages = new \WP_Query(array(
    'post_type'      => 'page',
    'meta_key'       => '_wp_page_template',
    'meta_value'     => 'page-services.php',
    'posts_per_page' => -1

  foreach($services_pages->posts as $p) {
    add_rewrite_rule('^'.$p->post_name.'/([^/]+)/?$', 'index.php?page_id='.$p->ID.'&service_tab=$matches[1]', 'top');
add_action('init', __NAMESPACE__.'\\custom_tab_rewrites_and_tag');


This setup works flawlessly on the Services page. However, this is a reusable Page Template and there could ultimately be multiple Services pages, each with different tabs.

The problem: When I add a new Page using the Services Page Template, my tab rewrites only work for that new Page if I flush my permalinks. I can do that in my rewrite function or on save_post, but neither of those are appealing, not to mention it’s inefficient. I don’t want to flush permalinks each time a new Service page is added and I suspect there may be a more efficient way to accomplish a setup like this. I may be overcomplicating this or overlooking something.

If anyone has pointers I’d greatly appreciate some input on a better way to accomplish this while maintaining this URI structure for this Page Template’s tabs.