Функция предварительной обработки для типа контента

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но это никогда не называется.

Есть ли способ лучше?

cherouvim
источник

Ответы:

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, но, вероятно, лучше остаться простым.
Черувим
Я реализовал hook_preprocess_node()пользовательский модуль и надеялся, что это ограничит вызов хука, но это не так. Любой способ ограничить, когда ловушка вызывается по типу контента?
Кевен
@Keven Вы не можете остановить его вызов, если функция существует, но if ($vars['node']->type == 'foo') { ...достигнет желаемого эффекта
Клайв
Я просто ищу небольшие оптимизации, похожие на то, что вы можете сделать hook_block_view_MODULE_DELTA_alter(). В настоящее время я делаю то, что вы говорите, но хотелось бы, чтобы был способ ограничить, когда ударил крючок.
Кевен
Хотя @Keven не будет оптимизацией - вы просто перенесете процесс принятия решений на другую часть кода. На самом деле, если бы Drupal предлагал такое переопределение, он должен был быть универсальным и почти наверняка потребовал бы больше процессорного времени для выполнения. Вы уже выигрываете, только принимая решение в последний момент
Клайв
28

Подтема дзен выполняет это, добавляя это к своей функции 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, остальные вы можете создать сами. то, как вы их называете, на самом деле довольно произвольно, но лучше дать им имена, которые хорошо идентифицируют их и соответствуют всей системе именования drupal.
далее к содержанию этих файлов!

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файл, за исключением того, что мы больше не вызываем функцию preprocess:

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

надеюсь, это поможет, если кто-нибудь когда-нибудь снова наткнется на этот вопрос (:

Птица-Kid
источник
1

call_user_func()не передает параметры по ссылке. Итак, в случае, если $variablesваши preprocess_foo()функции будут работать только с копиями исходного массива; изменения не-объектов не будут применены во время оставшегося процесса рендеринга.

kishkash
источник
1

В вашем основном hook_preprocess_node Реализуйте следующий код в конце

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

Таким образом, вы бы сейчас препроцессировать по типу узла

Ziftman
источник