I need to act on a block insert/update/save/delete of other modules in a module (for e.g. filter out all URLs in a block and save the URLs in an extra table). This should work like hook_nodeapi(). Is there anything available that allows this or a workaround that gives me the content and title of a block on save so I can run a regex on it!?

Comments

hass’s picture

Title: hook_blockapi() functionality for a module » Need hook_blockapi() functionality for a module

Solved this in the following way. Maybe someone else search for hook_blockapi and may find this helpful...

function MYMODULE_form_alter(&$form, &$form_state, $form_id) {
  switch ($form_id) {
    // Catch the block add/configure form and add custom submit handler.
    case 'block_add_block_form':
      // Add custom submit handler to block add form.
      $form['#submit'][] = 'MYMODULE_add_form_submit';
      break;

    case 'block_admin_configure':
      // Add custom submit handler to block configuration form.
      $form['#submit'][] = 'MYMODULE_configure_form_submit';
      break;

    case 'block_admin_display_form':
      // Add submit handler into admin/build/block for e.g. to catch "status"
      $form['#submit'][] = 'MYMODULE_admin_display_form_submit';
      break;

    default:
      break;
  }
}

function MYMODULE_add_form_submit($form, &$form_state) {
  // Get last inserted block id.
  $bid = db_last_insert_id('boxes', 'bid');
  // Execute your functions.
  _MYMODULE_foo($form_state['values'], $bid);
}

function MYMODULE_configure_form_submit($form, &$form_state) {
  // $form_state['values']['delta'] is the block id.
  // Execute your functions.
}

function MYMODULE_admin_display_form_submit($form, &$form_state) {
  // Execute your functions.
}

hass’s picture

Title: Need hook_blockapi() functionality for a module » hook_blockapi() functionality for a module
Category: feature » support
Status: Active » Fixed

Title: Need hook_blockapi() functionality for a module » hook_blockapi() functionality for a module
Status: Fixed » Closed (fixed)

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

hass’s picture

Title: hook_blockapi() functionality for a module » hook_blockapi() functionality for modules
Category: support » feature
Status: Closed (fixed) » Active

Mayor problem with above code is that $bid = db_last_insert_id('boxes', 'bid'); returns wrong values. See #369520: db_last_insert_id returns watchdog (wid) if comment (cid) is selected

hass’s picture

Title: hook_blockapi() functionality for modules » Implement hook_block_* (insert/update/prepare/delete) functionality for modules
moonray’s picture

Category: feature » bug
Priority: Normal » Critical

This is actually a critical issue, and can even be considered a bug. With db_last_insert_id gone, there's no way to act on a newly inserted block without trying to load the block based on module and title (which is not unique); we don't have a delta or a bid assigned yet.

andypost’s picture

Category: bug » support
Priority: Critical » Normal

I think it's enough to implement MYMODULE_preprocess_block()

jacine’s picture

Category: support » bug
Priority: Normal » Critical

MYMODULE_preprocess_block() to act on a newly inserted block? I don't know if that is a reasonable approach or not, but it sounds very wrong.

Is this really going to be the recommended way modules deal with these events in D7?

moonray’s picture

An alternate fix would be to inject the bid and delta (which will have been assigned to the $block object on insert) into the $form_state array? But that, again, seems more like a patch than a good API fix.

andypost’s picture

Priority: Critical » Normal

@Jacine I think you should take a look on approach used in #684774: Block visibility settings cannot be properly extended

Also this is not critical issue

andypost’s picture

Category: bug » feature

Also much better to use http://api.drupal.org/api/function/hook_form_FORM_ID_alter/7 but not all blocks have content at the add/edit stage

I think core have enought hook, alter, preprocess abilities to stop making api bigger

moonray’s picture

Now that delta is injected into $form_state (core update with #684774: Block visibility settings cannot be properly extended) modules can react on block inserts.
I'm still not sure if this is the ideal way of doing it, but it works.

hass’s picture

This feature is to sync the not existing api with node and comment hooks. Form alter with submit hook cannot solve the problems for sure as you cannot be sure what bid you get. It could we a wrong bid and only the hook can provide the correct auto increment value to other modules for sure.

See linkchecker module...example in #1 is not 100% up to date... And the workaround i used IS NOT reliable.

andypost’s picture

@hass all blocks are different, also they could be altered by other modules but using $module and $delta from $form_state you could make things easy.

If you are talking about custom blocks so it's much easy to use {block_custom}.bid which is equal to $form_state['values']['delta']
IMO, API already good:
http://api.drupal.org/api/function/block_add_block_form_submit/7
http://api.drupal.org/api/function/block_schema/7

jacine’s picture

@andypost Thank you for the resources and information. It's much appreciated :)

hass’s picture

Andypost: no. You have no chance to reliable get the correct bid. You may need to dig deeper or try to implement a blocks module that fire on block save as one example. If you compare to node orcomment api you may get the reasons why the current solutions are nothing else like unreliable buggy hacks.

andypost’s picture

@hass tell me why this could bring a wrong result?

function block_add_block_form_submit($form, &$form_state) {
  $delta = db_insert('block_custom')
    ->fields(array(
      'body' => $form_state['values']['body'],
      'info' => $form_state['values']['info'],
      'format' => $form_state['values']['format'],
    ))
    ->execute();
  // Store block delta to allow other modules to work with new block.
  $form_state['values']['delta'] = $delta;
hass’s picture

Aha... Maybe something have changed in D7 I have not seen yet. But how does my module hook in here? I do not see that other modules are called before the block is saved (hook_prepare), after the block is saved (hook_insert) and what will happen on update or delete and how my module is hooked to delete other data from myblock module tables... Obove line looks like aform helper, but not like an api implementation that is working like the node api.

andypost’s picture

@hass You should use hook_form_FORMID_alter() for block_add_block_form(), block_admin_configure() and block_custom_block_delete() to add your validation and submit handlers.

validation is like _presave and submit with $form->name is _insert _update _delete

Take into account that insert works only for custom (users' provided blocks) to hook into module provided blocks use hook_block_info_alter

hass’s picture

This is the bad way used in D6 + I really hope we can get rid of workarounds like below. They are really bad. Additional it's more worse that there is a need to have two different logics to hook into block forms. Linkchecker need to hook into custom and normal blocks.

I'm for cleaning up this workarounds and make the DX and API much cleaner and better - nevertheless it may work - it's much more complex and unreliable than the node and comment hooks that are really easy to understand.

function linkchecker_form_alter(&$form, $form_state, $form_id) {
  switch ($form_id) {
    // Catch the block add/configure form and add custom submit handler.
    case 'block_add_block_form':
      // Add custom submit handler to block add form.
      $form['#submit'][] = 'linkchecker_block_add_form_submit';
      break;

    case 'block_admin_configure':
      // Add custom submit handler to block configuration form.
      $form['#submit'][] = 'linkchecker_block_configure_form_submit';
      break;

    case 'block_box_delete':
      $form['#submit'][] = 'linkchecker_block_box_delete_form_submit';
      break;
  }
}


/**
 * Custom submit handler for block add page.
 */
function linkchecker_block_add_form_submit($form, &$form_state) {
  // UNRELIABLE WORKAROUND to get the $bid of the last added block.
  $bid = db_result(db_query("SELECT MAX(bid) FROM {boxes}"));
  _linkchecker_add_box_links($form_state['values'], $bid);
}

/**
 * Custom submit handler for block configure page.
 */
function linkchecker_block_configure_form_submit($form, &$form_state) {
  _linkchecker_add_box_links($form_state['values'], $form_state['values']['delta']);
}

/**
 * Custom submit handler for block delete page.
 */
function linkchecker_block_box_delete_form_submit($form, &$form_state) {
  _linkchecker_delete_box_links($form_state['values']['bid']);
}
andypost’s picture

Add submit handler should be the same

/**
* Custom submit handler for block add page.
*/
function linkchecker_block_add_form_submit($form, &$form_state) {
  _linkchecker_add_box_links($form_state['values'], $form_state['values']['delta']);
}
andypost’s picture

Status: Active » Fixed

Suppose we could close this because commited [560746]

Linkchecker need to hook into custom and normal blocks.

Hook into what? content (render) or config (form alter)

andypost’s picture

hass’s picture

Status: Fixed » Active

As said i need hook_block_*: insert, delete, update. There is nothing fixed here. Still open.

andypost’s picture

@hass what do you mean with hook_block insert()? insert into {block} {block_custom} {block_roles} ?
Drupal way is _alter

hass’s picture

Title: Implement hook_block_* (insert/update/prepare/delete) functionality for modules » DX: Implement hook_block_* (insert/update/prepare/delete) functionality for modules
Version: 7.x-dev » 8.x-dev

Why is this so difficult to understand? Please try to read the public API documentation at these links. While you are reading, replace the words "hook_node_*" with "hook_block_*" and "node" with "block":
http://api.drupal.org/api/function/hook_node_insert/7
http://api.drupal.org/api/function/hook_node_delete/7
http://api.drupal.org/api/function/hook_node_update/7

Example results:
http://api.drupal.org/api/function/hook_block_insert/8

Respond to creation of a new block.

This hook is invoked from block_save() after the block is inserted into the block table in the database, after the type-specific hook_insert() is invoked, and after field_attach_insert() is called.

http://api.drupal.org/api/function/hook_block_delete/8

Respond to block deletion.

This hook is invoked from block_delete_multiple() after the block has been removed from the block table in the database, after the type-specific hook_delete() has been invoked, and before field_attach_delete() is called.

http://api.drupal.org/api/function/hook_block_update/8

Respond to updates to a block.

This hook is invoked from block_save() after the block is updated in the block table in the database, after the type-specific hook_update() is invoked, and after field_attach_update() is called.

You may get the idea. Moving to D8 as API changes need to wait for the next major version.

andypost’s picture

@hass I talk about implementation not about concept. Some concept and planing goes http://groups.drupal.org/node/63708
But for now we need to fix #735900: Deleting module's blocks when module is uninstalled

grendzy’s picture

Issue tags: +API clean-up

fixing tag

alan d.’s picture

Strangely, validation was not included here and this would be a more common requirement than insert/update hooks. I had a developer wtf moment after realizing that the refactored block system lacked this. Even the core system blocks use validation (unique block names), so why enforce another form alter to do? It would be as easy as this:

/**
 * Form validation handler for the block configuration form.
 *
 * @see block_admin_configure()
 * @see block_admin_configure_submit()
 */
function block_admin_configure_validate($form, &$form_state) {
  // Direct call the function so that we can pass the $form_state by reference.
  if (module_hook($form_state['values']['module'], 'block_validate')) {
    $func = $form_state['values']['module'] . '_block_validate';
    $func($form, $form_state, $form_state['values']['delta']);
  }
}

# Move to block.module.

/**
 * Implements hook_block_validate().
 */
function block_block_validate($form, &$form_state, $delta = '') {
  $custom_block_exists = (bool) db_query_range('SELECT 1 FROM {block_custom} WHERE bid <> :bid AND info = :info', 0, 1, array(
    ':bid' => $delta,
    ':info' => $form_state['values']['info'],
  ))->fetchField();
  if (empty($form_state['values']['info']) || $custom_block_exists) {
    form_set_error('info', t('Ensure that each block description is unique.'));
  }
}
indytechcook’s picture

Cross posting #430886: Make all blocks fieldable entities

With Custom blocks becoming entities and using the new entity class pattern, we will have access to hook_block_$op for custom blocks.

Does that cover it for d8?

traviscarden’s picture

Re-tagging.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

tim.plunkett’s picture

Issue summary: View changes
Status: Active » Closed (outdated)

Blocks are now entities, see the hook_entity_* hooks.