Функція попередньої обробки для типу вмісту


25

У мене є кілька типів вмісту, які мені потрібно попередньо обробити різними способами. Тож template.phpу моїй темі fooзараз виглядає так:

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

Я хотів би мати можливість вказати специфічну функцію попереднього оброблення для Drupal, яка причепиться до назви машини типу вмісту. Я спробував використовувати, foo_preprocess_newsале це ніколи не називається.

Чи є кращий спосіб?

Відповіді:


10

Назва функції попередньої обробки заснована на назві теми, тому для theme_table()вашої функції попередньої обробки є MYTHEME_preprocess_table().

Оскільки немає theme_node_node_typeфункції, гачок для попередньої обробки, такий як foo_preprocess_newsабо foo_preprocess_node_newsне вийде з коробки.

Ви можете зайнятися переосмисленням реєстру тем, щоб він поводився по-різному для вузлів, але я дійсно не рекомендував би його; це може стати дуже безладним.

Я великий шанувальник коду рефакторингу, але у вашому випадку я не думаю, що це потрібно; якщо у вас є складна логіка, яку потрібно запускати у вашому гачку попередньої обробки залежно від типу вузла, то розведення її на різні функції, як ви зараз робите, здається мені гарною практикою.

Іншим методом, звичайно, було б реалізувати спеціальний модуль для кожного з різних типів вмісту та реалізувати hook_preprocess_node()в кожному. Таким чином, функція попередньої обробки кожного модуля може відповідати за різний тип вмісту.

Однак це може бути надмірним для вашої ситуації; якщо у вас немає додаткової логіки (тобто логіки попередньої обробки теми) для виконання кожного типу вмісту, цей метод, ймовірно, не додає зайвого значення.


1
ДОБРЕ. Я також міг би "автоматизувати" це foo_preprocess_node, реалізуючи його так call_user_func('_preprocess_' . $vars['type'], $vars);, щоб уникнути повторення ifs, але, мабуть, найкраще залишатися простим.
cherouvim

Я реалізував hook_preprocess_node()на користувальницькому модулі, і сподівався, що це обмежить, коли гачок буде викликаний, але це не так. Будь-який спосіб обмежити, коли гачок викликається за типом вмісту?
Кевен

@Keven Ви не можете зупинити його виклику, якщо функція існує, але if ($vars['node']->type == 'foo') { ...ви досягнете ефекту, який шукаєте
Clive

Я справді просто шукаю невеликих оптимізацій, подібних до того, що ти можеш зробити hook_block_view_MODULE_DELTA_alter(). Я зараз роблю те, що ви говорите, але хотілося б, щоб було обмеження, коли гак потрапить.
Кевен

Це не буде оптимізацією, хоча @Keven - ви просто перенесите процес прийняття рішень на іншу частину коду. Насправді, якби Drupal запропонував таке переосмислення, це повинно бути загальним, і майже напевно знадобиться більше процесорного часу, щоб досягти. Ви вже виграєте, лише прийнявши рішення в останній момент
Клайв

28

Підтема zen виконує це, додавши це до своєї функції 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);
  } 
  ...
}

Якщо у вас є тип вмісту під назвою "новини", ви зможете створити функцію, яка називається foo_preprocess_node_news у вашому файлі template.php.


Ми також використовуємо це на фундаменті ZURB з власним імпементацією, дуже корисним фрагментом коду.
Марко Блажекович

2

У мене тільки що було подібне питання , через що google привів мене на цю сторінку: моя функція попередньої обробки вузла зростала настільки величезно, що я скоріше розділив цю функцію на кілька файлів.

Я вже зробив подібний підхід у своєму файлі template.php, який містить усі функції alter, і оскільки той самий метод тут чудово працює, я подумав, що поділюсь своїм підходом:

налаштування файлу всередині папки MYTHEME/preprocess:

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

ви вже повинні мати node.preprocess.inc, інші, які ви можете створити самостійно. як ви їх називаєте насправді, досить умовно, але краще дайте їм імена, які добре їх ідентифікують і відповідають всій системі імен друпінгу.
далі до вмісту цих файлів!

node.preprocess.inc, ось я роблю щось подібне:

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

}

ми в основному переходимо через тип поточного вузла. те, через що ви переходите, залежить від вас; #id,#view_mode Все залежить від ваших конкретних потреб.
як тільки є збіг, він завантажить вказаний файл і діятиме на його вміст так само, як якщо б він був написаний прямо у цій функції.

вміст цих includedфайлів виглядає точно так, як ви б його помістили у node.preprocess.incфайл, за винятком того, що ми знову не викликаємо функцію попередньої обробки:

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

в основному це можна зробити з потрібною кількістю файлів і навіть каскадом декількох комутаторів, наприклад, додатково розбиваючи певні файли попереднього оброблення вузла залежно від #view_mode, маючи один файл для fullрежиму перегляду та інший дляteaser

сподіваюся, що це допоможе, якщо хтось знову натрапить на це питання (:


1

call_user_func()не передає параметри за посиланням. Отже, у випадку, якщо $variablesваші preprocess_foo()функції працюватимуть лише над копіями вихідного масиву; зміни щодо не-об’єктів не застосовуватимуться під час решти процесу візуалізації.


1

У вашому головному_укрі__пропроцес_нод Реалізуйте наступний код наприкінці

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

Отже, ви мали б попередню обробку за типом вузла

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.