Attached is a small patch that enables you to include additional block classes by altering the block object in the render array. This is very useful if you programmatically insert blocks on your page, or you want to alter an existing block in hook_page_alter(). Unfortunately, it isn't possible to remove existing block classes using this approach.

This is how you would add a class to the render array:
$render_array['blah']['blah']['#block']->classes = array('myclass');

Simple :)

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

DYdave’s picture

Hi ttkaminski,

Thanks very much for posting this issue and submitting a patch.

I have tried to review the patch and your comment, but I'm not completely sure I understand what you would like to achieve.

Could you maybe take a concrete example or perhaps elaborate a little bit more on how this patch could be tested?
I'm not so sure where the $block->classes in the patch would come from.
Would that be set programmatically or by any existing modules? (which ones)

Could you please provide some examples of use cases?

If you could please let us know how we could test the patch, we would be glad to give you further feedback on this feature request or reviews on the patch.

Feel free to let me know if you would have any further questions, issues, comments, suggestions, recommendations or concerns on any aspects of my comment or this ticket in general, I would be glad to provide more information or explain with more details.

Thanks very much in advance for your replies, comments, testing, reporting and reviews.
Cheers!

Status: Needs review » Needs work

The last submitted patch, block_class-add_classes.patch, failed testing.

jthorson’s picture

Test requeued manually on testbot.

ttkaminski’s picture

Here's a simple example of how I can create a custom page with a programmatically invoked block, and add a custom class "myclass".

function _custom_page_callback_example() {
  $block = block_load('system', 'powered-by');
  $build = _block_get_renderable_array(_block_render_blocks(array($block)));
  $build['system_powered-by']['#block']->classes = array("myclass");
  return $build;
}
DYdave’s picture

Category: feature » support
Status: Needs work » Fixed
FileSize
1.17 KB

Hi ttkaminski,

Thanks very much for your prompt reply on this with a very clear example.

So I have tried to take a closer look at the code snippet you posted and I am afraid indeed that this feature is most likely not going to be implemented in the 7.x-1.x branch.

The reason why this isn't currently working in the 7.x-1.x version is because block classes get inserted at the Theme level and not earlier (upon loading, for example).
Therefore, as you mentioned, we would have to either apply your patch for it to work, or, another solution, would be to add a setter in the block_class function to allow you to add your classes to the statically cached $block_class array (see in block_class.module, line 64) through a call in your code such as: <?php block_class($block, array("myclass")); ?>
instead of: <?php $build['system_powered-by']['#block']->classes = array("myclass"); ?>
If you would be interested in this approach, I have attached a quick patch that illustrates this implentation (not likely to be committed): block_class-add-block-classes-render-array-1908184-5.patch.

But in any case, you would still have to go through a drupal_render at some point, to process the theme variable $classes_array (since this is the way it is currently implemented for the 7.x branches).

I certainly encourage you to update and take a look at the 7.x-2.x branch (in particular the 7.x-2.0 or 7.x-2.x-dev releases). If you were using the 7.x-2.x version, since the css_block is a property of the $block object, it is accessible at different levels of the loading/rendering process through $block->css_class.

So for example your code would become:

<?php
function _custom_page_callback_example() {
  $block = block_load('system', 'powered-by');
  $block->css_class .= 'myclass';
  $build = _block_get_renderable_array(_block_render_blocks(array($block)));
  return $build;
}
?>

 
Lastly, If you still wanted to stick with the 7.x-1.x branch, an easy work-around would be for you to add the following function in a custom module or theme:

<?php
/**
 * Override or insert variables into the block template.
 */
function [MODULE_OR_THEME_NAME]_preprocess_block(&$variables) {
  if (!empty($variables['block']->classes)) {
    $variables['classes_array'] = array_merge($variables['classes_array'], $variables['block']->classes);
  }
}
?>

This has been tested and works as expected with the code from #4.
 
I hope this answer will help clarifying a little bit how to access at the theme level (template tpl files or template.php) custom block classes added through Block Class.
 
To sum this up, considering the different alternatives this feature request could be achieved (updating to 7.x-2.x or staying with 7.x-1.x but overridding in a custom theme or module), I am not particularly convinced this patch and feature would be absolutely necessary.
 
Therefore, I allowed myself to move this feature request to support request (since it seems there would be other existing solutions described in this comment) and mark this issue as fixed for now.
But, feel free to re-open it, or post a new ticket, at any time if you have any further objections, questions or comments with any points discussed in this comment.
 
I would certainly greatly appreciate to have your feedbacks, comments, questions, issues, objections, reviews, testing, reporting, suggestions or concerns on this ticket, I would be glad to provide more information or explain in more details.
 
Thanks again to everyone for your help, reviews, feedback, reporting and comments on this issue.
Cheers!

ttkaminski’s picture

Unfortunately your suggested patch to the 7.x-2.x branch and your suggested workaround for the 7.x-1.x branch no not solve the problem. The problem with this patch is that it would apply the same class to all blocks of that type, whereas I only want to apply the class for that particular instance. Consider this case:

function _custom_page_callback_example() {
  // First block
  $block = block_load('system', 'powered-by');
  $build = _block_get_renderable_array(_block_render_blocks(array($block)));
  $build['system_powered-by']['#block']->classes = array("myclass");
  
  // Second block (same block loaded somewhere else, perhaps loaded by context module)
  $block2 = block_load('system', 'powered-by');
  $build2 = _block_get_renderable_array(_block_render_blocks(array($block2)));
  $build2['system_powered-by']['#block']->classes = array("myclass2");
  
  $build['part2'] = $build2;
  
  return $build;
}

Secondly the problem with inserting the block class in the hook_preprocess_block() is that it may not always provide enough information about the context to determine when to add the extra class. In my case, I use hook_page_alter() to add a class to a block if some other element on the page exists:

function [MODULE_OR_THEME_NAME]_page_alter(&$page) {
  if( isset($page['content']['system_main']['user_login']) ) {
    $page['content']['system_main']['system_powered-by']['#block']->classes[] = 'extra';
  }
}

Not sure how you would accomplish that using hook_preprocess_block() without resorting to some global variables.

As I said in my original post, it isn't possible to remove existing block classes with my patch, so perhaps there's a better solution. The ideal solution would allow for the following:

1. Ability to add and *remove* block classes by modifying the render array
2. Multiple instances of the same block to have different block classes

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.