1471 lines
44 KiB
Plaintext
1471 lines
44 KiB
Plaintext
<?php
|
|
|
|
/**
|
|
* @file
|
|
* Handles core Skinr functionality.
|
|
*/
|
|
|
|
/**
|
|
* The Skinr API version.
|
|
*/
|
|
define('SKINR_VERSION', 2);
|
|
|
|
/**
|
|
* Show this rule on every page except the listed pages.
|
|
*/
|
|
define('SKINR_RULE_VISIBILITY_NOTLISTED', 0);
|
|
|
|
/**
|
|
* Show this rule on only the listed pages.
|
|
*/
|
|
define('SKINR_RULE_VISIBILITY_LISTED', 1);
|
|
|
|
/**
|
|
* Show this rule if the associated PHP code returns TRUE.
|
|
*/
|
|
define('SKINR_RULE_VISIBILITY_PHP', 2);
|
|
|
|
/**
|
|
* Implements hook_help().
|
|
*/
|
|
function skinr_help($path, $arg) {
|
|
switch ($path) {
|
|
case 'admin/help#skinr':
|
|
if (module_exists('advanced_help')) {
|
|
return t('Visit the <a href="@skinr-help">help page</a> for full documentation.', array('@skinr-help' => url('admin/advanced_help/skinr')));
|
|
}
|
|
else {
|
|
return t('Please download and enable the <a href="http://drupal.org/project/advanced_help">Advanced Help</a> module for full Skinr documentation.');
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_hook_info().
|
|
*/
|
|
function skinr_hook_info() {
|
|
$hooks = array(
|
|
'skinr_api_2',
|
|
'skinr_elements',
|
|
'skinr_group_info',
|
|
'skinr_group_info_alter',
|
|
'skinr_skin_info',
|
|
'skinr_skin_info_alter',
|
|
'skinr_theme_hooks',
|
|
'skinr_theme_hooks_alter',
|
|
);
|
|
$hooks = array_fill_keys($hooks, array(
|
|
'group' => 'skinr',
|
|
));
|
|
return $hooks;
|
|
}
|
|
|
|
/**
|
|
* Clears cached Skinr information.
|
|
*/
|
|
function skinr_cache_reset() {
|
|
cache_clear_all('skinr_', 'cache', TRUE);
|
|
}
|
|
|
|
/**
|
|
* Implements hook_preprocess().
|
|
*
|
|
* @todo Optimize this function by removing dependencies on
|
|
* skinr_get_skin_info() and similar resource heavy functions.
|
|
* @todo Account for Drupal's caching being enabled and make it work.
|
|
*/
|
|
function skinr_preprocess(&$variables, $hook) {
|
|
// Fix for update script.
|
|
if ($hook == 'maintenance_page') {
|
|
return;
|
|
}
|
|
|
|
$current_theme = skinr_current_theme();
|
|
$skin_info = skinr_get_skin_info();
|
|
|
|
$theme_registry = theme_get_registry();
|
|
$original_hook = (isset($theme_registry[$hook]['original hook']) ? $theme_registry[$hook]['original hook'] : $hook);
|
|
|
|
// An array of $elements based on $module and $original_hook, derived from $variables.
|
|
$array_elements = skinr_invoke_all('skinr_elements', $variables, $original_hook, 'preprocess');
|
|
foreach ($array_elements as $module => $elements) {
|
|
if (empty($elements)) {
|
|
// We can receive empty arrays; if that happens, there's no point
|
|
// in continuing.
|
|
continue;
|
|
}
|
|
|
|
// Get a list of skin configuration IDs to pass to
|
|
// skinr_skin_load_multiple().
|
|
$params = array(
|
|
'theme' => $current_theme,
|
|
'module' => $module,
|
|
'element' => $elements,
|
|
'status' => 1,
|
|
);
|
|
$sids = skinr_skin_get_sids($params);
|
|
if (empty($sids)) {
|
|
// Noting to apply.
|
|
continue;
|
|
}
|
|
|
|
$applied_skins = array();
|
|
foreach (skinr_skin_load_multiple($sids) as $skin) {
|
|
$applied_skins = array($skin->skin => $skin->options) + $applied_skins;
|
|
}
|
|
|
|
// Invoke hook_skinr_preprocess_alter() in all modules.
|
|
// @todo Review whether this alter hook is useful or not, and if it's in
|
|
// the right place or not.
|
|
$context = array(
|
|
'hook' => $hook,
|
|
'variables' => &$variables,
|
|
'theme' => $current_theme,
|
|
'module' => $module,
|
|
'elements' => $elements,
|
|
'options' => $applied_skins,
|
|
);
|
|
drupal_alter('skinr_preprocess', $context);
|
|
|
|
// Use drupal_process_attached() to add attachements such as JS and CSS.
|
|
if (!empty($applied_skins)) {
|
|
foreach ($applied_skins as $skin_name => $skin_options) {
|
|
|
|
// Special case for _additional.
|
|
if ($skin_name == '_additional') {
|
|
continue;
|
|
}
|
|
|
|
// Make sure this skin is enabled for the current theme.
|
|
if (isset($skin_info[$skin_name]['attached'])) {
|
|
$elements['#attached'] = $skin_info[$skin_name]['attached'];
|
|
drupal_process_attached($elements);
|
|
}
|
|
|
|
if (!is_array($skin_options)) {
|
|
$skin_options = array($skin_options);
|
|
}
|
|
foreach ($skin_options as $skin_option) {
|
|
if (isset($skin_info[$skin_name]['options'][$skin_option]['attached'])) {
|
|
$elements['#attached'] = $skin_info[$skin_name]['options'][$skin_option]['attached'];
|
|
drupal_process_attached($elements);
|
|
}
|
|
}
|
|
}
|
|
|
|
$variables['classes_array'] = array_merge($variables['classes_array'], skinr_flatten_skins_array($applied_skins));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns an array of classes.
|
|
*
|
|
* @param $skin_options
|
|
* An array of skin options keyed by their skin name. The key '_additional'
|
|
* is reserved for additional classes entered by the user.
|
|
*
|
|
* @todo Optimize this function by removing dependencies on the resource heavy
|
|
* skinr_get_skin_info() function.
|
|
* @todo Rename function to reflect new functionality.
|
|
*/
|
|
function skinr_flatten_skins_array($skin_options) {
|
|
$skin_info = skinr_get_skin_info();
|
|
|
|
$classes = array();
|
|
foreach ($skin_options as $skin_name => $options) {
|
|
if ($skin_name == '_additional') {
|
|
$classes = array_merge($classes, $options);
|
|
}
|
|
else {
|
|
foreach ($options as $option) {
|
|
if (!empty($skin_info[$skin_name]['options'][$option]['class'])) {
|
|
$classes = array_merge($classes, $skin_info[$skin_name]['options'][$option]['class']);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return array_unique($classes);
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Rule functions.
|
|
|
|
/**
|
|
* Validate a rule object.
|
|
*
|
|
* @param $rule
|
|
* A rule object.
|
|
*
|
|
* @return
|
|
* TRUE on success, FALSE on failure.
|
|
*/
|
|
|
|
function skinr_rule_validate(&$rule) {
|
|
if (empty($rule->title) || empty($rule->rule_type)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!isset($rule->node_types)) {
|
|
$rule->node_types = array();
|
|
}
|
|
if (!isset($rule->roles)) {
|
|
$rule->roles = array();
|
|
}
|
|
if (!isset($rule->visibility)) {
|
|
$rule->visibility = 0;
|
|
}
|
|
if (!isset($rule->pages)) {
|
|
$rule->pages = '';
|
|
}
|
|
|
|
if (!is_array($rule->node_types) || !is_array($rule->roles)) {
|
|
return FALSE;
|
|
}
|
|
if ($rule->visibility !== 0 && $rule->visibility !== 1 && $rule->visibility !== 2) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Save a skinr rule object.
|
|
*
|
|
* @param $rule
|
|
* A rule object.
|
|
*
|
|
* @return
|
|
* The rule ID.
|
|
*/
|
|
function skinr_rule_save($rule) {
|
|
// Make sure we're getting valid data.
|
|
if (!skinr_rule_validate($rule)) {
|
|
return FALSE;
|
|
}
|
|
|
|
$status = drupal_write_record('skinr_rules', $rule, !empty($rule->rid) ? array('rid') : array());
|
|
return $status;
|
|
}
|
|
|
|
/**
|
|
* Load a skinr rule object.
|
|
*
|
|
* @param $rid
|
|
* (optional) The rule ID.
|
|
*
|
|
* @return
|
|
* A rule object. If no $rid is specified an array of all rules will be
|
|
* returned.
|
|
*/
|
|
function skinr_rule_load($rid = NULL) {
|
|
$rids = (isset($rid) ? array($rid) : array());
|
|
$rules = skinr_rule_load_multiple($rids);
|
|
return $rules ? reset($rules) : FALSE;
|
|
}
|
|
|
|
/**
|
|
* Loads multiple skinr rule objects.
|
|
*
|
|
* @param $rids
|
|
* An array of rule IDs. Optional.
|
|
* @param $conditions
|
|
* An array of conditions on the {skinr_rules} table in the form 'field' =>
|
|
* $value.
|
|
*
|
|
* @return
|
|
* An array of rule objects indexed by rid. If $rids is not provided, all
|
|
* rules are returned.
|
|
*/
|
|
function skinr_rule_load_multiple($rids = array(), $conditions = array()) {
|
|
$rules = array();
|
|
$select = db_select('skinr_rules')->fields('skinr_rules');
|
|
if (!empty($rids)) {
|
|
$select->condition('rid', $rids);
|
|
}
|
|
foreach ($conditions as $field => $condition) {
|
|
$select->condition($field, $condition);
|
|
}
|
|
foreach ($select->execute() as $rule) {
|
|
$rule->node_types = unserialize($rule->node_types);
|
|
$rule->roles = unserialize($rule->roles);
|
|
$rules[$rule->rid] = $rule;
|
|
}
|
|
return $rules;
|
|
}
|
|
|
|
/**
|
|
* Delete a skinr rule object.
|
|
*
|
|
* @param $rid
|
|
* The rule ID.
|
|
*/
|
|
function skinr_rule_delete($rid) {
|
|
if ($rule = skinr_rule_load($rid)) {
|
|
db_delete('skinr_rules')
|
|
->condition('rid', $rule->rid)
|
|
->execute();
|
|
db_delete('skinr_skins')
|
|
->condition('module', 'page')
|
|
->condition('element', $rule->rid)
|
|
->execute();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determines if the rule should be visible for a given path.
|
|
*
|
|
* @param $rid
|
|
* The rule ID.
|
|
* @param $path
|
|
* (optional) The path to check. Defaults to the path of the current page.
|
|
* @param $account
|
|
* (optional) The account to check. Defaults to currently logged in user.
|
|
*
|
|
* @return
|
|
* TRUE if the rule should be visible, FALSE otherwise.
|
|
*/
|
|
function skinr_rule_is_visible($rid, $path = NULL, $account = NULL) {
|
|
global $user;
|
|
|
|
if (!isset($account)) {
|
|
$account = $user;
|
|
}
|
|
|
|
if ($rule = skinr_rule_load($rid)) {
|
|
if (!isset($path)) {
|
|
$path = $_GET['q'];
|
|
}
|
|
|
|
// Check role visibility.
|
|
if (!empty($rule->roles) && ($account->uid != 1) && !count(array_intersect(array_keys($account->roles), $rule->roles))) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Check content type visibility.
|
|
// If a rule has no node types associated, it is displayed for every type.
|
|
// For rules with node types associated, if the node type does not match
|
|
// the settings from this rule, return FALSE.
|
|
if (!empty($rule->node_types)) {
|
|
$node = menu_get_object('node', 1, $path);
|
|
$node_types = node_type_get_types();
|
|
if (arg(0, $path) == 'node' && arg(1, $path) == 'add' && arg(2, $path)) {
|
|
$node_add_arg = strtr(arg(2, $path), '-', '_');
|
|
}
|
|
|
|
if (!empty($node)) {
|
|
// This is a node or node edit page.
|
|
if (empty($rule->node_types[$node->type])) {
|
|
// This rule should not be displayed for this node type.
|
|
return FALSE;
|
|
}
|
|
}
|
|
elseif (isset($node_add_arg) && isset($node_types[$node_add_arg])) {
|
|
// This is a node creation page.
|
|
if (!isset($rule->node_types[$node_add_arg]) || !$rule->node_types[$node_add_arg]) {
|
|
// This rule should not be displayed for this node type.
|
|
return FALSE;
|
|
}
|
|
}
|
|
else {
|
|
// This is not a node page, remove the rule.
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// Match path if necessary.
|
|
if ($rule->pages) {
|
|
// Convert path to lowercase. This allows comparison of the same path
|
|
// with different case. Ex: /Page, /page, /PAGE.
|
|
$pages = drupal_strtolower($rule->pages);
|
|
if ($rule->visibility < SKINR_RULE_VISIBILITY_PHP) {
|
|
// Convert the Drupal path to lowercase
|
|
$path = drupal_strtolower(drupal_get_path_alias($path));
|
|
// Compare the lowercase internal and lowercase path alias (if any).
|
|
$page_match = drupal_match_path($path, $pages);
|
|
if ($path != $_GET['q']) {
|
|
$page_match = $page_match || drupal_match_path($path, $pages);
|
|
}
|
|
// When $rule->visibility has a value of 0 (SKINR_RULE_VISIBILITY_NOTLISTED),
|
|
// the rule is displayed on all pages except those listed in $rule->pages.
|
|
// When set to 1 (SKINR_RULE_VISIBILITY_LISTED), it is displayed only on those
|
|
// pages listed in $rule->pages.
|
|
$page_match = !($rule->visibility xor $page_match);
|
|
}
|
|
elseif (module_exists('php')) {
|
|
$page_match = php_eval($rule->pages);
|
|
}
|
|
else {
|
|
$page_match = FALSE;
|
|
}
|
|
}
|
|
else {
|
|
$page_match = TRUE;
|
|
}
|
|
return $page_match;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* Returns a list of extensions that implement this API version of Skinr.
|
|
*
|
|
* @return
|
|
* An associative array whose keys are system names of extensions and whose
|
|
* values are again associative arrays containing:
|
|
* - type: Either 'module' or 'theme'.
|
|
* - name: The system name of the extension.
|
|
* - path: The path to the extension.
|
|
* - directory: (optional) The sub-directory holding Skinr plugin files.
|
|
* - ...: Any other properties defined by the module or theme.
|
|
*/
|
|
function skinr_implements_api() {
|
|
$cache = &drupal_static(__FUNCTION__);
|
|
|
|
if (!isset($cache)) {
|
|
if ($cached = cache_get('skinr_implements_api')) {
|
|
$cache = $cached->data;
|
|
return $cache;
|
|
}
|
|
$cache = array();
|
|
|
|
// Collect hook_skinr_api_VERSION() module implementations. This will also
|
|
// auto-load $module.skinr.inc files, which may contain skin/group hook
|
|
// implementations (when not using the plugin system).
|
|
$module_info = system_get_info('module');
|
|
foreach (module_implements('skinr_api_' . SKINR_VERSION) as $module) {
|
|
// Ensure that $module and the extension type is registered.
|
|
$cache[$module] = array(
|
|
'type' => 'module',
|
|
'name' => $module,
|
|
'version' => isset($module_info[$module]['version']) ? $module_info[$module]['version'] : NULL,
|
|
);
|
|
// Check whether the hook returns any information.
|
|
$function = $module . '_skinr_api_' . SKINR_VERSION;
|
|
$info = $function();
|
|
if (isset($info) && is_array($info)) {
|
|
$cache[$module] += $info;
|
|
}
|
|
// If the module specified a custom path, check whether it contains a
|
|
// $module.skinr.inc file and auto-load it. module_implements() only
|
|
// auto-loads $module.skinr.inc in a module's root folder.
|
|
if (isset($cache[$module]['path'])) {
|
|
$file = $cache[$module]['path'] . '/' . $module . '.skinr.inc';
|
|
if (file_exists(DRUPAL_ROOT . '/' . $file)) {
|
|
$cache[$module]['include file'] = $file;
|
|
}
|
|
}
|
|
// Populate defaults.
|
|
$cache[$module] += array(
|
|
'path' => drupal_get_path('module', $module),
|
|
'directory' => NULL,
|
|
);
|
|
}
|
|
// Collect the equivalent of hook_skinr_api_VERSION() implementations in
|
|
// themes. The theme system only initializes one theme (and optionally its
|
|
// base themes) for the current request, and the phptemplate engine only
|
|
// loads template.php during theme initialization. Furthermore, template.php
|
|
// is a custom concept of the phptemplate engine and does not exist for
|
|
// other theme engines. Since we are interested in all existing
|
|
// implementations of all enabled themes, the equivalent of the module hook
|
|
// is a theme .info file property 'skinr' that has the sub-keys 'api' and
|
|
// optionally 'directory' defined.
|
|
// Account for all enabled themes and (any recursive) base themes of them,
|
|
// regardless of whether base themes are enabled.
|
|
$all_themes = list_themes();
|
|
$themes = array();
|
|
// Additionally record the base themes and sub themes of each theme, in
|
|
// order to apply inheritance rules elsewhere. Do not assign these variables
|
|
// as properties on the theme objects themselves, since all objects are
|
|
// pointers (much like references) in PHP 5, so our properties would be
|
|
// visible for everyone else who calls list_themes().
|
|
$base_themes = array();
|
|
$sub_themes = array();
|
|
foreach ($all_themes as $name => $theme) {
|
|
// If the theme is enabled, add it to the stack.
|
|
if (!empty($theme->status)) {
|
|
$themes[$name] = $theme;
|
|
// Find and add all base themes of the enabled theme to the stack.
|
|
// @see drupal_theme_initialize()
|
|
$sub_theme_name = $name;
|
|
while ($name && isset($all_themes[$name]->base_theme)) {
|
|
// Record the sub theme for the base theme.
|
|
$sub_themes[$all_themes[$name]->base_theme][$name] = $name;
|
|
|
|
// Add the base theme to the stack.
|
|
$name = $all_themes[$name]->base_theme;
|
|
$themes[$name] = $all_themes[$name];
|
|
|
|
// Record the base theme for the original sub theme.
|
|
$base_themes[$sub_theme_name][$name] = $name;
|
|
}
|
|
}
|
|
}
|
|
foreach ($themes as $name => $theme) {
|
|
if (isset($theme->info['skinr']['api']) && $theme->info['skinr']['api'] == SKINR_VERSION) {
|
|
// Ensure that the theme name and the extension type is registered.
|
|
$cache[$name] = array(
|
|
'type' => 'theme',
|
|
'name' => $name,
|
|
'version' => isset($theme->info['version']) ? $theme->info['version'] : NULL,
|
|
'base themes' => isset($base_themes[$name]) ? $base_themes[$name] : array(),
|
|
'sub themes' => isset($sub_themes[$name]) ? $sub_themes[$name] : array(),
|
|
);
|
|
// Add any additional information that has been registered.
|
|
$cache[$name] += $theme->info['skinr'];
|
|
// Populate defaults.
|
|
$cache[$name] += array(
|
|
'path' => drupal_get_path('theme', $name),
|
|
// Since themes cannot do anything else than registering skins and
|
|
// groups, we default to the sub-directory 'skins'.
|
|
'directory' => 'skins',
|
|
);
|
|
// Lastly, for API consistency with modules, check whether the theme
|
|
// contains a $theme.skinr.inc file and auto-load it, if any.
|
|
$file = $cache[$name]['path'] . '/' . $name . '.skinr.inc';
|
|
if (file_exists(DRUPAL_ROOT . '/' . $file)) {
|
|
$cache[$name]['include file'] = $file;
|
|
}
|
|
}
|
|
}
|
|
|
|
cache_set('skinr_implements_api', $cache);
|
|
}
|
|
|
|
return $cache;
|
|
}
|
|
|
|
/**
|
|
* Determine whether a module implements a hook.
|
|
*
|
|
* Replacement for module_hook() that only invokes modules that implement
|
|
* the current version of Skinr API. It also supports $module.skinr.inc files
|
|
* in themes and custom paths.
|
|
*
|
|
* @param $module
|
|
* The name of the module (without the .module extension).
|
|
* @param $hook
|
|
* The name of the hook (e.g. "skinr_skin_info" or "skinr_theme_hooks").
|
|
*
|
|
* @return
|
|
* TRUE if the module is both installed and enabled, and the hook is
|
|
* implemented in that module.
|
|
*/
|
|
function skinr_hook($module, $hook) {
|
|
$function = $module . '_' . $hook;
|
|
if (function_exists($function)) {
|
|
return TRUE;
|
|
}
|
|
// If the hook implementation does not exist, check whether it may live in an
|
|
// include file in a custom path.
|
|
$extensions = skinr_implements_api();
|
|
if (isset($extensions[$module])) {
|
|
$extension = $extensions[$module];
|
|
if (isset($extension['include file'])) {
|
|
// The module specified a custom path. module_hook() only auto-loads
|
|
// $module.skinr.inc in a module's root folder.
|
|
skinr_load_include($extension['include file']);
|
|
if (function_exists($module . '_' . $hook)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
else {
|
|
// Run through module_hook() to auto-load $module.skinr.inc from a
|
|
// non-custom path.
|
|
if (module_hook($module, $hook)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* Determine which modules are implementing a hook.
|
|
*
|
|
* Replacement for module_implements() that only invokes modules that implement
|
|
* the current version of Skinr API. It also supports $module.skinr.inc files
|
|
* in themes and custom paths.
|
|
*
|
|
* @param $hook
|
|
* The name of the hook (e.g. "skinr_skin_info" or "skinr_theme_hooks").
|
|
*
|
|
* @return
|
|
* An array with the names of the modules which are implementing this hook.
|
|
*
|
|
* @see skinr_exit()
|
|
*/
|
|
function skinr_implements($hook) {
|
|
$implementations = &drupal_static(__FUNCTION__, array());
|
|
|
|
// Fetch implementations from cache.
|
|
if (empty($implementations)) {
|
|
$implementations = cache_get('skinr_implements', 'cache_bootstrap');
|
|
if ($implementations === FALSE) {
|
|
$implementations = array();
|
|
}
|
|
else {
|
|
$implementations = $implementations->data;
|
|
}
|
|
}
|
|
|
|
if (!isset($implementations[$hook])) {
|
|
$implementations['#write_cache'] = TRUE;
|
|
|
|
$extensions = skinr_implements_api();
|
|
$implementations[$hook] = array();
|
|
foreach ($extensions as $module => $extension) {
|
|
if (isset($extension['include file'])) {
|
|
// The module specified a custom path. module_implements() and
|
|
// module_hook() only auto-load $module.skinr.inc in a module's
|
|
// root folder.
|
|
$include_file = skinr_load_include($extension['include file']);
|
|
if (function_exists($module . '_' . $hook)) {
|
|
$implementations[$hook][$module] = $include_file ? $extension['include file'] : FALSE;
|
|
}
|
|
}
|
|
else {
|
|
// Run through module_hook() to auto-load $module.skinr.inc from a
|
|
// non-custom path.
|
|
if (module_hook($module, $hook)) {
|
|
$implementations[$hook][$module] = FALSE;
|
|
}
|
|
}
|
|
}
|
|
// Allow modules to change the weight of specific implementations but avoid
|
|
// an infinite loop.
|
|
if ($hook != 'skinr_implements_alter') {
|
|
drupal_alter('skinr_implements', $implementations[$hook], $hook);
|
|
}
|
|
}
|
|
else {
|
|
foreach ($implementations[$hook] as $module => $file) {
|
|
if ($file) {
|
|
skinr_load_include($file);
|
|
}
|
|
else {
|
|
module_hook($module, $hook);
|
|
}
|
|
// It is possible that a module removed a hook implementation without the
|
|
// implementations cache being rebuilt yet, so we check whether the
|
|
// function exists on each request to avoid undefined function errors.
|
|
// Since module_hook() may needlessly try to load the include file again,
|
|
// function_exists() is used directly here.
|
|
if (!function_exists($module . '_' . $hook)) {
|
|
// Clear out the stale implementation from the cache and force a cache
|
|
// refresh to forget about no longer existing hook implementations.
|
|
unset($implementations[$hook][$module]);
|
|
$implementations['#write_cache'] = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return array_keys($implementations[$hook]);
|
|
}
|
|
|
|
/**
|
|
* Implements hook_exit().
|
|
*
|
|
* @see module_implements_write_cache()
|
|
*/
|
|
function skinr_exit($destination = NULL) {
|
|
$implementations = &drupal_static('skinr_implements');
|
|
// Check whether we need to write the cache. We do not want to cache hooks
|
|
// which are only invoked on HTTP POST requests since these do not need to be
|
|
// optimized as tightly, and not doing so keeps the cache entry smaller.
|
|
if (isset($implementations['#write_cache']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD')) {
|
|
unset($implementations['#write_cache']);
|
|
cache_set('skinr_implements', $implementations, 'cache_bootstrap');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Invoke a hook in all enabled modules and themes that implement it.
|
|
*
|
|
* Replacement for module_invoke_all() that only invokes modules that implement
|
|
* the current version of Skinr API. It also supports $module.skinr.inc files
|
|
* in themes and custom paths.
|
|
*
|
|
* @param $hook
|
|
* The name of the hook to invoke.
|
|
* @param ...
|
|
* Arguments to pass to the hook.
|
|
*
|
|
* @return
|
|
* An array of return values of the hook implementations. If modules return
|
|
* arrays from their implementations, those are merged into one array.
|
|
*/
|
|
function skinr_invoke_all($hook) {
|
|
$args = func_get_args();
|
|
// Remove $hook from the arguments.
|
|
unset($args[0]);
|
|
$return = array();
|
|
foreach (skinr_implements($hook) as $module) {
|
|
$function = $module . '_' . $hook;
|
|
if (function_exists($function)) {
|
|
$result = call_user_func_array($function, $args);
|
|
if (isset($result) && is_array($result)) {
|
|
$return = array_merge_recursive($return, $result);
|
|
}
|
|
elseif (isset($result)) {
|
|
$return[] = $result;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Loads a $module.skinr.inc include file.
|
|
*/
|
|
function skinr_load_include($file) {
|
|
if (is_file($file)) {
|
|
include_once $file;
|
|
return $file;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* Includes Skinr plugin files for an extension, if any.
|
|
*
|
|
* @param $extension
|
|
* The API information for an extension, as returned by skinr_implements_api().
|
|
*/
|
|
function skinr_load_plugins($extension) {
|
|
static $loaded = array();
|
|
|
|
// If plugins have already been loaded for this extension, return them.
|
|
if (isset($loaded[$extension['name']])) {
|
|
return $loaded[$extension['name']];
|
|
}
|
|
$loaded[$extension['name']] = array();
|
|
|
|
// If the extension defines a plugin directory, scan its plugins.
|
|
if (isset($extension['directory'])) {
|
|
$dir = DRUPAL_ROOT . '/' . $extension['path'] . '/' . $extension['directory'];
|
|
$mask = '@^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.inc$@';
|
|
$loaded[$extension['name']] = file_scan_directory($dir, $mask, array(
|
|
'key' => 'name',
|
|
'recurse' => TRUE,
|
|
'min_depth' => 1,
|
|
'callback' => 'skinr_include_once',
|
|
));
|
|
}
|
|
return $loaded[$extension['name']];
|
|
}
|
|
|
|
/**
|
|
* file_scan_directory() callback wrapper around include_once.
|
|
*
|
|
* include_once is a PHP construct, not a function, so it cannot be invoked
|
|
* directly as 'callback' in file_scan_directory().
|
|
*/
|
|
function skinr_include_once($file) {
|
|
include_once $file;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Skinr data handling functions.
|
|
|
|
/**
|
|
* Validate a skinr object.
|
|
*
|
|
* @param $skin
|
|
* A skin object.
|
|
*
|
|
* @return
|
|
* TRUE on success, FALSE on failure.
|
|
*/
|
|
function skinr_skin_validate(&$skin) {
|
|
if (empty($skin->theme) || empty($skin->module) || empty($skin->element) || empty($skin->skin) || empty($skin->options)) {
|
|
return FALSE;
|
|
}
|
|
if (!is_array($skin->options)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Strip empty skins.
|
|
$skin->options = _skinr_array_strip_empty($skin->options);
|
|
if (empty($skin->options)) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Save a skin object.
|
|
*
|
|
* @param $skin
|
|
* A skin object.
|
|
*
|
|
* @return
|
|
* TRUE on success, FALSE on failure.
|
|
*/
|
|
function skinr_skin_save(&$skin) {
|
|
// Make sure we're getting valid data.
|
|
if (!skinr_skin_validate($skin)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Load the stored skin configuration object, if any.
|
|
if (!empty($skin->sid)) {
|
|
if (!isset($skin->original)) {
|
|
// Load an uncached version of the skin configuration object.
|
|
$skin->original = skinr_skin_load_unchanged($skin->sid);
|
|
}
|
|
}
|
|
|
|
// Let modules modify the node before it is saved to the database.
|
|
module_invoke_all('skinr_skin_presave', $skin);
|
|
|
|
if (!empty($skin->sid)) {
|
|
// Record exists, so let's update.
|
|
$status = drupal_write_record('skinr_skins', $skin, 'sid');
|
|
module_invoke_all('skinr_skin_update', $skin);
|
|
}
|
|
else {
|
|
// Insert a new record.
|
|
$status = drupal_write_record('skinr_skins', $skin);
|
|
module_invoke_all('skinr_skin_insert', $skin);
|
|
}
|
|
|
|
// Clear internal properties.
|
|
unset($skin->original);
|
|
// Clear the static loading cache.
|
|
// @todo Once we have a more granular reset for skinr_skin_load_multiple(), we
|
|
// need to use it here.
|
|
drupal_static_reset('skinr_skin_load_multiple');
|
|
|
|
return $status;
|
|
}
|
|
|
|
/**
|
|
* Delete a skin object.
|
|
*
|
|
* @param $sid
|
|
* The skin configuration ID.
|
|
*/
|
|
function skinr_skin_delete($sid) {
|
|
skinr_skin_delete_multiple(array($sid));
|
|
}
|
|
|
|
/**
|
|
* Delete multiple skin configuration objects.
|
|
*
|
|
* @param $sids
|
|
* An array of skin configuration IDs.
|
|
*/
|
|
function skinr_skin_delete_multiple($sids) {
|
|
$transaction = db_transaction();
|
|
if (!empty($sids)) {
|
|
$skins = skinr_skin_load_multiple($sids);
|
|
|
|
try {
|
|
foreach ($skins as $sid => $skin) {
|
|
module_invoke_all('skinr_skin_delete', $skin);
|
|
}
|
|
|
|
// Delete after calling hooks so that they can query node tables as needed.
|
|
db_delete('skinr_skins')
|
|
->condition('sid', $sids, 'IN')
|
|
->execute();
|
|
}
|
|
catch (Exception $e) {
|
|
$transaction->rollback();
|
|
watchdog_exception('skinr', $e);
|
|
throw $e;
|
|
}
|
|
|
|
// Clear the skinr_skin_load_multiple cache.
|
|
drupal_static_reset('skinr_skin_load_multiple');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load a skin configuration object from the database.
|
|
*
|
|
* @param $sid
|
|
* The skin configuration ID.
|
|
*
|
|
* @return
|
|
* A fully-populated skin configuration object.
|
|
*/
|
|
function skinr_skin_load($sid = NULL) {
|
|
$sids = (isset($sid) ? array($sid) : array());
|
|
$skin = skinr_skin_load_multiple($sids);
|
|
return $skin ? reset($skin) : FALSE;
|
|
}
|
|
|
|
/**
|
|
* Load skin configuration objects from the database.
|
|
*
|
|
* This function should be used whenever you need to load more than one skin
|
|
* configuration from the database. Skin configurations are loaded into memory
|
|
* and will not require database access if loaded again during the same page
|
|
* request.
|
|
*
|
|
* @see skinr_skin_get_sids()
|
|
*
|
|
* @param $sids
|
|
* An array of skin configuration IDs.
|
|
*
|
|
* @return
|
|
* An array of skin configuration objects indexed by sid.
|
|
*/
|
|
function skinr_skin_load_multiple($sids = array()) {
|
|
// @todo Do we want to write a more granular cache reset?
|
|
$skins = &drupal_static(__FUNCTION__, array());
|
|
|
|
// Create a new variable which is either a prepared version of the $sids
|
|
// array for later comparison with cached skin configuration objects, or FALSE
|
|
// if no $sids were passed. The $sids array is reduced as items are loaded
|
|
// from cache, and we need to know if it's empty for this reason to avoid
|
|
// querying the database when all requested skin configuration objects are
|
|
// loaded from cache.
|
|
$passed_sids = !empty($sids) ? array_flip($sids) : FALSE;
|
|
if ($passed_sids) {
|
|
$sids = array_keys(array_diff_key($passed_sids, $skins));
|
|
}
|
|
|
|
// Load any remaining skin configurations from the database. This is the
|
|
// case if $sids is set to FALSE (so we load all skins), or if there are any
|
|
// sids left to load.
|
|
if ($sids === FALSE || $sids) {
|
|
// Build the query.
|
|
$queried_skins = db_select('skinr_skins', 's')
|
|
->fields('s')
|
|
->condition('sid', $sids)
|
|
->execute()
|
|
->fetchAllAssoc('sid');
|
|
|
|
foreach ($queried_skins as $sid => $skin) {
|
|
// Unserialize options array.
|
|
$queried_skins[$sid]->options = unserialize($skin->options);
|
|
|
|
// Let modules modify the skin configurations.
|
|
module_invoke_all('skinr_skin_load', $queried_skins[$sid]);
|
|
}
|
|
$skins += $queried_skins;
|
|
}
|
|
|
|
// Ensure that the returned array is ordered the same as the original
|
|
// $sids array if this was passed in and remove any invalid sids.
|
|
if ($passed_sids) {
|
|
// Remove any invalid sids from the array.
|
|
$passed_sids = array_intersect_key($passed_sids, $skins);
|
|
$return = array();
|
|
foreach ($passed_sids as $sid => $ignore) {
|
|
$return[$sid] = $skins[$sid];
|
|
}
|
|
}
|
|
else {
|
|
$return = $skins;
|
|
}
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Load an uncached version of a skin configuration object.
|
|
*
|
|
* @param $sid
|
|
* The skin configuration ID.
|
|
*
|
|
* @return
|
|
* A fully-populated skin configuration object.
|
|
*/
|
|
function skinr_skin_load_unchanged($sid) {
|
|
// Load an uncached version of the skin configuration object.
|
|
$skin = db_query("SELECT * FROM {skinr_skins} WHERE sid = :sid", array(
|
|
':sid' => $sid,
|
|
))
|
|
->fetchObject();
|
|
|
|
// Unserialize options array.
|
|
$skin->options = unserialize($skin->options);
|
|
|
|
// Let modules modify the skin configuration.
|
|
module_invoke_all('skinr_skin_load', $skin);
|
|
|
|
return $skin;
|
|
}
|
|
|
|
/**
|
|
* Get skin configuration IDs.
|
|
*
|
|
* @param $filter_by
|
|
* An associative array whose keys are:
|
|
* - theme: (optional) The theme.
|
|
* - module: (optional) The module.
|
|
* - element: (optional) The element ID.
|
|
* - skin: (optional) The skin name.
|
|
* - status: (optional) Boolean indicating whether or not this skin
|
|
* configuration is enabled.
|
|
*
|
|
* @return
|
|
* An array of skin configuration IDs.
|
|
*/
|
|
function skinr_skin_get_sids($filter_by = array()) {
|
|
$query = db_select('skinr_skins', 's')
|
|
->fields('s', array('sid'));
|
|
if (isset($filter_by['theme'])) {
|
|
$query->condition('theme', $filter_by['theme']);
|
|
}
|
|
if (isset($filter_by['module'])) {
|
|
$query->condition('module', $filter_by['module']);
|
|
}
|
|
if (isset($filter_by['element'])) {
|
|
$query->condition('element', $filter_by['element']);
|
|
}
|
|
if (isset($filter_by['skin'])) {
|
|
$query->condition('skin', $filter_by['skin']);
|
|
}
|
|
if (isset($filter_by['status'])) {
|
|
$query->condition('status', $filter_by['status']);
|
|
}
|
|
return $query->execute()
|
|
->fetchCol();
|
|
}
|
|
|
|
/**
|
|
* Helper function to remove empty skins from an array.
|
|
*
|
|
* @param $array
|
|
* A single or multi-dimensional array to strip of empty values.
|
|
*
|
|
* @return
|
|
* An array stripped of empty values.
|
|
*/
|
|
function _skinr_array_strip_empty($array) {
|
|
$new_array = array();
|
|
foreach ($array as $key => $value) {
|
|
if (is_array($value)) {
|
|
$value = _skinr_array_strip_empty($value);
|
|
}
|
|
if (!empty($value)) {
|
|
$new_array[$key] = $value;
|
|
}
|
|
}
|
|
return $new_array;
|
|
}
|
|
|
|
/**
|
|
* Helper function to retrieve the current theme.
|
|
*
|
|
* The global variable $theme_key doesn't work for our purposes when an admin
|
|
* theme is enabled.
|
|
*
|
|
* @param $exclude_admin_theme
|
|
* Optional. Set to TRUE to exclude the admin theme from possible themes to
|
|
* return.
|
|
*
|
|
* @return
|
|
* The current theme name.
|
|
*/
|
|
function skinr_current_theme($exclude_admin_theme = FALSE) {
|
|
global $user, $custom_theme;
|
|
|
|
if (!empty($user->theme) && drupal_theme_access($user->theme)) {
|
|
$current_theme = $user->theme;
|
|
}
|
|
elseif (!empty($custom_theme) && drupal_theme_access($custom_theme) && !($exclude_admin_theme && $custom_theme == variable_get('admin_theme', '0'))) {
|
|
// Don't return the admin theme if we're editing skinr settings.
|
|
$current_theme = $custom_theme;
|
|
}
|
|
else {
|
|
$current_theme = variable_get('theme_default', 'bartik');
|
|
}
|
|
return $current_theme;
|
|
}
|
|
|
|
/**
|
|
* Prepare the default status for a skin.
|
|
*
|
|
* @param $skin_info
|
|
* Information about a registered skin.
|
|
*
|
|
* @return
|
|
* An array of default statuses for each enabled theme.
|
|
*/
|
|
function skinr_skin_info_status_default($skin_info) {
|
|
$status = array();
|
|
// Retrieve the explicit default status of the registering theme for itself.
|
|
$base_theme_status = NULL;
|
|
if (isset($skin_info['status'][$skin_info['source']['name']])) {
|
|
$base_theme_status = $skin_info['status'][$skin_info['source']['name']];
|
|
}
|
|
// Retrieve the sub themes of the base theme that registered the skin.
|
|
$sub_themes = array();
|
|
if (isset($skin_info['source']['sub themes'])) {
|
|
$sub_themes = $skin_info['source']['sub themes'];
|
|
}
|
|
$themes = list_themes();
|
|
foreach ($themes as $name => $theme) {
|
|
if (!$theme->status) {
|
|
continue;
|
|
}
|
|
// If this theme is a sub theme of the theme that registered the skin, check
|
|
// whether we need to inherit the status of the base theme to the sub theme.
|
|
// This is the case when a skin of a base theme enables itself for the base
|
|
// theme (not knowing about potential sub themes).
|
|
if (isset($base_theme_status) && isset($sub_themes[$name])) {
|
|
$status[$name] = $base_theme_status;
|
|
}
|
|
// Apply global default.
|
|
$status += array($name => $skin_info['default status']);
|
|
}
|
|
// Lastly, apply all explicit defaults.
|
|
$status = array_merge($status, $skin_info['status']);
|
|
|
|
return $status;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the overridden status of a skin.
|
|
*
|
|
* @param $skin_info
|
|
* Information about a registered skin.
|
|
*
|
|
* @return
|
|
* An array of statuses for each enabled theme. If no overrides are found,
|
|
* the status defaults will be returned.
|
|
*/
|
|
function skinr_skin_info_status_get($skin_info) {
|
|
return variable_get('skinr_skin_' . $skin_info['name'] . '_status', $skin_info['status']);
|
|
}
|
|
|
|
/**
|
|
* Set the status of a skin. Overrides the skin plugin settings.
|
|
*
|
|
* @param $skin_info
|
|
* Information about a registered skin.
|
|
* @param $status
|
|
* An array of statuses for each theme.
|
|
*/
|
|
function skinr_skin_info_status_set($skin_info, $status) {
|
|
variable_set('skinr_skin_' . $skin_info['name'] . '_status', $status);
|
|
}
|
|
|
|
/**
|
|
* Helper function to prepend a path to an array of stylesheet or script filenames.
|
|
*
|
|
* If the url is absolute (e.g. the url start with 'http://' or 'https://')
|
|
* the path does not get prepended.
|
|
*
|
|
* @param $files
|
|
* A an array of filenames that need the path prepended.
|
|
* @todo Adjust docs to account for arrays instead of filenames.
|
|
* @param $path
|
|
* The path to prepend.
|
|
*/
|
|
function _skinr_add_path_to_files(&$files, $path) {
|
|
foreach ($files as $key => $file) {
|
|
if (is_array($file)) {
|
|
if (strpos($file[0], 'http://') === 0 || strpos($file[0], 'https://') === 0 ) {
|
|
continue;
|
|
}
|
|
$files[$key][0] = $path . '/' . $file[0];
|
|
}
|
|
else {
|
|
if (strpos($file, 'http://') === 0 || strpos($file, 'https://') === 0) {
|
|
continue;
|
|
}
|
|
$files[$key] = $path . '/' . $file;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parse a skin_infos array as returned from a skins plugin.
|
|
*
|
|
* This function inserts any missing defaults and updates the stylesheet and
|
|
* script paths to be relative to Drupal's root.
|
|
*
|
|
* @param $skin_infos
|
|
* An array of skins as returned from skin plugins.
|
|
* @param $source
|
|
* An associative array containing information about the source of the skin.
|
|
* See skinr_implements() for details.
|
|
*
|
|
* @todo Merge into skinr_get_skin_info() and remove this function.
|
|
*/
|
|
function skinr_skin_info_process(&$skin_infos, $source) {
|
|
foreach ($skin_infos as $skin_name => $skin_info) {
|
|
// Populate default properties.
|
|
$skin_infos[$skin_name] += array(
|
|
'name' => '',
|
|
'title' => '',
|
|
'type' => 'checkboxes',
|
|
'description' => '',
|
|
'group' => 'general',
|
|
'theme hooks' => array('*'),
|
|
'attached' => array(),
|
|
'options' => array(),
|
|
'weight' => NULL,
|
|
'default status' => 0,
|
|
'status' => array(),
|
|
);
|
|
|
|
// Merge in name.
|
|
$skin_infos[$skin_name]['name'] = $skin_name;
|
|
|
|
// Merge in source information.
|
|
$skin_infos[$skin_name]['source'] = $source;
|
|
|
|
// Merge in default status for all themes.
|
|
$skin_infos[$skin_name]['status'] = skinr_skin_info_status_default($skin_infos[$skin_name]);
|
|
|
|
// Add path to stylesheets.
|
|
if (isset($skin_infos[$skin_name]['attached']['css'])) {
|
|
_skinr_add_path_to_files($skin_infos[$skin_name]['attached']['css'], $source['path']);
|
|
}
|
|
// Add path to scripts.
|
|
if (isset($skin_infos[$skin_name]['attached']['js'])) {
|
|
_skinr_add_path_to_files($skin_infos[$skin_name]['attached']['js'], $source['path']);
|
|
}
|
|
|
|
foreach ($skin_infos[$skin_name]['options'] as $option_name => $option) {
|
|
// Add path to stylesheets.
|
|
if (isset($option['attached']['css'])) {
|
|
_skinr_add_path_to_files($skin_infos[$skin_name]['options'][$option_name]['attached']['css'], $source['path']);
|
|
}
|
|
// Add path to scripts.
|
|
if (isset($option['attached']['js'])) {
|
|
_skinr_add_path_to_files($skin_infos[$skin_name]['options'][$option_name]['attached']['js'], $source['path']);
|
|
}
|
|
|
|
// Validate class by running it through drupal_html_class().
|
|
if (!is_array($skin_infos[$skin_name]['options'][$option_name]['class'])) {
|
|
$skin_infos[$skin_name]['options'][$option_name]['class'] = array($skin_infos[$skin_name]['options'][$option_name]['class']);
|
|
}
|
|
foreach ($skin_infos[$skin_name]['options'][$option_name]['class'] as $key => $class) {
|
|
$skin_infos[$skin_name]['options'][$option_name]['class'][$key] = drupal_html_class($class);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieves all skins registered by modules and themes.
|
|
*
|
|
* @return
|
|
* An array of skins.
|
|
*/
|
|
function skinr_get_skin_info() {
|
|
$skin_info = &drupal_static(__FUNCTION__);
|
|
|
|
if (!isset($skin_info)) {
|
|
if ($cached = cache_get('skinr_skin_info')) {
|
|
$skin_info = $cached->data;
|
|
return $skin_info;
|
|
}
|
|
$skin_info = array();
|
|
|
|
foreach (skinr_implements_api() as $name => $extension) {
|
|
$hooks = array();
|
|
// Run through skinr_hook to ensure the required include gets loaded.
|
|
if (skinr_hook($name, 'skinr_skin_info')) {
|
|
$hooks["{$name}_skinr_skin_info"] = $extension;
|
|
}
|
|
|
|
// Load the extension's plugins, if any.
|
|
if ($files = skinr_load_plugins($extension)) {
|
|
// The base path for plugins is the directory defined by the extension.
|
|
$dir = $extension['path'] . '/' . $extension['directory'];
|
|
foreach ($files as $plugin => $file) {
|
|
$hooks["{$name}_skinr_skin_{$plugin}_info"] = array(
|
|
// The source path for a plugin is the plugin directory.
|
|
'path' => $dir . '/' . basename(dirname($file->uri)),
|
|
'filename' => $file->filename,
|
|
) + $extension;
|
|
}
|
|
}
|
|
foreach ($hooks as $function => $source) {
|
|
if (function_exists($function)) {
|
|
$extension_info = $function();
|
|
if (isset($extension_info) && is_array($extension_info)) {
|
|
// Prepare the skin information.
|
|
skinr_skin_info_process($extension_info, $source);
|
|
|
|
$skin_info += $extension_info;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Allow modules to alter registered skin information.
|
|
drupal_alter('skinr_skin_info', $skin_info);
|
|
|
|
cache_set('skinr_skin_info', $skin_info);
|
|
}
|
|
|
|
return $skin_info;
|
|
}
|
|
|
|
/**
|
|
* Retrieves all skin groups registered by modules and themes.
|
|
*
|
|
* @return
|
|
* An array of groups.
|
|
*/
|
|
function skinr_get_group_info() {
|
|
$group_info = &drupal_static(__FUNCTION__);
|
|
|
|
if (!isset($group_info)) {
|
|
if ($cached = cache_get('skinr_group_info')) {
|
|
$group_info = $cached->data;
|
|
return $group_info;
|
|
}
|
|
$group_info = array();
|
|
|
|
foreach (skinr_implements_api() as $name => $extension) {
|
|
$hooks = array();
|
|
// Run through skinr_hook to ensure the required include gets loaded.
|
|
if (skinr_hook($name, 'skinr_group_info')) {
|
|
$hooks["{$name}_skinr_group_info"] = $extension;
|
|
}
|
|
|
|
// Load the extension's plugins, if any.
|
|
if ($files = skinr_load_plugins($extension)) {
|
|
// The base path for plugins is the directory defined by the extension.
|
|
$dir = $extension['path'] . '/' . $extension['directory'];
|
|
foreach ($files as $plugin => $file) {
|
|
$hooks["{$name}_skinr_group_{$plugin}_info"] = array(
|
|
// The source path for a plugin is the plugin directory.
|
|
'path' => $dir . '/' . basename(dirname($file->uri)),
|
|
'filename' => $file->filename,
|
|
) + $extension;
|
|
}
|
|
}
|
|
foreach ($hooks as $function => $source) {
|
|
if (function_exists($function)) {
|
|
$extension_info = $function();
|
|
if (isset($extension_info) && is_array($extension_info)) {
|
|
// Prepare the skin group information.
|
|
foreach ($extension_info as &$group) {
|
|
$group += array(
|
|
'title' => '',
|
|
'description' => '',
|
|
'weight' => 0,
|
|
);
|
|
}
|
|
$group_info += $extension_info;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Allow modules to alter groups through hook_skinr_group_info_alter().
|
|
drupal_alter('skinr_group_info', $group_info);
|
|
|
|
cache_set('skinr_group_info', $group_info);
|
|
}
|
|
|
|
return $group_info;
|
|
}
|
|
|
|
/**
|
|
* Fetch Skinr configuration data from functionality plugins.
|
|
*
|
|
* @return
|
|
* An array of all configuration data.
|
|
*/
|
|
function skinr_get_config_info() {
|
|
$config_info = &drupal_static(__FUNCTION__);
|
|
|
|
if (!isset($config_info)) {
|
|
if ($cached = cache_get('skinr_config_info')) {
|
|
$config_info = $cached->data;
|
|
return $config_info;
|
|
}
|
|
$config_info = skinr_invoke_all('skinr_config_info');
|
|
|
|
// Allow modules to alter config info via hook_skinr_config_info_alter().
|
|
drupal_alter('skinr_config_info', $config_info);
|
|
|
|
cache_set('skinr_config_info', $config_info);
|
|
}
|
|
|
|
return $config_info;
|
|
}
|
|
|
|
/**
|
|
* Provide a list of all available theme hooks for a given element.
|
|
*
|
|
* @param $module
|
|
* The module implementing given element.
|
|
* @param $element
|
|
* An element.
|
|
*
|
|
* @return
|
|
* An array of theme hooks.
|
|
*/
|
|
function skinr_theme_hooks($module, $element) {
|
|
$theme_hooks = &drupal_static(__FUNCTION__, array());
|
|
|
|
if (!isset($theme_hooks[$module][$element])) {
|
|
// Invoke hook_skinr_theme_hooks() and hook_skinr_theme_hooks_alter().
|
|
$theme_hooks[$module][$element] = skinr_invoke_all('skinr_theme_hooks', $module, $element);
|
|
drupal_alter('skinr_theme_hooks', $theme_hooks[$module][$element], $module, $element);
|
|
}
|
|
|
|
return $theme_hooks[$module][$element];
|
|
}
|
|
|
|
/**
|
|
* Implements hook_modules_enabled().
|
|
*/
|
|
function skinr_modules_enabled() {
|
|
skinr_cache_reset();
|
|
}
|
|
|
|
/**
|
|
* Implements hook_modules_disabled().
|
|
*/
|
|
function skinr_modules_disabled() {
|
|
skinr_cache_reset();
|
|
}
|
|
|
|
/**
|
|
* Implements hook_themes_enabled().
|
|
*/
|
|
function skinr_themes_enabled() {
|
|
skinr_cache_reset();
|
|
}
|
|
|
|
/**
|
|
* Implements hook_themes_disabled().
|
|
*/
|
|
function skinr_themes_disabled() {
|
|
skinr_cache_reset();
|
|
}
|
|
|
|
/**
|
|
* Helper function for built-in integration code.
|
|
*/
|
|
function skinr_skinr_api_modules() {
|
|
return array(
|
|
'path' => drupal_get_path('module', 'skinr') . '/modules',
|
|
);
|
|
}
|
|
|
|
function block_skinr_api_2() {
|
|
return skinr_skinr_api_modules();
|
|
}
|
|
|
|
function comment_skinr_api_2() {
|
|
return skinr_skinr_api_modules();
|
|
}
|
|
|
|
function node_skinr_api_2() {
|
|
return skinr_skinr_api_modules();
|
|
}
|
|
|
|
function views_skinr_api_2() {
|
|
return skinr_skinr_api_modules();
|
|
}
|