Allow people to administer only on certain content type? Under "admin/people/permissions" there is a permission that allows users to administer all the content types.



I want to create a role that can only administer an "Article" content type. 
How can I achieve this?
The menu callback for "admin/structure/types/manage/%node_type" is defined in node_menu() using the following array item:

  $items['admin/structure/types/manage/%node_type'] = array(
    'title' =&gt; 'Edit content type', 
    'title callback' =&gt; 'node_type_page_title', 
    'title arguments' =&gt; array(4), 
    'page callback' =&gt; 'drupal_get_form', 
    'page arguments' =&gt; array('node_type_form', 4), 
    'access arguments' =&gt; array('administer content types'), 
    'file' =&gt; 'content_types.inc',
  );


There are other two menu items that follow it, but they depend from that menu item for the access callback.

  $items['admin/structure/types/manage/%node_type/edit'] = array(
    'title' =&gt; 'Edit', 
    'type' =&gt; MENU_DEFAULT_LOCAL_TASK,
  );
  $items['admin/structure/types/manage/%node_type/delete'] = array(
    'title' =&gt; 'Delete', 
    'page arguments' =&gt; array('node_type_delete_confirm', 4), 
    'access arguments' =&gt; array('administer content types'), 
    'file' =&gt; 'content_types.inc',
  );


Once you change the access callback for the first menu item, the other two will use the same access callback.

The first step, for the custom module I would implement to achieve what you want is to implement hook_permission(). node_permission() is useful as guideline to write the code you need.

function mymodule_permission() {
  $perms = array();

  foreach (node_type_get_types() as $type =&gt; $info) {
    $perms["administer $type content type"] = array(
      'title' =&gt; t('%type_name: administer content type', array('%type_name' =&gt; $info-&gt;name)),
    );
  }

  return $perms;
}


The foreach() part could be rewritten as the following code:

  foreach (node_permissions_get_configured_types() as $type) {
    $info = node_type_get_type($type);

    $perms["administer $type content type"] = array(
      'title' =&gt; t('%type_name: administer content type', array('%type_name' =&gt; $info-&gt;name)),
    );
  }


The difference is that node_permissions_get_configured_types() is using some Drupal variables that are set in a settings page. The function is used also from the Node module when creating the list of the permissions associated to a node of a content type. The documentation for the function reports the following text:


  To exclude a specific node from getting permissions defined for it, set the "node_permissions_$type" variable to 0. Core does not provide an interface for doing so; however, contrib modules may exclude their own nodes in hook_install(). Alternatively, contrib modules may configure all node types at once, or decide to apply some other hook_node_access() implementation to some or all node types.


The second step is to alter the menu item already defined by the Node module.

function mymodule_menu_alter(&amp;$items) {
  if (isset($items['admin/structure/types/manage/%node_type']) {
    $items['admin/structure/types/manage/%node_type']['access callback'] = '_mymodule_content_type_access';    
    $items['admin/structure/types/manage/%node_type']['access arguments'] = array(4);
  }
}


_mymodule_content_type_access() should contain code similar to the following one:

function _mymodule_content_type_access($type) {
  return user_access("administer {$type-&gt;type} content type");
}