4

I want to write a module that redirects visitors to another page based on the geoip module.

There is hook_boot() which runs on all page requests, but before the modules are loaded. There is also hook_init() which isn't run on cached pages. I'd need something that runs after all modules are loaded - but before cached pages are served. Did I miss another hook in the documentation?

Note: Turning off the cache is not an option for performance reasons.

7

I think it's best to summarize the options in a new answer:

First off: There is no hook that's executed between hook_boot() and hook_init(). That means there is no hook that has a fully initialized drupal environment and is executed regardless of the page cache. -- thanks @kiamlaluno for clearing that up.

There are still two methods to get a similar effect:

  1. It's possible to selectively load include files or modules in hook_boot() using module_load_include() or drupal_load() respectively. This is especially useful if you only need some rather self-contained functionality which isn't spread over a lot of files.
  2. The module dynamic_cache can be used to dynamically deactivate the cache on certain page loads by setting $GLOBALS['conf']['cache'] = FALSE in hook_boot() and then do the heavy lifting in hook_init(). - thanks to @David Meister

The two methods can also be combined to narrow down the number of requests where caching needs to be disabled: Use a minimal-bootstrap in hook_boot() to determine exactly when caching needs to be disabled.

The dynamic_cache module seems rather hackish though. So I'll stick to method 1 for now.

7

I'd need something that runs after all modules are loaded - but before cached pages are served.

You cannot, as loading all the modules is the last phase of Drupal bootstrap, while cached pages are served in the second bootstrap phase.

See the code used by drupal_bootstrap().

  switch ($current_phase) {
    case DRUPAL_BOOTSTRAP_CONFIGURATION:
      _drupal_bootstrap_configuration();
      break;

    case DRUPAL_BOOTSTRAP_PAGE_CACHE:
      _drupal_bootstrap_page_cache();
      break;

    case DRUPAL_BOOTSTRAP_DATABASE:
      _drupal_bootstrap_database();
      break;

    case DRUPAL_BOOTSTRAP_VARIABLES:
      _drupal_bootstrap_variables();
      break;

    case DRUPAL_BOOTSTRAP_SESSION:
      require_once DRUPAL_ROOT . '/' . variable_get('session_inc', 'includes/session.inc');
      drupal_session_initialize();
      break;

    case DRUPAL_BOOTSTRAP_PAGE_HEADER:
      _drupal_bootstrap_page_header();
      break;

    case DRUPAL_BOOTSTRAP_LANGUAGE:
      drupal_language_initialize();
      break;

    case DRUPAL_BOOTSTRAP_FULL:
      require_once DRUPAL_ROOT . '/includes/common.inc';
      _drupal_bootstrap_full();
      break;
  }

If you look at _drupal_bootstrap_page_cache(), you will notice that hook_boot() is eventually invoked before the page is served from the cached data, while hook_exit() is eventually invoked after the page is served from the cached data. Those hooks are invoked if the value of the Drupal variable "page_cache_invoke_hooks" is TRUE.

  if (variable_get('page_cache_invoke_hooks', TRUE)) {
    bootstrap_invoke_all('boot');
  }
  drupal_serve_page_from_cache($cache);
  // If the skipping of the bootstrap hooks is not enforced, call
  // hook_exit.
  if (variable_get('page_cache_invoke_hooks', TRUE)) {
    bootstrap_invoke_all('exit');
  }

Notice that in Drupal 8, hook_boot()has been removed and so does hook_exit(). This means Drupal 8 will never invoke those hooks.

  • That's a more verbose description of my problem - thanks. – zwirbeltier Jun 30 '12 at 12:51
  • While it was not the solution to my problem it still is a comprehensive answer to my question. – zwirbeltier Jun 30 '12 at 16:37
1

I know you said that turning off the cache is not an option but the Dynamic Cache module lets you turn off the cache conditionally in hook_boot which might actually be an option as the cache will only be off for users you're about to redirect - http://drupal.org/project/dynamic_cache

If you can get the logic you need out of GeoIP in hook_boot() then you can turn off the cache for that page load and just do a drupal_goto() in hook_init().

1

Or you could just load the modules in hook_boot(), then drupal won't have to load them later and you can do whatever you want with the modules. I understand that this is a bit irregular, but programming in Drupal seems to require several irregular ways of doing things.

0

You can try hook_exit which is run even on cached pages. I'm not sure if drupal_goto works inside it but if it doesn't you could do what the boost module does and use header('Location: mynewurl').

  • 1
    drupal_goto won't work because drupal_serve_page_from_cache() already started sending headers at that time. – zwirbeltier Jun 30 '12 at 12:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.