How do I add an access condition to a menu item? How can I add new conditions on top of existing conditions that determine whether a menu item is visible? These conditions should not be limited to permissions settings.

As an example use case (not necessarily the reason for this question): Suppose I have a content type of which users are only allowed to create one node. I have a menu item for adding that type of content. But if the user has already created a node of that content type, I want to hide the menu item. My first thought is to run a query to check for the existence of a node created by the current user that is of the specific content type. If one exists, hide the menu item.

I would think this type of functionality should go into hook_menu_alter() and add the required logic there. But I'm not sure how to do that without bypassing the existing checks, like checking if the user has permissions to create that type of content. Would I have to include that logic within my own condition? Or can I add to the existing access logic without overwriting it?



Edit: Some people seem focused on answering "how do I limit a user to creating one node of a content type". That is not the question here. The question is how to I add custom access conditions to a menu item.
What you need to do is to add your callback via hook_menu_alter(), and then inside your callback you simply do your logic then return the data via the original callback.

To be certain that you don't overwrite any other hook_menu_alter() changes, you should pass the previous callback to your callback via the access argument.

This is all theoretical, but the code should go something like this:

MYMODULE_menu_alter(&amp;$items) {
  $items['menu']['access arguments'] = array_merge(array($items['menu']['access callback']), $item['menu']['access arguments']);
  $items['menu']['access callback'] = 'MYMODULE_access_callback';
}

MYMODULE_access_callback() {
  $args = func_get_args();

  // Do Stuff.
  if ($something == FALSE) {
    return FALSE;
  }

  $function = array_shift($args);
  return call_user_func_array($function, $args);
}