Jak powiedzieć Drupalowi, aby szukał szablonów w katalogu modułów?


11

Chciałbym zapewnić implementację szablonu w moim module i pozwolić motywom na zastąpienie go. Zasadniczo dodaję sugestię za pomocą tego uproszczonego kodu:

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

(Nie chcę używać hook_theme do dodawania nowego motywu, ponieważ chcę ponownie użyć funkcji węzła preprocesowania. Nazwa motywu jest niezręczna, ale nie chcę pisać node_ attach _%, aby uniknąć pomyłki z typem węzła).

Następnie używam hook_theme_registry_alter (), aby dodać ścieżkę modułu:

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

Jednak to nie działa. To znaczy: plik themes / node - super.tpl.php nie jest używany. Jest używany tylko wtedy, gdy skopiowałem go do folderu motywu.


Wyjaśnienie: Chcę, aby Drupal szukał w katalogu modułów (a także w katalogach motywów) szablonu zdefiniowanego przez kod (tutaj: szablon węzła). Nie chcę definiować nowego szablonu.
— jcisio

Odpowiedzi:


5

Zasadniczo możesz zaoszczędzić sobie trochę bólu głowy, wdrażając hook_theme()zamiast modyfikować rejestr.

Proponuję rzucić okiem na theming_example w projekcie przykładów , ręcznie odtworzonym na tej stronie dokumentu API , być może ze szczególnie pomocnym kodem na tej stronie .

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

To wszystko dotyczy Drupala 7.


Jak powiedziałem w pytaniu, nie chcę używać hook_theme (), ponieważ chcę ponownie użyć zmiennych $ w szablonie węzła. Te zmienne są generowane w procesie hook_ (pre) wielu modułów, które nie wiedzą o istnieniu mojego motywu (jeśli go zdefiniuję).
— jcisio

Sposób definiowania motywu jest ... za pomocą hook_theme (). :-) Możesz zdefiniować funkcje tematyczne w hook_theme (). Nazwij je, jak chcesz. Wykonuj funkcje podkładek, jeśli chcesz. Dokumenty API: „hook_theme_HOOK () ... należy używać tylko wtedy, gdy moduł musi przesłonić lub dodać do wstępnego przetwarzania kompozycji dla haka motywu, którego nie zdefiniował”.
— paul-m

Nie chcę definiować motywu. Jeśli zdefiniujesz „mynode” motywu zamiast ponownie używać „węzła”, w pliku .tpl.php nie będzie żadnych zmiennych.
— jcisio

1
To nie wydaje się prawdą: wywołania tematyczne są kumulatywne, więc implementacja hook_themepowinna dać ci $existingparametr, który pozwala modyfikować rzecz, a nie przesłonić ją. Jeśli tak nie jest, być może trafiłeś w błąd.
— Countzero

@Countzero podczas deklarowania kompozycji node_attach, wówczas wszystkie funkcje hook_preprocess_node nie będą działać z nowym motywem. Tzn. Nie masz nic w swoim węźle-attach.tpl.php.
— jcisio

5

Może ten działa:

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

Ważne jest tutaj kluczowe „ hak podstawowy ”.


Oto problem z dodaniem dokumentacji dla base hook: drupal.org/node/2106635
— Andy

+1 upvote - ta i pochodna odpowiedź z batigotix, które znalazłem, by działać. Dzięki.
— therobyouknow

2

Lubię rozwiązanie dashohoxha implementacji hook_theme, ale nie udało mi się go uruchomić. Po kilku kolejnych googlingach znalazłem odmianę, która działała dla mnie dobrze:

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

Uwagi: mój niestandardowy moduł nazywa się „mymoduł”, a mój niestandardowy typ zawartości to „blog_post”. Używany przeze mnie tpl.php nazywa się „node - blog_post.tpl.php” i znajduje się w podfolderze „templates” mojego modułu.


+1 dzięki znalazłem, że to działa. Jeśli chcesz również zastąpić funkcje template.php w swoim module niestandardowym, spójrz na: snugug.com/musings/override-theme-functions-drupal-7-module - Przekonałem się, że to działa bardzo dobrze
— therobyouknow

2

Oto mój fragment kodu do deklarowania szablonów widoków przechowywanych w folderze „template” mojego „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;
    }
  }
}

Mam nadzieję, że to komuś pomoże.


oszczędził mi czas. Działa również i wymagane dla d8
— Mykoła Mikołajowicz Dolynskyi

-1

Zapytałem o to raz na Stack Overflow . Zasadniczo musisz wdrożyć, hook_theme_registry_alter()aby dodać ścieżkę do ścieżki szablonu zaczepu motywu; następnie hook_enable()wywołujesz drupal_theme_rebuild (), aby wyczyścić pamięć podręczną rejestru motywów i przeskanować ścieżkę w poszukiwaniu szablonów.


Może to, co Cię powstrzymuje, to po prostu czyszczenie pamięci podręcznej.
— Capi Etheriel

Zasadniczo to samo rozwiązanie. Próbowałem „drush cc all” nie mniej niż 50 razy, bez powodzenia przetestowałem go na nowej stronie instalacyjnej itp. Zmodyfikuję i skompresuję mój kod do minimalnego modułu, aby każdy mógł go przetestować.
— jcisio

hook_enable()jest wywoływany, gdy moduł jest włączony; jeśli moduł jest już włączony, należy go wyłączyć, a następnie włączyć ponownie.
— kiamlaluno

@kiamlaluno: iḿ używam hook_enable do czyszczenia pamięci podręcznej, jeśli jest już zainstalowany, użytkownik może po prostu wyczyścić pamięć podręczną ręcznie.
— Capi Etheriel

NIE , -1 punktów. To rozwiązanie jest tak stare (2009), że nawet nie jestem pewien, czy było przeznaczone dla D7. Chociaż stare rozwiązanie jest dostosowane do widoków, nie jest idealne w sytuacjach innych niż widoki, w których programiści mogą chcieć spakować więcej niż 1 szablon domyślny na klucz motywu w swoich modułach. Wyobraź sobie wdrożenie swojego rozwiązania dla 100 sugestii dynamicznych motywów dla jednego klucza motywu. Zastosowany poza kontekstem Widoków nazwałbym twoje rozwiązanie kontr-wzorem.
— amator barista
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.