A store-manager role scenario covering add_role timing, map_meta_cap for post ownership edge cases, and safely rolling out capability changes to existing installs.
Works with Claude / GPT730 uses★ 4.2
The prompt
code-custom-user-role-capabilities
I need a custom role called "Store Manager" that can manage products and orders (a
custom post type `shop_order`) but cannot access Plugins, Themes, or Users screens,
and cannot edit other roles' posts outside their own department.
CONTEXT: [this plugin is already installed on about 200 client sites, and I need to
add this role in a plugin update without breaking sites where an admin has already
manually created a role with the same name]
Build this like a senior dev rolling out a capability change safely, in order:
1. Show the `add_role()` call with a specific capability array (not just cloning
`administrator`), explicitly listing `edit_shop_orders`, `edit_products`,
`read`, etc., and explain why granting `manage_options` "just to be safe" is the
wrong instinct here, since it would expose the Plugins and Themes screens this role
is supposed to be locked out of.
2. Explain the critical timing issue: `add_role()` only needs to run once (it persists
in the `wp_options` table), so calling it on every page load is wasteful, but it
must NOT be called on `plugin activation` alone either, since a user might already
have the role from a previous version. Show the correct pattern: check a stored
option like `myplugin_role_version`, and only re-run `add_role()` (removing and
re-adding to pick up capability changes) when that version is behind the current
plugin version, so upgrades can add new capabilities to the existing role.
3. Handle the "site already has a role with this name" collision: check
`get_role( 'store_manager' )` before creating, and if it exists with a different
capability set than expected, log a notice rather than silently overwriting a
site's manually customized role.
4. Show a `map_meta_cap` filter for the department-ownership rule: a Store Manager
should only get `edit_post` capability on `shop_order` posts where a custom
`department` meta field matches their own user meta, not on every order, which the
default capability system can't express without this filter.
5. On plugin uninstall, remove the role via `remove_role()` only if it matches the
plugin's known capability signature, to avoid deleting a role a site admin
customized further after install.
Replace the role name, capabilities, and post types with your actual setup.
The version-gated add_role() pattern in step 2 is the part most tutorials skip entirely, and it’s exactly what breaks a capability rollout across an existing install base: without it, upgrades either never apply new capabilities or wipe out an admin’s manual customizations on every activation.