Comment dire à Drupal de rechercher des modèles dans le répertoire du module?


11

Je voudrais fournir une implémentation de modèle dans mon module et permettre aux thèmes de le remplacer. Fondamentalement, j'ajoute une suggestion par ce code simplifié:

function attach_preprocess_node(&$vars) {
  $vars['theme_hook_suggestions'][] = 'node__test';
}

(Je ne veux pas utiliser hook_theme pour ajouter un nouveau thème car je veux réutiliser les fonctions de nœud de prétraitement. Le nom du thème est maladroit mais je ne veux pas écrire node_ attach _% pour éviter toute confusion avec le type de nœud.)

Ensuite, j'utilise hook_theme_registry_alter () pour ajouter le chemin du module:

function attach_theme_registry_alter(&$theme_registry) {
  $path = drupal_get_path('module', 'attach') . '/themes';
  $theme_registry_copy = $theme_registry;
  _theme_process_registry($theme_registry_copy, 'phptemplate', 'theme_engine', 'node', drupal_get_path('module', 'node'));
  $theme_registry += array_diff_key($theme_registry_copy, $theme_registry);
  if (!isset($theme_registry['node']['theme paths'])) {
    $theme_registry['node']['theme paths'] = array();
  }
  if (!isset($theme_registry['node']['theme paths'])) {
    $first_element = array_shift($theme_registry['node']['theme paths']);
    if ($first_element) {
      array_unshift($theme_registry['node']['theme paths'], $first_element, $path);
    }
    else {
      array_unshift($theme_registry['node']['theme paths'], $path);
    }
  }
}

Mais ça ne marche pas. Cela signifie que le fichier themes / node - super.tpl.php n'est pas utilisé. Il n'est utilisé que si je l'ai copié dans le dossier du thème.


Clarification: je veux que Drupal recherche dans le répertoire des modules (et aussi dans les répertoires de thèmes) un modèle défini par du code (ici: modèle de nœud). Je ne veux pas définir de nouveau modèle.
jcisio

Réponses:


5

Fondamentalement, vous pouvez vous épargner un peu de maux de tête en implémentant hook_theme()au lieu de modifier le registre.

Je suggère de jeter un œil à theming_example dans le projet Exemples , reproduit à la main sur cette page de documentation API , peut-être avec du code particulièrement utile sur cette page .

function theming_example_list_page() {
  $items = array(
    t('First item'),
    t('Second item'),
    t('Third item'),
    t('Fourth item'),
  );

  // First we'll create a render array that simply uses theme_item_list.
  $title = t("A list returned to be rendered using theme('item_list')");
  $build['render_version'] = array(
    // We use #theme here instead of #theme_wrappers because theme_item_list()
    // is the classic type of theme function that does not just assume a
    // render array, but instead has its own properties (#type, #title, #items).
    '#theme' => 'item_list',
    // '#type' => 'ul',  // The default type is 'ul'
    // We can easily make sure that a css or js file is present using #attached. 
    '#attached' => array('css' => array(drupal_get_path('module', 'theming_example') . '/theming_example.css')), 
    '#title' => $title, 
    '#items' => $items, 
    '#attributes' => array('class' => array('render-version-list')),
  );

  // Now we'll create a render array which uses our own list formatter,
  // theme('theming_example_list').
  $title = t("The same list rendered by theme('theming_example_list')");
  $build['our_theme_function'] = array(
    '#theme' => 'theming_example_list', 
    '#attached' => array('css' => array(drupal_get_path('module', 'theming_example') . '/theming_example.css')), 
    '#title' => $title, 
    '#items' => $items,
  );
  return $build;
}

C'est tout pour Drupal 7.


Comme je l'ai dit dans la question, je ne veux pas utiliser hook_theme () parce que je veux réutiliser $ variables dans le modèle de noeud. Ces variables sont générées dans le processus hook_ (pre) de nombreux modules qui ne connaissent pas l'existence de mon thème (si j'en définis un).
jcisio

La façon dont vous définissez un thème est ... avec hook_theme (). :-) Vous pouvez définir des fonctions de thème dans hook_theme (). Nommez-les tout ce que vous voulez. Faites des fonctions de shim si vous le souhaitez. Documentation API: "hook_theme_HOOK () ... ne doit être utilisé que si un module doit remplacer ou ajouter au prétraitement de thème pour un hook de thème qu'il n'a pas défini."
paul-m

Je ne veux pas définir de thème. Si vous définissez votre thème 'mynode' au lieu de réutiliser 'node', vous n'avez aucune variable dans votre fichier .tpl.php.
jcisio

1
Cela ne semble pas vrai: les appels de thème sont cumulatifs, donc l'implémentation hook_themedevrait vous donner le $existingparamètre qui vous permet de modifier la chose, pas de la remplacer. Si ce n'est pas le cas, vous rencontrez peut-être un bug.
Countzero

@Countzero lorsque vous déclarez un thème node_attach, toutes les fonctions hook_preprocess_node ne se produiront pas avec votre nouveau thème. C'est-à-dire que vous n'avez rien dans votre node-attach.tpl.php.
jcisio

5

Peut-être que celui-ci fonctionne:

/**
 * Implements hook_theme().
 */
function MODULE_theme($existing, $type, $theme, $path) {
  return array (
    'node__CONTENTTYPE' => array (
      'variables' => array( . . . ),
      'template' => 'node--CONTENTTYPE' ,
      'base hook' => 'node',
      'path' => drupal_get_path('module', 'MODULE'),
    ),
  );
}

L'important ici est la clé « crochet de base ».


Voici le problème pour ajouter de la documentation pour base hook: drupal.org/node/2106635
Andy

+1 vote positif - cela et la réponse dérivée de batigotix que j'ai trouvé fonctionner. Merci.
therobyouknow

2

J'aime la solution de dashohoxha de l'implémentation hook_theme mais je n'ai pas pu la faire fonctionner. Après un peu de recherche sur Google, j'ai trouvé une variante qui fonctionnait bien pour moi:

/**
 * Implements hook_theme().
 */
function mymodule_theme($existing, $type, $theme, $path) {
  $theme = array();
  $theme['node__blog_post'] = array(
    'render element' => 'content',
    'base hook' => 'node',
    'template' => 'node--blog_post',
    'path' => drupal_get_path('module', 'mymodule') . '/templates',
   );
  return $theme;
}

Remarques: mon module personnalisé s'appelle 'mymodule' et mon type de contenu personnalisé s'appelle 'blog_post'. Le tpl.php que j'utilise s'appelle 'node - blog_post.tpl.php' et se trouve dans le sous-dossier 'templates' de mon module.


+1 merci, j'ai trouvé que cela fonctionnait. Si vous êtes également intéressé à remplacer les fonctions template.php dans votre module personnalisé, jetez un œil à: snugug.com/musings/override-theme-functions-drupal-7-module - J'ai trouvé que cela fonctionnait très bien
therobyouknow

2

Voici mon extrait pour déclarer les modèles de vues stockés dans le dossier "template" de mon "custom_module":

/**
 * Implements hook_theme_registry_alter().
 */
function custom_module_theme_registry_alter(&$theme_registry) {
  $extension   = '.tpl.php';
  $module_path = drupal_get_path('module', 'custom_module');
  $files       = file_scan_directory($module_path . '/templates', '/' . preg_quote($extension) . '$/');

  foreach ($files as $file) {
    $template = drupal_basename($file->filename, $extension);
    $theme    = str_replace('-', '_', $template);
    list($base_theme, $specific) = explode('__', $theme, 2);

    // Don't override base theme.
    if (!empty($specific) && isset($theme_registry[$base_theme])) {
      $theme_info = array(
        'template'   => $template,
        'path'       => drupal_dirname($file->uri),
        'variables'  => $theme_registry[$base_theme]['variables'],
        'base hook'  => $base_theme,
        // Other available value: theme_engine.
        'type'       => 'module',
        'theme path' => $module_path,
      );

      $theme_registry[$theme] = $theme_info;
    }
  }
}

J'espère que cela aide quelqu'un.


sauvé mon temps.
Fonctionne

-1

J'ai posé cette question une fois sur Stack Overflow . Fondamentalement, vous devez implémenter hook_theme_registry_alter()pour que votre chemin soit ajouté au chemin du modèle de hook de thème; puis, le hook_enable(), vous appelez drupal_theme_rebuild () pour effacer le cache du registre de thème et obtenir votre chemin analysé pour les modèles.


Peut-être que ce qui vous retient est simplement de vider les caches.
Capi Etheriel

Donc, fondamentalement, la même solution. J'ai essayé "drush cc all" pas moins de 50 fois, je l'ai testé sur un nouveau site d'installation, etc. sans succès. Je vais modifier et compacter mon code en un module minimal pour que tout le monde puisse tester.
jcisio

hook_enable()est invoqué lorsqu'un module est activé; si le module est déjà activé, il doit être désactivé, puis réactivé.
kiamlaluno

@kiamlaluno: si j'utilise hook_enable pour effacer les caches, s'il est déjà installé, l'utilisateur peut simplement effacer les caches manuellement.
Capi Etheriel

NON , -1 points. Cette solution est tellement ancienne (2009), je ne suis même pas sûr qu'elle était destinée au D7. Bien que votre ancienne solution soit adaptée aux vues, elle n'est pas idéale pour les situations autres que les vues où les développeurs peuvent vouloir regrouper plus d'un modèle par défaut par clé de thème dans leurs modules. Imaginez mettre en œuvre votre solution pour 100 suggestions de thèmes dynamiques pour une seule clé de thème. Appliqué en dehors d'un contexte de vues, j'appellerais votre solution un contre-modèle.
barista amateur
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.