Tuesday, February 25, 2014

Drupal 7 - Creating a contentype with repeatable expandable fieldcollections

I want to make me a simple to manage contenttype containing fields and field collections that I can present as collapsible fields.
On page load the field value will be hidden and the labels will be shown as clickable links. Clicking them will expand the content of the field.
I want to use field collections in the same way, but there give the maintainer the power to edit the 'label'. Adding fieldcollections of the form (title, content) should do that. On page load the title will be shown as a clickable link, and clicking on that will expand the content.

For the collapsing functionality we use, as it is already there, ctools.

1. make a field display collapsible with ctools
In general using ctools it's very easy to make a field display collapsible.

1.a Put this function in your template file
function MyTheme_collapse_content($c_content, $collapse_heading) {
   print theme('ctools_collapsible', array('handle' => $collapse_heading, 'content' => $c_content, 'collapsed' => TRUE));
}

1.b  In the field template file simply put this code
<?php
   $collapse_heading = $label;
   foreach ($items as $delta => $item): 
     $c_content.='<div class="field-item ';
     $c_content.=$delta % 2 ? 'odd' : 'even'; 
     $c_content.='"';
     $c_content.=' '. $item_attributes[$delta].'>';
     $c_content.= render($item).'</div>';
   endforeach;
  MyTheme_collapse_content($c_content, $collapse_heading);
?>

1.b.1 template naming
If you worry what to name the field template files simply check https://api.drupal.org/api/drupal/modules!field!field.module/function/theme_field/7


Now, how to accomplish this task for the fieldcollections?

2. Add a fieldcollection field to the contenttype
In this example called Page or machinename field_event_sub_page
2.1 Add two fields to the fieldcollection
2.1.a text field page_title
2.1.b  and a textarea page_text (filtered html)

Now you can add field collections to the node consisting of a text field (page_title) and a textarea (page_text).
Now I want these text fields  (the page_title) to show as links, and clicking on these links should open the corresponding textarea's (page_text), giving me a single ode behaving more or less like a book with only two levels.

Using the ctools collapsing the problem is now reduced to getting the page_title and page_text field content in the $c_content and the $collapse_heading variables in a theme function like the above:

  MyTheme_collapse_content($c_content, $collapse_heading);

This is usually a very annoying deconstruction of the fieldcollection instance, I must say I get lost a lot of times.
But now I found this very elegant solution by Mike Minecki



2.2  put these functions in your template.php

function MyTheme_preprocess_field(&$vars, $hook) {
  $element = $vars['element'];
  if (isset($element['#field_name'])) {
    if ($element['#field_name'] == 'field_event_sub_page') {
    $vars['theme_hook_suggestions'][] = 'field__event_sub_page_collected';// waar is dit eigenlijk voor nodig

     $field_array = array('field_fesp_linktitle', 'field_fesp_text');//must match the fields you added to the field collection
    rows_from_field_collection($vars, 'field_event_sub_page', $field_array);
    }
  }
}

function rows_from_field_collection(&$vars, $field_name, $field_array) {
  $vars['rows'] = array();
  foreach($vars['element']['#items'] as $key => $item) {
    $entity_id = $item['value'];
    $entity = field_collection_item_load($entity_id);
    $wrapper = entity_metadata_wrapper('field_collection_item', $entity);
    $row = array();
    foreach($field_array as $field){
       $row[$field] = $wrapper->$field->value();
    }
    $vars['rows'][] = $row;
  }
 }


2.2   Put this rendering in your fieldcollection template file
In this example that would be the field--field_event_sub_page.tpl.php template file.
 <?php 
   foreach($rows as $row): 
      $collapse_heading $row['field_fesp_linktitle'];
      $c_content $row['field_fesp_text']['safe_value'];
      MyTheme_collapse_content($c_content, $collapse_heading);

   endforeach; ?>

No comments:

Post a Comment