humanmade / hm-url-tabs
Tab-based navigation with rewrite endpoints for conditional block visibility
Package info
github.com/humanmade/hm-url-tabs
Language:JavaScript
Type:wordpress-plugin
pkg:composer/humanmade/hm-url-tabs
Requires
- composer/installers: ^1 || ^2
This package is auto-updated.
Last update: 2026-08-12 18:47:02 UTC
README
A WordPress plugin that allows editors to use the core navigation block to create tab-based navigation with rewrite endpoints for conditional block visibility.
Features
-
Tab Navigation Variations: Extends the core
navigation-linkblock with three variations:- Home Tab: Links to the current page without any endpoint
- Base Tab: Links to just the endpoint without a value (e.g.,
/tab/) - Tab: Links with a rewrite endpoint and value (e.g.,
/tab/settings/)
-
Rewrite Endpoints: Registers filterable rewrite endpoints (default:
tab) withEP_ALLmask -
URL Rewriting: Automatically rewrites navigation link URLs to use the current page with the appropriate endpoint
-
Dynamic Tab Visibility Controls: Adds a "Tab Visibility" panel to all blocks (except navigation-link) that automatically appears when the page contains tab navigation (no refresh needed), with options to:
- Always show the block
- Show only when no endpoint is active
- Show only when the endpoint is in use but has no value (e.g.,
/tab) - Show only for a specific tab value (e.g.,
/tab/settings)
-
Active State: Automatically adds
hm-url-tab-activeclass to the current tab link
Installation
- Clone this repository into your
wp-content/pluginsdirectory - Run
npm installto install dependencies - Run
npm run buildto build the assets - Activate the plugin through the WordPress admin
Usage
Creating Tab Navigation
- Add a Navigation block to your page
- Insert a navigation link and select one of the tab variations:
- Home Tab: Links to the page without any endpoint
- Base Tab: Links to just the endpoint (e.g.,
/tab/) - useful for "All" or default views - Tab: Links to a specific tab value (e.g.,
/tab/settings/)
- For regular tabs:
- Set the label (e.g., "Settings")
- Enter the tab slug in the URL field (e.g., "settings")
- The final URL will be automatically built from the current page URL with the endpoint and slug on the frontend
Controlling Block Visibility
When your page contains tab navigation links:
- Select any block on the page (except navigation links)
- Open the "Tab Visibility" panel in the block sidebar
- Choose the display condition:
- Always show: Block is always visible
- Show when no endpoint is active: Block is only visible on the base page (Home Tab)
- Show when endpoint has no value: Block is visible when accessing
/tab/(Base Tab) - Show for specific tab: Block is only visible for the selected tab value
Example
Create a settings page with tabbed sections:
Page URL: /settings
Navigation:
- Home Tab → /settings
- All Settings Tab (Base Tab) → /settings/tab/
- General Tab → /settings/tab/general/
- Privacy Tab → /settings/tab/privacy/
Blocks:
- Welcome message (Visibility: Show when no endpoint is active)
- All settings list (Visibility: Show when endpoint has no value)
- General settings (Visibility: Show for specific tab → general)
- Privacy settings (Visibility: Show for specific tab → privacy)
Customization
Adding Custom Endpoints
You can register additional endpoints using the hm_url_tabs_endpoints filter:
add_filter( 'hm_url_tabs_endpoints', function( $endpoints ) { $endpoints[] = [ 'name' => 'section', 'mask' => EP_ALL, ]; return $endpoints; } );
When multiple endpoints are registered, a selector will appear in the navigation link settings to choose which endpoint to use.
Development
Build Scripts
npm start: Start development build with watch modenpm run build: Build production assetsnpm run format: Format codenpm run lint:js: Lint JavaScriptnpm run lint:js:fix: Lint and fix JavaScriptnpm run lint:css: Lint CSSnpm run lint:css:fix: Lint and fix CSS
Local Development
Use WordPress Playground for local development:
npm run playground:start
This will start a WordPress instance at http://localhost:9400 with the plugin activated.
Testing
Run Playwright tests:
npm run test:e2e # Run tests npm run test:e2e:debug # Run tests in debug mode npm run test:e2e:watch # Run tests in watch mode
Filters
hm_url_tabs_endpoints
Filters the registered tab endpoints.
Parameters:
$endpoints(array): Array of endpoints with 'name' and 'mask' keys.
Example:
add_filter( 'hm_url_tabs_endpoints', function( $endpoints ) { $endpoints[] = [ 'name' => 'custom', 'mask' => EP_PAGES, ]; return $endpoints; } );
Technical Details
Block Attributes
Navigation Link (core/navigation-link):
kind(string): Set to "tab-home" for home tab, "tab-base" for base tab, or "tab" for regular tabtabEndpoint(string): The endpoint name to use (default: "tab")url(string): The URL slug for the tab (uses the standard navigation-link URL field, empty for Base Tab)
All Other Blocks:
hmUrlTabVisibility(object):condition(string): "always", "no-endpoint", "endpoint-empty", or "specific-tab"endpoint(string): The endpoint nametabUrl(string): The tab URL slug to match (for "specific-tab" condition)
URL Structure
- Base page:
/settings - Home tab:
/settings - Base tab (endpoint without value):
/settings/tab/ - Tab with value:
/settings/tab/general/
Note: Tab URL slugs are automatically lowercased for consistency (e.g., "Settings" becomes /tab/settings/). All generated URLs include a trailing slash.
Release Process
Releases are cut manually via GitHub Actions. Each release builds the plugin, stamps the version into the source, and creates an immutable tag that already points at the built, versioned code — the tag is created exactly once and is never moved or force-pushed, so Packagist accepts it without conflict.
Creating a Release
- Go to the Actions tab and select the Release workflow
- Click Run workflow and enter the version to cut, without a leading
v(e.g.1.2.3). Versions must follow semantic versioning (X.Y.Z). - Run the workflow. It will automatically:
- Validate the version format and fail if the tag already exists (tags are immutable)
- Build the production assets (
npm ci && npm run build) - Replace the
__VERSION__placeholder inhm-url-tabs.phpwith the version - Commit the built, versioned code and create the tag (e.g.
v1.2.3), pushing only the tag - Build a production ZIP with
git archive(honouring the.gitattributesexport-ignore rules, so dev files are excluded and the compiledbuild/directory is included) - Publish a GitHub release with auto-generated notes and the ZIP attached
Because tags are never re-tagged or force-pushed, bumping a release means running the workflow again with a new version number.
License
GPL-2.0-or-later
Author
Human Made Limited - https://humanmade.com