Overview
Custom policies let you go beyond the built-in templates. Write JSON rules that precisely control menu access, page blocking, and capability stripping for specific WordPress roles. This is the most flexible way to configure AdminLocks and is ideal for agencies managing complex multi-role environments.
Every policy in AdminLocks ultimately resolves to a JSON rule object. The visual policy builder generates these rules for you, but you can also write them by hand in the AdminLocks → Policies → Custom JSON editor for full control.
Rule Structure
A policy rule is a JSON object with three optional arrays. Each array controls a different aspect of the WordPress admin experience. You can include any combination of the three -- all are optional, and omitted arrays have no effect.
{
"deny_menus": ["plugins.php", "themes.php"],
"deny_pages": ["plugins.php", "theme-install.php"],
"deny_capabilities": ["install_plugins", "switch_themes"]
}
All three arrays work together. If you deny a menu item but do not deny the corresponding page or capability, the user may still access the functionality through direct URL navigation or API calls. For complete lockdowns, use all three arrays in combination.
deny_menus
An array of WordPress menu slugs to hide from the admin sidebar. These are the filenames used in add_menu_page() and correspond to top-level admin menu items. When a menu slug is denied, the sidebar item is removed entirely.
Common menu slugs:
| Slug | Menu Item |
|---|---|
plugins.php | Plugins |
themes.php | Appearance |
users.php | Users |
tools.php | Tools |
options-general.php | Settings |
edit-comments.php | Comments |
upload.php | Media |
edit.php | Posts |
The user will not see the menu item in the sidebar, but they could still navigate to the page directly by entering the URL. Always pair deny_menus with deny_pages for complete enforcement.
deny_pages
An array of admin page filenames to block. AdminLocks matches these values against the WordPress $pagenow global variable on every admin page load. When a user navigates directly to a denied page, they receive a 403 "Access Denied" response with a message explaining that their access has been restricted by a policy.
This is the enforcement layer. While deny_menus hides the navigation, deny_pages actually blocks access. Common page filenames:
plugins.php-- Main plugins listplugin-install.php-- Add new plugin screentheme-install.php-- Add new theme screenthemes.php-- Manage themes screenoptions-general.php-- General settingsoptions-writing.php-- Writing settingsoptions-reading.php-- Reading settingsexport.php-- Export toolimport.php-- Import tool
deny_capabilities
An array of WordPress capabilities to strip from targeted users. When a capability is stripped, the user cannot perform any action that requires it. WordPress checks capabilities throughout the admin via current_user_can(), so this is the deepest level of enforcement -- it affects UI elements, REST API calls, AJAX requests, and all programmatic capability checks.
| Capability | What it controls |
|---|---|
install_plugins | Installing new plugins |
activate_plugins | Activating and deactivating plugins |
delete_plugins | Deleting plugins from the server |
install_themes | Installing new themes |
switch_themes | Changing the active theme |
delete_themes | Deleting themes from the server |
edit_theme_options | Customizer and widget access |
create_users | Creating new user accounts |
delete_users | Deleting user accounts |
promote_users | Changing user roles |
edit_users | Editing other users' profiles |
manage_options | Accessing the Settings screens |
moderate_comments | Moderating and managing comments |
Targeting Roles
Policies can target specific WordPress roles via a comma-separated list in the policy's Roles field. When roles are specified, the policy only applies to users who hold one of those roles.
If the roles field is left empty, the policy applies to all non-administrator users by default. Administrators with the manage_options capability are always exempt unless they lack the adminlocks_bypass capability and a policy explicitly targets the administrator role.
// Target editors and authors only
Roles: "editor,author"
// Target all non-admin users (leave empty)
Roles: ""
Be careful when targeting the administrator role. Locking yourself out of the Settings screen will require WP-CLI or direct database access to recover. Always keep at least one account with the adminlocks_bypass capability.
Examples
Lock out editors from plugins and themes
{
"deny_menus": ["plugins.php", "themes.php"],
"deny_pages": ["plugins.php", "plugin-install.php", "themes.php", "theme-install.php"],
"deny_capabilities": ["install_plugins", "activate_plugins", "delete_plugins",
"install_themes", "switch_themes", "delete_themes"]
}
Roles: "editor"
Content-only mode for authors
{
"deny_menus": ["plugins.php", "themes.php", "users.php", "tools.php",
"options-general.php"],
"deny_pages": ["plugins.php", "themes.php", "users.php", "tools.php",
"options-general.php", "import.php", "export.php"],
"deny_capabilities": ["install_plugins", "activate_plugins", "switch_themes",
"manage_options", "create_users", "edit_users"]
}
Roles: "author"
Block settings for all non-admins
{
"deny_menus": ["options-general.php"],
"deny_pages": ["options-general.php", "options-writing.php", "options-reading.php",
"options-discussion.php", "options-media.php", "options-permalink.php"],
"deny_capabilities": ["manage_options"]
}
Roles: ""
Validation
All policy rules are validated when you save them. AdminLocks checks that the rule is valid JSON, that the top-level value is an object, and that each key maps to an array of strings.
- Invalid JSON is rejected with a parse error message indicating the line and character position of the syntax error.
- Unknown keys are silently ignored. You can include comments or metadata fields without breaking anything, though they will have no effect.
- Empty arrays are valid but have no effect. A rule like
{"deny_menus": []}is accepted but does not block anything. - Duplicate values within an array are deduplicated automatically.
You can test your custom policy rules without affecting live users by setting the policy to inactive. Activate it only after you have verified the JSON structure and tested with a staging account.