Blocks in Drupal

In this post, we cover how to programmatically create blocks in Drupal. To create manually block in Drupal, it has to be done in a separate module and cannot be done from theme space.

Add Block in Admin UI

To add block in admin ui(structure->blocks), add the following in the .module file:

function MODULENAME_block_info(){
    $blocks = array();

    $blocks['add_to_cart'] = array(
        'info' => t('Some Theme: Add to Cart Block'),//admin ui block name
    );

    return $blocks;
}

This will show the block in admin ui from which you can assign this block to particular region

Implementing Block

In the .module file add the following:

function MODULENAME_block_view($delta = ''){
    $blocks = array();
    switch($delta){
        case 'add_to_cart':{
            $blocks['subject'] = t('Add To Cart');
            $blocks['content'] = add_to_cart_block_contents($delta);
            break;
        }
    }
    return $blocks;
}

function add_to_cart_block_contents($delta){
    $output = '';
    switch($delta){
        case 'add_to_cart':{
            $output .= '<div> Add To Cart Content</div>';
            break;
        }
    }
    return $output;
}

Here, we add a block containing the string. If your block contains a lot of code, then you can override a template file in the theme or put in separate file and include it as following:

function add_to_cart_block_contents($delta){
...
        case 'add_to_cart':{
                        $block['content'] = theme_render_template(drupal_get_path('module', 'moduleName').'/inc/block--some-theme--contact-info.tpl.php', _config_contact_info());
            break;
        }
...
}

Here the content of block is put in the file ‘block–some-theme–contact-info.tpl.php’ and then rendered into the block content. The function _config_contact_info() is for passing the variables into the template file and returns array as following:

function _config_about_author(){
    return array(
        'title' => 'Contact Info',
        'content' => 'this is block content',
        'profile_photo' => '#',
    );
}

Here we are passing three variables – title, content and profile_photo into template file that is available as ‘$title’,’$content’ and ‘$profile_photo’
You can also return already rendered block instead array before rendered:

...
$block['content'] = array(
                 '#markup' => driver_config_content($delta),
              );
...

By putting in markup tag, it is already rendered content. This will not allow other module to alter/hook into your block

Include CSS and JS files

Sometimes your block will need Js or Css files, then you can include them as follows:

...
$blocks = array();
$blocks['content'] = array(
  '#markup' => mymodule_testblock_content(),
  '#attached' => array(
      'css' => array(
        drupal_get_path('module', 'mymodule') . '/css/mymodule.css',
      ),
      'js' => array(
        drupal_get_path('module', 'mymodule') . '/js/mymodule.js',
    ),
  ),
);
return blocks;
...

Adding a Form in the Block

Here is how to add the form:

function THEMENAME_block_view($delta = ''){
    $block = array();
    switch($delta){
        case 'add_to_cart':{
            $block['subject'] = t('Add To Cart');
            $block['content'] = drupal_get_form('fav_color_form');
            break;
        }
    }
}

function fav_color_form($form, &$form_submit){
    $form['color'] = array(
        '#title' => t('Favorite color'),
        '#type' => 'textfield',
        '#required' => TRUE,
        '#description' => t('What is your favorite color? Blue? No, wait-'),
    );
    $form['submit'] = array(
        '#type' => 'submit',
        '#value' => 'Submit',
    );
    return $form;
}

Here, we use drupal function ‘drupal_get_form’ to build the render array with an argument of name of function that constructs the render array

Pass and Access Variables

So if you want to pass a variable into the ‘variable’ array accessible in other parts (modules, themes, etc.) of the site, then:

function THEMENAME_block_view($delta = ''){
    $block = array();

    switch($delta){
        case 'add_to_cart':{
            $block['subject'] = t('Add To Cart');
            $block['some_product'] = t('Default product comes here');
            $block['default_product_price'] = some_default_product(drupal_set_page_content());
            $block['content'] = add_to_cart_block_contents($delta);
            break;
        }
}

Here, by setting $block[‘some_product’] value, it becomes available in the variables array in other parts of drupal
In case, you like to access the nodes variables in block, here we accomplish this by calling ‘drupal_set_page_contents()’ which returns variables array containing variables from the node, page and other levels

Retrieve Block To Render

Say, you want to render a block in particular place in some template file then you can retrieve and render any block as following:

...
<?php $block = block_load('MODULE_NAME','BLOCK_DELTA');?>
<?php $renderable_block =  _block_get_renderable_array(_block_render_blocks(array($block)));?>
<?php print render($renderable_block);?>

In first line, the block is loaded from module its declared. Next line converts it into renderable array before rendering in last line

Note: if the block utilizes template file that receives some variables then the above example will break because those variables are not passed to the template(see _block_get_renderable_array()). For that reason, consider using the content instead covered next.

The above example makes the block into renderable array, so you can update before rendering, however. If there is no need to make any changes, then just render content to avoid overhead of reengineering renderable array as following:

                $block_raw = block_load('MODULE-NAME', BLOCK-DELTA);
                $block_list = _block_render_blocks(array($block_raw));
                $renderable_block = array_shift($block_list);
                $variable['SOME-BLOCKE'] = render($renderable_block->content);

In line first, it loads the block. In the second line, it generates the content of the block. Afterwards, the content is extracted and rendered

Make Block Configurable

To make

function MODULE_NAME_block_configure($delta='') {
    $form = array();

    switch($delta) {
        case 'twitter_feed' :
            // Text field form element
            $form['builder_twitter_title'] = array(
                '#type' => 'textfield',
                '#prefix' => t('Title of Twitter Feed'),
                '#default_value' => variable_get('builder_twitter_title', ''),
            );
            $form['builder_twitter_invite'] = array(
                '#type' => 'textarea',
                '#rows' => '3',
                '#title' => t('Enter twitter invite description displayed next to tweets'),
                '#default_value' => variable_get('builder_twitter_invite', ''),
            );
            break;
...
return $form;
}

Here, two fields – builder_twitter_invite, builder_twitter_title is being added to the block with delta(ID) of twitter_feed’ edit form, so user can edit these fields

To process user input, function

 
function MODULE_NAME_block_save($delta = '', $edit = array()) {
    switch($delta) {
        case 'twitter_feed' :
            variable_set('builder_twitter_invite', $edit['builder_twitter_invite']);
            variable_set('builder_twitter_title', $edit['builder_twitter_title']);
            break;
...

Here, the user input is retrieved from the form and then saved into variables accordingly.

Troubleshooting

1. Notice: Undefined property: stdClass::$content in _block_get_renderable_array() (line 337 of

This was happening when calling “$ctx_plugin->block_get_blocks_by_region($region_key);”. The solution was cache the blocks before calling block_get_blocks_by_region($region_key) as following:

        $list = $ctx_plugin->block_list($region_key);
        _block_render_blocks($list);

        $ctx_blocks = $ctx_plugin->block_get_blocks_by_region($region_key);

This ensures that the ‘content’ is set before calling block_get_blocks_by_region solving the error

Useful Links

  • http://fourkitchens.com/blog/2012/07/18/building-custom-blocks-drupal-7
  • https://api.drupal.org/api/drupal/modules!block!block.api.php/function/hook_block_view/7
  • https://api.drupal.org/api/drupal/developer%21topics%21forms_api_reference.html/7#attached

Leave a Reply

Your email address will not be published. Required fields are marked *