diff --git a/docroot/profiles/publisher/modules/contrib/expire/expire.admin.inc b/docroot/profiles/publisher/modules/contrib/expire/expire.admin.inc
index b6f19b6..5a1f705 100644
--- a/docroot/profiles/publisher/modules/contrib/expire/expire.admin.inc
+++ b/docroot/profiles/publisher/modules/contrib/expire/expire.admin.inc
@@ -764,3 +764,225 @@ function expire_node_settings_form(&$form) {
// Attach js.
$form['#attached']['js'][] = drupal_get_path('module', 'expire') . '/js/expire.admin.js';
}
+
+/**
+ * Menu callback to fulfill autocompletes on expire_manualexpire_form.
+ *
+ * @returns
+ * A standard Form API form-array.
+ */
+function expire_manualexpire_autocomplete($string) {
+ $query_limit = 10;
+ $matches = array();
+
+ // Overwrite $string and work around Drupal buggingly ignoring slashes.
+ $string = implode('/', array_slice(explode('/', $_GET['q']), 6));
+
+ // Scan for node/ lookups as they're quite common.
+ if (substr($string, 0, 1) == 'n') {
+ $query = db_select('node', 'n')
+ ->fields('n', array('nid'))
+ ->range(0, $query_limit);
+
+ // Lookup node IDs if the user entered node/, else limit on 15.
+ if (strlen($string) > 5) {
+ $string = (int) str_replace('node/', '', $string);
+ $query->condition('n.nid', '%' . db_like($string) . '%', 'LIKE');
+ }
+
+ $results = $query->execute();
+ foreach ($results as $nid) {
+ $path = 'node/' . $nid->nid;
+ $matches[] = $path;
+ }
+ }
+
+ // Scan for URL aliases when the path module is enabled.
+ if (module_exists('path')) {
+ $query = db_select('url_alias', 'u')
+ ->fields('u', array('alias'))
+ ->condition('alias', db_like($string) . '%', 'LIKE')
+ ->range(0, $query_limit)
+ ->execute();
+ foreach ($query as $alias) {
+ $matches[] = $alias->alias;
+ }
+ }
+
+ // Scan for menu_router paths, as long as they don't contain % characters.
+ if (module_exists('menu')) {
+ $query = db_select('menu_router', 'm')
+ ->fields('m', array('path'))
+ ->condition('path', db_like($string) . '%', 'LIKE')
+ ->condition('path', 'admin%', 'NOT LIKE')
+ ->range(0, $query_limit)
+ ->execute();
+ foreach ($query as $path) {
+ if (strpos($path->path, '%') !== FALSE) {
+ continue;
+ }
+ $matches[] = $path->path;
+ }
+ }
+
+ // Sort the values alphabetically.
+ sort($matches);
+
+ // Rewrite the matches array by copying the values into keys.
+ $clean_url = variable_get('clean_url', 0);
+ foreach ($matches as $key => $path) {
+ if (!$clean_url) {
+ $path = "index.php?q=$path";
+ }
+ unset($matches[$key]);
+ $matches[$path] = $path;
+ }
+
+ // Return the output JSON'ed.
+ drupal_json_output($matches);
+}
+
+/**
+ * Menu callback to drupal_get_form; let users manual expire pages.
+ *
+ * @returns
+ * A standard Form API form-array.
+ */
+function expire_manualexpire_form($form, &$form_state) {
+ $form['description'] = array(
+ '#markup' => t('
This form allows you to expire one or more paths. This
+ form is not intended for day-to-day use and only meant for site
+ administrators, for instance in emergency cases when a outdated copy of a
+ page remains being served. It is highly recommended to automate these
+ expirations using rules so editorial users can rely on a fully fresh site
+ instead of relying on this form.
'),
+ );
+
+ // Because we have many fields with the same values, we have to set
+ // #tree to be able to access them.
+ $form['#tree'] = TRUE;
+
+ // Allow the user to limit expire to selected modules
+ $modules = drupal_map_assoc(module_implements('expire_cache'));
+ $form['modules'] = array(
+ '#type' => 'checkboxes',
+ '#options' => $modules,
+ '#title' => t('Limit cache expiration to the following modules'),
+ '#default_value' => $modules,
+ );
+
+ // We'll group all paths both in a HTML wrapper and logically in the form.
+ $title = t('Paths to be expired:');
+ $form['paths'] = array(
+ '#prefix' => '',
+ );
+
+ // Fill paths with the right amount of form items according to num_paths.
+ $ac_path = 'admin/config/system/expire/manualexpire/autocomplete';
+ if (empty($form_state['num_paths'])) {
+ $form_state['num_paths'] = 1;
+ }
+ for ($i = 0; $i < $form_state['num_paths']; $i++) {
+ $form['paths']['path'][$i] = array(
+ '#type' => 'textfield',
+ '#autocomplete_path' => $ac_path,
+ '#size' => 30,
+ '#prefix' => '',
+ '#suffix' => '',
+ );
+ }
+
+ // Declare the add and remove buttons.
+ $form['paths']['add_path'] = array(
+ '#type' => 'submit',
+ '#value' => t('Add'),
+ '#submit' => array('expire_manualexpire_form_add_one'),
+ '#ajax' => array(
+ 'callback' => 'expire_manualexpire_form_callback',
+ 'wrapper' => 'paths-wrapper',
+ ),
+ );
+ if ($form_state['num_paths'] > 1) {
+ $form['paths']['remove_path'] = array(
+ '#type' => 'submit',
+ '#value' => t('Remove last item'),
+ '#submit' => array('expire_manualexpire_form_remove_one'),
+ '#limit_validation_errors' => array(),
+ '#ajax' => array(
+ 'callback' => 'expire_manualexpire_form_callback',
+ 'wrapper' => 'paths-wrapper',
+ ),
+ );
+ }
+
+ // Render the submit button and return the form.
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t("I know the risks, expire!"),
+ );
+ return $form;
+}
+
+/**
+ * Callback to drupal_get_form: the AJAX callback to paths-wrapper.
+ */
+function expire_manualexpire_form_callback($form, $form_state) {
+ return $form['paths'];
+}
+
+/**
+ * Callback to drupal_get_form: add a path textfield.
+ */
+function expire_manualexpire_form_add_one($form, &$form_state) {
+ $form_state['num_paths']++;
+ $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Callback to drupal_get_form: remove a path textfield.
+ */
+function expire_manualexpire_form_remove_one($form, &$form_state) {
+ if ($form_state['num_paths'] > 1) {
+ $form_state['num_paths']--;
+ }
+ $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Callback to drupal_get_form: validate the form.
+ */
+function expire_manualexpire_form_validate($form, &$form_state) {
+ $paths = array();
+ foreach ($form_state['values']['paths']['path'] as $id => $path) {
+ if (empty($path)) {
+ form_set_error('paths][path][' . $id,
+ t('The path can not be empty, use <front> for your frontpage!'));
+ }
+ elseif (!is_string($path)) {
+ form_set_error('paths][path][' . $id,
+ t("The path has to be a string!"));
+ }
+ elseif (stristr($path, 'http:') || stristr($path, 'https:')) {
+ form_set_error('paths][path][' . $id,
+ t("You can't provide a URL, only paths!"));
+ }
+ elseif (preg_match('/\s/', $path)) {
+ form_set_error('paths][path][' . $id,
+ t('The path can not contain a space!'));
+ }
+ elseif (in_array($path, $paths)) {
+ form_set_error('paths][path][' . $id,
+ t('You have already listed this path!'));
+ }
+ $paths[] = $path;
+ }
+}
+
+/**
+ * Callback to drupal_get_form: handle the form submit.
+ */
+function expire_manualexpire_form_submit($form, &$form_state) {
+ $modules = array_filter($form_state['values']['modules']);
+ ExpireAPI::executeExpiration($form_state['values']['paths']['path'], '', NULL, FALSE, $modules);
+}
diff --git a/docroot/profiles/publisher/modules/contrib/expire/expire.module b/docroot/profiles/publisher/modules/contrib/expire/expire.module
index 7d9b294..21bbeef 100644
--- a/docroot/profiles/publisher/modules/contrib/expire/expire.module
+++ b/docroot/profiles/publisher/modules/contrib/expire/expire.module
@@ -100,10 +100,48 @@ function expire_menu() {
'file' => 'expire.admin.inc',
);
+ // Default local task for the above menu item.
+ $items['admin/config/system/expire/default'] = array(
+ 'title' => 'Cache Expiration',
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ 'weight' => -5,
+ );
+
+ // Allow administrators to manual queue purge paths on the performance page.
+ $items['admin/config/system/expire/manualexpire'] = array(
+ 'type' => MENU_LOCAL_TASK,
+ 'title' => 'Manual expire',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('expire_manualexpire_form'),
+ 'access arguments' => array('administer site configuration'),
+ 'file' => 'expire.admin.inc',
+ );
+
+ // Autocomplete callback for the manual expire field
+ $items['admin/config/system/expire/manualexpire/autocomplete'] = array(
+ 'type' => MENU_CALLBACK,
+ 'page callback' => 'expire_manualexpire_autocomplete',
+ 'access arguments' => array('administer site configuration'),
+ 'file' => 'expire.admin.inc',
+ );
+
return $items;
}
/**
+ * Implements hook_menu_alter().
+ */
+function expire_menu_alter(&$items) {
+ // Hide the Acquia Purge Manual Purge admin for if present
+ if (isset($items['admin/config/development/performance/manualpurge'])) {
+ unset($items['admin/config/development/performance/manualpurge']);
+ }
+ if (isset($items['admin/config/system/expire/manualpurge'])) {
+ unset($items['admin/config/system/expire/manualpurge']);
+ }
+}
+
+/**
* Implements hook_form_FORM_ID_alter().
*/
function expire_form_node_type_form_alter(&$form, &$form_state) {
diff --git a/docroot/profiles/publisher/modules/contrib/expire/includes/expire.api.inc b/docroot/profiles/publisher/modules/contrib/expire/includes/expire.api.inc
index d49a94f..bdbbbd1 100644
--- a/docroot/profiles/publisher/modules/contrib/expire/includes/expire.api.inc
+++ b/docroot/profiles/publisher/modules/contrib/expire/includes/expire.api.inc
@@ -21,8 +21,12 @@ class ExpireAPI {
*
* @param $absolute_urls_passed
* Indicates whether absolute URLs or internal paths were passed.
+ *
+ * @param $modules
+ * Array with a list of modules for which to trigger expire. Empty array
+ * triggers expire on all modules implementing hook_cache_expire.
*/
- public static function executeExpiration($urls, $object_type = '', $object = NULL, $absolute_urls_passed = FALSE) {
+ public static function executeExpiration($urls, $object_type = '', $object = NULL, $absolute_urls_passed = FALSE, $modules = array()) {
// Allow other modules to modify the list prior to expiring.
drupal_alter('expire_cache', $urls, $object_type, $object, $absolute_urls_passed);
@@ -83,7 +87,7 @@ class ExpireAPI {
self::executeInternalExpiration($urls, $wildcards);
}
elseif ($status == EXPIRE_STATUS_ENABLED_EXTERNAL) {
- self::executeExternalExpiration($urls, $wildcards, $object_type, $object);
+ self::executeExternalExpiration($urls, $wildcards, $object_type, $object, $modules);
}
}
@@ -124,9 +128,16 @@ class ExpireAPI {
*
* @param $object
* Object (node, comment, user, etc) for which expiration is executes.
+ *
+ * @param $modules
+ * Array with a list of modules for which to trigger expire. Empty array
+ * triggers expire on all modules implementing hook_cache_expire.
*/
- protected static function executeExternalExpiration($urls, $wildcards, $object_type, $object) {
- $modules = module_implements('expire_cache');
+ protected static function executeExternalExpiration($urls, $wildcards, $object_type, $object, $modules = array()) {
+ // Default to expiring for all modules.
+ if (empty($modules)) {
+ $modules = module_implements('expire_cache');
+ }
foreach ($modules as $module) {
module_invoke($module, 'expire_cache', $urls, $wildcards, $object_type, $object);
}