WordPress Admin URL Building

SkillDev tools

Patterns for building WordPress admin page URLs in Simple History. Use when constructing admin links, settings tabs, or menu URLs dynamically.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the WordPress Admin URL Building skill

What this skill tells your AI

The instructions your AI receives, as published by bonny/wordpress-simple-history in .claude/skills/wp-admin-urls/SKILL.md and read by ahel’s review.

Simple History's admin pages can live in different locations depending on user settings (top-level, inside Tools, inside Dashboard). Never hardcode admin URLs. Always use the helper methods.

Key Helpers

All in inc/class-helpers.php:

MethodReturnsExample
Helpers::get_history_admin_url()Main history page URL (no filters)admin.php?page=simple_history_admin_menu_page
Helpers::get_filtered_history_url($args)History URL with filters appliedSee "Building Filtered URLs" below
Helpers::get_settings_page_url()Settings page URLadmin.php?page=simple_history_settings_page
Helpers::get_settings_page_tab_url($tab)Settings tab URL...&selected-tab=general_settings_subtab_general
Helpers::get_settings_page_sub_tab_url($sub_tab)Settings sub-tab URL...&selected-tab=...&selected-sub-tab=...

Why URLs Are Dynamic

The base admin URL changes with menu location:

Location settingHistory baseSettings base
top / bottomadmin.php?page=...admin.php?page=...
inside_toolstools.php?page=...options-general.php?page=...
inside_dashboardindex.php?page=...options-general.php?page=...

Menu Page Slugs

Defined as constants in inc/class-simple-history.php:

  • Simple_History::MENU_PAGE_SLUG - Main history page
  • Simple_History::SETTINGS_MENU_PAGE_SLUG - Settings page

Settings Tab URL Structure

Settings uses a tab/sub-tab system with query parameters:

?page=simple_history_settings_page
  &selected-tab=general_settings_subtab_general    ← main tab
  &selected-sub-tab=general_settings_subtab_alerts ← sub-tab

Build these with Helpers::get_settings_page_sub_tab_url('slug') — never manually.

Common Tab Slugs

Look up tab slugs in the module or service that registers them:

  • Alerts (free teaser): Alerts_Settings_Page_Teaser::MENU_SLUG (general_settings_subtab_alerts)
  • Alerts (premium): Alerts_Module::ALERTS_TAB_SLUG (same value, premium add-on only)
  • General settings: Setup_Settings_Page::SETTINGS_GENERAL_SUBTAB_SLUG
  • Check module/service classes for their *_TAB_SLUG or MENU_SLUG constants

History Page Filter Parameters

The main history page accepts URL query parameters that pre-fill filters:

ParameterFormatExample
datelastdays:N, allDates, month:YYYY-MM, customRangedate=allDates
contextkey:value (one per line)context=post_id:123
show-filters1 to expand filter panelshow-filters=1
messagesJSON array (URL-encoded)See below
usersJSON array of user objects[{"id":"1","value":"Jane (jane@example.com)"}]

Building the messages Parameter

The messages param is a JSON array of objects, each with value (display label) and search_options (array of LoggerSlug:message_key strings):

$messages_json = wp_json_encode( array(
    array(
        'value'          => 'All posts & pages activity',
        'search_options' => array(
            'SimplePostLogger:post_created',
            'SimplePostLogger:post_updated',
            'SimplePostLogger:post_trashed',
        ),
    ),
) );

Building Filtered URLs

Always use Helpers::get_filtered_history_url() — it handles the JSON encoding gotcha internally:

// General-purpose filtered URL.
$url = Helpers::get_filtered_history_url( array(
    'date'         => 'allDates',
    'context'      => 'post_id:123',
    'show_filters' => true,
    'messages'     => array(
        array(
            'value'          => 'All posts & pages activity',
            'search_options' => array(
                'SimplePostLogger:post_created',
                'SimplePostLogger:post_updated',
            ),
        ),
    ),
) );

// Shortcut for post-specific history (used by row actions and History column).
$url = Post_History_Column::get_post_history_url( $post_id );

Never pass messages via add_query_arg() — it double-encodes JSON. The shared helper handles this correctly with rawurlencode().

Finding Logger Slugs and Message Keys

Each logger has a $slug property and messages array in get_info(). The search_options format is LoggerSlug:message_key. Check the logger class to find available keys:

grep -n "slug\|messages" loggers/class-post-logger.php | head -20

Anti-Patterns

// WRONG: Hardcoded URL breaks when menu location changes.
$url = admin_url('admin.php?page=simple_history_settings_page&selected-sub-tab=alerts');

// WRONG: Building URL manually in JavaScript.
const url = `${adminUrl}admin.php?page=simple_history_settings_page...`;

// RIGHT: Use helper in PHP, pass to JS if needed.
$url = Helpers::get_settings_page_sub_tab_url( Alerts_Settings_Page_Teaser::MENU_SLUG );

Passing URLs to JavaScript

When JS components need admin URLs, generate them in PHP and pass them via:

  1. wp_localize_script — for URLs needed immediately on page load
  2. simple_history/search_options_data filter — for URLs consumed by React components via the search-options REST API

See the php-to-react-data skill for details on choosing between these approaches.

Signals

GitHub stars
317
Forks
74
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
wp-admin-urls
Source
github.com/bonny/wordpress-simple-history