You are here

themekey_debug.module in ThemeKey 7.3

Provides a debug mode for module ThemeKey.

@author Markus Kalkbrenner | bio.logis GmbH

File

themekey_debug.module
View source
<?php

/**
 * @file
 * Provides a debug mode for module ThemeKey.
 * @see themekey.module
 *
 * @author Markus Kalkbrenner | bio.logis GmbH
 *   @see http://drupal.org/user/124705
 */

/**
 * Implements hook_permission().
 */
function themekey_debug_permission() {
  return array(
    'themekey_debug_see_messages' => array(
      'title' => t('See ThemeKey debug messages'),
      'description' => t('Using this permission debug messages will be displayed to users in that role.'),
    ),
  );
}

/**
 * Iterates over all ThemeKey Properties and prints
 * out their current values.
 */
function themekey_debug_properties() {
  global $user;
  if (1 == $user->uid || user_access('themekey_debug_see_messages', $user) || variable_get('themekey_debug_non_admin_users', FALSE)) {
    module_load_include('inc', 'themekey', 'themekey_base');
    $properties = variable_get('themekey_properties', array());
    $message = t('These are the current values of all available ThemeKey Properties. By clicking the value you can start creating a corresponding Theme Switching Rule.') . '<ul>';
    $parameters = themekey_get_global_parameters();
    foreach ($properties as $property) {
      if (!isset($parameters[$property])) {
        themekey_property_value($parameters, $property);
      }
      $value = '';
      if (is_null($parameters[$property])) {
        if ('drupal:path' == $property) {
          $value = '<em>no debug information</em>';
        }
        else {
          $value = '<em>empty</em>';
        }
      }
      else {
        $values = is_array($parameters[$property]) ? $parameters[$property] : array(
          $parameters[$property],
        );
        $links = array();
        foreach ($values as $single_value) {

          // Don't use the l() function at this early stage of bootstrapping because it will initialize the theme engine. Use url() instead.
          $links[] = '<a href="' . url('admin/config/user-interface/themekey', array(
            'fragment' => 'themekey_new_rule',
            'query' => array(
              'property' => $property,
              'value' => $single_value,
            ),
          )) . '">' . $single_value . '</a>';
        }
        $value = implode('<br />', $links);
      }
      $message .= '<li>' . $property . '<br />' . $value . '</li><br />';
    }
    $message .= '</ul>';
    themekey_set_debug_message($message, array(), FALSE);
  }
}

/**
 * Implements hook_menu().
 */
function themekey_debug_menu() {
  $items = array();
  $items['admin/config/user-interface/themekey/settings/debug'] = array(
    'title' => 'Debug',
    'access callback' => 'user_access',
    'access arguments' => array(
      'administer themekey settings',
    ),
    'file' => 'themekey_debug_admin.inc',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'themekey_debug_settings_form',
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 10,
  );
  return $items;
}

/**
 * Implements hook_theme().
 */
function themekey_debug_theme() {
  $items = array(
    'themekey_debug_messages' => array(
      'template' => 'themekey-debug-messages',
      'variables' => array(
        'messages' => array(),
      ),
    ),
  );
  return $items;
}

/**
 * Implements hook_init().
 *
 * Detects if hook_custom_theme() has been skipped because
 * a different module already initialized the theme engine.
 */
function themekey_debug_init() {
  if (variable_get('themekey_debug_trace_rule_switching', FALSE)) {
    if (!in_array('system', variable_get('themekey_compat_modules_enabled', array())) && path_is_admin($_GET['q']) && variable_get('admin_theme', '0')) {
      themekey_set_debug_message('"%admin_theme" is configured as administration theme at !link. This setting is more powerful than a corresponding ThemeKey rule.', array(
        '%admin_theme' => variable_get('admin_theme', '0'),
        '!link' => l(t('!path', array(
          '!path' => 'admin/appearance',
        )), 'admin/appearance'),
      ), TRUE, TRUE);
    }
    $custom_theme_called =& drupal_static('themekey_custom_theme_called', FALSE);
    if (!$custom_theme_called) {
      themekey_set_debug_message("Consider to activate the module ThemeKey Compatibility to integrate a different theme switching module into ThemeKey's theme switching rule chain", array(), TRUE, TRUE);
      themekey_set_debug_message('Skipped rule checking because another module already initialized the theme engine.', array(), TRUE, TRUE);
    }
    else {
      global $theme;
      $themekey_custom_theme =& drupal_static('themekey_custom_theme', '');
      if (!empty($themekey_custom_theme) && 'default' != $themekey_custom_theme) {
        if ($theme != $themekey_custom_theme) {
          themekey_set_debug_message('Theme switching to custom theme "%custom_theme" did not work because theme has been set to "%theme" by another module.', array(
            '%custom_theme' => $themekey_custom_theme,
            '%theme' => $theme,
          ), TRUE, TRUE);
        }
      }
      else {
        if (variable_get('theme_default', 'bartik') != $theme) {
          themekey_set_debug_message('ThemeKey did not switch the theme because no rule matched. But something else set the theme to "%theme".', array(
            '%theme' => $theme,
          ), TRUE, TRUE);
        }
      }
    }
  }
}

/**
 * Implements hook_form_node_form_alter().
 *
 * Detects if custom theme has been skipped because
 * the adminstration theme is used for node editing.
 */
function themekey_debug_form_node_form_alter() {
  if (variable_get('themekey_debug_trace_rule_switching', FALSE)) {
    if (variable_get('node_admin_theme', '0')) {
      themekey_set_debug_message('As configured at !link adding or editing a node will use the administration theme %admin_theme.', array(
        '%admin_theme' => variable_get('admin_theme', '0'),
        '!link' => l(t('!path', array(
          '!path' => 'admin/appearance',
        )), 'admin/appearance'),
      ), TRUE, TRUE);
    }
  }
}

/**
 * Implements hook_page_alter().
 *
 * Prints out debug messages at the end of the page.
 *
 * @return string
 */
function themekey_debug_page_alter(&$page) {
  if (variable_get('themekey_debug_show_property_values', FALSE)) {

    // add the properties to the end of debug messages
    themekey_debug_properties();
  }
  if (variable_get('themekey_css_debug_css_files', FALSE)) {

    // add the list of css files to the end of debug messages.
    $list['title'] = t('Css files on a page');
    $list['items'] = array_filter(explode("\n", drupal_get_css()), 'themekey_debug_filter_css_array');
    themekey_set_debug_message(theme('item_list', $list));
  }
  if ($messages = themekey_set_debug_message('flush')) {
    $page['page_bottom']['themekey'] = array(
      '#type' => 'markup',
      '#markup' => $messages,
    );

    // Avoid caching of pages containing debug info in internal page cache
    drupal_page_is_cacheable(FALSE);

    // ... and external caches like varnish, boost, ...
    drupal_add_http_header('Status', '503 Service unavailable');
  }
}

/**
 * Function for filtering array elements.
 *
 * Filters elements with empty strings and elements with strings
 * that contains '<style>' tag from array generated by
 * explode("\n", drupal_get_css()). drupal_get_css() returns
 * html markup with "@import" statements combined in <style> tags.
 * themekey_set_debug_message() use filter_xss() to filtering html
 * from string, but filter_xss() leaves empty string where was html markup.
 *
 * @param string $element
 *   Array element.
 *
 * @return bool
 *   TRUE if element is not an empty string or string without <style> tag.
 */
function themekey_debug_filter_css_array($element) {
  if (strlen(trim($element)) > 0 && strpos($element, '<style') === FALSE && strpos($element, '</style>') === FALSE) {
    return TRUE;
  }
  else {
    return FALSE;
  }
}

/**
 * Replacement for drupal_set_message() during ThemeKey's initialization.
 * drupal_set_message() might inititialize the theme engine too early,
 * which causes ThemeKey to not switch the theme.
 *
 * themekey_debug_set_debug_message() put the untranslated messages on a
 * stack and hand them over to drupal_set_message() on demand.
 *
 * @param $msg
 *   the message as string. If the message is 'flush'
 *   all messages stored on the stack will be printed using
 *   drupal_set_message()
 *
 * @param $placeholder
 *   associative array of string replacments for $msg
 *   @see t()
 *
 * @param $translate
 *   boolean, if set to TRUE $msg will be handled by t()
 *   when handed over to drupal_set_message()
 */
function themekey_debug_set_debug_message($msg, $placeholder = array(), $translate = TRUE, $unshift = FALSE) {
  static $msg_stack = array();
  global $user, $theme;
  if (1 == $user->uid || user_access('themekey_debug_see_messages', $user) || variable_get('themekey_debug_non_admin_users', FALSE)) {
    if ('flush' == $msg) {
      $messages = array();
      if (variable_get('themekey_debug_trace_rule_switching', FALSE)) {
        $messages[] = t('Current theme: %theme', array(
          '%theme' => $theme,
        ));
      }
      foreach ($msg_stack as $key => $msg) {
        $messages[] = filter_xss($msg['translate'] ? t($msg['msg'], $msg['placeholder']) : $msg['msg'], array(
          'a',
          'b',
          'br',
          'li',
          'ul',
        ));
        unset($msg_stack[$key]);
      }
      if (!empty($messages)) {
        return theme('themekey_debug_messages', array(
          'messages' => $messages,
        ));
      }
    }
    else {
      $tmp = array(
        'msg' => $msg,
        'placeholder' => $placeholder,
        'translate' => $translate,
      );
      if ($unshift) {
        $tmp['msg'] = '<b>' . $tmp['msg'] . '</b>';
        array_unshift($msg_stack, $tmp);
      }
      else {
        $msg_stack[] = $tmp;
      }
    }
  }
}

Functions

Namesort descending Description
themekey_debug_filter_css_array Function for filtering array elements.
themekey_debug_form_node_form_alter Implements hook_form_node_form_alter().
themekey_debug_init Implements hook_init().
themekey_debug_menu Implements hook_menu().
themekey_debug_page_alter Implements hook_page_alter().
themekey_debug_permission Implements hook_permission().
themekey_debug_properties Iterates over all ThemeKey Properties and prints out their current values.
themekey_debug_set_debug_message Replacement for drupal_set_message() during ThemeKey's initialization. drupal_set_message() might inititialize the theme engine too early, which causes ThemeKey to not switch the theme.
themekey_debug_theme Implements hook_theme().