Dashboard Create Screen Skill
Creates new screens in client/dashboard with automatic route discovery and registration.
Step 1: Discover Available Routes
First, find all router files and extract available routes.
Find Router Files
Use Glob to discover router files:
client/dashboard/app/router/.tsx client/dashboard/app/router/.ts
Extract Routes from Each File
For each router file, use Grep to extract route information.
Find exported route constants:
export\s+const\s+(\w+Route)\s*=\s*createRoute
Extract parent relationships:
getParentRoute:\s*()\s*=>\s*(\w+Route)
Extract path segments:
path:\s*'"['"]
Extract component import paths:
import(\s*'"['"]\s*)
Build Route Information
For each discovered route, record:
-
Route variable name (e.g., siteBackupsRoute )
-
Parent route name (e.g., siteRoute )
-
Path segment (e.g., 'backups' )
-
Source file path
-
Component directory (derived from import path)
Step 2: Discover Navigation Menus (After Route Selection)
Menu discovery happens after the user selects a parent route. Find menus relative to the route's location.
Determine Menu Search Path
Based on the selected parent route's import path, determine where to search for menus:
Extract the component directory from the parent route's lazy import
-
Example: import('../../sites/backups') → search in client/dashboard/sites/
-
Example: import('../../me/profile') → search in client/dashboard/me/
Use Glob to find menu files in that area:
client/dashboard/{area}/**/*-menu/index.tsx
Also check the app-level menu for top-level routes:
client/dashboard/app/*-menu/index.tsx
Extract Menu Information
For each discovered menu file, use Grep to find:
Existing menu items pattern:
<ResponsiveMenu.Item\s+to=
Route references in menu:
to={?\s*['"/]([^'"}\s]+)
This helps understand the menu's structure and where to add new items.
Menu Item Pattern
Menu items use ResponsiveMenu.Item :
<ResponsiveMenu.Item to="/path/to/screen"> { __( 'Menu Label' ) } </ResponsiveMenu.Item>
Conditional menu items check feature support:
{ siteTypeSupports.featureName && (
<ResponsiveMenu.Item to={ /sites/${ siteSlug }/feature }>
{ __( 'Feature' ) }
</ResponsiveMenu.Item>
) }
Step 3: Gather User Input
Ask the user for the following using AskUserQuestion:
-
Parent Route: Present discovered routes grouped by source file
-
Screen Name: lowercase-with-dashes (e.g., custom-settings )
-
Route Path: URL path segment (e.g., custom-settings )
-
Page Title: Human-readable title (e.g., Custom settings )
-
Page Description (optional): Description shown below title
-
Add to Navigation Menu?: Yes or No
Step 4: Determine File Locations
Based on the selected parent route's import path, determine where to create the component.
Pattern: If parent imports from ../../sites/backups , new screen goes in client/dashboard/sites/{screen-name}/
For sites area: client/dashboard/sites/{screen-name}/index.tsx
For me area: client/dashboard/me/{screen-name}/index.tsx
For other areas: Follow the same pattern from parent's import path
Step 5: Create Component File
Generate a basic component with the standard layout.
Screen Template
import { __ } from '@wordpress/i18n'; import { PageHeader } from '../../components/page-header'; import PageLayout from '../../components/page-layout';
export default function {ComponentName}() { return ( <PageLayout header={ <PageHeader title={ __( '{PageTitle}' ) } description={ __( '{PageDescription}' ) } /> } > {/* Content goes here */} </PageLayout> ); }
Step 6: Register the Route
Add the route definition to the same router file as the parent route.
Route Definition Pattern
Add after other route exports in the file:
export const {routeName}Route = createRoute( { head: () => ( { meta: [ { title: __( '{PageTitle}' ), }, ], } ), getParentRoute: () => {parentRoute}, path: '{routePath}', } ).lazy( () => import( '{componentImportPath}' ).then( ( d ) => createLazyRoute( '{routeId}' )( { component: d.default, } ) ) );
Wire into Route Tree
Find where the parent route is used in the create*Routes() function and add the new route.
For standalone routes (direct child of main area route):
// Find the routes array (e.g., siteRoutes, meRoutes) // Add the new route to the array siteRoutes.push( newScreenRoute );
For nested routes (child of a feature route):
// Find where parent uses .addChildren() // Add the new route to the children array parentRoute.addChildren( [ existingRoute, newScreenRoute ] )
Step 7: Add Navigation Menu Entry (Optional)
If the user requested a navigation menu entry, add it to the discovered menu file.
Locate Target Menu File
Use the menu discovered in Step 2 based on the route's area:
-
From the parent route's import path, extract the area (e.g., sites , me , plugins )
-
Glob for client/dashboard/{area}/**/*-menu/index.tsx
-
If multiple menus found, present them to the user for selection
-
If no area-specific menu found, fall back to client/dashboard/app/primary-menu/index.tsx
Add Menu Item
Read the target menu file and find an appropriate location (typically before the closing </ResponsiveMenu> tag).
Build the route path from parent route's path + new screen path:
-
If parent path is /sites/$siteSlug and screen path is analytics → /sites/${ siteSlug }/analytics
-
If parent path is /me and screen path is api-keys → /me/api-keys
Insert menu item:
<ResponsiveMenu.Item to={ {fullRoutePath} }>
{ __( '{PageTitle}' ) }
</ResponsiveMenu.Item>
Match Existing Patterns
Analyze the existing menu items to match the pattern:
-
If menu uses template literals with siteSlug , use the same pattern
-
If menu uses simple strings, use simple strings
-
If menu items have conditional wrappers, ask user if one is needed
Conditional Menu Items
If the screen requires feature gating (check if similar items in the menu use conditions):
{ siteTypeSupports.{featureName} && (
<ResponsiveMenu.Item to={ /sites/${ siteSlug }/{routePath} }>
{ __( '{PageTitle}' ) }
</ResponsiveMenu.Item>
) }
Coding Standards
Follow the coding standards documented in client/dashboard/docs/ .