Função de pré-processamento por tipo de conteúdo

25

Eu tenho alguns tipos de conteúdo que eu preciso pré-processar de diferentes maneiras. Então, template.phpno meu tema, fooatualmente se parece com:

function foo_preprocess_node(&$variables) {
    if ('news' ==$variables['type']) _preprocess_news($variables);
    if ('event'==$variables['type']) _preprocess_event($variables);
    if ('alert'==$variables['type']) _preprocess_alert($variables);
    ...
}

function _preprocess_news(&$variables) {
    ...
}

function _preprocess_event(&$variables) {
    ...
}

function _preprocess_alert(&$variables) {
    ...
}

Eu gostaria de poder especificar uma função de pré-processo específica do Drupal que seria conectada ao nome da máquina do tipo de conteúdo. Eu tentei usar, foo_preprocess_newsmas nunca é chamado.

Existe uma maneira melhor?

cherouvim
fonte

Respostas:

10

O nome da função de pré-processo é baseado no nome do tema, portanto, para theme_table()sua função de pré-processo MYTHEME_preprocess_table().

Como não há theme_node_node_typefunção, um gancho de pré-processo como foo_preprocess_newsou foo_preprocess_node_newsnão funciona imediatamente .

Você pode substituir o registro do tema para que ele se comporte de maneira diferente nos nós, mas eu realmente não o recomendaria; pode ficar muito bagunçado.

Sou um grande fã de código de refatoração, mas no seu caso não acho necessário; se você possui uma lógica complexa que precisa ser executada em seu gancho de pré-processo, dependendo do tipo de nó, cultivá-la em diferentes funções da maneira que você está fazendo atualmente me parece uma boa prática.

O outro método, é claro, seria implementar um módulo personalizado para cada um dos diferentes tipos de conteúdo e implementar hook_preprocess_node()em cada um. Dessa forma, a função de pré-processo de cada módulo pode ser responsável por um tipo de conteúdo diferente.

No entanto, isso pode ser um exagero para a sua situação; se você não tiver uma lógica extra (ou seja, lógica de pré-processo sem tema) para executar em cada tipo de conteúdo, esse método provavelmente não adicionará nenhum valor extra.

Clive
fonte
11
ESTÁ BEM. Eu também poderia "automatizar" o foo_preprocess_nodeimplementando-o call_user_func('_preprocess_' . $vars['type'], $vars);para evitar repetir os ifs, mas provavelmente é melhor permanecer simples.
cherouvim
Eu implementei hook_preprocess_node()em um módulo personalizado e esperava que isso restringisse quando o gancho for chamado, mas não. Alguma maneira de restringir quando o gancho é chamado por tipo de conteúdo?
Keven
@Keven Você não pode pará-lo a ser invocado se a função existir, mas if ($vars['node']->type == 'foo') { ...vai conseguir o efeito que você está procurando
Clive
Na verdade, estou apenas procurando pequenas otimizações, semelhantes às que você pode fazer hook_block_view_MODULE_DELTA_alter(). Atualmente, faço o que você diz, mas gostaria que houvesse uma maneira de restringir quando o gancho é atingido.
Keven
Embora não fosse uma otimização, @Keven - você apenas mudaria o processo de tomada de decisão para outra parte do código. De fato, se o Drupal oferecesse essa substituição, ele precisaria ser genérico e levaria quase certamente mais tempo do processador para ser realizado. Você já está ganhando apenas tomando a decisão no último momento
Clive
28

O subtema zen realiza isso adicionando isso à sua função theme_preprocess_node:

function foo_preprocess_node(&$variables, $hook) {
  ...
    // Optionally, run node-type-specific preprocess functions, like
  // foo_preprocess_node_page() or foo_preprocess_node_story().
  $function = __FUNCTION__ . '_' . $variables['node']->type;
  if (function_exists($function)) {
    $function($variables, $hook);
  } 
  ...
}

Se você tiver um tipo de conteúdo chamado 'news', poderá criar uma função chamada foo_preprocess_node_news no seu arquivo template.php.

Evil E
fonte
Também usamos isso na fundação ZURB com nosso próprio trecho de código muito útil, de impelementação.
Marko Blazekovic
2

Eu só tive um problema semelhante e é por isso que o google me trouxe a esta página: minha função de pré-processo de nó estava crescendo tão enormemente, que eu preferia dividir a função em vários arquivos.

Eu já fiz uma abordagem semelhante no meu arquivo template.php que contém todas as funções alter e, como o mesmo método funciona perfeitamente bem aqui, pensei em compartilhar minha abordagem:

configuração do arquivo dentro da pasta MYTHEME/preprocess:

- node.preprocess.inc
- node--blog-post.preprocess.inc
- node--device-variation.preprocess.inc
- (...)

você já deveria ter node.preprocess.inc, os outros que você pode criar a si mesmo. como você os chama realmente é bastante arbitrário, mas é melhor dar nomes que os identifiquem bem e que se ajustem a todo o sistema de nomes drupal.
em diante para o conteúdo desses arquivos!

node.preprocess.inc, aqui estou fazendo algo parecido com isto:

<?php

function MYTHEME_preprocess_node(&$variables) {

    switch($variables['type']) {

      case 'blog_post':
        // if the type of the node is a Blog Post, include this:
        include 'node--blog-post.preprocess.inc';
        break;

      case 'device_variation':
        // if Device Variation, include this:
        include 'node--device-variation.preprocess.inc';
        break;

      case 'foo':
        // ...
        break;
    }

    // additional stuff for all nodes

}

Basicamente, alternamos o tipo do nó atual. o que você muda depende de você; #id, #view_modetudo dependendo das suas necessidades exatas.
quando houver uma correspondência, ele carregará o arquivo especificado e atuará sobre seu conteúdo, como se tivesse sido escrito exatamente dentro desta função.

o conteúdo desses includedarquivos se parece exatamente com o que você colocaria no node.preprocess.incarquivo, exceto que não chamamos a função de pré-processo novamente:

node--device-variation.preprocess.inc

<?php

    // Device Name
    $device = drupal_clean_css_identifier(strtolower($variables['title']));

    // Determine whether only Device Version is of type 'N/A' and set ppvHasVariations accordingly
    $deviceHasVariations = true;
    if( $variables['content']['product:field_model_variation'][0]['#options']['entity']->weight == 0 ) {
        $deviceHasVariations = false;
    }
    //...

você pode basicamente fazer isso com quantos arquivos quiser e até mesmo alternar vários switches, por exemplo, dividindo ainda mais arquivos de pré-processamento de nós específicos, dependendo de #view_mode, ter um arquivo para o fullmodo de exibição e outro para oteaser

espero que isso ajude, se alguém voltar a tropeçar nessa pergunta (:

Bird-Kid
fonte
1

call_user_func()não passa parâmetros por referência. Portanto, no caso de $variablessuas preprocess_foo()funções funcionarem apenas em cópias da matriz original; alterações em objetos não serão aplicadas durante o processo de renderização restante.

kishkash
fonte
1

Em seu hook_preprocess_node principal, implemente o código a seguir no final

$preprocess_function = 'themename_node__' . $node->type . '__preprocess';
if (function_exists($preprocess_function)) {
 $preprocess_function($variables);
}

Agora você teria pré-processado por tipo de nó

Ziftman
fonte