home | career | drupal | java | mac | mysql | perl | php | scala | uml | unix

Drupal example source code file (fieldgroup.module)

This example Drupal source code file (fieldgroup.module) is included in the DevDaily.com "Drupal Source Code Warehouse" project. The intent of this project is to help you "Learn Drupal by Example".

PHP - Drupal tags/keywords

array, content_type, element, field_name, foreach, form, function, group_name, groups, if, isset, php, type_name, variable

The fieldgroup.module Drupal example source code

<?php
// $Id: fieldgroup.module,v 1.79.2.53 2011/01/03 11:03:47 yched Exp $

/**
 * @file
 * Create field groups for CCK fields.
 *
 * Hooks for other modules to intervene include:
 * - hook_fieldgroup_view: Alter the group $element added to $node->content.
 * - hook_fieldgroup_form: Alter the group portion of the node form.
 * - hook_fieldgroup_types: Add additional fieldgroup group_types.
 * - hook_fieldgroup_default_settings: Add additional fieldgroup default settings.
 * - hook_fieldgroup_save: Do additional processing when a fieldgroup is saved.
 */
/**
 * Implementation of hook_init().
 */
function fieldgroup_init() {
  drupal_add_css(drupal_get_path('module', 'fieldgroup') .'/fieldgroup.css');
}

/**
 * Implementation of hook_ctools_plugin_directory().
 */
function fieldgroup_ctools_plugin_directory($module, $plugin) {
  if ($module == 'ctools' && $plugin == 'content_types') {
    return 'panels/' . $plugin;
  }
}

/**
 * Implementation of hook_menu().
 */
function fieldgroup_menu() {
  $items = array();

  // Make sure this doesn't fire until content_types is working,
  // needed to avoid errors on initial installation.
  if (!defined('MAINTENANCE_MODE')) {
    foreach (node_get_types() as $type) {
      $type_name = $type->type;
      $content_type = content_types($type_name);
      $type_url_str = $content_type['url_str'];
      $items['admin/content/node-type/'. $type_url_str .'/groups/%'] = array(
        'title' => 'Edit group',
        'page callback' => 'drupal_get_form',
        'page arguments' => array('fieldgroup_group_edit_form', $type_name, 5),
        'access arguments' => array('administer content types'),
        'type' => MENU_CALLBACK,
      );
      $items['admin/content/node-type/'. $type_url_str .'/groups/%/remove'] = array(
        'title' => 'Edit group',
        'page callback' => 'drupal_get_form',
        'page arguments' => array('fieldgroup_remove_group', $type_name, 5),
        'access arguments' => array('administer content types'),
        'type' => MENU_CALLBACK,
      );
    }
  }
  return $items;
}

/**
 * Implementation of hook_theme().
 */
function fieldgroup_theme() {
  return array(
    'fieldgroup_simple' => array(
      'template' => 'fieldgroup-simple',
      'arguments' => array('element' => NULL),
    ),
    'fieldgroup_fieldset' => array(
      'arguments' => array('element' => NULL),
    ),
    'fieldgroup_display_overview_form' => array(
      'arguments' => array('form' => NULL),
    ),
  );
}

/**
 * Implementation of hook_elements().
 */
function fieldgroup_elements() {
  return array(
    'fieldgroup_simple' => array(),
    'fieldgroup_fieldset' => array('#collapsible' => FALSE, '#collapsed' => FALSE, '#value' => NULL,),
  );
}

/**
 * Implementation of hook_fieldapi().
 */
function fieldgroup_content_fieldapi($op, $field) {
  switch ($op) {
    case 'delete instance':
      db_query("DELETE FROM {". fieldgroup_fields_tablename() ."} WHERE field_name = '%s' AND type_name = '%s'", $field['field_name'], $field['type_name']);
      cache_clear_all('fieldgroup_data:', content_cache_tablename(), TRUE);
      break;
  }
}

function fieldgroup_group_edit_form(&$form_state, $type_name, $group_name) {
  $content_type = content_types($type_name);
  $groups = fieldgroup_groups($content_type['type']);

  if (!$group = $groups[$group_name]) {
    drupal_not_found();
    exit;
  }

  $form['label'] = array(
    '#type' => 'textfield',
    '#title' => t('Label'),
    '#default_value' => $group['label'],
    '#required' => TRUE,
  );

  // Set a default value for group type early in the form so it
  // can be overridden by subsequent form elements added by other modules.
  $group_type = !empty($group['group_type']) ? $group['group_type'] : 'standard';
  $form['group_type'] = array('#type' => 'hidden', '#default_value' => $group_type);

  $form['settings']['#tree'] = TRUE;
  $form['settings']['form'] = array(
    '#type' => 'fieldset',
    '#title' => t('Form settings'),
    '#description' => t('These settings apply to the group in the node editing form.'),
  );
  $form['settings']['form']['style'] = array(
    '#type' => 'radios',
    '#title' => t('Style'),
    '#default_value' => $group['settings']['form']['style'],
    '#options' => array(
      'fieldset' => t('always open'),
      'fieldset_collapsible' => t('collapsible'),
      'fieldset_collapsed' => t('collapsed'),
    )
  );
  $form['settings']['form']['description'] = array(
    '#type' => 'textarea',
    '#title' => t('Help text'),
    '#default_value' => $group['settings']['form']['description'],
    '#rows' => 5,
    '#description' => t('Instructions to present to the user on the editing form.'),
    '#required' => FALSE,
  );
  $form['settings']['display'] = array(
    '#type' => 'fieldset',
    '#title' => t('Display settings'),
    '#description' => t('These settings apply to the group on node display.'),
  );
  $form['settings']['display']['description'] = array(
    '#type' => 'textarea',
    '#title' => t('Description'),
    '#default_value' => $group['settings']['display']['description'],
    '#rows' => 5,
    '#description' => t('A description of the group.'),
    '#required' => FALSE,
  );

  foreach (array_keys(content_build_modes()) as $key) {
    $form['settings']['display'][$key]['format'] = array('#type' => 'value', '#value' => isset($group['settings']['display'][$key]['format']) ? $group['settings']['display'][$key]['format'] : 'fieldset');
    $form['settings']['display'][$key]['exclude'] = array('#type' => 'value', '#value' => isset($group['settings']['display'][$key]['exclude']) ? $group['settings']['display'][$key]['exclude'] : 0);
  }
  $form['settings']['display']['label'] = array('#type' => 'value', '#value' => $group['settings']['display']['label']);
  $form['weight'] = array('#type' => 'hidden', '#default_value' => $group['weight']);
  $form['group_name'] = array('#type' => 'hidden', '#default_value' => $group_name);

  $form['#content_type'] = $content_type;

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
    '#weight' => 10,
  );

  return $form;
}

function fieldgroup_group_edit_form_submit($form, &$form_state) {
  $form_values = $form_state['values'];
  $content_type = $form['#content_type'];
  fieldgroup_save_group($content_type['type'], $form_values);
  $form_state['redirect'] = 'admin/content/node-type/'. $content_type['url_str'] .'/fields';
}

function fieldgroup_remove_group(&$form_state, $type_name, $group_name) {
  $content_type = content_types($type_name);
  $groups = fieldgroup_groups($content_type['type']);
  $group = isset($groups[$group_name]) ? $groups[$group_name] : '';

  if (empty($group)) {
    drupal_not_found();
    exit;
  }

  $form['#submit'][] = 'fieldgroup_remove_group_submit';
  $form['#content_type'] = $content_type;
  $form['#group_name'] = $group_name;

  return confirm_form($form,
                  t('Are you sure you want to remove the group %label?',
                  array('%label' => t($group['label']))),
                  'admin/content/node-type/'. $content_type['url_str'] .'/fields', t('This action cannot be undone.'),
                  t('Remove'), t('Cancel'));
}

function fieldgroup_remove_group_submit($form, &$form_state) {
  $form_values = $form_state['values'];
  $content_type = $form['#content_type'];
  $group_name = $form['#group_name'];
  fieldgroup_delete($content_type['type'], $group_name);
  drupal_set_message(t('The group %group_name has been removed.', array('%group_name' => $group_name)));
  $form_state['redirect'] = 'admin/content/node-type/'. $content_type['url_str'] .'/fields';
}

/**
 * Returns all groups for a content type
 */
function fieldgroup_groups($content_type = '', $sorted = FALSE, $reset = FALSE) {
  global $language;
  static $groups, $groups_sorted;
  if (!isset($groups) || $reset) {
    if ($cached = cache_get('fieldgroup_data:'. $language->language, content_cache_tablename())) {
      $data = $cached->data;
      $groups = $data['groups'];
      $groups_sorted = $data['groups_sorted'];
    }
    else {
      $result = db_query("SELECT * FROM {". fieldgroup_tablename() ."} ORDER BY weight, group_name");
      $groups = array();
      $groups_sorted = array();
      while ($group = db_fetch_array($result)) {
        $group['settings'] = unserialize($group['settings']);
        $group['fields'] = array();

        // Allow external modules to translate field group strings.
        $group_strings = array(
          'label' => $group['label'],
          'form_description' => $group['settings']['form']['description'],
          'display_description' => $group['settings']['display']['description'],
        );
        drupal_alter('content_fieldgroup_strings', $group_strings, $group['type_name'], $group['group_name']);
        $group['label'] = $group_strings['label'];
        $group['settings']['form']['description'] = $group_strings['form_description'];
        $group['settings']['display']['description'] = $group_strings['display_description'];

        $groups[$group['type_name']][$group['group_name']] = $group;
        $groups_sorted[$group['type_name']][] = &$groups[$group['type_name']][$group['group_name']];
      }
      //load fields
      $result = db_query("SELECT nfi.*, ng.group_name FROM {". fieldgroup_tablename() ."} ng ".
 "INNER JOIN {". fieldgroup_fields_tablename() ."} ngf ON ngf.type_name = ng.type_name AND ngf.group_name = ng.group_name ".
 "INNER JOIN {". content_instance_tablename() ."} nfi ON nfi.field_name = ngf.field_name AND nfi.type_name = ngf.type_name ".
 "WHERE nfi.widget_active = 1 ORDER BY nfi.weight");
      while ($field = db_fetch_array($result)) {
        // Allow external modules to translate field strings.
        $field_strings = array(
          'widget_label' => $field['label'],
          'widget_description' => $field['description'],
        );
        drupal_alter('content_field_strings', $field_strings, $field['type_name'], $field['field_name']);
        $field['label'] = $field_strings['widget_label'];
        $field['description'] = $field_strings['widget_description'];

        $groups[$field['type_name']][$field['group_name']]['fields'][$field['field_name']] = $field;
      }
      cache_set('fieldgroup_data:'. $language->language, array('groups' => $groups, 'groups_sorted' => $groups_sorted), content_cache_tablename());
    }
  }
  if (empty($content_type)) {
    return $groups;
  }
  elseif (empty($groups) || empty($groups[$content_type])) {
    return array();
  }
  return $sorted ? $groups_sorted[$content_type] : $groups[$content_type];
}


function _fieldgroup_groups_label($content_type) {
  $groups = fieldgroup_groups($content_type);

  $labels[''] = '<'. t('none') .'>';
  foreach ($groups as $group_name => $group) {
    $labels[$group_name] = t($group['label']);
  }
  return $labels;
}

function _fieldgroup_field_get_group($content_type, $field_name) {
  return db_result(db_query("SELECT group_name FROM {". fieldgroup_fields_tablename() ."} WHERE type_name = '%s' AND field_name = '%s'", $content_type, $field_name));
}

/**
 * Implementation of hook_form_alter()
 */
function fieldgroup_form_alter(&$form, $form_state, $form_id) {
  if (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] .'_node_form' == $form_id) {
    foreach (fieldgroup_groups($form['type']['#value']) as $group_name => $group) {
      $form[$group_name] = array(
        '#type' => 'fieldset',
        '#title' => check_plain(t($group['label'])),
        '#collapsed' => $group['settings']['form']['style'] == 'fieldset_collapsed',
        '#collapsible' => in_array($group['settings']['form']['style'], array('fieldset_collapsed', 'fieldset_collapsible')),
        '#weight' => $group['weight'],
        '#description' => content_filter_xss(t($group['settings']['form']['description'])),
        '#attributes' => array('class' => strtr($group['group_name'], '_', '-')),
      );

      $has_accessible_field = FALSE;
      foreach ($group['fields'] as $field_name => $field) {
        if (isset($form[$field_name])) {
          $form[$group_name][$field_name] = $form[$field_name];
          // Track whether this group has any accessible fields within it.
          if (!isset($form[$field_name]['#access']) || $form[$field_name]['#access'] !== FALSE) {
            $has_accessible_field = TRUE;
          }
          unset($form[$field_name]);
        }
      }
      if (!empty($group['fields']) && !element_children($form[$group_name])) {
        //hide the fieldgroup, because the fields are hidden too
        unset($form[$group_name]);
      }

      if (!$has_accessible_field) {
        // Hide the fieldgroup, because the fields are inaccessible.
        $form[$group_name]['#access'] = FALSE;
      }

      // Allow other modules to alter the form.
      // Can't use module_invoke_all because we want
      // to be able to use a reference to $form and $form_state.
      foreach (module_implements('fieldgroup_form') as $module) {
        $function = $module .'_fieldgroup_form';
        $function($form, $form_state, $form_id, $group);
      }

    }

  }
  // The group is only added here so it will appear in the export
  // when using Content Copy.
  elseif ($form_id == 'content_field_edit_form' && isset($form['widget'])) {
    $content_type = content_types($form['type_name']['#value']);
    $form['widget']['group'] = array(
      '#type' => 'value',
      '#value' => _fieldgroup_field_get_group($content_type['type'], $form['field_name']['#value']),
    );
  }
  elseif ($form_id == 'content_field_overview_form') {
    $form['#validate'][] = 'fieldgroup_field_overview_form_validate';
    $form['#submit'][] = 'fieldgroup_field_overview_form_submit';
  }
  elseif ($form_id == 'content_display_overview_form' && !empty($form['#groups'])) {
    $form['#submit'][] = 'fieldgroup_display_overview_form_submit';
    if (!isset($form['submit'])) {
      $form['submit'] = array('#type' => 'submit', '#value' => t('Save'), '#weight' => 10);
    }
  }
  elseif ($form_id == 'content_field_remove_form') {
    $form['#submit'][] = 'fieldgroup_field_remove_form_submit';
  }
}

/**
 * API for group name validation.
 *
 * Pulled into separate function to be re-usable.
 */
function fieldgroup_validate_name($group, $type_name) {
  $errors = array();

  // No label.
  if (!$group['label']) {
    $errors['label'][] = t('You need to provide a label.');
  }

  // No group name.
  if (!$group['group_name']) {
    $errors['group_name'][] = t('You need to provide a group name.');
  }
  // Group name validation.
  else {
    $group_name = $group['group_name'];
    $group['group_type'] = !empty($group['group_type']) ? $group['group_type'] : 'standard';

    // Add the 'group_' prefix.
    if (substr($group_name, 0, 6) != 'group_') {
      $group_name = 'group_'. $group_name;
    }

    // Invalid field name.
    if (!preg_match('!^group_[a-z0-9_]+$!', $group_name)) {
      $errors['group_name'][] = t('The group name %group_name is invalid. The name must include only lowercase unaccentuated letters, numbers, and underscores.', array('%group_name' => $group_name));
    }
    if (strlen($group_name) > 32) {
      $errors['group_name'][] = t('The group name %group_name is too long. The name is limited to 32 characters, including the \'group_\' prefix.', array('%group_name' => $group_name));
    }

    // Group name already exists.
    $groups = fieldgroup_groups($type_name);
    if (isset($groups[$group_name])) {
      $errors['group_name'][] = t('The group name %group_name already exists.', array('%group_name' => $group_name));
    }
    if (empty($errors['group_name'])) {
      $group['group_name'] = $group_name;
    }
  }
  return array('group_name' => $group['group_name'], 'errors' => $errors);
}

function fieldgroup_field_overview_form_validate($form, &$form_state) {
  $form_values = $form_state['values'];
  $group = $form_values['_add_new_group'];

  if (array_filter(array($group['label'], $group['group_name']))) {
    $validation = fieldgroup_validate_name($group, $form['#type_name']);
    if (!empty($validation['errors'])) {
      foreach ($validation['errors'] as $type => $messages) {
        foreach ($messages as $message) {
          if ($type == 'label') {
            form_set_error('_add_new_group][label', t('Add new group:') .' '. $message);
          }
          else {
            form_set_error('_add_new_group][group_name', t('Add new group:') .' '. $message);
          }
        }
      }
    }
    $group_name = $validation['group_name'];
    form_set_value($form['_add_new_group']['group_name'], $group_name, $form_state);
  }
  else {
    // Fail validation if attempt to nest fields under a new group without the
    // proper information. Not raising an error would cause the nested fields
    // to get weights the user doesn't expect.

    foreach ($form_values as $key => $values) {
      if ($values['parent'] == '_add_new_group') {
        form_set_error('_add_new_group][label', t('Add new group: you need to provide a label.'));
        form_set_error('_add_new_group][group_name', t('Add new group: you need to provide a group name.'));
        break;
      }
    }
  }
}

function fieldgroup_field_overview_form_submit($form, &$form_state) {
  $form_values = $form_state['values'];
  $type_name = $form['#type_name'];

  // Create new group if needed.
  if (!empty($form_values['_add_new_group']['label'])) {
    $group = $form_values['_add_new_group'];
    $group['settings'] = field_group_default_settings($group['group_type']);
    fieldgroup_save_group($type_name, $group);
    $new_group_name = $group['group_name'];
  }

  // Parse incoming rows.
  $add_field_rows = array('_add_new_field', '_add_existing_field');
  $field_rows = array_merge($form['#fields'], $add_field_rows);
  foreach ($form_values as $key => $values) {
    // If 'field' row: update field parenting.
    if (in_array($key, $field_rows)) {
      // If newly added fields were added to a group:
      if (in_array($key, $add_field_rows)) {
        // We replace the '_add_*_field' key with the actual name of
        // the field that got added.
        // content_field_overview_form_submit() placed those
        // in $form_state['fields_added'] for us.
        if (isset($form_state['fields_added'][$key])) {
          $key = $form_state['fields_added'][$key];
        }
        else {
          // No field was actually created : skip to next row.
          continue;
        }
      }
      // If the field was added to the newly created group, replace the
      // '_add_new_group' value with the actual name of the group.
      $parent = ($values['parent'] == '_add_new_group' && isset($new_group_name)) ? $new_group_name : $values['parent'];
      // TODO: check the parent group does exist ?
      fieldgroup_update_fields(array('field_name' => $key, 'group' => $parent, 'type_name' => $type_name));
    }

    // If 'group' row:  update groups weights
    // (possible newly created group has already been taken care of).
    elseif (in_array($key, $form['#groups'])) {
      db_query("UPDATE {". fieldgroup_tablename() ."} SET weight = %d WHERE type_name = '%s' AND group_name = '%s'",
        $values['weight'], $type_name, $key);
    }
  }

  cache_clear_all('fieldgroup_data:', content_cache_tablename(), TRUE);
}

function field_group_default_settings($group_type) {
  $settings = array(
    'form' => array('style' => 'fieldset', 'description' => ''),
    'display' => array('description' => '', 'label' => 'above'),
  );
  module_load_include('inc', 'content', 'includes/content.admin');
  foreach (array_keys(content_build_modes()) as $key) {
    $settings['display'][$key]['format'] = 'fieldset';
    $settings['display'][$key]['exclude'] = 0;
  }
  // Allow other modules to add new default settings.
  $settings = array_merge($settings, module_invoke_all('fieldgroup_default_settings', $group_type));
  return $settings;
}

function fieldgroup_display_overview_form_submit($form, &$form_state) {
  $form_values = $form_state['values'];
  $groups = fieldgroup_groups($form['#type_name']);
  foreach ($form_values as $key => $values) {
    if (in_array($key, $form['#groups'])) {
      $group = $groups[$key];
      // We have some numeric keys here, so we can't use array_merge.
      $group['settings']['display'] = $values + $group['settings']['display'];
      fieldgroup_save_group($form['#type_name'], $group);
    }
  }
}

function fieldgroup_field_remove_form_submit($form, &$form_state) {
  $form_values = $form_state['values'];
  // TODO:
  // - when a (non last) field is removed from a group, a 'ghost row' remains in the fields overview
  // - when the last field is removed, the group disappears
  // seems to be fixed when emptying the cache.
  db_query("DELETE FROM {". fieldgroup_fields_tablename() ."} WHERE type_name = '%s' AND field_name = '%s'", $form_values['type_name'], $form_values['field_name']);
}

/**
 * Implementation of hook_nodeapi().
 */
function fieldgroup_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
  switch ($op) {
    case 'view':
      // Prevent against invalid 'nodes' built by broken 3rd party code.
      if (isset($node->type)) {
        // Build the node content element needed to render each fieldgroup.
        foreach (fieldgroup_groups($node->type) as $group) {
          fieldgroup_build_content($group, $node, $teaser, $page);
        }
      }
      break;
  }
}

/**
 * Build the node content element needed to render a fieldgroup.
 *
 * @param $group
 *   The field group definition.
 * @param $node
 *   The node containing the field group to display. Can be a 'pseudo-node',
 *   containing at least 'type', 'nid', 'vid', and the content for fields
 *   required for the group.
 * @param $teaser
 * @param $page
 *   Similar to hook_nodeapi('view').
 *
 * @see fieldgroup_nodeapi()
 * @see fieldgroup_view_group()
 */
function fieldgroup_build_content($group, &$node, $teaser, $page) {
  // NODE_BUILD_NORMAL is 0, and ('whatever' == 0) is TRUE, so we need a ===.
  if ($node->build_mode === NODE_BUILD_NORMAL || $node->build_mode == NODE_BUILD_PREVIEW) {
    $context = $teaser ? 'teaser' : 'full';
  }
  else {
    $context = $node->build_mode;
  }

  $group_name = $group['group_name'];

  // Do not include group labels when indexing content.
  if ($context == NODE_BUILD_SEARCH_INDEX) {
    $group['settings']['display']['label'] = 'hidden';
  }
  $label = $group['settings']['display']['label'] == 'above';
  $element = array(
    '#title' => $label ? check_plain(t($group['label'])) : '',
    '#description' => $label ? content_filter_xss(t($group['settings']['display']['description'])) : '',
  );
  $format = isset($group['settings']['display'][$context]['format']) ? $group['settings']['display'][$context]['format'] : 'fieldset';

  switch ($format) {
    case 'simple':
      $element['#type'] = 'fieldgroup_simple';
      $element['#group_name'] = $group_name;
      $element['#node'] = $node;
      break;
    case 'hidden':
      $element['#access'] = FALSE;
      break;
    case 'fieldset_collapsed':
      $element['#collapsed'] = TRUE;
    case 'fieldset_collapsible':
      $element['#collapsible'] = TRUE;
    case 'fieldset':
      $element['#type'] = 'fieldgroup_fieldset';
      $element['#attributes'] = array('class' => 'fieldgroup '. strtr($group['group_name'], '_', '-'));
      break;
  }
  foreach ($group['fields'] as $field_name => $field) {
    if (isset($node->content[$field_name])) {
      $element[$field_name] = $node->content[$field_name];
    }
  }

  // Allow other modules to alter the group view.
  // Can't use module_invoke_all because we want
  // to be able to use a reference to $node and $element.
  foreach (module_implements('fieldgroup_view') as $module) {
    $function = $module .'_fieldgroup_view';
    $function($node, $element, $group, $context);
  }

  // Unset the original field values now that we've moved them.
  foreach ($group['fields'] as $field_name => $field) {
    if (isset($node->content[$field_name])) {
      unset($node->content[$field_name]);
    }
  }

  // The wrapper lets us get the themed output for the group
  // to populate the $GROUP_NAME_rendered variable for node templates,
  // and hide it from the $content variable if needed.
  // See fieldgroup_preprocess_node(), theme_fieldgroup_wrapper().
  $wrapper = array(
    'group' => $element,
    '#weight' => $group['weight'],
    '#post_render' => array('fieldgroup_wrapper_post_render'),
    '#group_name' => $group_name,
    '#type_name' => $node->type,
    '#context' => $context,
  );

  $node->content[$group_name] = $wrapper;
}

/**
 * Render a single field group, fully themed with label.
 *
 * To be used by third-party code (Panels, ...) that needs to output an
 * isolated field group. Do *not* use inside node templates, use the
 * $GROUP_NAME_rendered variables instead. You can also use the 'simple'
 * style format and override the template fieldgroup-simple.tpl.php.
 *
 * By default, the field group is displayed using the settings defined for the
 * 'full node' or 'teaser' contexts (depending on the value of the $teaser param).
 * Set $node->build_mode to a different value to use a different context.
 *
 * Different settings can be specified by adjusting $group['settings']['display'].
 *
 * @param $group
 *   The field group definition.
 * @param $node
 *   The node containing the field group to display. Can be a 'pseudo-node',
 *   containing at least 'type', 'nid', 'vid', and the field data required
 *   for the group.
 * @param $teaser
 * @param $page
 *   Similar to hook_nodeapi('view').
 * @return
 *   The themed output for the field group.
 *
 * @see content_view_field()
 */
function fieldgroup_view_group($group, &$node, $teaser = FALSE, $page = FALSE) {
  $group_name = $group['group_name'];
  $field_types = _content_field_types();

  // Clone the node to prevent from altering the original.
  $node_copy = drupal_clone($node);

  // Use 'full'/'teaser' if not specified otherwise.
  $node_copy->build_mode = isset($node_copy->build_mode) ? $node_copy->build_mode : NODE_BUILD_NORMAL;

  // Build the content element for individual fields in the field group.
  if (!isset($node_copy->content)) {
    $node_copy->content = array();
  }
  foreach (array_keys($group['fields']) as $field_name) {
    $field = content_fields($field_name, $node_copy->type);

    if (isset($node_copy->{$field_name})) {
      $items = $node_copy->{$field_name};

      // One-field equivalent to _content_field_invoke('sanitize').
      $module = $field_types[$field['type']]['module'];
      $function = $module .'_field';
      if (function_exists($function)) {
        $function('sanitize', $node_copy, $field, $items, $teaser, $page);
        $node_copy->{$field_name} = $items;
      }

      $field_view = content_field('view', $node_copy, $field, $items, $teaser, $page);
      // content_field('view') adds a wrapper to handle variables and 'excluded'
      // fields for node templates. We bypass it and get the actual field.
      $node_copy->content[$field_name] = $field_view[$field_name];
    }
  }

  // Build the content element of the field group itself.
  fieldgroup_build_content($group, $node_copy, $teaser, $page);

  // fieldgroup_build_content() adds a wrapper to handle variables and 'excluded'
  // groups for node templates. We bypass it and render the actual field group.
  $output = drupal_render($node_copy->content[$group_name]['group']);

  return $output;
}

/**
 * Hide specified fields from the $content variable in node templates.
 */
function fieldgroup_wrapper_post_render($content, $element) {
  $groups = fieldgroup_groups($element['#type_name']);
  $group = $groups[$element['#group_name']];

  // The display settings are not in quite the same place in the
  // group and the field, so create the value the theme will expect.
  $group['display_settings'] = $group['settings']['display'];
  if (theme('content_exclude', $content, $group, $element['#context'])) {
    return '';
  }
  return $content;
}

/*
 * Get the group name for a field.
 * If the field isn't in a group, FALSE will be returned.
 * @return The name of the group, or FALSE.
 */
function fieldgroup_get_group($content_type, $field_name) {
  foreach (fieldgroup_groups($content_type) as $group_name => $group) {
    if (in_array($field_name, array_keys($group['fields']))) {
      return $group_name;
    }
  }
  return FALSE;
}

/**
 *  Implementation of hook_node_type()
 *  React to change in node types
 */
function fieldgroup_node_type($op, $info) {
  if ($op == 'update' && !empty($info->old_type) && $info->type != $info->old_type) {
    // update the tables
    db_query("UPDATE {". fieldgroup_tablename() ."} SET type_name='%s' WHERE type_name='%s'", array($info->type, $info->old_type));
    db_query("UPDATE {". fieldgroup_fields_tablename() ."} SET type_name='%s' WHERE type_name='%s'", array($info->type, $info->old_type));
    cache_clear_all('fieldgroup_data:', content_cache_tablename(), TRUE);
  }
  elseif ($op == 'delete') {
    db_query("DELETE FROM {". fieldgroup_tablename() ."} WHERE type_name = '%s'", $info->type);
    db_query("DELETE FROM {". fieldgroup_fields_tablename() ."} WHERE type_name = '%s'", $info->type);
  }
}

function fieldgroup_types() {
  $types = array('standard' => t('Standard group'));
  // Allow other modules to add new group_types.
  $types = array_merge($types, module_invoke_all('fieldgroup_types'));
  return $types;
}

function fieldgroup_tablename($version = NULL) {
  if (is_null($version)) {
    $version = variable_get('fieldgroup_schema_version', 0);
  }
  return $version < 6000 ? 'node_group' : 'content_group';
}

function fieldgroup_fields_tablename($version = NULL) {
  if (is_null($version)) {
    $version = variable_get('fieldgroup_schema_version', 0);
  }
  return $version < 6000 ? 'node_group_fields' : 'content_group_fields';
}

/**
 * CRUD API for fieldgroup module.
 *
 * @todo
 * Make this into more of a real API for groups.
 */
/*
 * Saves the given group for this content-type
 */
function fieldgroup_save_group($type_name, $group) {
  $groups = fieldgroup_groups($type_name);

  // Allow other modules to intervene when the group is saved.
  foreach (module_implements('fieldgroup_save_group') as $module) {
    $function = $module .'_fieldgroup_save_group';
    $function($group);
  }

  if (!isset($groups[$group['group_name']])) {
    // Accept group name from programmed submissions if valid.
    db_query("INSERT INTO {". fieldgroup_tablename() ."} (group_type, type_name, group_name, label, settings, weight)".
      " VALUES ('%s', '%s', '%s', '%s', '%s', %d)", $group['group_type'], $type_name, $group['group_name'], $group['label'], serialize($group['settings']), $group['weight']);
    cache_clear_all('fieldgroup_data:', content_cache_tablename(), TRUE);
    return SAVED_NEW;
  }
  else {
    db_query("UPDATE {". fieldgroup_tablename() ."} SET group_type = '%s', label = '%s', settings = '%s', weight = %d ".
             "WHERE type_name = '%s' AND group_name = '%s'",
             $group['group_type'], $group['label'], serialize($group['settings']), $group['weight'], $type_name, $group['group_name']);
    cache_clear_all('fieldgroup_data:', content_cache_tablename(), TRUE);
    return SAVED_UPDATED;
  }
}

function fieldgroup_update_fields($form_values) {
  $default = _fieldgroup_field_get_group($form_values['type_name'], $form_values['field_name']);

  if ($default != $form_values['group']) {
    if ($form_values['group'] && !$default) {
      db_query("INSERT INTO {". fieldgroup_fields_tablename() ."} (type_name, group_name, field_name) VALUES ('%s', '%s', '%s')", $form_values['type_name'], $form_values['group'], $form_values['field_name']);
    }
    elseif ($form_values['group']) {
      db_query("UPDATE {". fieldgroup_fields_tablename() ."} SET group_name = '%s' WHERE type_name = '%s' AND field_name = '%s'", $form_values['group'], $form_values['type_name'], $form_values['field_name']);
    }
    else {
      db_query("DELETE FROM {". fieldgroup_fields_tablename() ."} WHERE type_name = '%s' AND field_name = '%s'", $form_values['type_name'], $form_values['field_name']);
    }
    cache_clear_all('fieldgroup_data:', content_cache_tablename(), TRUE);
  }
}

function fieldgroup_delete($content_type, $group_name) {
  db_query("DELETE FROM {". fieldgroup_tablename() ."} WHERE  type_name = '%s' AND group_name = '%s'", $content_type, $group_name);
  db_query("DELETE FROM {". fieldgroup_fields_tablename() ."} WHERE  type_name = '%s' AND group_name = '%s'", $content_type, $group_name);
  cache_clear_all('fieldgroup_data:', content_cache_tablename(), TRUE);
}

/**
 * Format a fieldgroup using a 'fieldset'.
 *
 * Derived from core's theme_fieldset, with no output if the content is empty.
 */
function theme_fieldgroup_fieldset($element) {
  if (empty($element['#children']) && empty($element['#value'])) {
    return '';
  }

  if ($element['#collapsible']) {
    drupal_add_js('misc/collapse.js');

    if (!isset($element['#attributes']['class'])) {
      $element['#attributes']['class'] = '';
    }

    $element['#attributes']['class'] .= ' collapsible';
    if ($element['#collapsed']) {
      $element['#attributes']['class'] .= ' collapsed';
    }
  }
  return '<fieldset'. drupal_attributes($element['#attributes']) .'>'. ($element['#title'] ? '<legend>'. $element['#title'] .'</legend>' : '') . (isset($element['#description']) && $element['#description'] ? '<div class="description">'. $element['#description'] .'</div>' : '') . (!empty($element['#children']) ? $element['#children'] : '') . (isset($element['#value']) ? $element['#value'] : '') ."</fieldset>\n";
}


/**
 * Process variables for fieldgroup.tpl.php.
 *
 * The $variables array contains the following arguments:
 * - $group_name
 * - $group_name_css
 * - $label
 * - $description
 * - $content
 *
 * @see fieldgroup-simple.tpl.php
 */
function template_preprocess_fieldgroup_simple(&$vars) {
  $element = $vars['element'];

  $vars['group_name'] = $element['#group_name'];
  $vars['group_name_css'] = strtr($element['#group_name'], '_', '-');
  $vars['label'] = isset($element['#title']) ? $element['#title'] : '';;
  $vars['description'] = isset($element['#description']) ? $element['#description'] : '';;
  $vars['content'] = isset($element['#children']) ? $element['#children'] : '';
  $vars['template_files'] = array(
    'fieldgroup-simple-',
    'fieldgroup-simple-'. $element['#group_name'],
    'fieldgroup-simple-'. $element['#node']->type,
    'fieldgroup-simple-'. $element['#group_name'] .'-'. $element['#node']->type,
  );
}

/**
 * Theme preprocess function for node.
 *
 * Adds $GROUP_NAME_rendered variables,
 * containing the themed output for the whole group.
 */
function fieldgroup_preprocess_node(&$vars) {
  $node = $vars['node'];

  foreach (fieldgroup_groups($node->type) as $group_name => $group) {
    // '#chilren' might not be set if the group is empty.
    $vars[$group_name .'_rendered'] = isset($node->content[$group_name]['#children']) ? $node->content[$group_name]['#children'] : '';
  }
}

Other Drupal examples (source code examples)

Here is a short list of links related to this Drupal fieldgroup.module source code file:

new blog posts

"Drupal" is a registered trademark of Dries Buytaert.

my drupal tutorials and examples  

Copyright 1998-2016 Alvin Alexander, alvinalexander.com
All Rights Reserved.

Beginning in 2016, a portion of the proceeds from pages under the '/drupal-code-examples/' URI will be donated to charity.