Función de preproceso por tipo de contenido

25

Tengo un par de tipos de contenido que necesito preprocesar de diferentes maneras. Entonces template.phpen mi tema fooactualmente se ve así:

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) {
    ...
}

Me gustaría poder especificar una función de preproceso específica de Drupal que enganche el nombre de la máquina del tipo de contenido. Intenté usarlo foo_preprocess_newspero nunca se llama.

¿Hay una mejor manera?

cherouvim
fuente

Respuestas:

10

El nombre de la función de preproceso se basa en el nombre del tema, por lo que theme_table()su función de preproceso es MYTHEME_preprocess_table().

Dado que no hay ninguna theme_node_node_typefunción, un gancho de preproceso como foo_preprocess_newso foo_preprocess_node_newsno funcionará de la caja.

Usted podría ir sobre anular el registro de temas para que se comporte de manera diferente para los nodos, pero realmente no lo recomendaría; Podría ponerse muy desordenado.

Soy un gran fanático de la refactorización de código, pero en su caso no creo que sea necesario; si tiene una lógica compleja que necesita ejecutarse en su gancho de preproceso dependiendo del tipo de nodo, entonces desarrollarlo para diferentes funciones en la forma en que lo hace actualmente me parece una buena práctica.

El otro método, por supuesto, sería implementar un módulo personalizado para cada uno de los diferentes tipos de contenido e implementar hook_preprocess_node()en cada uno. De esa forma, la función de preproceso de cada módulo puede ser responsable de un tipo de contenido diferente.

Sin embargo, esto puede ser excesivo para su situación; Si no tiene lógica adicional (es decir, lógica de preproceso sin tema) para realizar en cada tipo de contenido, entonces este método probablemente no agregue ningún valor adicional.

Clive
fuente
1
OKAY. También podría "automatizar" al foo_preprocess_nodeimplementarlo call_user_func('_preprocess_' . $vars['type'], $vars);para evitar repetir los ifs, pero probablemente sea mejor mantenerse simple.
cherouvim
Implementé hook_preprocess_node()en un módulo personalizado, y esperaba que eso restringiría cuando se llama al gancho, pero no lo hace. ¿Alguna forma de restringir cuándo se llama al gancho por tipo de contenido?
Keven
@Keven No puedes evitar que se invoque si la función existe, pero lograrás if ($vars['node']->type == 'foo') { ...el efecto que estás buscando
Clive
Realmente solo estoy buscando ligeras optimizaciones, similares a las que puedes hacer hook_block_view_MODULE_DELTA_alter(). Actualmente hago lo que dices, pero desearía que hubiera una manera de restringir cuando se golpea el gancho.
Keven
Sin embargo, no sería una optimización @Keven: simplemente estaría cambiando el proceso de toma de decisiones a otra parte del código. De hecho, si Drupal ofreciera dicha anulación, tendría que ser genérica, y casi seguramente tomaría más tiempo de procesador para lograrla. Ya estás ganando al tomar la decisión en el último momento
Clive
28

El subtema zen logra esto agregando esto a su función 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);
  } 
  ...
}

Si tiene un tipo de contenido llamado 'noticias', podrá crear una función llamada foo_preprocess_node_news en su archivo template.php.

E malvado
fuente
También usamos esto en la base ZURB con nuestra propia impelementación, fragmento de código muy útil.
Marko Blazekovic
2

Acabo de tener un problema similar , por eso Google me trajo a esta página: mi función de preproceso de nodo estaba creciendo tan enormemente que preferiría dividir la función en varios archivos.

Ya hice un enfoque similar en mi archivo template.php que contiene todas las funciones alter, y dado que el mismo método funciona perfectamente bien aquí, pensé en compartir mi enfoque:

configuración de archivo dentro de la carpeta MYTHEME/preprocess:

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

ya deberías tener node.preprocess.inclos otros que puedes crear tú mismo. cómo los llamas realmente es bastante arbitrario, pero mejor dales nombres que los identifiquen bien y se ajusten a todo el sistema de nombres de drupal.
en adelante al contenido de estos archivos!

node.preprocess.inc, aquí estoy haciendo algo como esto:

<?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

}

básicamente cambiamos por el tipo del nodo actual. lo que cambies depende de ti; #id, #view_modetodo dependiendo de sus necesidades exactas.
una vez que haya una coincidencia, cargará el archivo especificado y actuará sobre su contenido como si estuviera escrito dentro de esta función.

el contenido de estos includedarchivos se ve exactamente como lo pondría en el node.preprocess.incarchivo, excepto que no llamamos a la función de preproceso nuevamente:

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

Básicamente, puede hacer esto con tantos archivos como desee e incluso conectar en cascada múltiples conmutadores, por ejemplo, dividir aún más archivos de preprocesos de nodos específicos dependiendo de #view_mode, tener un archivo para el fullmodo de vista y otro para elteaser

Espero que esto ayude, si alguien alguna vez tropieza con esta pregunta nuevamente (:

Bird-Kid
fuente
1

call_user_func()no pasa parámetros por referencia. Entonces, en caso de que $variablessus preprocess_foo()funciones funcionen solo en copias de la matriz original; Los cambios en objetos que no sean objetos no se aplicarán durante el proceso de representación restante.

kishkash
fuente
1

En su hook_preprocess_node principal Implemente el siguiente código al final

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

Entonces ahora tendría que preprocesar por tipo de nodo

Ziftman
fuente