Limited Admin Menu Access by URLs

Changelog

3.1.3 — Normal checking

  • Changed: Checking with the last version of wordpress, Version: 7.0

3.1.2 — including JS and/or CSS Fixes

including JS and/or CSS Fixes

  • Fixed: Access-denied page styling and layout broken by Tailwind v3.4.1. The plugin now bundles its own Tailwind CSS (assets/tailwind.min.css) and loads it via wp_enqueue_style() instead of relying on the admin-footer global stylesheet.
  • Fixed: Missing Font Awesome icons on the access-denied page. The plugin now bundles assets/font-awesome.min.css and loads it via wp_enqueue_style().

3.1.1 — Bug Fix

Bug Fixes

  • Fixed: Infinite redirect loop when a restricted user tried to access an unallowed page. The access-denied page guard required a valid _wpnonce parameter, but the redirect URL never included one — causing the access-denied page itself to be treated as blocked and redirected back to itself endlessly.
  • Fixed: Access-denied page bypass check moved before the allowed-links loop so it is evaluated first regardless of the allowlist contents.
  • Removed: Unnecessary nonce requirement on the access-denied page routing check — this is a read-only page display, not a state-changing action.
  • Changed: Prefixed all JavaScript functions with limiadme_ to prevent global scope conflicts and adhere to WordPress standards.
  • Fixed: Resolved the “Uncaught ReferenceError: limiadmeData is not defined” issue by correctly enqueuing the restricted-user JS and properly timing its data localization.
  • Fixed: Resolved PHPCS warnings (unslashed inputs, heredocs, output escaping, discouraged parse_url).
  • Fixed: Removed discouraged load_plugin_textdomain and missing Domain Path header.
  • Fixed: allowed.map is not a function JS error caused by double-encoding of the allowed JSON array.

3.1.0 — Security & WP.org Compliance Release

Security

  • Fixed: Replaced stripslashes() with wp_unslash() throughout for canonical WordPress input handling.
  • Fixed: $_SERVER[‘REQUEST_URI’] now passed through wp_unslash() before use.
  • Fixed: aur_page_render() now has an explicit current_user_can(‘manage_options’) guard independent of menu registration.
  • Fixed: AJAX handler now uses wp_send_json_error() with HTTP 403 for unauthorized requests instead of plain wp_die().
  • Fixed: wp_json_encode() in inline <script> blocks now uses JSON_HEX_TAG | JSON_HEX_AMP flags to prevent XSS via stored data.
  • Fixed: URL scheme validation in sanitizer now explicitly rejects javascript:, data:, ftp: and other non-HTTP(S)/non-relative values.
  • Fixed: onmouseover/onmouseout inline JavaScript event handlers in the Access Denied page replaced with CSS :hover rules — compatible with strict Content Security Policy headers.
  • Fixed: Anonymous closure used as sanitize_callback for dashboard widget option replaced with named function aur_sanitize_bool_option() — anonymous closures cannot be serialized by WordPress on some host configurations.
  • Added: Plugin self-protection — restricted users who are granted access to the Plugins page can no longer deactivate this plugin. The Deactivate and Settings row-action links are removed from the plugin list for restricted users (plugin_action_links_ filter). A separate admin_init hook verifies WordPress’s own deactivate-plugin_* nonce and then intercepts and redirects any deactivation attempt before it is processed, displaying a dismissible admin notice explaining the block.

WordPress.org Compliance

  • Changed: Plugin renamed from “Admin URL Restrictor PRO” to “Limited Admin Menu Access by URLs” — better reflects the primary support-agent use case; WP.org guidelines prohibit “PRO” and similar suffixes.
  • Changed: External CDN asset loading (Tailwind CSS from cdn.tailwindcss.com, Font Awesome from cdnjs) replaced with locally bundled assets loaded via wp_enqueue_style() — WP.org guidelines prohibit external CDN dependencies.
  • Changed: Inline <script> and <link> tags in render callback replaced with proper wp_enqueue_style() calls.
  • Changed: wp_add_inline_script() target changed from ‘jquery’ to ‘wp-dom-ready’ — jQuery may be dequeued on certain admin screens (e.g. block editor), causing the menu-hider script to silently fail.
  • Added: uninstall.php — removes all plugin options (limiadme_restricted_users, limiadme_allowed_links, limiadme_remove_dashboard_widgets, aur_version) when the plugin is deleted.
  • Added: register_activation_hook() seeds default option values and stores plugin version on first activation.
  • Added: load_plugin_textdomain() registered on init hook for full internationalization support.
  • Added: Text domain string ‘limited-admin-menu-access-by-urls’ added to all translatable strings.
  • Added: Plugin header now includes Requires at least, Requires PHP, License, and License URI fields.
  • Fixed: Author field updated from AI tool attribution to valid WordPress.org username.

Code Quality

  • Removed: Dead function aur_uri_to_file() which was defined but never called.
  • Removed: limiadme_restricted_users_baseline[] hidden form inputs which were redundant — the JavaScript syncUsers() function already handles cross-filter user persistence correctly.
  • Fixed: Dashboard widget removal now uses remove_meta_box() per widget instead of directly wiping $wp_meta_boxes[‘dashboard’] — direct global mutation conflicts with other plugins hooking wp_dashboard_setup.
  • Changed: Version bumped to 3.1.0 to reflect the scope of security and compliance changes.

2.5.0 — URL Picker & Tag UI Release

New Features

  • Added: Interactive CTRL link-picker mode — hold CTRL (or CMD on Mac) to activate an overlay on the admin sidebar; click any link to add it to the allowlist instantly.
  • Added: Visual tag-chip allowlist UI replaces the plain textarea — each allowed URL is shown as a dark chip with its menu title and URL, with individual remove buttons.
  • Added: “Remove All” button clears the entire allowlist with a confirmation prompt.
  • Added: Allowed URLs are now stored as JSON objects containing both the URL and the menu title captured at pick time.
  • Added: Access Denied page now shows the page title alongside the URL for each permitted link.
  • Added: CTRL picker highlights already-added links in green; clicking them removes them from the allowlist.
  • Added: Blue banner at the top of the screen is displayed while picker mode is active.
  • Added: Legacy plain-text URL format automatically migrated to JSON on first save — no data loss on upgrade.

Improvements

  • Improved: URL matching in menu-hider JS now uses browser-native <a> element resolution — bare slugs (edit.php?post_type=page) are resolved against the current page base automatically, eliminating all edge cases.
  • Improved: Protocol-agnostic comparison strips http:///https:// before matching so full URLs and relative paths always match correctly regardless of how the site URL scheme is configured.
  • Improved: &amp; HTML entity decoding added to URL normalisation to handle WordPress-encoded href attributes in menu links.

2.4.0 — Menu Hiding & Access Denied Overhaul

New Features

  • Added: Admin sidebar menu items not in the allowlist are now hidden for restricted users via a JavaScript pass over #adminmenu after DOM ready.
  • Added: Two-pass menu hiding — first hides individual items, then hides top-level parent items whose all children are hidden (prevents orphaned section headers).
  • Added: Access Denied page redesigned as a full-page card with a gradient header, allowed URLs list, and dashboard button.
  • Added: Allowed URLs in the Access Denied page are now rendered as clickable cards.

Bug Fixes

  • Fixed: Hardcoded bypass for the plugin settings page removed — restricted users were always able to access it regardless of the allowlist.
  • Fixed: home_url() double-prepending on full URLs in the Access Denied page — the plugin now detects whether a stored URL is already absolute before prepending the site URL.
  • Fixed: Access Denied page body width overridden to 100% — WordPress’s wp_die() injects max-width: 700px on the body which was constraining the full-page layout.
  • Fixed: URL matching changed from strpos() substring match to exact parse_url() path + query-string comparison — substring matching allowed crafted URL bypass attacks.

2.3.0 — Dashboard Widgets & Persistence Release

New Features

  • Added: “Hide All Dashboard Widgets” checkbox — when enabled, all dashboard widgets are removed for restricted users while keeping the Dashboard page itself accessible.
  • Added: Capability filter selection is now remembered across page reloads using localStorage.

Bug Fixes

  • Fixed: is_super_admin() used to filter the user list returned true for all administrators on single-site WordPress installs, causing the Target Users list to always appear empty.
  • Fixed: ‘capability’ was passed as a WP_User_Query argument — this key is not recognised by WordPress. Replaced with role__in mapped from the capability dropdown selection.
  • Fixed: search_columns not specified in user search query caused inconsistent search results across WordPress versions.
  • Fixed: Users not visible in the current filtered/paginated view were silently removed from the restricted list on save. Fixed with an in-memory checked-users Set persisted across filter changes.
  • Fixed: Anonymous function used as sanitize_callback for limiadme_restricted_users — replaced with named function aur_sanitize_user_ids().

2.2.0 — UI & Search Release

New Features

  • Added: AJAX-powered user table with live search by display name, login, and email address.
  • Added: Capability-based user filter dropdown (All Users, Editors/Authors, Administrators, Subscribers, Authors+).
  • Added: Search debounce (300ms) to prevent excessive AJAX requests while typing.
  • Added: “Select All” checkbox in the user table header.
  • Added: Loading state opacity transition on the user table during AJAX fetch.
  • Added: Error message displayed in the user table if the AJAX request fails.
  • Added: “Loading users…” placeholder shown while the initial user list loads.

Improvements

  • Improved: Modern card-based admin UI built with Tailwind CSS utility classes.
  • Improved: User table shows display name, email address, and role for each user.

2.1.0 — Nonce & AJAX Security Release

Security

  • Added: Nonce verification (check_ajax_referer) on the aur_filter_users AJAX endpoint.
  • Added: current_user_can(‘manage_options’) check on the AJAX endpoint.
  • Added: Nonce value passed from PHP to JavaScript via wp_json_encode().

2.0.0 — Hard Block & Protection Logic

New Features

  • Added: admin_init hook intercepts requests to blocked admin pages for restricted users and calls wp_die() with a 403 response.
  • Added: Restricted users who attempt to access a blocked URL are shown an Access Denied screen.
  • Added: Dashboard (index.php) is always allowed as a fallback landing page regardless of the allowlist.
  • Added: AJAX requests (admin-ajax.php) are always permitted to avoid breaking plugin functionality.

Improvements

  • Improved: Exact URL path matching using parse_url() instead of simple string comparison.
  • Improved: Stored allowlist is trimmed and filtered to remove empty lines on each comparison.

1.0.0 — Initial Release

  • Initial release.
  • Added: Settings page with user selection checkboxes and a plain-text URL allowlist textarea.
  • Added: manage_options-only admin menu page registered via add_menu_page().
  • Added: Settings registered via register_setting() with WordPress Settings API.
  • Added: Plugin action link added to the Plugins list page pointing to the settings page.

Plugin Website
Visit website

Author
wp-buy
Version:
3.1.3
Last Updated
May 23, 2026
Requires
WordPress 5.9
Tested Up To
WordPress 7.0
Requires PHP
7.4

Share Post

Join our newsletter.

Get insights into what’s happening at ChangelogWP right in your inbox. We don’t believe in spam.