Hi, I'm just wondering if this is still on the cards.

CommentFileSizeAuthor
#2 region_visibility-d7.zip4.14 KBnirbhasa

Comments

alan d.’s picture

Also, here is an alternative, based off core Drupal 7 block code. It has no dependencies and comes in at a mere 200 lines of code. Maybe 300 after some UI improvements, 400 with some more comments.

The module that I implemented this in was iwd, for the 3 hooks used.

hook_form_block_admin_display_form_alter() makes the region title a link in the list regions / blocks page.
hook_block_list_alter() removes the blocks on the list before they are rendered.

function iwd_menu() {
  $items['admin/structure/block/regions/%/%'] = array(
    'title' => 'Region visibility',
    'page arguments' => array('region_visibility_form', 4,5),
    'page callback' => 'drupal_get_form',
    'type' => MENU_VISIBLE_IN_BREADCRUMB,
    'access arguments' => array('administer blocks'),
  );

  return $items;
}

function iwd_form_block_admin_display_form_alter(&$form, $form_state) {
  $current_theme = $form['edited_theme']['#value'];
  if (empty($current_theme)) {
    return;
  }
  foreach ($form['block_regions']['#value'] as $key => $title) {
    $settings = region_visibility_theme_settings($current_theme, $key);
    $title = l($title, 'admin/structure/block/regions/' . $current_theme . '/' . $key, array('html' => TRUE));
    if (!empty($settings['roles']) && !empty($settings['pages'])) {
      $title = t('!title - <em>restricted by user role and to certain pages</em>.', array('!title' => $title));
    }
    elseif (!empty($settings['roles'])) {
      $title = t('!title - <em>restricted by user role</em>.', array('!title' => $title));
    }
    elseif (!empty($settings['pages'])) {
      $title = t('!title - <em>restricted to certain pages</em>.', array('!title' => $title));
    }
    $form['block_regions']['#value'][$key] = $title;
  }
}

function iwd_block_list_alter(&$blocks) {
  global $user, $theme_key;
  foreach ($blocks as $key => $block) {
    if (!isset($block->theme) || $block->theme != $theme_key) {
      continue;
    }

    $settings = region_visibility_theme_settings($block->theme, $block->region);

    // If a block has no roles associated, it is displayed for every role.
    if (!empty($settings['roles']) && !array_intersect($settings['roles'], array_keys($user->roles))) {
      unset($blocks[$key]);
      continue;
    }

    // Match path if necessary.
    if ($settings['pages']) {
      $pages = drupal_strtolower($settings['pages']);
      if ($block->visibility < BLOCK_VISIBILITY_PHP) {
        $path = drupal_strtolower(drupal_get_path_alias($_GET['q']));
        $page_match = drupal_match_path($path, $pages);
        if ($path != $_GET['q']) {
          $page_match = $page_match || drupal_match_path($_GET['q'], $pages);
        }
        $page_match = !($block->visibility xor $page_match);
      }
      elseif (module_exists('php')) {
        $page_match = php_eval($settings['pages']);
      }
      else {
        $page_match = FALSE;
      }
    }
    else {
      $page_match = TRUE;
    }
    if (!$page_match) {
      unset($blocks[$key]);
    }
  }
}

function region_visibility_theme_settings($theme, $region = NULL) {
  static $settings = array();
  if (!isset($settings[$theme])) {
    $settings[$theme] = variable_get('region_visibility_' . $theme, array());
  };
  if ($region != NULL) {
    if (!isset($settings[$theme][$region])) {
      $settings[$theme][$region] = array(
        'pages' => '',
        'visibility' => BLOCK_VISIBILITY_NOTLISTED,
        'roles' => array(),
      );
    }
    $settings[$theme][$region]['roles'] = array_filter($settings[$theme][$region]['roles']);
    return $settings[$theme][$region];
  }
  return $settings[$theme];
}

function region_visibility_form($form, $form_state, $theme, $region) {
  $settings = variable_get('region_visibility_' . $theme, array());
  $settings += array($region => array(
    'pages' => '',
    'visibility' => BLOCK_VISIBILITY_NOTLISTED,
    'roles' => array(),
  ));

  $form['#settings'] = $settings;
  $form['#theme'] = $theme;
  $form['#region'] = $region;

  $form['visibility'] = array(
    '#type' => 'vertical_tabs',
    '#attached' => array(
      'js' => array(drupal_get_path('module', 'block') . '/block.js'),
    ),
  );

  // Per-path visibility.
  $form['visibility']['path'] = array(
    '#type' => 'fieldset',
    '#title' => t('Pages'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
    '#group' => 'visibility',
    '#weight' => 0,
  );

  $access = user_access('use PHP for settings');
  if (isset($settings[$region]['visibility']) && $settings[$region]['visibility'] == BLOCK_VISIBILITY_PHP && !$access) {
    $form['visibility']['path']['visibility'] = array(
      '#type' => 'value',
      '#value' => BLOCK_VISIBILITY_PHP,
    );
    $form['visibility']['path']['pages'] = array(
      '#type' => 'value',
      '#value' => isset($settings[$region]['pages']) ? $settings[$region]['pages'] : '',
    );
  }
  else {
    $options = array(
      BLOCK_VISIBILITY_NOTLISTED => t('All pages except those listed'),
      BLOCK_VISIBILITY_LISTED => t('Only the listed pages'),
    );
    $description = t("Specify pages by using their paths. Enter one path per line. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '<front>'));

    if (module_exists('php') && $access) {
      $options += array(BLOCK_VISIBILITY_PHP => t('Pages on which this PHP code returns TRUE (experts only)'));
      $title = t('Pages or PHP code');
      $description .= ' ' . t('If the PHP option is chosen, enter PHP code between %php. Note that executing incorrect PHP code can break your Drupal site.', array('%php' => '< ?php ? >'));
    }
    else {
      $title = t('Pages');
    }
    $form['visibility']['path']['visibility'] = array(
      '#type' => 'radios',
      '#title' => t('Show block on specific pages'),
      '#options' => $options,
      '#default_value' => isset($settings[$region]['visibility']) ? $settings[$region]['visibility'] : BLOCK_VISIBILITY_NOTLISTED,
    );
    $form['visibility']['path']['pages'] = array(
      '#type' => 'textarea',
      '#title' => '<span class="element-invisible">' . $title . '</span>',
      '#default_value' => isset($settings[$region]['pages']) ? $settings[$region]['pages'] : '',
      '#description' => $description,
    );
  }

  // Per-role visibility.
  $role_options = array_map('check_plain', user_roles());
  $form['visibility']['role'] = array(
    '#type' => 'fieldset',
    '#title' => t('Roles'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
    '#group' => 'visibility',
    '#weight' => 10,
  );
  $form['visibility']['role']['roles'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Show block for specific roles'),
    '#default_value' => $settings[$region]['roles'],
    '#options' => $role_options,
    '#description' => t('Show this block only for the selected role(s). If you select no roles, the block will be visible to all users.'),
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
  );
  return $form;
}

I would have really thought that this module would have a higher rate of usage. Dropping the dependency may help it usage stats.

nirbhasa’s picture

StatusFileSize
new4.14 KB

I took Alan D.'s work and also added the ability to edit regions per user role - in other words a sub editor could access the block configuration page, but certain regions can be made off limits. Here is the attached module

donquixote’s picture

Could you make this a sandbox project?

dubs’s picture

Can this be made a version 7 release - I don't mind doing it if I'm made a co-maintainer.

chefnelone’s picture

Hope to see a D7 version, too.

chefnelone’s picture

using the module attached in #2: I get this error:

Notice: Undefined index: role-edit en region_visibility_form() (línea 233 de /Applications/MAMP/htdocs/mysite.com/sites/all/modules/region_visibility/region_visibility.module).

Warning: Invalid argument supplied for foreach() en form_type_checkboxes_value() (línea 2288 de /Applications/MAMP/htdocs/mysite.com/includes/form.inc).
dman’s picture

I've taken the work here, cleaned it up a fair bit (for internal docs, user-facing text, whitespace and PHP-strict notices), and put it into a D7 branch (rooted from the current 6.x-2.x) and it's up at
https://drupal.org/sandbox/dman/2052469 as a sandbox.

The UI and things seem to work as promised. I've not deep-tested the permissions and things yet as I don't know if I need them personally.. I feel that it may be a bit overkill. If my editors have block admin rights, then that's probably enough. Though I do understand that you may want them to be able to put blocks HERE but not THERE sometimes because they can completely destroy the theme like that.
It's sorta scope-creep for this module though. it becomes region_access as well as region_visibility. ... so yeah, still pretty close - not QUITE worth making into a separate supporting module.

dman’s picture

@q0rban - if you'd like to let me and/or Dubs and/or Alan D join the project we could take on the D7 work?

alan d.’s picture

Removing myself from the task.

The d6 to d7 upgrades were like small molehills in comparison to the d7 to d8 upgrades that are looking like huge mountains at this point in time, so my other projects will be getting all of my free time.

klonos’s picture

@dman: the 6.x branch depends on Visibility API. Will that be the case for the 7.x version? I'm asking because currently there's not D7 version of that module: #1990008: D7 version of the Visibility API module.

dman’s picture

The copy I took, from [#comment-5585104] above seems to work without it. I believe it's more of a rewrite than an upgrade.

This D7 version integrates tightly with the block management screen (in a clever way) while the D6 original is quite different and has its own stand-alone management UI. I think they just do a similar thing, but have little code in common.

So no, there is no dependency on visibility_api, for better or worse.

I still endorse context.module if we need to do block-visibility with any advanced logic.

alan d.’s picture

@klonos - the dependency was dropped as I personally saw no reason for it, although q0rban may object to this. I have always hated enabling 2 modules for this functionality. I must admit that I usually just manually nuke regions in code as required now, meaning zero additional modules ;)

klonos’s picture

Got it. Thanx for taking the time to reply guys.