diff --git media_gallery.module media_gallery.module
index 5149707..1a69d81 100644
--- media_gallery.module
+++ media_gallery.module
@@ -226,10 +226,11 @@ function media_gallery_view($node, $view_mode) {
       // @todo Drupal could really use a theme_menu_local_actions() function...
       '#prefix' => '<ul class="field action-links">',
       '#suffix' => '</ul>',
-      // Add front-end resources related to this link, only when it is actually
-      // being rendered.
-      '#pre_render' => array('media_gallery_add_images_link_pre_render'),
     );
+    // Add front end resources related to this link.
+    $node->content['add_media_link']['#attached']['js'][] = drupal_get_path('module', 'media_gallery') . '/media_gallery.addimage.js';
+    module_load_include('inc', 'media', 'media.browser');
+    media_attach_browser_js($node->content['add_media_link']);
 
     // These JS settings are used by the "add media" link but are also shared
     // by the drag-and-drop code below.
@@ -353,17 +354,6 @@ function media_gallery_view($node, $view_mode) {
 }
 
 /**
- * Prerender function to add front-end resources for the "Add media" link.
- */
-function media_gallery_add_images_link_pre_render($elements) {
-  drupal_add_library('media', 'media_browser');
-  module_load_include('inc', 'media', 'media.browser');
-  media_attach_browser_js($elements);
-  drupal_add_js(drupal_get_path('module', 'media_gallery') . '/media_gallery.addimage.js');
-  return $elements;
-}
-
-/**
  * Implements hook_field_extra_fields().
  */
 function media_gallery_field_extra_fields() {
@@ -503,6 +493,29 @@ function media_gallery_update($node) {
       ->condition('delta', $node->nid)
       ->execute();
   }
+  // Clear the block cache for this node.
+  cache_clear_all('media_gallery_block:' . $node->nid, 'cache_block', TRUE);
+}
+
+/**
+ * Implements hook_media_rendered_flush().
+ */
+function media_gallery_media_rendered_flush($fid = FALSE) {
+  // @todo: it may be possible to do an EntityFieldQuery to find all nodes
+  // that reference the fid if it is passed in. This would allow the cache
+  // to be cleared by nid instead of all block entries. However this may
+  // be expensive in itself compared to just rebuilding the cache.
+  cache_clear_all('media_gallery_block:', 'cache_block', TRUE);
+}
+
+/**
+ * Implements hook_field_update_instance().
+ */
+function media_gallery_field_update_instance($instance, $prior_instance) {
+  if ($instance['bundle'] == 'media_gallery') {
+    // Clear the media block cache.
+    media_gallery_media_rendered_flush();
+  }
 }
 
 /**
@@ -546,49 +559,20 @@ function media_gallery_block_view($delta = '') {
     $block['content'] = t('No content available.');
   }
   else {
-    // Collect an array of file IDs associated with this gallery. For
-    // simplicity we will assume (here and below) that this is not a
-    // multilingual field. Also note that the node may have been loaded and
-    // viewed elsewhere on the page, in which case the 'media_gallery_media'
-    // field was modified and does not contain what we want, so we have to go
-    // back to the original field value set in hook_node_load() instead, and
-    // also clone the node before changing it so our modifications do not
-    // affect other places where it might be being viewed.
-    $node = clone $node;
-    $node->media_gallery_media = $node->media_gallery_media_original;
-    $files = &$node->media_gallery_media[LANGUAGE_NONE];
-    $gallery_fids = array();
-    foreach ($files as $file) {
-      $gallery_fids[] = _media_gallery_get_media_fid($file);
-    }
-    // Construct a list of file IDs that is limited to the specified number of
-    // items and ordered by most recent; these are the files that will be
-    // displayed in the block.
-    $columns = !empty($node->media_gallery_block_columns[LANGUAGE_NONE][0]['value']) ? $node->media_gallery_block_columns[LANGUAGE_NONE][0]['value'] : 1;
-    $rows = !empty($node->media_gallery_block_rows[LANGUAGE_NONE][0]['value']) ? $node->media_gallery_block_rows[LANGUAGE_NONE][0]['value'] : 1;
-    $number_to_show = $columns * $rows;
-    $block_fids = db_select('file_managed', 'f')
-      ->fields('f', array('fid'))
-      ->condition('fid', $gallery_fids, 'IN')
-      ->orderBy('timestamp', 'DESC')
-      ->range(0, $number_to_show)
-      ->execute()
-      ->fetchCol();
-    // Before sorting, remove any items that will not display in the block.
-    $fid_order = array_flip($block_fids);
-    if ($number_to_show < count($files)) {
-      foreach ($files as $key => $file) {
-        if (!isset($fid_order[_media_gallery_get_media_fid($file)])) {
-          unset($files[$key]);
-        }
-      }
-    }
-    // Prepare the sorting function with the list of file ID orders.
-    _media_gallery_sort_by_recent(NULL, NULL, $fid_order);
-    // Perform the sort.
-    usort($files, '_media_gallery_sort_by_recent');
-    // Display the block.
-    $block['content'] = node_view($node, 'media_gallery_block');
+    $block['content'] = array(
+      '#node' => $node,
+      '#pre_render' => array('media_gallery_block_build'),
+      '#cache' => array(
+        'keys' => array(
+          'media_gallery_block',
+          $node->nid,
+          (int) node_access('update', $node),
+          (int) $GLOBALS['is_https'],
+        ),
+        'bin' => 'cache_block',
+        'expire' => 86400,
+      ),
+    );
     $block['content']['more_link'] = array(
       '#theme' => 'more_link',
       '#url' => 'node/' . $node->nid,
@@ -596,11 +580,65 @@ function media_gallery_block_view($delta = '') {
       '#weight' => 1000,
     );
   }
-
   return $block;
 }
 
 /**
+ * Build a renderable array for the media gallery block content.
+ */
+function media_gallery_block_build($elements) {
+  // Collect an array of file IDs associated with this gallery. For
+  // simplicity we will assume (here and below) that this is not a
+  // multilingual field. Also note that the node may have been loaded and
+  // viewed elsewhere on the page, in which case the 'media_gallery_media'
+  // field was modified and does not contain what we want, so we have to go
+  // back to the original field value set in hook_node_load() instead, and
+  // also clone the node before changing it so our modifications do not
+  // affect other places where it might be being viewed.
+  $node = clone $elements['#node'];
+  $node->media_gallery_media = $node->media_gallery_media_original;
+  $files = &$node->media_gallery_media[LANGUAGE_NONE];
+  $gallery_fids = array();
+  foreach ($files as $file) {
+    $gallery_fids[] = _media_gallery_get_media_fid($file);
+  }
+  // Construct a list of file IDs that is limited to the specified number of
+  // items and ordered by most recent; these are the files that will be
+  // displayed in the block.
+  $columns = !empty($node->media_gallery_block_columns[LANGUAGE_NONE][0]['value']) ? $node->media_gallery_block_columns[LANGUAGE_NONE][0]['value'] : 1;
+  $rows = !empty($node->media_gallery_block_rows[LANGUAGE_NONE][0]['value']) ? $node->media_gallery_block_rows[LANGUAGE_NONE][0]['value'] : 1;
+  $number_to_show = $columns * $rows;
+  $block_fids = db_select('file_managed', 'f')
+    ->fields('f', array('fid'))
+    ->condition('fid', $gallery_fids, 'IN')
+    ->orderBy('timestamp', 'DESC')
+    ->range(0, $number_to_show)
+    ->execute()
+    ->fetchCol();
+  // Before sorting, remove any items that will not display in the block.
+  $fid_order = array_flip($block_fids);
+  if ($number_to_show < count($files)) {
+    foreach ($files as $key => $file) {
+      if (!isset($fid_order[_media_gallery_get_media_fid($file)])) {
+        unset($files[$key]);
+      }
+    }
+  }
+  // Prepare the sorting function with the list of file ID orders.
+  _media_gallery_sort_by_recent(NULL, NULL, $fid_order);
+  // Perform the sort.
+  usort($files, '_media_gallery_sort_by_recent');
+  // Display the block.
+  $elements['gallery'] = node_view($node, 'media_gallery_block');
+  if (isset($elements['gallery']['#contextual_links'])) {
+    $elements['#contextual_links'] = $elements['gallery']['#contextual_links'];
+    unset($elements['gallery']['#contextual_links']);
+  }
+
+  return $elements;
+}
+
+/**
  * Implements hook_block_configure().
  */
 function media_gallery_block_configure($delta = '') {
