Как сказать Drupal искать шаблоны в каталоге модулей?

11

Я хотел бы обеспечить реализацию шаблона в моем модуле и позволить темам переопределить его. По сути, я добавляю предложение с помощью этого упрощенного кода:

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

(Я не хочу использовать hook_theme , чтобы добавить новую тему , потому что я хочу , чтобы повторно использовать Preprocess функции узла. Название темы громоздки , но я не хочу писать node_ присоединять _% , чтобы избежать путаницы с типом узла.)

Затем я использую hook_theme_registry_alter (), чтобы добавить путь к модулю:

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

Однако это не работает. Это означает: файл themes / node - super.tpl.php не используется. Он используется только если я скопировал его в папку темы.

jcisio
источник
Пояснение: я хочу, чтобы Drupal посмотрел в каталоге модулей (а также в каталогах тем) шаблон, определенный кодом (здесь: шаблон узла). Я не хочу определять новый шаблон.
jcisio

Ответы:

5

По сути, вы можете избавить себя от головной боли, внедрив hook_theme()вместо изменения реестра.

Я предлагаю взглянуть на theming_example в проекте « Примеры» , который легко воспроизвести на этой странице документации API , возможно, с особенно полезным кодом на этой странице .

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

Это все для Drupal 7.

Поль-м
источник
Как я уже сказал в этом вопросе, я не хочу использовать hook_theme (), потому что я хочу повторно использовать переменные $ в шаблоне узла. Эти переменные генерируются в процессе hook_ (pre) многих модулей, которые не знают о существовании моей темы (если я ее определю).
jcisio
Вы определяете тему ... с помощью hook_theme (). :-) Вы можете определить тематические функции в hook_theme (). Назовите их как хотите. Сделайте функции подкладки, если хотите. Документы API: «hook_theme_HOOK () ... следует использовать, только если модуль должен переопределить или добавить к предварительной обработке темы для ловушки темы, которую он не определил».
Paul-M
Я не хочу определять тему. Если вы определите свою тему «mynode» вместо повторного использования «node», в вашем файле .tpl.php не будет никакой переменной.
jcisio
1
Это не похоже на правду: вызовы тем являются кумулятивными, поэтому реализация hook_themeдолжна дать вам $existingпараметр, который позволяет вам изменять объект, не переопределяя его. Если это не так, то, возможно, вы попали в ошибку.
Countzero
@Countzero, когда вы объявляете тему node_attach, тогда все функции hook_preprocess_node не будут работать с вашей новой темой. Т.е. у вас ничего нет в вашем node-attach.tpl.php.
jcisio
5

Может быть, это работает:

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

Важным здесь является ключ « базовый крюк ».

dashohoxha
источник
Вот проблема добавления документации для base hook: drupal.org/node/2106635
Энди
+1 upvote - это и производный ответ от batigotix, который я нашел для работы. Спасибо.
therobyouknow
2

Мне нравится решение dashohoxha по реализации hook_theme, но я не смог заставить его работать. После еще одного поиска в Google я нашел вариант, который работал хорошо для меня:

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

Примечания: мой пользовательский модуль называется «mymodule», а мой пользовательский тип контента называется «blog_post». Используемый мной tpl.php называется «node - blog_post.tpl.php» и находится в подпапке «templates» моего модуля.

batigolix
источник
+1 спасибо я нашел это на работу. Если вы также заинтересованы в переопределении функций template.php внутри вашего пользовательского модуля, взгляните на: snugug.com/musings/override-theme-functions-drupal-7-module - я обнаружил, что это работает очень хорошо
therobyouknow
2

Вот мой фрагмент для объявления шаблонов представлений, хранящихся в папке «template» моего «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;
    }
  }
}

Надеюсь, это поможет кому-то.

Себастьян М.
источник
сэкономил мое время. Также работает и требуется для d8
Николай Николаевич Долинский
-1

Я спросил это однажды на переполнении стека . По сути, вы должны реализовать, hook_theme_registry_alter()чтобы ваш путь был добавлен к пути шаблона ловушки темы; затем hook_enable()вы вызываете drupal_theme_rebuild (), чтобы очистить кэш реестра тем и просканировать ваш путь на наличие шаблонов.

Capi Etheriel
источник
Может быть, то, что вас сдерживает, это просто очистка кешей.
Capi Etheriel
Итак, в основном то же решение. Я пробовал "drush cc all" не менее 50 раз, безуспешно тестировал его на новом месте установки и т. Д. Я изменю и сожму свой код в минимальный модуль, чтобы каждый мог тестировать.
jcisio
hook_enable()вызывается, когда модуль включен; если модуль уже включен, его необходимо отключить, а затем снова включить.
kiamlaluno
@kiamlaluno: я использую hook_enable для очистки кешей, если он уже установлен, пользователь может просто очистить кеши вручную.
Capi Etheriel
НЕТ , -1 балл. Это решение настолько старое (2009), что я даже не уверен, что оно предназначено для D7. Хотя ваше старое решение разработано специально для представлений, оно не идеально для ситуаций, не связанных с представлениями, когда разработчики могут захотеть упаковать более одного шаблона по умолчанию на ключ темы в своих модулях. Представьте себе, что вы реализуете свое решение для 100 предложений динамических тем для одного ключа темы. Применяемый вне контекста Views, я бы назвал ваше решение контр-шаблоном.
бариста-любитель