Define all blocks provided by the module.

Define all blocks provided by the module.

This hook declares to Drupal what blocks are provided by your module and can optionally specify initial block configuration settings.

In hook_block_info(), each block your module provides is given a unique identifier referred to as "delta" (the array key in the return value). Delta values only need to be unique within your module, and they are used in the following ways:

  • Passed into the other block hooks in your module as an argument to identify the block being configured or viewed.
  • Used to construct the default HTML ID of "block-MODULE-DELTA" applied to each block when it is rendered. This ID may then be used for CSS styling or JavaScript programming.
  • Used to define a theming template suggestion of block__MODULE__DELTA, for advanced theming possibilities.
  • Used by other modules to identify your block in hook_block_info_alter() and other alter hooks.

The values of delta can be strings or numbers, but because of the uses above it is preferable to use descriptive strings whenever possible, and only use a numeric identifier if you have to (for instance if your module allows users to create several similar blocks that you identify within your module code with numeric IDs). The maximum length for delta values is 32 bytes.


kvvnn’s picture

In my experience, the following will break the jQuery object, throwing "jQuery is not defined":

< ? php
drupal_add_js(drupal_get_path('module', 'mymodule') . '/js/mymodule.js');

It must be used within a function. The following will work :

< ? php
function mymodule_block_view($delta=''){
drupal_add_js(drupal_get_path('module', 'eyedsafe') . '/js/eyedsafe.js');

Since this is different than D6, I wanted to point it out.

dalin’s picture

This is still the wrong way to add JS to a block. See documentation on render arrays and the #attached property.

normk’s picture

I believe what dalin was referring to was building the block array in hook_block_view as shown in the example on https://api.drupal.org/api/drupal/modules!block!block.api.php/function/h...

with the switch statement using the $delta parameter along with the example of creating the $content array as an #attached render array described in the comment by chrisroane https://api.drupal.org/comment/44413#comment-44413 which looked like this:

$block['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',

Using this technique, you can encapsulate the js and css loading in your module_block_view and not have to place it in a hook_page_alter or theme preprocess_page() hook. Hope that clarifies things a little better.

Martijn Houtman’s picture

I was unable to find how to set the content-types for which this block should be visible, and found out that it is actually handled in the node module. So I finally did this:

function hook_block_info() {
    // Limit on node types
    $form_state = array(
        'values' => array(
            'module' => '...',
            'delta'  => '...',
            'types'  => array('...', '...'),
    node_form_block_admin_configure_submit(NULL, $form_state);

Not sure if it is actually a preferred way, but at least it works in a way so that the settings can still be changed through the admin interface.

malfist’s picture

Drupal doesn't seem to expose a means of filtering by content type on the hook_block_info, or really anywhere but the UI.

However, examine the contents of the table block_node_type. It has the module name, block delta/name, and then the content type it's filtered too. You can edit this directly to filter it.

This is probably a bad idea, but it'll work.

kingandy’s picture

TBH it is probably easier to just check node type inside your hook_block_view() implementation.

$node = menu_get_object();
if (!$node || $node->type != 'my_node_type') {
  return array();
pkiekens’s picture

This code shows an example of a block containing a link that only appears when the user hasn't already logged in.

// ...
function loginlink_block_info() {
  $blocks['myloginlink'] = array(
    'info' => t('Login Link'),
    'status' => TRUE,
    'region' => 'sidebar_first',
    'visibility' => BLOCK_VISIBILITY_PHP,
    'pages' => '<?php global $user; if ($user->uid == 0) return TRUE; else return FALSE; ?>'
// ..

Important: Verify that the PHP filter module is enabled if you want to use BLOCK_VISIBILITY_PHP!

noctifer’s picture

Note: There's a php coding error in the code for 'pages' in the example above (its missing brackets in the conditional statement). It should be:

'pages' => ' global $user; if ($user->uid == 0) { return TRUE; } else { return FALSE; } '

I banged my head against this an hour or so before I realized the php was a bit off. Was still what lead me to the solution, though!

kingandy’s picture

This sort of check can easily be done inside hook_block_view() without relying on the PHP filter (or allowing admins to override your settings). Returning an empty array means the block will not appear.

global $user;
if ($user->uid != 0) {
  return array();
mattsmith3’s picture

Setting block region doesn't work unless you set status to 1.
Hope this saves someone some time.

Toby Wild’s picture

Just wanted to leave a message saying Thanks.
Was driving me crazy.

And just confirming to people as well that the region name is the machine name found in the template.info file.
In my instance, 'Main Content' is called 'content'.

Tajdar Khan Afridi’s picture

I have checked that by uninstalling mymodule and it works without
set status to 1.

tengoku’s picture

if you use $block['block_name]['region'] you must declare $block['block_name]['status'] in TRUE in order to work, if not you will get a php warning when loads the module/site

medien-vp’s picture


like mentioned above, I'd need to set the status to 1 to get region to work - anything similar needed for pages? I've set status to 1, visibility to BLOCK_VISIBILITY_LISTED and pages to 'mypath'. Cleared all caches, and my block still shows on all pages.

Can anyone help?

Thanks a lot

chrisolof’s picture

Uninstall the module providing the block, then re-enable the module.

It seems that once you do anything to the block via Drupal's UI, your UI config overrides the config in code. By uninstalling the module providing the block, I believe you're removing any stored settings in the DB surrounding that block. Maybe someone is aware of a "revert to default" block action from within the UI, but I haven't found it.

brianwagner’s picture

If you're comfortable with mysql queries you can delete the row from the block table. There should be one row for each theme, e.g. one for default theme and one for admin.

You can select by field 'module' or 'delta', both of which were the name of the module in my case.

DELETE FROM block WHERE module='block_name';

JurgenR’s picture

There's also a theme key-value pair:

'exposed_order' => array(
'info' => t('Exposed commerce order filter'),
'theme' => $admin_theme,
'region' => 'content',
'pages' => ORDER_MENU_LINK,
'status' => 1,
'visibility' => 1,

tterranigma’s picture

There is no such key available for this hook. The $theme key is auto populated by the core block module.

rayjames’s picture

This is a quick and easy example:

 * Implements hook_block_info().
function example_block_info() {
  $blocks['ad_banner1'] = array(
    'info' => t('Ad Banner 1'),
  $blocks['ad_banner2'] = array(
    'info' => t('Ad Banner 2'),

  return $blocks;

 * Implements hook_block_view().
function example_block_view($delta = '') {
  $block = array();

  switch ($delta) {
    case 'ad_banner1':
      $block['content'] = 'shtuffenins';

    case 'ad_banner2':
      $block['content'] = 'shtuffenins2';

  return $block;
leopathu’s picture

i need to create a block while the submit button clicked

agalligani’s picture

I have a module that simply adds a few blocks. I enabled it and the blocks were added. I added some other blocks to it as well, but the new blocks do not appear even after I refresh cache. Then I created and enabled other modules that add blocks and none of these blocks appear. When I enable/disable the original module, the same blocks that showed up show up again but nothing I do will make any of the other blocks show up.

Here is the code.

 * Implements hook_block_info().
function mymodule_block_info() {

  $blocks = array();

  $blocks['footer_first_block_1'] = array(
    // info: The name of the block.
    'info' => t('Footer first block 1'),
    'status' => TRUE,
    'weight' => 1,
  $blocks['footer_first_block_2'] = array(
    'info' => t('Footer first block 2'),
    'status' => TRUE,
    'weight' => 2,
  $blocks['footer_first_block_3'] = array(
    'info' => t('Footer first block 3'),
    'status' => TRUE,
    'weight' => 3,

  $blocks['footer_first_block_4'] = array(
    'info' => t('Footer first block 4'),
    'status' => TRUE,
    'weight' => 4,

  return $blocks;

So footer_first_block_4 is the block I added.... but it doesn't show up, nor do any other blocks I add in a similar fashion. However I enabled blocks_example and it works fine (this as a sanity check). I've refreshed cache many many times and it doesn't help. Any ideas how this can possibly happen?

djbobbydrake’s picture

I ran into the same issue as agalligani. Looked at the block table in MySQL and saw that the region column had no value for new blocks that were not showing up in the block admin page. This is odd because the region column is set to not have any NULL values. Perhaps the default value should be "-1". When I changed the regions of my missing blocks to -1, they then showed up on the admin page.

MKorostoff’s picture

In Drupal 8 this is deprecated, and replaced with the "Block API" more information here https://api.drupal.org/api/drupal/core%21modules%21block%21block.api.php...

kingandy’s picture

Not so much "deprecated" as "removed".

("Deprecated" means "Still in place but will be removed in a subsequent version, please move over to the new system before that happens")

Wolf_22’s picture


1.) The code from the example module corresponding to the hook_block_info implementation uses a Boolean value of TRUE instead of a Boolean *numeric* value of 1 and while both likely get interpreted in both the Drupal architecture and PHP engine synonymously, the documentation above **explicitly** states that "1 = enabled, 0 = disabled." This kind of implicit documentation causes a lot of problems and if someone can, they should fix this.

2.) For whatever reasons, there is no direct link to the the example module it makes references to, so here it is: https://api.drupal.org/api/examples/block_example!block_example.module/f...

3.) From what I'm seeing, most of the users on here who needed to set an initial region noticed that the "status" key isn't exactly optional if the "region" is needing to be set. So, again, it should not be **explicitly** noted as an optional configuration aspect if it is not optional.

I hope this helps.

kingandy’s picture

Buggy or inaccurate documentation? Please file an issue instead of commenting here.

sachinwable’s picture

tterranigma’s picture

If you use the 'region' key, you may get some warning that the block was disabled:
"The block Highlighted slider was assigned to the invalid region highlighted and has been disabled. "

This is due to some enabled themes not using such a region. However, the block will be correctly enabled for any themes that do.

franperr’s picture

I found out that you can not use the module name in the value of delta. For example, if your module is called "example", you can not have a delta value like "example_block1". The blocks will not appear.
I hope this is useful for someone else.

Rajender Rajan’s picture

  function myblock_block_info() {
    $blocks = array();
    if (variable_get('hare_block', 0)) {
      $blocks['abc'] = array(
        'info' => t('test block'),
        'visibility' => 0,
        'status' => TRUE,
        'region' => 'none',
        'weight' => 99,
        'cache' => DRUPAL_NO_CACHE,
   return $blocks;

I don't want to show block the block to any region by default. User select himself/herself to any region as of his/her choice. As i set 'region' => 'none' but it disabled the block. Or i simply remove the region section only ?

brianwagner’s picture

As we can now have multiple versions of a block, default settings are not set this way. Much of the custom block configuration is moved to Config API in Drupal 8. Specifically PAGES and VISIBILITY are tied to an instance of the block. So workflow: add the block, export config, and grab the relevant block config file. Then you have the option of leaving it in the site config, or moving to a my_custom_module/config/install directory.