Role-Based Access
Add an access key to any tab, section, or field to gate it. Two verbs — view and edit — accept either a role slug (editor, author) or a capability (manage_options, edit_posts). Arrays evaluate as OR.
Quick examples
Section titled “Quick examples”// Split view and edit per verb.[ 'id' => 'api_key', 'type' => 'text', 'label' => __('API Key', 'my-plugin'), 'access' => [ 'view' => 'editor', // editors and above can see the key 'edit' => 'manage_options', // only admins can change it ],],
// Shorthand — same role/cap for both verbs.[ 'id' => 'internal_note', 'type' => 'textarea', 'label' => __('Internal note', 'my-plugin'), 'access' => 'editor',],
// Hide an entire section from non-admins.[ 'id' => 'danger_zone', 'title' => __('Danger Zone', 'my-plugin'), 'access' => ['view' => 'manage_options'], 'fields' => [ /* … */ ],],How resolution works
Section titled “How resolution works”When the framework sees a string in access, it tries role slugs first via get_role(), then falls back to capability lookups via current_user_can(). This means 'editor' works as a role and 'edit_posts' works as a capability without you having to declare which is which.
Arrays mean any of these grants access:
'access' => ['view' => ['editor', 'author', 'edit_others_posts']],Section and tab access bubbles up from fields
Section titled “Section and tab access bubbles up from fields”A tab or section with no access key of its own takes its visibility from its children: it shows for anyone who can view at least one field inside it, and hides when they can view none. Annotate the fields and the containers follow — no need to repeat the rule on the section to stop it rendering as an empty card.
Give a tab or section its own access key only when you want to gate it top-down regardless of its fields. wp-wireframe/access/resolve still runs for containers without an access key, so a filter can deny them.
Behaviour when RBAC is active
Section titled “Behaviour when RBAC is active”Once at least one access key is declared anywhere on the page, RBAC mode engages.
| Behaviour | Default | Override |
|---|---|---|
| Page capability | manage_options | Set capability on the boot config |
| Menu visibility | Floor drops to read; menu suppressed entirely when the user has zero accessible elements | n/a |
access shorthand 'editor' | Applied to both view and edit | Use long form ['view' => …, 'edit' => …] to split |
access arrays | Logical OR — any match grants access | n/a |
edit without view | Implicitly denied | edit always requires view |
Field with no access key | Inherits from its section / tab (ultimately the page capability) | Add an access key |
Tab / section with no access key | Visibility bubbles up — shown if the user can view at least one descendant field | Add an explicit access key to gate it top-down |
| Non-viewable elements | Stripped from the config sent to the browser entirely | wp-wireframe/config/for_user filter |
| Non-editable but viewable fields | Rendered with the input disabled; server rejects any writes | n/a |
| Empty tab/section after filtering | Auto-hidden | n/a |
| Save endpoint | Merges editable fields into existing values — fields outside scope are never touched | wp-wireframe/save/editable_fields, wp-wireframe/save/payload |
| Reset endpoint | Resets only the user’s editable fields | wp-wireframe/access/can_reset filter |
Action / header action $values | Only fields the user can view; view-only fields carry the stored value (or default), never the posted one | n/a |
| Save / Reset buttons | Hidden when the user has no editable fields | n/a |
| REST permission callback | read AND: GET — any viewable element; POST — an editable field; DELETE — an editable field and can_reset. Action and table routes use the GET rule | wp-wireframe/access/resolve filter |
Developer filters
Section titled “Developer filters”Five filters let you override decisions per-request without forking the config tree:
// Override the yes/no for a single (verb, level, id, user) check.add_filter('wp-wireframe/access/resolve', fn($allowed, $ctx) => $allowed, 10, 2);
// Mutate the config after access filtering, before localize.add_filter('wp-wireframe/config/for_user', fn($config, $pageId, $map) => $config, 10, 3);
// Prune or extend the writable field list for the current save.add_filter('wp-wireframe/save/editable_fields', fn($ids, $pageId, $map) => $ids, 10, 3);
// Transform sanitised values before they're merged into saved state.add_filter('wp-wireframe/save/payload', fn($values, $pageId, $payload) => $values, 10, 3);
// Override whether the current user may reset on this page.add_filter('wp-wireframe/access/can_reset', fn($can, $user, $viewable, $editable) => $can, 10, 4);See Hooks & Filters for the full signatures.
Custom field types: honour field.readOnly
Section titled “Custom field types: honour field.readOnly”When the current user has view but not edit access, the field’s React component receives a field.readOnly prop. Honour it by disabling your input — the server enforces writes regardless, so this is a UI hint not a security boundary.
function MyFieldEdit({ field, value, onChange }) { return ( <input value={value} onChange={(e) => onChange(e.target.value)} disabled={field.readOnly} /> );}