Como dizer ao Drupal para procurar modelos no diretório de módulos?

11

Eu gostaria de fornecer a implementação de modelo no meu módulo e permitir que os temas o substituam. Basicamente, adiciono uma sugestão por este código simplificado:

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

(Não quero usar hook_theme para adicionar um novo tema, pois quero reutilizar as funções do nó de pré-processamento. O nome do tema é estranho, mas não quero escrever node_ attach _% para evitar confusão com o tipo de nó.)

Então eu uso hook_theme_registry_alter () para adicionar o caminho do 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);
    }
  }
}

No entanto, isso não funciona. Isso significa: o arquivo themes / node - super.tpl.php não é usado. Ele é usado apenas se eu o tiver copiado para a pasta do tema.

jcisio
fonte
Esclarecimento: Quero que o Drupal procure no diretório de módulos (e também nos diretórios de temas) um modelo definido pelo código (aqui: modelo de nó). Não quero definir um novo modelo.
jcisio

Respostas:

5

Basicamente, você pode economizar um pouco de dor de cabeça implementando em hook_theme()vez de alterar o registro.

Sugiro dar uma olhada em theming_example no projeto Examples , reproduzido com facilidade nesta página de documento da API , talvez com um código especialmente útil nesta 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;
}

Isso é tudo para o Drupal 7.

paul-m
fonte
Como eu disse na pergunta, não quero usar hook_theme () porque quero reutilizar variáveis ​​$ no modelo de nó. Essas variáveis ​​são geradas no processo hook_ (pré) de muitos módulos que não conhecem a existência do meu tema (se eu definir um).
jcisio
A maneira como você define um tema é ... com hook_theme (). :-) Você pode definir funções de temas em hook_theme (). Nomeie-os como quiser. Faça funções de calço, se quiser. Documentos da API: "hook_theme_HOOK () ... só deve ser usado se um módulo precisar substituir ou adicionar ao pré-processamento do tema para um gancho de tema que ele não definiu."
paul-m
Não quero definir um tema. Se você definir seu tema 'mynode' em vez de reutilizar 'node', não terá nenhuma variável no seu arquivo .tpl.php.
jcisio
1
Isso não parece verdadeiro: as chamadas de tema são cumulativas; portanto, a implementação hook_themedeve fornecer o $existingparâmetro que permite modificar a coisa, sem substituí-la. Se não for o caso, talvez você esteja atingindo um bug.
Countzero 23/03
@Countzero quando você declara um tema node_attach, todas as funções hook_preprocess_node não acontecerão com o seu novo tema. Ou seja, você não tem nada no seu node-attach.tpl.php.
jcisio
5

Talvez 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 aqui é a chave ' gancho de base '.

dashohoxha
fonte
Aqui está o problema para adicionar documentação para base hook: drupal.org/node/2106635
Andy
+1 voto positivo - esta e a resposta derivada do batigotix que encontrei para trabalhar. Obrigado.
Therobyouknow 13/11/2015
2

Eu gosto da solução dashohoxha da implementação hook_theme, mas não consegui fazê-la funcionar. Depois de pesquisar mais, encontrei uma variação que funcionou bem para mim:

/**
 * 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: meu módulo personalizado é chamado 'mymodule' e meu tipo de conteúdo personalizado é chamado 'blog_post'. O tpl.php que eu uso é chamado 'node - blog_post.tpl.php' e está localizado na subpasta 'templates' do meu módulo.

batigolix
fonte
+1 graças, achei que funcionasse. Se você também estiver interessado em substituir as funções template.php dentro de seu módulo personalizado, dê uma olhada em: snugug.com/musings/override-theme-functions-drupal-7-module - Eu achei que isso funcionava muito bem
therobyouknow
2

Aqui está meu snippet para declarar os modelos de visualizações armazenados na pasta "template" do meu "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;
    }
  }
}

Espero que ajude alguém.

Sebastien M.
fonte
economizei meu tempo. Também funciona e é necessário para o d8
Mykola Mykolayovich Dolynskyi
-1

Eu perguntei isso uma vez no Stack Overflow . Basicamente, você precisa implementar hook_theme_registry_alter()para adicionar seu caminho ao caminho do modelo de gancho do tema; em seguida, hook_enable()chame drupal_theme_rebuild () para limpar o cache do registro do tema e verificar o caminho para encontrar modelos.

Capi Etheriel
fonte
Talvez o que está te impedindo seja apenas limpar os caches.
Capi Etheriel 22/03/12
Então, basicamente a mesma solução. Eu tentei "drush cc all" não menos de 50 vezes, testei-o em um novo site de instalação etc. sem sucesso. Modificarei e compactarei meu código em um módulo mínimo para que todos possam testar.
jcisio
hook_enable()é chamado quando um módulo está ativado; se o módulo já estiver ativado, ele deverá ser desativado e, em seguida, ativado novamente.
kiamlaluno
@kiamlaluno: usando hook_enable para limpar os caches, se já estiver instalado, o usuário poderá limpá-los manualmente.
Capi Etheriel 29/03/12
NÃO , -1 pontos. Essa solução é tão antiga (2009) que nem tenho certeza de que ela foi criada para o D7. Embora sua solução antiga seja personalizada para Views, ela não é ideal para situações que não sejam Views, onde os desenvolvedores podem querer compactar para mais de 1 modelo padrão por chave de tema em seus módulos. Imagine implementar sua solução para 100 sugestões de temas dinâmicos para uma única chave de tema. Aplicado fora do contexto do Views, eu chamaria sua solução de contra-padrão.
Barista amador 2/14