Fungsi preprocess per jenis konten

25

Saya memiliki beberapa jenis konten yang harus saya preproses dengan cara yang berbeda. Jadi template.phpdalam tema saya foosaat ini terlihat seperti:

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

Saya ingin dapat menentukan fungsi preproses khusus Drupal yang akan menghubungkan nama mesin tipe konten. Saya mencoba menggunakan foo_preprocess_newstetapi tidak pernah dipanggil.

Apakah ada cara yang lebih baik?

cherouvim
sumber

Jawaban:

10

Nama fungsi praproses didasarkan pada nama tema, jadi untuk theme_table()fungsi praproses Anda MYTHEME_preprocess_table().

Karena tidak ada theme_node_node_typefungsi kait preproses seperti foo_preprocess_newsatau foo_preprocess_node_newstidak akan berfungsi di luar kotak.

Anda dapat mengubah registri tema sehingga berperilaku berbeda untuk node, tapi saya benar-benar tidak akan merekomendasikannya; itu bisa sangat berantakan.

Saya penggemar kode refactoring tetapi dalam kasus Anda, saya pikir itu tidak perlu; jika Anda memiliki logika kompleks yang perlu dijalankan di hook preprocess Anda tergantung pada jenis node kemudian bertani keluar ke fungsi yang berbeda dengan cara yang Anda lakukan saat ini sepertinya praktik yang baik bagi saya.

Metode lain, tentu saja, akan menerapkan modul khusus untuk masing-masing jenis konten yang berbeda dan menerapkannya hook_preprocess_node()di masing-masing. Dengan begitu, fungsi preprocess setiap modul dapat bertanggung jawab untuk jenis konten yang berbeda.

Namun ini mungkin berlebihan untuk situasi Anda; jika Anda tidak memiliki logika tambahan (yaitu logika preproses non-tema) untuk tampil di setiap jenis konten, maka metode ini mungkin tidak menambah nilai tambahan.

Clive
sumber
1
BAIK. Saya juga bisa "mengotomatisasi" foo_preprocess_nodedengan mengimplementasikannya call_user_func('_preprocess_' . $vars['type'], $vars);untuk menghindari pengulangan tetapi jika itu mungkin yang terbaik untuk tetap sederhana.
cherouvim
Saya menerapkan hook_preprocess_node()pada modul khusus, dan berharap itu akan membatasi ketika kait dipanggil, tetapi tidak. Adakah cara untuk membatasi ketika hook dipanggil oleh tipe konten?
Keven
@Keven Anda tidak dapat menghentikannya dipanggil jika fungsinya ada, tetapi if ($vars['node']->type == 'foo') { ...akan mencapai efek yang Anda cari
Clive
Saya benar-benar hanya mencari sedikit optimasi, mirip dengan apa yang dapat Anda lakukan hook_block_view_MODULE_DELTA_alter(). Saat ini saya melakukan apa yang Anda katakan, tetapi berharap ada cara untuk membatasi kapan kailnya mengenai.
Keven
Itu tidak akan menjadi optimasi, meskipun @Keven - Anda hanya akan menggeser proses pengambilan keputusan ke bagian lain dari kode. Bahkan jika Drupal menawarkan penggantian seperti itu, itu harus generik, dan hampir pasti akan membutuhkan lebih banyak waktu prosesor untuk menyelesaikannya. Anda sudah menang dengan hanya membuat keputusan pada saat terakhir
Clive
28

Subtema zen menyelesaikan ini dengan menambahkan ini ke fungsi theme_preprocess_node-nya:

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

Jika Anda memiliki tipe konten yang disebut 'berita', maka Anda dapat membuat fungsi yang disebut foo_preprocess_node_news di file template.php Anda.

Evil E
sumber
Kami juga menggunakan ini pada ZURB foundation dengan implementasi kami sendiri, potongan kode yang sangat berguna.
Marko Blazekovic
2

Saya hanya punya masalah serupa yang menyebabkan Google membawa saya ke halaman ini: fungsi preprocess node saya tumbuh sangat besar, sehingga saya lebih suka membagi fungsi menjadi beberapa file.

Saya sudah melakukan pendekatan yang serupa di file template.php saya yang berisi semua fungsi alter, dan karena metode yang sama bekerja dengan baik di sini, saya pikir saya akan membagikan pendekatan saya:

pengaturan file di dalam folder MYTHEME/preprocess:

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

Anda seharusnya sudah memiliki node.preprocess.inc, yang lain Anda dapat membuat sendiri. bagaimana Anda memanggil mereka sebenarnya agak sewenang-wenang, tetapi lebih baik memberi mereka nama yang mengidentifikasi mereka dengan baik dan cocok dengan seluruh sistem penamaan drupal.
selanjutnya ke konten file-file ini!

node.preprocess.inc, di sini saya melakukan sesuatu seperti ini:

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

}

kami pada dasarnya beralih melalui jenis node saat ini. apa yang Anda beralih terserah Anda; #id,, #view_modesemua tergantung kebutuhan Anda.
sekali ada kecocokan, itu akan memuat file yang ditentukan dan bertindak atas isinya sama seperti itu ditulis tepat di dalam fungsi ini.

konten includedfile - file ini terlihat persis seperti Anda akan memasukkannya ke dalam node.preprocess.incfile, kecuali kami tidak memanggil fungsi preprocess lagi:

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

Anda pada dasarnya dapat melakukan ini dengan banyak file yang Anda inginkan dan bahkan membuat banyak switch, misalnya lebih lanjut membagi file preprocess node tertentu tergantung pada #view_mode, memiliki satu file untuk fullmode tampilan dan yang lain untukteaser

Semoga ini bisa membantu, haruskah seseorang menemukan pertanyaan ini lagi (:

Bird-Kid
sumber
1

call_user_func()tidak lulus parameter dengan referensi. Jadi, jika fungsi $variablesAnda hanya preprocess_foo()akan bekerja pada salinan array asli; perubahan pada non-objek tidak akan berlaku selama proses render yang tersisa.

kishkash
sumber
1

Di hook_preprocess_node utama Anda, Terapkan kode berikut di akhir

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

Jadi Anda sekarang akan memiliki preprocess dengan tipe node

Ziftman
sumber