9

I have created a block programmatically but I don't know how I can programmatically assign the access to it. How can I achieve it?

3
  • Could you expand your question and show your code?
    – Triskelion
    Apr 12, 2013 at 16:27
  • In the block code itself you can lookup the user (global $user) and check their role using the method in the link. bywombats.com/blog/ryan/10-25-2007/…
    – user6614
    Apr 12, 2013 at 16:35
  • The Panels module has some great access controls using regions, not blocks.
    – Louis
    Apr 12, 2013 at 17:17

5 Answers 5

9

Setting the "roles" array in the array returned from hook_block_info() doesn't work because:

  • The roles that are allowed to see a block, and which are set in the user interface, are saved from block_admin_configure_submit() in the "block_role" table

    $query = db_insert('block_role')->fields(array('rid', 'module', 'delta'));
    foreach (array_filter($form_state['values']['roles']) as $rid) {
      $query->values(array(
        'rid' => $rid,
        'module' => $form_state['values']['module'],
        'delta' => $form_state['values']['delta'],
      ));
    }
    $query->execute();
    
  • The code that decides which blocks should be shown to the currently logged-in user is contained in block_block_list_alter(), which is an implementation of hook_block_list_alter(), and uses only the content of that table

    $result = db_query('SELECT module, delta, rid FROM {block_role}');
    foreach ($result as $record) {
      $block_roles[$record->module][$record->delta][] = $record->rid;
    }
    
    foreach ($blocks as $key => $block) {
      if (!isset($block->theme) || !isset($block->status) || $block->theme != $theme_key || $block->status != 1) {
        // This block was added by a contrib module, leave it in the list.
        continue;
      }
    
      // If a block has no roles associated, it is displayed for every role.
      // For blocks with roles associated, if none of the user's roles matches
      // the settings from this block, remove it from the block list.
      if (isset($block_roles[$block->module][$block->delta]) && !array_intersect($block_roles[$block->module][$block->delta], array_keys($user->roles))) {
        // No match.
        unset($blocks[$key]);
        continue;
      }
    
      // …
    
    }
    
  • There isn't another Drupal function that checks the roles property in the data returned from hook_block_info(), nor is the content of the "block_role" table merged with what returned from the hook_block_info() implementations.

You could verify the user has the required role to see the block in hook_block_view(), but at that point Drupal is already rendering the block; that means the user would still see the block title, if one has been already set.

What you can do is implementing hook_block_list_alter() to remove the information about that block when the user doesn't have the required role.
To avoid confusion to the users who administer the blocks, I would also alter the form used to edit a block, and disable the form field used to set which roles can see that block, since the module implementing it is going to use its own list of roles; the minimal code should at least show a message about the role settings not having any effect, but I would also disable the form elements for the role settings.

Since the Block module already shows form fields to select which roles see a block, you could also simply set a default for your block, and let the administrator users change it if necessary.

screenshot

As per checking the roles a user has versus checking the permissions a user has, the last is preferred, especially when the alternative would be hard-coding a list of roles in a module.
As shown from the Block module, using permission is not the only alternative: A module could have setting for deciding which roles are allowed to see something.
Clearly, it is not always worth having a setting for which roles are allowed to do something. I imagine also what for the administrator users would mean if 10 modules would have their own settings for which roles are allowed to do something, instead of using permissions, and allowing the administrator users to use a single page to set them.

1
  • Well I obviously will will have to go with this one as the most appropriate answer. Thank-you for the detailed explanation as it really helps to understand how Drupal blocks work behind the scenes.
    – user5013
    Apr 15, 2013 at 16:21
1

In your hook_block_info you could try something like:

$blocks['myblock'] = array(
   ...
   'roles' => array(
      'administrator' => '3',
      'authenticated user' => '2',
   )
4
  • This seems like the best way to implement this using a programmatic approach as you define the which roles have access and then let Drupal determine if a user can access it or not. Did I miss any downside to this approach?
    – user5013
    Apr 12, 2013 at 18:54
  • If you must do it programatically, yes. No downside. However I would assume there would have to be a very good use case against simply going to /admin/structure/block and assigning roles to the block.
    – Triskelion
    Apr 12, 2013 at 19:04
  • The use case would be automatically do the set up for the user so they wouldn't have to. Strictly a convenience issue. Once set, they could then change it to what they want it to be if it doesn't suit their particular needs.
    – user5013
    Apr 12, 2013 at 19:12
  • 1
    This doesn't work; see my answer for why it doesn't.
    – apaderno
    Apr 13, 2013 at 0:08
0

Assuming that you are making the blocks yourself with hook_block_info() then you could just do user_access() in your hook_block_view() function. Check out the api docs since they have an example of this.

1
  • Yes I should have thought about using user_access. Totally slipped my mind - D'oh. I thinking about using role access but perhaps permission access might be a better way to go.
    – user5013
    Apr 12, 2013 at 19:08
0

It is impossible in hook_block_info(), but you can use this query to achive this. Change MODULE_NAME, BLOCK_DELTA and RID accordingly

$query = db_insert('block_role')
  ->fields(array(
    'module' => 'MODULE_NAME', 
    'delta' => 'BLOCK_DELTA', 
    'rid' => 2, // Authenticated User
  ))
  ->execute();
0

In hook_block_view , you can use global $user to get information about the user , then based on user's role you can assign different block['subject'] and block['content'] or even do not assign any subject and content to block if it is going to be invisible for that role . here is an example :

function ModuleNAME_block_view($delta = '') {
  switch ($delta) {
    case 'Your_BLOCK' :
      Global $user;
      if($user->uid != '0') {
        $block['subject'] = 'SUBJECT';
        $block['content'] = 'SOME CONTENT OR A FUNCTION FOR BLOCK';
      }
      break;
  }
  return $block;
}

using this code authenticated users (not guests) will have block become visible for authenticated users.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.