¿Cómo decirle a Drupal que busque plantillas en el directorio del módulo?

11

Me gustaría proporcionar una implementación de plantilla en mi módulo y permitir que los temas la anulen. Básicamente, agrego una sugerencia por este código simplificado:

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

(No quiero usar hook_theme para agregar un nuevo tema porque quiero reutilizar las funciones de nodo de preproceso. El nombre del tema es incómodo pero no quiero escribir node_ attach _% para evitar confusiones con el tipo de nodo).

Luego uso hook_theme_registry_alter () para agregar la ruta del módulo:

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);
    }
  }
}

Sin embargo, no funciona. Eso significa: el archivo themes / node - super.tpl.php no se usa. Solo se usa si lo copié en la carpeta de temas.

jcisio
fuente
Aclaración: Quiero que Drupal busque en el directorio del módulo (y también en los directorios del tema) una plantilla definida por código (aquí: plantilla de nodo). No quiero definir una nueva plantilla.
jcisio

Respuestas:

5

Básicamente, puede ahorrarse un poco de dolor de cabeza implementando en hook_theme()lugar de alterar el registro.

Sugiero echar un vistazo a theming_example en el proyecto de ejemplos , reproducido fácilmente en esta página de documentación API , quizás con un código especialmente útil en esta página .

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;
}

Todo esto es para Drupal 7.

paul-m
fuente
Como dije en la pregunta, no quiero usar hook_theme () porque quiero reutilizar $ variables en la plantilla de nodo. Esas variables se generan en el proceso hook_ (pre) de muchos módulos que no conocen la existencia de mi tema (si defino uno).
jcisio
La forma en que define un tema es ... con hook_theme (). :-) Puede definir funciones de tema en hook_theme (). Nómbralos como quieras. Realice funciones de calce si lo desea. Documentos de la API: "hook_theme_HOOK () ... solo debe usarse si un módulo necesita anular o agregar al preprocesamiento del tema para un enlace de tema que no definió".
Paul-m
No quiero definir un tema. Si define su tema 'mynode' en lugar de reutilizar 'node', no tiene ninguna variable en su archivo .tpl.php.
jcisio
1
Esto no parece cierto: las llamadas de tema son acumulativas, por lo que la implementación hook_themedebería darle el $existingparámetro que le permite modificar la cosa, no anularla. Si no es el caso, entonces tal vez estás golpeando un error.
Countzero
@Countzero cuando declaras un tema node_attach, entonces todas las funciones hook_preprocess_node no sucederán con tu nuevo tema. Es decir, no tiene nada en su nodo-attach.tpl.php.
jcisio
5

Quizás este funcione:

/**
 * 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'),
    ),
  );
}

Importante aquí es la clave ' gancho base '.

dashohoxha
fuente
Aquí está el problema para agregar documentación para base hook: drupal.org/node/2106635
Andy
Voto a favor +1: esto y la respuesta derivada de batigotix que encontré que funciona. Gracias.
therobyouknow
2

Me gusta la solución de dashohoxha de la implementación hook_theme pero no pude hacer que funcione. Después de buscar más en Google, encontré una variación que me funcionó bien :

/**
 * 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;
}

Notas: mi módulo personalizado se llama 'mymodule' y mi tipo de contenido personalizado se llama 'blog_post'. El tpl.php que uso se llama 'node - blog_post.tpl.php' y se encuentra en la subcarpeta 'templates' de mi módulo.

batigolix
fuente
+1 gracias, encontré que esto funcionaba. Si también está interesado en anular las funciones de template.php dentro de su módulo personalizado, eche un vistazo a: snugug.com/musings/override-theme-functions-drupal-7-module - Descubrí que esto funciona muy bien
therobyouknow
2

Aquí está mi fragmento para declarar plantillas de vistas almacenadas en la carpeta "plantilla" de mi "módulo_personalizado":

/**
 * 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;
    }
  }
}

Espero que ayude a alguien.

Sebastien M.
fuente
me salvó el tiempo También funciona y se requiere para d8
Mykola Mykolayovich Dolynskyi
-1

Pregunté esto una vez en Stack Overflow . Básicamente, debe implementar hook_theme_registry_alter()para agregar su ruta a la ruta de la plantilla de enlace de tema; luego, en hook_enable(), llama a drupal_theme_rebuild () para borrar el caché del registro de temas y escanear tu ruta en busca de plantillas.

Capi Etheriel
fuente
Tal vez lo que te está frenando es simplemente limpiar los cachés.
Capi Etheriel
Entonces, básicamente la misma solución. Probé "drush cc all" no menos de 50 veces, lo probé en un nuevo sitio de instalación, etc. sin éxito. Modificaré y compactaré mi código en un módulo mínimo para que todos puedan probarlo.
jcisio
hook_enable()se invoca cuando un módulo está habilitado; si el módulo ya está habilitado, debe deshabilitarse y luego habilitarse nuevamente.
kiamlaluno
@kiamlaluno: iḿ usando hook_enable para borrar los cachés, si ya está instalado, el usuario podría borrar los cachés manualmente.
Capi Etheriel
NO , -1 puntos. Esa solución es tan antigua (2009) que ni siquiera estoy seguro de que fuera para D7. Si bien su solución anterior está diseñada para Vistas, no es ideal para situaciones que no sean Vistas en las que los desarrolladores quieran empaquetar para más de 1 plantilla predeterminada por clave de tema en sus módulos. Imagine implementar su solución para 100 sugerencias de temas dinámicos para una sola clave de tema. Aplicado fuera de un contexto de Vistas, llamaría a su solución un contra-patrón.
barista aficionado