WordPress current_user_can Example: Check Object Permissions Safely
Learn how to use current_user_can() with object-aware capability checks instead of broad role assumptions or nonce-only logic.
Published
May 4, 2026
Reading Time
2 min read
Updated
May 4, 2026

Implementation Notes
Extension points, code paths, and implementation choices that should survive contact with production.
Best For
WordPress developers, agencies, and technical teams building custom plugin or theme functionality with cleaner operational defaults.
Primary Topics
Editorial Focus
Build Pattern: Extension points, code paths, and implementation choices that should survive contact with production. Updated on May 4, 2026.
Full Report
Last reviewed: May 4, 2026
Many WordPress permission bugs come from checking the wrong thing. Developers often gate an action with a broad role assumption, or they treat a valid nonce as if it were authorization. current_user_can() is the capability check that should answer the real question: can this specific user perform this specific action on this specific object?
This guide shows how to use current_user_can() safely with object-aware checks, why meta capabilities matter, and where permission checks belong in production plugin and theme code.
Check the actual action, not a guessed role
<?php
$post_id = 42;
if ( ! current_user_can( 'edit_post', $post_id ) ) {
wp_die( esc_html__( 'You are not allowed to edit this content.', 'vulnwp' ) );
}
This is stronger than checking a role name because WordPress maps the meta capability edit_post to the right primitive capabilities for the current user and the specific post.
Use object IDs when the capability is object-specific
The official reference notes that meta capabilities like edit_post, delete_post, and edit_user accept an object ID. That matters because two users can both have editorial access in general while only one of them can modify a given object.
<?php
if ( ! current_user_can( 'delete_post', $post_id ) ) {
return new WP_Error(
'forbidden',
__( 'You cannot delete this post.', 'vulnwp' ),
array( 'status' => 403 )
);
}
If the action belongs to one specific post, term, or user, the check should usually include that ID.
Keep nonce checks and capability checks separate
A nonce helps verify request intent. It does not grant permission. Production code should usually do both checks in sequence: verify the nonce, then verify the capability.
<?php
if ( ! isset( $_POST['vulnwp_nonce'] ) ) {
return;
}
if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['vulnwp_nonce'] ) ), 'vulnwp_save_note' ) ) {
return;
}
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
If a route, form handler, or AJAX action skips the capability check because a nonce exists, it is trusting the wrong signal.
Run the permission check in the execution path that changes data
It is fine to hide admin UI from unauthorized users, but the real control has to live where the write actually happens. Menu visibility is not protection. Button visibility is not protection. Endpoint code, form handlers, and save callbacks should perform the authoritative permission decision.
Common mistakes
- Checking roles by name. The WordPress reference discourages this because capabilities are the stable permission model.
- Using a broad capability when a meta capability exists.
edit_postsandedit_postare not interchangeable. - Treating a valid nonce as permission. Nonces and authorization solve different problems.
- Checking only in the UI layer. The write path must enforce the same rule again.
Production checklist
- Prefer capability checks over role checks.
- Pass the object ID when the action targets a specific post, term, or user.
- Keep nonce verification and authorization as separate checks.
- Enforce the permission decision inside the callback that changes state.
- Return a clear
403response for denied requests instead of failing silently.
Related reading
Pair this with the WordPress nonce example when the action is form-driven, and with the admin AJAX guide when the permission check guards a logged-in asynchronous workflow.


