web-dev-qa-db-ja.com

コンテンツタイプごとの前処理機能

いくつかのコンテンツタイプがあり、さまざまな方法で前処理する必要があります。したがって、私のテーマfootemplate.phpは現在次のようになります。

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を使用してみましたが、呼び出されません。

もっと良い方法はありますか?

24
cherouvim

前処理関数の名前はテーマ名に基づいているため、theme_table()の場合、前処理関数はMYTHEME_preprocess_table()です。

_theme_node_node_type_関数がないため、_foo_preprocess_news_や_foo_preprocess_node_news_などのプリプロセスフックはそのままでは機能しません。

あなたはcouldテーマレジストリをオーバーライドして、ノードに対して異なる動作をするようにしますが、実際にはお勧めしません。非常に厄介になる可能性があります。

私はコードのリファクタリングの大ファンですが、あなたの場合、それは必要ではないと思います。ノードタイプに応じてプリプロセスフックで実行する必要のある複雑なロジックがある場合、現在実行している方法でそれをさまざまな関数にファームすることは、私にとっては良い習慣のように思えます。

もちろん、もう1つの方法は、異なるコンテンツタイプごとにカスタムモジュールを実装し、それぞれにhook_preprocess_node()を実装することです。このようにして、各モジュールの前処理機能は、異なるコンテンツタイプを処理することができます。

ただし、これは状況によってはやり過ぎになる場合があります。各コンテンツタイプで実行する追加のロジック(テーマ以外の前処理ロジック)がない場合、このメソッドはおそらく追加の値を追加しません。

10
Clive

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

'news'というコンテンツタイプがある場合、template.phpファイルにfoo_preprocess_node_newsという関数を作成できます。

31
Evil E

私は似たようなissueしか持っていなかったので、Googleがこのページに移動しました。私のノードの前処理関数が非常に大きくなりすぎて、分割したほうがいいです。関数を複数のファイルに分割します。

私はすべての変更機能を含む私のtemplate.phpファイルで同様のアプローチをすでに行っており、同じメソッドがここで完全にうまく機能するので、私は私のアプローチを共有すると思いました:

ファイル設定フォルダー内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ファイルに配置した場合とまったく同じです。

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表示モード用に1つのファイルを持ち、別のteaser

誰かがこの質問に再び遭遇した場合、これが役立つことを願っています(:

2
Bird-Kid

メインのhook_preprocess_nodeで、最後に次のコードを実装します

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

したがって、ノードタイプごとに前処理する必要があります。

1
Ziftman

call_user_func()は、参照によってパラメーターを渡しません。したがって、_$variables_の場合、preprocess_foo()関数は元の配列のコピーでのみ機能します。非オブジェクトに対する変更は、残りのレンダリングプロセス中には適用されません。

1
kishkash