WordPress

Capability

Capability is a named permission in WordPress, such as edit_posts or manage_options. Roles are bundles of capabilities, and code checks the capability, not the role name.

How it is measured

The check is current_user_can( 'publish_posts' ) or current_user_can( 'edit_post', $post_id ). It returns true or false for the logged-in user. Roles and their capabilities live as a serialized array in the wp_user_roles option, with your table prefix in front of the name.

To inspect them, run wp cap list editor with WP-CLI or wp role list. Plugins such as User Role Editor show the same data as checkboxes in wp-admin.

Worked example

An agency gives a freelance writer the Author role, which carries upload_files and publish_posts but not edit_others_posts. The writer can publish her own posts, then cannot fix a typo on the editor's draft; the Edit link just does not appear.

The agency adds a custom role named Contributor Plus that has edit_published_posts but not delete_posts, and assigns it. A month later a plugin update adds its own capability named manage_shop_reports, which the new role lacks, so the writer's reports menu disappears.

How it differs

A capability says what an account may do. A nonce proves that this request came from a page the user was shown, and says nothing about permissions. A correct endpoint checks both: the nonce for intent, the capability for authority. Passing one without the other leaves a gap.

Common errors

Testing for a role name like administrator instead of a capability. Checking manage_options in code that only editors should reach. Adding a nonce and skipping the capability check on an AJAX handler. Granting unfiltered_html to a user role for convenience. Registering a custom post type without capability_type or map_meta_cap, so everyone gets the default post permissions.

In practice

This week, list your users with wp user list --fields=user_login,roles and downgrade anyone who is Administrator out of habit. Read each AJAX and REST handler in your custom code for a current_user_can call; a handler without one is open to any logged-in user.

See also

Nonce, WordPress

Sources

Count this on a real site.

Watch my website