=== Limited Admin Menu Access by URLs === Contributors: wp-buy Tags: limited, admin muenu, restriction, controlled access, support access Requires at least: 5.9 Tested up to: 7.0 Stable tag: 3.1.3 Requires PHP: 7.4 License: GPL-2.0-or-later License URI: https://www.gnu.org/licenses/gpl-2.0.html Give support agents limited WordPress admin access — restricted to specific pages you allow, with all others hidden and hard-blocked. == Description == **Limited Admin Menu Access by URLs** is built for site owners and administrators who need to give support agents, clients, or junior staff a tightly controlled window into the WordPress admin — without handing over full access. The typical use case: you have a support agent who needs to handle WooCommerce orders, or a client who should only see their own content settings, or a developer you want to restrict to specific tools. Instead of creating a custom role from scratch, you simply select the user and click the pages they are allowed to visit. The plugin hides everything else from their sidebar and blocks any attempt to navigate to restricted pages directly by URL. = Key Features = * **User Targeting** — Select one or more users from a searchable, filterable list. Filter by role (Administrator, Editor, Author, Subscriber) with live AJAX search by name or email. * **Visual Link Picker** — Hold `CTRL` (or `CMD` on Mac) to activate an interactive overlay on the admin sidebar. Click any link to instantly add it to the allowlist. Added links are highlighted green; click again to remove. * **URL + Title Tags** — Allowed URLs are stored with their menu title for a human-readable allowlist display and a friendlier Access Denied page. * **Menu Hiding** — All admin sidebar menu items not in the allowlist are automatically hidden for targeted users. * **Hard URL Blocking** — Direct navigation to a blocked URL is intercepted at `admin_init` and returns a styled 403 Access Denied page — even if the user tries to type the URL directly into the address bar. * **Access Denied Page** — A professional full-page block screen lists all pages the user *is* allowed to visit, with titles and URLs as clickable links. * **Empty Dashboard Option** — A single checkbox removes all dashboard widgets for restricted users, leaving a clean empty dashboard while keeping the page itself accessible. * **Plugin Self-Protection** — When a restricted user is granted access to the Plugins page, the *Deactivate* and *Settings* action links for this plugin are automatically removed from their view. A server-side guard additionally intercepts and blocks any direct deactivation request, even if crafted manually, ensuring the plugin cannot be disabled by a restricted user. * **Backwards Compatible** — Existing plain-text URL lists from earlier versions are automatically migrated to the new JSON format on first save. * **Clean Uninstall** — All plugin data is removed from the database when the plugin is deleted. = Primary Use Case: Granting Limited Admin Access to Support Agents = When a support agent needs to help with order management, content issues, or plugin configuration, giving them full admin access is a security and compliance risk. This plugin solves that problem cleanly: 1. Create a WordPress account for the support agent (any role). 2. Open **Limited Admin Access** in your sidebar. 3. Check the agent's name in the Target Users list. 4. Hold `CTRL` and click the exact sidebar pages they need — Orders, a specific settings tab, the media library, whatever the job requires. 5. Click **Apply Restrictions**. The agent now sees only those pages in their sidebar, and any attempt to navigate elsewhere returns a branded Access Denied screen listing exactly where they *are* allowed to go. No custom roles, no code, no guesswork. = Other Use Cases = * Give a client access to only their WooCommerce orders page and nothing else. * Restrict a content author to only the post editor and media library. * Limit a junior developer to only the tools relevant to their current task. * Prevent non-technical staff from accidentally accessing sensitive settings. * Provide a contractor with a scoped admin view for the duration of a project. = How It Works = 1. Go to **Limited Admin Access** in the WordPress admin sidebar. 2. Select one or more users to restrict using the Target Users panel. 3. Hold `CTRL` and click sidebar links to add them to the allowlist — or type URLs manually. 4. Optionally check **Hide All Dashboard Widgets** to give restricted users a blank dashboard. 5. Click **Apply Restrictions**. From that point on, restricted users will only see the allowed menu items and can only navigate to allowed pages. Attempting to visit any other admin URL returns a 403 page with links to permitted pages. = Security = * All inputs are sanitized using WordPress-native functions (`sanitize_text_field`, `esc_url_raw`, `absint`, `wp_unslash`). * URL scheme validation rejects `javascript:`, `data:`, and other non-HTTP schemes from the allowlist. * AJAX endpoints are protected with nonces and `current_user_can('manage_options')` checks. * URL matching uses exact path + query-string comparison — substring matching is not used, preventing crafted URL bypass attacks. * The plugin page render callback has an explicit capability gate independent of the menu registration. * Restricted users who are granted access to the Plugins page cannot deactivate this plugin — the *Deactivate* and *Settings* action links are stripped from the plugin row for those users, and a server-side `admin_init` guard verifies WordPress's own deactivation nonce before intercepting and blocking any direct deactivation request. * All data is removed on plugin deletion via `uninstall.php`. == Installation == = Automatic Installation = 1. Log in to your WordPress admin panel. 2. Navigate to **Plugins → Add New**. 3. Search for **Limited Admin Menu Access by URLs**. 4. Click **Install Now** and then **Activate**. = Manual Installation = 1. Download the plugin `.zip` file. 2. Extract it and upload the `limited-admin-menu-access-by-urls` folder to `/wp-content/plugins/`. 3. Activate the plugin from the **Plugins** screen in WordPress admin. = After Activation = 1. Go to **Limited Admin Access** in the admin sidebar. 2. Select users to restrict in the **Target Users** panel. 3. Hold `CTRL` and click sidebar links to add them to the allowlist. 4. Click **Apply Restrictions**. == Frequently Asked Questions == = Will this lock me out of the admin panel? = No. The plugin never restricts the currently logged-in admin user. You cannot add yourself to the restricted users list. Super-admins on Multisite installs are also protected from accidental restriction. = What happens if a restricted user tries to access a blocked URL directly? = They receive a styled 403 Access Denied page listing all pages they are permitted to visit. The page includes a link back to the dashboard. = Can I restrict an Administrator-role user? = Yes. Role does not determine restriction — only whether the user's ID is in the targeted users list. You can restrict any user except yourself and users with the `manage_options` capability who manage the plugin settings. = Does the plugin support Multisite? = The plugin works on single-site WordPress installations. Multisite support is planned for a future release. = What URL formats are accepted in the allowlist? = Both full URLs (`https://example.com/wp-admin/edit.php?post_type=page`) and relative paths (`/wp-admin/edit.php?post_type=page`) are accepted. The CTRL link-picker automatically captures the full absolute URL with its menu title. = What happens to existing plain-text URL lists after updating from an older version? = The plugin detects the old newline-separated format and reads it transparently. The data is migrated to the new JSON format automatically the next time you save settings. = Can I allow access to a specific subpage only (e.g. one WooCommerce settings tab)? = Yes. URL matching includes the full query string. Adding `/wp-admin/admin.php?page=wc-settings&tab=shipping` will allow only that specific tab, not the entire WooCommerce settings area. = Is there a way to allow the entire dashboard without listing every widget? = Yes — simply add `/wp-admin/index.php` to the allowlist. The dashboard is always accessible as a fallback landing page regardless of restrictions. To show it empty, enable the **Remove All Dashboard Widgets** option. = Can I use this to give a support agent access to WooCommerce orders only? = Absolutely — that is the primary use case this plugin was designed for. Select the agent's user account, hold CTRL and click the WooCommerce Orders link in the sidebar, then click Apply Restrictions. The agent will see only the Orders page (and the dashboard) and nothing else. == Screenshots == 1. **Visual Overview** Our clean, modern interface designed to demonstrate how Limited Admin Menu Access by URLs gives you precise control over the WordPress dashboard experience. 2. **Main Settings Page** — The admin panel showing the Target Users list, capability filter, and URL allowlist with tag chips. 3. **CTRL Link Picker Active** — The sidebar in picker mode with blue overlay masks on each link, a green highlight on already-added links, and the active-mode banner at the top. 4. **Allowed URLs Tag Chips** — The allowlist panel showing URL+title chips in dark tag style with remove buttons. 5. **Access Denied Page** — The 403 block screen showing the plugin branding, a list of permitted pages with titles, and a link back to the dashboard. 6. **Empty Dashboard** — The dashboard as seen by a restricted user with the Remove Widgets option enabled. == 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 `