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 example.com/services.

I want each tab to have its own permalink so that visiting a URI like example.com/services/tab-1 displays the Services page with “Tab 1” automatically active (instead of exposing a URI parameter like example.com/services/?tab=tab-1 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:

<?php

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.