When working with WordPress menu page permissions, you there’s a chance that you’ll eventually come across the “Cheatin’ uh?” message.

Cheatin uh

In short, this particular message shows up whenever a user of a certain role with a certain set of capabilities is trying to do something that they aren’t permitted to do. For example, say that you have an Editor who is trying to save options on a page created by the Settings API.

Technically speaking, this should be straightforward:

  1. Create the options menu (via, say, add_menu_page)
  2. Populate the page using the Settings API
  3. Allow the user to save the information

When defining add_menu_page, you have to specify a capability for which the user has the ability to save the options. Luckily, the Codex has a page that makes it really easy to know what capabilities are available to each role.

But what happens when you’ve defined a capability for a menu page and you’re still getting an error message when trying to save the data?

WordPress Menu Page Permissions

Let’s say that you initially have your code setup like this (and for all intents and purposes you’re working with the latest version of WordPress, are familiar with the APIs, and all of that fun stuff):

Everything looks good, but then you create an Editor account to test out the information and everything looks good, but then you click on the ‘Save Changes’ button and you see the error screen from above?

So what’s the deal with that?

To fix this, add the following code: First, define a filter – this may be in the context of a method if it’s in the context of a constructor or as its own method if it’s in a procedural file:

Then define the method itself:

And finally, make sure that the code you’re used to define the menu page (as well as any submenu pages) use the capability you’ve defined.

Note that I write my plugins in an object-oriented fashion so the full code that I’m about to share will be a little different than what I have above, but the gist of what’s happening is still the same.

Here’s how the full code should be structured:

What Gives?

At the time of writing this message, I have dug into core enough to trace exactly why this happens – as far as my understanding is concerned (which is easy to call into question :), it should would without the need for this filter.

Unfortunately, it does require this particular change.

When I have the time to look more into the code behind everything powering this, I’ll likely blog about it. But until then, the code above should resolve the problem that you may experience and should make sure the proper role has the ability to save the data for each of the settings pages to which it has access.