Fonction de prétraitement par type de contenu

25

J'ai quelques types de contenu que je dois prétraiter de différentes manières. Donc, template.phpdans mon thème fooressemble actuellement à:

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

Je voudrais pouvoir spécifier une fonction de prétraitement spécifique à Drupal qui accrocherait le nom de machine du type de contenu. J'ai essayé d'utiliser foo_preprocess_newsmais on ne l'appelle jamais.

Y a-t-il une meilleure façon?

cherouvim
la source

Réponses:

10

Le nom de la fonction de prétraitement est basé sur le nom du thème, donc pour theme_table()votre fonction de prétraitement est MYTHEME_preprocess_table().

Puisqu'il n'y a pas de theme_node_node_typefonction, un crochet de prétraitement tel que foo_preprocess_newsou foo_preprocess_node_newsne fonctionnera pas hors de la boîte.

Vous pouvez remplacer le registre de thèmes afin qu'il se comporte différemment pour les nœuds, mais je ne le recommanderais vraiment pas; cela pourrait devenir très salissant.

Je suis un grand fan de refactoring de code mais dans votre cas, je ne pense pas que ce soit nécessaire; si vous avez une logique complexe qui doit être exécutée dans votre hook de pré-traitement en fonction du type de nœud, alors le transformer en différentes fonctions de la manière que vous faites actuellement me semble une bonne pratique.

L'autre méthode, bien sûr, serait d'implémenter un module personnalisé pour chacun des différents types de contenu et de l'implémenter hook_preprocess_node()dans chacun. De cette façon, la fonction de prétraitement de chaque module peut être responsable d'un type de contenu différent.

Cependant, cela peut être exagéré pour votre situation; si vous n'avez pas de logique supplémentaire (c'est-à-dire une logique de prétraitement sans thème) à effectuer sur chaque type de contenu, cette méthode n'ajoute probablement aucune valeur supplémentaire.

Clive
la source
1
D'ACCORD. Je pourrais aussi "automatiser" le foo_preprocess_nodeen l'implémentant comme call_user_func('_preprocess_' . $vars['type'], $vars);pour éviter de répéter les ifs mais il vaut probablement mieux rester simple.
cherouvim
J'ai implémenté hook_preprocess_node()un module personnalisé et j'espérais que cela restreindrait le moment où le hook serait appelé, mais ce n'est pas le cas. Est-il possible de restreindre le moment où le hook est appelé par type de contenu?
Keven
@Keven Vous ne pouvez pas empêcher son invocation si la fonction existe, mais vous if ($vars['node']->type == 'foo') { ...obtiendrez l'effet que vous recherchez
Clive
Je recherche vraiment de légères optimisations, similaires à ce que vous pouvez faire hook_block_view_MODULE_DELTA_alter(). Je fais actuellement ce que vous dites, mais j'aimerais qu'il y ait un moyen de restreindre le moment où le crochet est touché.
Keven
Ce ne serait pas une optimisation, bien que @Keven - vous déplaceriez simplement le processus décisionnel vers une autre partie du code. En fait, si Drupal offrait une telle dérogation, elle devrait être générique et nécessiterait presque certainement plus de temps processeur. Vous gagnez déjà en ne prenant la décision qu'au dernier moment
Clive
28

Le sous-thème zen accomplit cela en ajoutant ceci à sa fonction 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 vous avez un type de contenu appelé 'news', vous pourrez alors créer une fonction appelée foo_preprocess_node_news dans votre fichier template.php.

Evil E
la source
Nous l'utilisons également sur la fondation ZURB avec notre propre impélémentation, extrait de code très utile.
Marko Blazekovic
2

Je viens juste d'avoir un problème similaire , c'est pourquoi Google m'a amené à cette page: ma fonction de prétraitement de nœud grandissait tellement énormément, que je préférerais diviser la fonction en plusieurs fichiers.

J'ai déjà fait une approche similaire dans mon fichier template.php qui contient toutes les fonctions alter, et puisque la même méthode fonctionne parfaitement bien ici, j'ai pensé partager mon approche:

configuration du fichier dans le dossier MYTHEME/preprocess:

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

vous devriez déjà avoir node.preprocess.inc, les autres que vous pouvez créer vous-même. la façon dont vous les appelez est vraiment plutôt arbitraire, mais il vaut mieux leur donner des noms qui les identifient bien et qui correspondent à tout le système de nommage drupal.
au contenu de ces fichiers!

node.preprocess.inc, ici je fais quelque chose comme ça:

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

}

nous passons essentiellement par le type du nœud actuel. ce que vous passez dépend de vous; #id, #view_modeTout en fonction de vos besoins.
une fois qu'il y a correspondance, il chargera le fichier spécifié et agira sur son contenu comme s'il avait été écrit directement dans cette fonction.

le contenu de ces includedfichiers ressemble exactement à ce que vous auriez mis dans le node.preprocess.incfichier, sauf que nous n'appelons pas à nouveau la fonction de prétraitement:

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

vous pouvez essentiellement le faire avec autant de fichiers que vous le souhaitez et même mettre en cascade plusieurs commutateurs, par exemple en divisant davantage des fichiers de prétraitement de nœuds spécifiques en fonction du #view_mode, en ayant un fichier pour le fullmode d'affichage et un autre pour leteaser

j'espère que cela vous aidera, si quelqu'un tombe à nouveau sur cette question (:

Bird-Kid
la source
1

call_user_func()ne transmet pas les paramètres par référence. Ainsi, dans le cas où $variablesvos preprocess_foo()fonctions fonctionneront uniquement sur des copies de la matrice d'origine; les modifications sur les non-objets ne s'appliqueront pas pendant le processus de rendu restant.

kishkash
la source
1

Dans votre hook_preprocess_node principal Implémentez le code suivant à la fin

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

Vous devriez donc prétraiter maintenant par type de nœud

Ziftman
la source