Add a Space Tab
Add a custom tab to a space page using the jetonomy_space_tabs filter. The tab appears alongside Discussions (or Questions / Ideas / Posts), Roadmap, and Members; clicking it loads a route you register separately.
How Space Tabs Work
When Jetonomy renders a space page it assembles an ordered tab map, then passes it through jetonomy_space_tabs before rendering the nav. Two details determine whether and how the nav renders:
The >1-tab rule: the <nav class="jt-space-tabs"> element is only rendered when the filtered map contains more than one tab. If your filter results in exactly one tab, no nav appears. Adding a custom tab to the default single-tab view (a non-ideas, members-hidden space) creates two tabs and triggers nav rendering.
The active flag: each tab entry can carry an 'active' => bool key. Set this to true on the tab that represents the current page. Jetonomy reads 'active' to add the on CSS class and aria-current="page" attribute. The built-in primary tab always starts as active => true; when your custom route renders, set active => false on primary and active => true on your tab (see the template example below).
The jetonomy_space_tabs Filter
apply_filters( 'jetonomy_space_tabs', $tabs, $space, $show_members )
Parameters
| Parameter | Type | Description |
|---|---|---|
$tabs |
array |
Ordered map: slug => ['label' => string, 'url' => string, 'active' => bool]. Built-ins: primary (always), roadmap (ideas spaces), members (logged-in users). |
$space |
object |
The space being viewed (slug, type, name, etc.). |
$show_members |
bool |
Whether the Members tab is visible (is_user_logged_in()). |
Return: array - the modified tab map. Entries missing label or url are skipped.
Source: templates/views/space.php
Step 1: Register a Template for the Tab Content
Register a new route via jetonomy_template_map. The template receives the space slug from get_query_var( 'jetonomy_slug' ).
add_filter( 'jetonomy_template_map', function( array $map ): array {
$map['space-analytics'] = MY_PLUGIN_DIR . 'templates/space-analytics.php';
return $map;
} );
A minimal template for the route. It sets the active flag correctly on the tab map via the same filter - because the filter runs again when this template is loaded under the space-analytics route:
<?php
// my-plugin/templates/space-analytics.php
$slug = get_query_var( 'jetonomy_slug' );
$space = \Jetonomy\Models\Space::find_by_slug( $slug );
if ( ! $space ) {
wp_redirect( home_url( '/' ) );
exit;
}
?>
<div class="jt-app">
<?php \Jetonomy\Template_Loader::partial( 'header' ); ?>
<div class="jt-container">
<?php
// Your custom content here.
// The tab bar is rendered by the partials/header - no need to
// re-emit it here. Your filter below handles the active flag.
?>
<h2><?php echo esc_html( $space->name ); ?> - Analytics</h2>
</div>
</div>
Step 2: Register the Rewrite Rule
add_action( 'init', function() {
$settings = get_option( 'jetonomy_settings', [] );
$base = $settings['base_slug'] ?? 'community';
add_rewrite_rule(
'^' . preg_quote( $base, '^' ) . '/s/([^/]+)/analytics/?$',
'index.php?jetonomy_route=space-analytics&jetonomy_slug=$matches[1]',
'top'
);
} );
Flush permalinks once after adding: Settings → Permalinks → Save Changes or wp rewrite flush.
Step 3: Add the Tab
Append the tab inside the filter. When running under the space-analytics route, also flip the active flag so the correct tab is highlighted.
add_filter( 'jetonomy_space_tabs', function( array $tabs, object $space, bool $show_members ): array {
$settings = get_option( 'jetonomy_settings', [] );
$base = $settings['base_slug'] ?? 'community';
$analytics_url = home_url( "/{$base}/s/{$space->slug}/analytics/" );
// Detect whether we are currently on the analytics page.
$is_active = ( 'space-analytics' === get_query_var( 'jetonomy_route' ) );
// When analytics is the active page, un-mark the primary tab.
if ( $is_active && isset( $tabs['primary'] ) ) {
$tabs['primary']['active'] = false;
}
$tabs['analytics'] = [
'label' => __( 'Analytics', 'my-plugin' ),
'url' => $analytics_url,
'active' => $is_active,
];
return $tabs;
}, 10, 3 );
Complete Example
/**
* Analytics tab on space pages.
*
* 1. Registers /community/s/{slug}/analytics/.
* 2. Loads a custom template for that URL.
* 3. Adds an "Analytics" tab to the space tab bar.
* 4. Marks the tab active when the analytics route is loaded.
*/
// Step 1 - template.
add_filter( 'jetonomy_template_map', function( array $map ): array {
$map['space-analytics'] = get_stylesheet_directory() . '/jetonomy/views/space-analytics.php';
return $map;
} );
// Step 2 - rewrite rule.
add_action( 'init', function() {
$settings = get_option( 'jetonomy_settings', [] );
$base = $settings['base_slug'] ?? 'community';
add_rewrite_rule(
'^' . preg_quote( $base, '^' ) . '/s/([^/]+)/analytics/?$',
'index.php?jetonomy_route=space-analytics&jetonomy_slug=$matches[1]',
'top'
);
} );
// Step 3 - tab (handles both the space view and the analytics route).
add_filter( 'jetonomy_space_tabs', function( array $tabs, object $space, bool $show_members ): array {
$settings = get_option( 'jetonomy_settings', [] );
$base = $settings['base_slug'] ?? 'community';
$analytics_url = home_url( "/{$base}/s/{$space->slug}/analytics/" );
$is_active = ( 'space-analytics' === get_query_var( 'jetonomy_route' ) );
if ( $is_active && isset( $tabs['primary'] ) ) {
$tabs['primary']['active'] = false;
}
$tabs['analytics'] = [
'label' => __( 'Analytics', 'my-plugin' ),
'url' => $analytics_url,
'active' => $is_active,
];
return $tabs;
}, 10, 3 );
Removing or Reordering Built-in Tabs
Remove a tab:
add_filter( 'jetonomy_space_tabs', function( array $tabs ): array {
// Hide the Members tab entirely.
unset( $tabs['members'] );
return $tabs;
}, 10, 3 );
Relabel a tab:
add_filter( 'jetonomy_space_tabs', function( array $tabs ): array {
if ( isset( $tabs['roadmap'] ) ) {
$tabs['roadmap']['label'] = __( 'Planned Features', 'my-plugin' );
}
return $tabs;
}, 10, 3 );
Reorder tabs (rebuild map):
add_filter( 'jetonomy_space_tabs', function( array $tabs ): array {
// Place Members before Roadmap.
$members = $tabs['members'] ?? null;
$roadmap = $tabs['roadmap'] ?? null;
if ( $members && $roadmap ) {
unset( $tabs['members'], $tabs['roadmap'] );
$tabs['members'] = $members;
$tabs['roadmap'] = $roadmap;
}
return $tabs;
}, 10, 3 );
Notes
- The
>1-tab ruleis evaluated after your filter runs. If your filter removes tabs and leaves only one, the nav will be hidden - this is by design. - The
activekey is optional; entries without it are treated as inactive. You only need to set it on the tab representing the current page. - The
jetonomy_slugandjetonomy_routequery vars are already registered by Jetonomy's router; you do not need to register them again. - Flush permalinks whenever you add or modify a rewrite rule. Use activation/deactivation hooks in a plugin - never call
flush_rewrite_rules()on every request. - See Template Overrides for the full
jetonomy_template_mapcontract and how to call partials correctly from custom templates.