Index: modules/block/block.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.module,v
retrieving revision 1.366
diff -u -p -r1.366 block.module
--- modules/block/block.module	24 Aug 2009 00:14:19 -0000	1.366
+++ modules/block/block.module	26 Aug 2009 06:26:36 -0000
@@ -855,3 +855,14 @@ function template_preprocess_block(&$var
   $variables['template_files'][] = 'block-' . $variables['block']->module;
   $variables['template_files'][] = 'block-' . $variables['block']->module . '-' . $variables['block']->delta;
 }
+
+/**
+ * Implement hook_filter_format_delete().
+ */
+function block_filter_format_delete($forma, $default) {
+  db_update('box')
+    ->fields(array('format' => $default->format))
+    ->condition('format', $format->format)
+    ->execute();
+}
+
Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.761
diff -u -p -r1.761 comment.module
--- modules/comment/comment.module	25 Aug 2009 21:53:47 -0000	1.761
+++ modules/comment/comment.module	26 Aug 2009 06:27:57 -0000
@@ -2442,3 +2442,14 @@ function comment_menu_alter(&$items) {
   // Add comments to the description for admin/content.
   $items['admin/content']['description'] = "View, edit, and delete your site's content and comments.";
 }
+
+/**
+ * Implement hook_filter_format_delete().
+ */
+function comment_filter_format_delete($format, $default) {
+  db_update('comment')
+    ->fields(array('format' => $default->format))
+    ->condition('format', $format->format)
+    ->execute();
+}
+
Index: modules/filter/filter.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.admin.inc,v
retrieving revision 1.39
diff -u -p -r1.39 filter.admin.inc
--- modules/filter/filter.admin.inc	26 Aug 2009 04:59:26 -0000	1.39
+++ modules/filter/filter.admin.inc	26 Aug 2009 06:25:16 -0000
@@ -225,9 +225,8 @@ function filter_admin_format_form_submit
  * @ingroup forms
  * @see filter_admin_delete_submit()
  */
-function filter_admin_delete() {
-  $format = arg(4);
-  $format = db_query('SELECT * FROM {filter_format} WHERE format = :format', array(':format' => $format))->fetchObject();
+function filter_admin_delete($format) {
+  $format = filter_format_load($format);
 
   if ($format) {
     if ($format->format != variable_get('filter_default_format', 1)) {
@@ -250,11 +249,11 @@ function filter_admin_delete() {
  * Process filter delete form submission.
  */
 function filter_admin_delete_submit($form, &$form_state) {
-  filter_format_delete($form_state['values']['format']);
+  $format = filter_format_load($form_state['values']['format']);
+  filter_format_delete($format);
   drupal_set_message(t('Deleted text format %format.', array('%format' => $form_state['values']['name'])));
 
   $form_state['redirect'] = 'admin/settings/formats';
-  return;
 }
 
 
Index: modules/filter/filter.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.api.php,v
retrieving revision 1.10
diff -u -p -r1.10 filter.api.php
--- modules/filter/filter.api.php	25 Aug 2009 10:35:32 -0000	1.10
+++ modules/filter/filter.api.php	26 Aug 2009 06:35:13 -0000
@@ -117,5 +117,58 @@ function hook_filter_info_alter(&$info) 
 }
 
 /**
+ * Perform actions when a new text format has been created.
+ *
+ * @param $format
+ *   The format object of the format being updated.
+ *
+ * @see hook_filter_format_update().
+ * @see hook_filter_format_delete().
+ */
+function hook_filter_format_insert($format) {
+  mymodule_cache_rebuild();
+}
+
+/**
+ * Perform actions when a text format has been updated.
+ *
+ * This hook allows modules to act when a text format has been updated in any
+ * way. For example, when filters have been reconfigured, disabled, or
+ * re-arranged in the text format.
+ *
+ * @param $format
+ *   The format object of the format being updated.
+ *
+ * @see hook_filter_format_insert().
+ * @see hook_filter_format_delete().
+ */
+function hook_filter_format_update($format) {
+  mymodule_cache_rebuild();
+} 
+
+/**
+ * Perform actions when a text format has been deleted.
+ *
+ * It is recommended for modules to implement this hook, when they store
+ * references to text formats to replace existing references to the deleted
+ * text format with the default format.
+ *
+ * @param $format
+ *   The format object of the format being deleted.
+ * @param $default
+ *   The format object of the site's default format.
+ *
+ * @see hook_filter_format_update().
+ * @see hook_filter_format_delete().
+ */
+function hook_filter_format_delete($format, $default) {
+  // Replace the deleted format with the default format.
+  db_update('my_module_table')
+    ->fields(array('format' => $default->format))
+    ->condition('format', $format->format)
+    ->execute();
+}
+
+/**
  * @} End of "addtogroup hooks".
  */
Index: modules/filter/filter.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.module,v
retrieving revision 1.280
diff -u -p -r1.280 filter.module
--- modules/filter/filter.module	26 Aug 2009 04:59:26 -0000	1.280
+++ modules/filter/filter.module	26 Aug 2009 06:35:47 -0000
@@ -193,6 +193,13 @@ function filter_format_save($format) {
   }
   $query->execute();
 
+  if ($status == SAVED_NEW) {
+    module_invoke_all('filter_format_insert', $format);
+  }
+  else {
+    module_invoke_all('filter_format_update', $format);
+  }
+
   cache_clear_all($format->format . ':', 'cache_filter', TRUE);
 
   return $status;
@@ -206,28 +213,17 @@ function filter_format_save($format) {
  */
 function filter_format_delete($format) {
   db_delete('filter_format')
-    ->condition('format', $format)
+    ->condition('format', $format->format)
     ->execute();
   db_delete('filter')
-    ->condition('format', $format)
+    ->condition('format', $format->format)
     ->execute();
 
-  $default = variable_get('filter_default_format', 1);
-  // Replace existing instances of the deleted format with the default format.
-  if (db_table_exists('comment')) {
-    db_update('comment')
-      ->fields(array('format' => $default))
-      ->condition('format', $format)
-      ->execute();
-  }
-  if (db_table_exists('box')) {
-    db_update('box')
-      ->fields(array('format' => $default))
-      ->condition('format', $format)
-      ->execute();
-  }
+  // Allow modules to react on text format deletion.
+  $default = filter_format_load(variable_get('filter_default_format', 1));
+  module_invoke_all('filter_format_delete', $format, $default);
 
-  cache_clear_all($format . ':', 'cache_filter', TRUE);
+  cache_clear_all($format->format . ':', 'cache_filter', TRUE);
 }
 
 /**
Index: modules/filter/filter.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.test,v
retrieving revision 1.33
diff -u -p -r1.33 filter.test
--- modules/filter/filter.test	25 Aug 2009 10:35:32 -0000	1.33
+++ modules/filter/filter.test	26 Aug 2009 06:13:20 -0000
@@ -746,3 +746,74 @@ class FilterUnitTest extends DrupalWebTe
     return $this->assertTrue(strpos(strtolower(decode_entities($haystack)), $needle) === FALSE, $message, $group);
   }
 }
+
+/**
+ * Tests for filter hook invocation.
+ */
+class FilterHooksTestCase extends DrupalWebTestCase {
+  function getInfo() {
+    return array(
+      'name' => 'Filter format hooks',
+      'description' => 'Test hooks for text formats insert/update/delete.',
+      'group' => 'Filter',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('block', 'filter_test');
+    $admin_user = $this->drupalCreateUser(array('administer filters', 'administer blocks'));
+    $this->drupalLogin($admin_user);
+  }
+
+  /**
+   * Test that hooks run correctly on creating, editing, and deleting a text format.
+   */
+  function testFilterHooks() {
+    // Add a text format.
+    $name = $this->randomName();
+    $edit = array();
+    $edit['name'] = $name;
+    $edit['roles[1]'] = 1;
+    $this->drupalPost('admin/settings/formats/add', $edit, t('Save configuration'));
+    $this->assertRaw(t('Added text format %format.', array('%format' => $name)), t('New format created.'));
+    $this->assertText(t('hook_filter_format_insert invoked.'), t('hook_filter_format_insert invoked.'));
+
+    $format = db_query("SELECT format FROM {filter_format} WHERE name = :name", array(':name' => $name))->fetchField();
+
+    // Update text format.
+    $edit = array();
+    $edit['roles[2]'] = 1;
+    $this->drupalPost('admin/settings/formats/' . $format, $edit, t('Save configuration'));
+    $this->assertRaw(t('The text format settings have been updated.'), t('Full HTML format successfully updated.'));
+    $this->assertText(t('hook_filter_format_update invoked.'), t('hook_filter_format_update() was invoked.'));
+
+    // Add a new custom block.
+    $box = array();
+    $box['info'] = $this->randomName(8);
+    $box['title'] = $this->randomName(8);
+    $box['body'] = $this->randomName(32);
+    // Use the format created.
+    $box['body_format'] = $format;
+    $this->drupalPost('admin/structure/block/add', $box, t('Save block'));
+    $this->assertText(t('The block has been created.'), t('New block successfully created.'));
+
+    // Verify the new block is in the database.
+    $bid = db_query("SELECT bid FROM {box} WHERE info = :info", array(':info' => $box['info']))->fetchField();
+    $this->assertNotNull($bid, t('New block found in database'));
+
+    // Delete the text format.
+    $this->drupalPost('admin/settings/formats/delete/' . $format, array(), t('Delete'));
+    $this->assertRaw(t('Deleted text format %format.', array('%format' => $name)), t('Format successfully deleted.'));
+    $this->assertText(t('hook_filter_format_delete invoked.'), t('hook_filter_format_delete() was invoked.'));
+
+    // Verify that the deleted format was replaced with the default format.
+    $current_format = db_select('box', 'b')
+      ->fields('b', array('format'))
+      ->condition('bid', $bid)
+      ->execute()
+      ->fetchField();
+    $default = variable_get('filter_default_format', 1);
+    $this->assertEqual($current_format, $default, t('Deleted text format replaced with the default format.'));
+  }
+}
+
Index: modules/simpletest/tests/filter_test.info
===================================================================
RCS file: modules/simpletest/tests/filter_test.info
diff -N modules/simpletest/tests/filter_test.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/filter_test.info	26 Aug 2009 06:28:49 -0000
@@ -0,0 +1,8 @@
+; $Id$
+name = Filter test module
+description = Tests filter hooks and functions.
+package = Testing
+version = VERSION
+core = 7.x
+files[] = filter_test.module
+hidden = TRUE
Index: modules/simpletest/tests/filter_test.module
===================================================================
RCS file: modules/simpletest/tests/filter_test.module
diff -N modules/simpletest/tests/filter_test.module
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/filter_test.module	26 Aug 2009 06:36:38 -0000
@@ -0,0 +1,29 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Test module for Filter module hooks and functions not used in core.
+ */
+
+/**
+ * Implement hook_filter_format_insert().
+ */
+function filter_test_filter_format_insert($format) {
+  drupal_set_message(t('hook_filter_format_insert invoked.'));
+}
+
+/**
+ * Implement hook_filter_format_update().
+ */
+function filter_test_filter_format_update($format) {
+  drupal_set_message(t('hook_filter_format_update invoked.'));
+}
+
+/**
+ * Implement hook_filter_format_delete().
+ */
+function filter_test_filter_format_delete($format, $default) {
+  drupal_set_message(t('hook_filter_format_delete invoked.'));
+}
+
