How to run code on every page request - after modules are loaded? 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.
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.