diff --git a/sitecatalyst.module b/sitecatalyst.module
old mode 100644
new mode 100755
index e852ae1..ecc0b10
--- a/sitecatalyst.module
+++ b/sitecatalyst.module
@@ -140,7 +140,7 @@ function sitecatalyst_page_alter(&$page) {
 
   // Add any custom code snippets if specified and replace any tokens.
   $context = _sitecatalyst_get_token_context();
-  $codesnippet = token_replace(variable_get('sitecatalyst_codesnippet', ''), $context, array(
+  $codesnippet = sitecatalyst_token_replace(variable_get('sitecatalyst_codesnippet', ''), $context, array(
     'clear' => TRUE,
     'sanitize' => TRUE,
   )) . "\n";
@@ -444,7 +444,7 @@ function _sitecatalyst_format_variables(array $variables = array()) {
 
     // Cannot use check_plain() here because $key may contain quotes (e.g. 's.contextData["tve_domain"]').
     $key = htmlspecialchars($key, ENT_NOQUOTES, 'UTF-8');
-    $value = token_replace($value, $context, array(
+    $value = sitecatalyst_token_replace($value, $context, array(
       'clear' => TRUE,
       'sanitize' => FALSE,
     ));
@@ -454,6 +454,84 @@ function _sitecatalyst_format_variables(array $variables = array()) {
   return $variables_formatted;
 }
 
+
+/**
+ * Replaces all tokens in a given string with appropriate values, with caching.
+ *
+ * This function is a memoizing wrapper for token_replace(), which is quite slow
+ * and inefficient.  It takes advantage of specific knowledge about how this
+ * module works to cache the result of token replacement. It is not a fully
+ * general solution but works for this module.
+ *
+ * @param string $text
+ *   A string potentially containing replaceable tokens.
+ * @param $data
+ *   (optional) An array of keyed objects. See token_replace(). Known objects
+ *   here will also be used to form the cache key.
+ * @param array $options
+ *   An array of options to pass to token_replace().  See that function for
+ *   further documentation.
+ * @return string
+ *   Text with tokens replaced.
+ *
+ * @see token_replace()
+ */
+function sitecatalyst_token_replace($text, $data = array(), array $options = array()) {
+  $processed_strings = drupal_static(__FUNCTION__, NULL);
+
+  // Short-circuit the degenerate case, just like token_replace() does.
+  $text_tokens = token_scan($text);
+  if (empty($text_tokens)) {
+    return $text;
+  }
+
+  // Determine the cache key for this text string. That way we can cache reliably.
+  $key = _sitecatalyst_token_replace_make_key($text, $data);
+
+  $cache_name = 'sitecatalyst:tag_token_results';
+
+  // Lookup any already-cached token replacements.
+  if (is_null($processed_strings)) {
+    $cache = cache_get($cache_name);
+    $processed_strings = $cache
+      ? $cache->data
+      : array();
+  }
+
+  // If the processed string we're looking for isn't already in the cache,
+  // then, and only then, do we call the expensive token_replace() (and cache
+  // the result).
+  if (is_null($processed_strings[$key])) {
+    // Regenerate this particular replacement.
+    $processed_strings[$key] = token_replace($text, $data, $options);
+    cache_set($cache_name, $processed_strings);
+  }
+
+  return $processed_strings[$key];
+}
+
+/**
+ * Generates an identifying key for the lookup to be processed.
+ *
+ * @param string $text
+ *   The text to be processed.
+ * @param array $data
+ *   The array of data parameters that will be passed to token_generate().
+ *   We'll use knowledge of what is expected in that array to build a
+ *   meaningful lookup key.
+ * @return string
+ *   The key in the lookup array that corresponds to this tokenization request.
+ */
+function _sitecatalyst_token_replace_make_key($text, array $data) {
+
+  $keys[] = $text;
+  $keys[] = isset($data['node']->nid) ? $data['node']->nid : NULL;
+  $keys[] = isset($data['menu']->menu_name) ? $data['menu']->menu_name : NULL;
+  $keys[] = isset($data['tag']->machinename) ? $data['tag']->machinename : NULL;
+
+  return implode('|', array_filter($keys));
+}
+
 /**
  * Helper form builder for a variables form.
  */
