'admin/content/types/'. arg(3) .'/add_group', 'title' => t('Add group'), 'callback' => 'fieldgroup_edit_group', 'access' => user_access('administer content types'), 'callback arguments' => array($content_type, '', 'add'), 'type' => MENU_LOCAL_TASK, 'weight' => 3, ); if (arg(4) == 'groups' && arg(5)) { $items[] = array( 'path' => 'admin/content/types/'. arg(3) .'/groups/'. arg(5) .'/edit', 'title' => t('Edit group'), 'callback' => 'fieldgroup_edit_group', 'access' => user_access('administer content types'), 'callback arguments' => array($content_type, arg(5), 'edit'), 'type' => MENU_CALLBACK_ITEM, ); $items[] = array( 'path' => 'admin/content/types/'. arg(3) .'/groups/'. arg(5) .'/remove', 'title' => t('Edit group'), 'callback' => 'drupal_get_form', 'callback arguments' => array('fieldgroup_remove_group', $content_type, arg(5)), 'access' => user_access('administer content types'), 'type' => MENU_CALLBACK_ITEM, ); } } } drupal_add_css(drupal_get_path('module', 'fieldgroup') .'/fieldgroup.css'); } return $items; } function fieldgroup_edit_group($content_type, $group_name, $action) { return drupal_get_form('fieldgroup_edit_group_form', $content_type, $group_name, $action); } function fieldgroup_edit_group_form($content_type, $group_name, $action) { $groups = fieldgroup_groups($content_type['type']); $group = $groups[$group_name]; if ($action == 'add') { //adding a new one $group = array(); $form['submit'] = array( '#type' => 'submit', '#value' => t('Add'), '#weight' => 10, ); } else if ($group) { $form['submit'] = array( '#type' => 'submit', '#value' => t('Save'), '#weight' => 10, ); } else { drupal_not_found(); exit; } $form['label'] = array( '#type' => 'textfield', '#title' => t('Label'), '#default_value' => $group['label'], '#required' => TRUE, ); $form['settings']['#tree'] = TRUE; $form['settings']['form'] = array( '#type' => 'fieldset', '#title' => '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'] ? $group['settings']['form']['style'] : 'fieldset', '#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' => '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_merge(array_keys(_content_admin_display_contexts()), array('label')) as $key) { $form['settings']['display'][$key] = array('#type' => 'value', '#value' => $group['settings']['display'][$key]); } $form['weight'] = array('#type' => 'hidden', '#default_value' => $group['weight']); $form['group_name'] = array('#type' => 'hidden', '#default_value' => $group_name); $form['#submit'] = array('fieldgroup_edit_group_submit' => array($content_type, $action)); return $form; } /** * Group name validation for programmatic group addition. */ function fieldgroup_edit_group_validate($form_id, $form_values, $content_type, $action) { if (!empty($form_values['group_name']) && $action == 'add') { $groups = fieldgroup_groups($content_type['type']); $group = $groups[$form_values['group_name']]; if (isset($group[$form_values['group_name']])) { form_set_error('group_name', t('The group name %name already exists.', array( '%group_name' => $form_values['group_name']))); } if (!preg_match('!^[a-z0-9_]+$!', $form_values['group_name'])) { form_set_error('group_name', t('The group name %name is invalid.', array( '%group_name' => $form_values['group_name']))); } } } function fieldgroup_edit_group_submit($form_id, &$form_values, $content_type, $action) { $groups = fieldgroup_groups($content_type['type']); $group = $groups[$form_values['group_name']]; fieldgroup_save_group($content_type['type'], $form_values); cache_clear_all('fieldgroup_data', 'cache_content'); return 'admin/content/types/'. $content_type['url_str'] .'/fields'; } /* * Saves the given group for this content-type */ function fieldgroup_save_group($type_name, $group) { $groups = fieldgroup_groups($type_name); $old_group = $groups[$group['group_name']]; if (!$old_group) { // Accept group name from programmed submissions if valid. if (!empty($group['group_name'])) { $group_name = $group['group_name']; } else { // Otherwise, find a valid, computer-friendly name. $group_name = trim($group['label']); $group_name = drupal_strtolower($group_name); $group_name = str_replace(array(' ', '-'), '_', $group_name); $group_name = preg_replace('/[^a-z0-9_]/', '', $group_name); $group_name = 'group_'. $group_name; $group_name = substr($group_name, 0, 30); if (isset($groups[$group_name])) { $group_name_base = $group_name; $counter = 0; while (isset($groups[$group_name])) { $group_name = $group_name_base .'_'. $counter++; } } } db_query("INSERT INTO {node_group} (type_name, group_name, label, settings, weight) VALUES ('%s', '%s', '%s', '%s', %d)", $type_name, $group_name, $group['label'], serialize($group['settings']), $group['weight']); return SAVED_NEW; } else { db_query("UPDATE {node_group} SET label = '%s', settings = '%s', weight = %d ". "WHERE type_name = '%s' AND group_name = '%s'", $group['label'], serialize($group['settings']), $group['weight'], $type_name, $group['group_name']); return SAVED_UPDATED; } } function fieldgroup_remove_group($content_type, $group_name) { $groups = fieldgroup_groups($content_type['type']); $group = $groups[$group_name]; if (!$group) { drupal_not_found(); exit; } $form['#submit'] = array(fieldgroup_remove_group_submit => array($content_type, $group_name)); return confirm_form($form, t('Are you sure you want to remove the group %label?', array('%label' => t($group['label']))), 'admin/content/types/'. $content_type['url_str'] .'/fields', t('This action cannot be undone.'), t('Remove'), t('Cancel')); } function fieldgroup_remove_group_submit($form_id, &$form_values, $content_type, $group_name) { db_query("DELETE FROM {node_group} WHERE type_name = '%s' AND group_name = '%s'", $content_type['type'], $group_name); db_query("DELETE FROM {node_group_fields} WHERE type_name = '%s' AND group_name = '%s'", $content_type['type'], $group_name); cache_clear_all('fieldgroup_data', 'cache_content'); drupal_set_message(t('The group %group_name has been removed.', array('%group_name' => $group_name))); return 'admin/content/types/'. $content_type['url_str'] .'/fields'; } /* * Returns all groups for a content type */ function fieldgroup_groups($content_type = '', $sorted = FALSE, $reset = FALSE) { static $groups, $groups_sorted; if (!isset($groups) || $reset) { if ($cached = cache_get('fieldgroup_data', 'cache_content')) { $data = unserialize($cached->data); $groups = $data['groups']; $groups_sorted = $data['groups_sorted']; } else { $result = db_query("SELECT * FROM {node_group} ORDER BY weight, group_name"); $groups = array(); $groups_sorted = array(); while ($group = db_fetch_array($result)) { $group['settings'] = unserialize($group['settings']); $group['fields'] = array(); $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 {node_group} ng ". "INNER JOIN {node_group_fields} ngf ON ngf.type_name = ng.type_name AND ngf.group_name = ng.group_name ". "INNER JOIN {node_field_instance} nfi ON nfi.field_name = ngf.field_name AND nfi.type_name = ngf.type_name ". "ORDER BY nfi.weight"); while ($field = db_fetch_array($result)) { $groups[$field['type_name']][$field['group_name']]['fields'][$field['field_name']] = $field; } cache_set('fieldgroup_data', 'cache_content', serialize(array('groups' => $groups, 'groups_sorted' => $groups_sorted))); } } if (empty($content_type)) { return $groups; } elseif (!$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[0] = t('No group'); 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 {node_group_fields} WHERE type_name = '%s' AND field_name = '%s'", $content_type, $field_name)); } /* * Implementation of hook_form_alter() */ function fieldgroup_form_alter($form_id, &$form) { if (isset($form['type']) && $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'], '_', '-')), ); foreach ($group['fields'] as $field_name => $field) { if (isset($form[$field_name])) { $form[$group_name][$field_name] = $form[$field_name]; 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]); } } } else if ($form_id == '_content_admin_field') { $content_type = content_types($form['type_name']['#value']); $form['widget']['group'] = array( '#type' => 'select', '#title' => t('Display in group'), '#options' => _fieldgroup_groups_label($content_type['type']), '#default_value' => _fieldgroup_field_get_group($content_type['type'], $form['field_name']['#value']), '#description' => t('Select a group, in which the field will be displayed on the editing form.'), '#weight' => 5, ); $form['widget']['weight']['#weight'] = 5; $form['widget']['description']['#weight'] = 7; $form['#submit']['fieldgroup_content_admin_form_submit'] = array($form['widget']['group']['#default_value']); } else if ($form_id == 'content_admin_display_overview_form') { $form['groups'] = fieldgroup_display_overview_form($form['type_name']['#value']); $form['groups']['#theme'] = 'fieldgroup_display_overview_form'; $form['#submit']['fieldgroup_display_overview_form_submit'] = array(); if (!is_array($form['submit']) && count(fieldgroup_groups($form['type_name']['#value']))) { $form['submit'] = array('#type' => 'submit', '#value' => t('Submit'), '#weight' => 10); } } else if ($form_id == '_content_admin_field_remove') { $form['#submit']['fieldgroup_content_admin_field_remove_submit'] = array(); } } function fieldgroup_content_admin_form_submit($form_id, &$form_values, $default) { if ($default != $form_values['group']) { if ($form_values['group'] && !$default) { db_query("INSERT INTO {node_group_fields} (type_name, group_name, field_name) VALUES ('%s', '%s', '%s')", $form_values['type_name'], $form_values['group'], $form_values['field_name']); } else if ($form_values['group']) { db_query("UPDATE {node_group_fields} 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 {node_group_fields} WHERE type_name = '%s' AND field_name = '%s'", $form_values['type_name'], $form_values['field_name']); } cache_clear_all('fieldgroup_data', 'cache_content'); } } function fieldgroup_content_admin_field_remove_submit($form_id, &$form_values) { db_query("DELETE FROM {node_group_fields} WHERE type_name = '%s' AND field_name = '%s'", $form_values['type_name'], $form_values['field_name']); } function fieldgroup_nodeapi(&$node, $op, $teaser, $page) { switch ($op) { case 'view': $context = $teaser ? 'teaser' : 'full'; foreach (fieldgroup_groups($node->type) as $group_name => $group) { $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'])) : '', '#weight' => $group['weight'], '#attributes' => array('class' => 'fieldgroup '. strtr($group['group_name'], '_', '-')), ); switch ($group['settings']['display'][$context]) { case 'simple': $element['#type'] = 'fieldgroup_simple'; break; case 'hidden': $element['#access'] = FALSE; break; case 'fieldset_collapsed': $element['#collapsed'] = TRUE; case 'fieldset_collapsible': $element['#collapsible'] = TRUE; case 'fieldset': $element['#type'] = 'fieldset'; break; } $node->content[$group_name] = $element; $visible = FALSE; foreach ($group['fields'] as $field_name => $field) { if (isset($node->content[$field_name])) { $node->content[$group_name][$field_name] = $node->content[$field_name]; if ($node->content[$field_name]['#access'] && !empty($node->content[$field_name]['#value'])) { $visible = TRUE; } unset($node->content[$field_name]); } } if (!$visible) { // Hide the group, because the fields are empty or not accessible. unset($node->content[$group_name]); } } break; } } /* * Themes a simple fieldgroup on node view */ function theme_fieldgroup_simple($element) { $output = ''; if ($element['#title']) { $output .= '

'. $element['#title'] .'

'; $output .= ($element['#description'] ? '
'. $element['#description'] .'
' : ''); } $output .= '
'. $element['#children'] .'
'; $output .= ''; return $output; } /* * Gets 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' && $info->type != $info->old_type) { // update the tables db_query("UPDATE {node_group} SET type_name='%s' WHERE type_name='%s'", array($info->type, $info->old_type)); db_query("UPDATE {node_group_fields} SET type_name='%s' WHERE type_name='%s'", array($info->type, $info->old_type)); cache_clear_all('fieldgroup_data', 'cache_content'); } else if ($op == 'delete') { db_query("DELETE FROM {node_group_fields} WHERE type_name = '%s'", $info->type); db_query("DELETE FROM {node_group} WHERE type_name = '%s'", $info->type); } } /* * Adds a own table to the "display fields" tab */ function fieldgroup_display_overview_form($content_type) { $groups = fieldgroup_groups($content_type); $form = array(); $form['#tree'] = TRUE; foreach ($groups as $group_name => $group) { $form[$group_name] = fieldgroup_display_overview_form_row($group); } return $form; } function fieldgroup_display_overview_form_row($group) { $defaults = &$group['settings']['display']; //shortcut $label_options = array( 'above' => t('Above'), 'hidden' => t(''), ); $options = array( 'no_style' => t('no styling'), 'simple' => t('simple'), 'fieldset' => t('fieldset'), 'fieldset_collapsible' => t('fieldset - collapsible'), 'fieldset_collapsed' => t('fieldset - collapsed'), 'hidden' => t(''), ); $row = array(); $row['group_label'] = array('#value' => check_plain($group['label'])); $row['label'] = array( '#type' => 'select', '#options' => $label_options, '#default_value' => isset($defaults['label']) ? $defaults['label'] : 'above', ); foreach (_content_admin_display_contexts() as $key => $title) { $row[$key] = array( '#type' => 'select', '#options' => $options, '#default_value' => isset($defaults[$key]) ? $defaults[$key] : 'fieldset', ); } return $row; } /* * Themes the group part of the form as table */ function theme_fieldgroup_display_overview_form($form) { $header = array(t('Group'), t('Label')); foreach (_content_admin_display_contexts() as $key => $title) { $header[] = $title; } $rows = array(); foreach (element_children($form) as $group) { $row = array(); foreach (element_children($form[$group]) as $key) { $row[] = drupal_render($form[$group][$key]); } $rows[] = $row; } $output = ''; if (!empty($rows)) { $output = theme('table', $header, $rows, array('class' => 'content-group-display-overview')); } $output .= drupal_render($form); return $output; } function fieldgroup_display_overview_form_submit($form_id, $form_values) { $type = $form_values['type_name']; $groups = fieldgroup_groups($type); if (isset($form_values['groups'])) { foreach ($form_values['groups'] as $group_name => $groupvalues) { $group = &$groups[$group_name]; foreach ($groupvalues as $key => $value) { $group['settings']['display'][$key] = $value; } fieldgroup_save_group($type, $group); } cache_clear_all('fieldgroup_data', 'cache_content'); } } /** * Implementation of hook_panels_content_types() */ function fieldgroup_panels_content_types() { $items = array(); $items['content_fieldgroup'] = array( 'title' => t('Content fieldgroup'), 'content_types' => 'fieldgroup_panels_fieldgroup_content_types', 'single' => TRUE, // only provides a single content type 'render callback' => 'fieldgroup_panels_render_fieldgroup', 'add callback' => 'fieldgroup_panels_edit_fieldgroup', 'edit callback' => 'fieldgroup_panels_edit_fieldgroup', 'title callback' => 'fieldgroup_panels_fieldgroup_title', ); return $items; } /** * 'Render' callback for the 'fieldgroup' panel. */ function fieldgroup_panels_render_fieldgroup($conf, $panel_args, $context) { $node = isset($context->data) ? drupal_clone($context->data) : NULL; $block = new stdClass(); $block->module = 'fieldgroup'; if ($node) { // Assemble the fields into groups $node = node_build_content($node); // Get the "machine name" of the group from the options $groupname = $conf['group']; // Print out the contents of the given group // Note, not using drupal_render($node->content[$groupname]) here to avoid printing the fieldset $vars = array(); if (is_array($node->content[$groupname])) { foreach (element_children($node->content[$groupname]) as $key) { $vars[$key] = drupal_render($node->content[$groupname][$key]); } } $block->subject = $node->content[$groupname]['#title']; $block->content = $vars ? theme('fieldgroup_panel', $vars, $node->nid) : $conf['empty']; $block->delta = $node->nid; } else { $block->subject = $conf['group']; $block->content = t('Content fieldgroup content goes here.'); $block->delta = 'unknown'; } return $block; } /** * Allows users to theme the panels group. */ function theme_fieldgroup_panel($vars, $nid) { return implode('', $vars); } /** * Return all fieldgroup panel types available. */ function fieldgroup_panels_fieldgroup_content_types() { return array( 'description' => array( 'title' => t('Content fieldgroup'), 'icon' => 'icon_node.png', 'path' => panels_get_path('content_types/node'), 'description' => t('All fields from a fieldgroup on the referenced node.'), 'required context' => new panels_required_context(t('Node'), 'node'), 'category' => array(t('Node context'), -9), ), ); } /** * 'Edit' callback for the 'fieldgroup' panel. */ function fieldgroup_panels_edit_fieldgroup($id, $parents, $conf = array()) { // Apply defaults if (empty($conf)) { $conf = array('title' => '', 'group' => '', 'empty' => ''); } // Retrieve the list of all groups on all content types $group_list = array(); $types = fieldgroup_groups(NULL, FALSE, FALSE); // Add each group to the list with the content type it is from in parentheses foreach ($types as $type) { foreach ($type as $group) { $group_list[$group['group_name']] = $group['label'] . ' (' . $group['type_name'] . ')'; } } $form['type_name'] = array( '#type' => 'value', '#value' => $group['type_name'], ); $form['group'] = array( '#type' => 'select', '#title' => t('Fieldgroup'), '#options' => $group_list, '#default_value' => $conf['group'], '#prefix' => '
', '#suffix' => '
', ); $form['empty'] = array( '#type' => 'textarea', '#title' => 'Empty text', '#description' => t('Text to display if group has no data. Note that title will not display unless overridden.'), '#rows' => 5, '#default_value' => $conf['empty'], '#prefix' => '
', '#suffix' => '
', ); return $form; } /** * 'Title' callback for the 'fieldgroup' panel. */ function fieldgroup_panels_fieldgroup_title($conf, $context) { $types = fieldgroup_groups(NULL, FALSE, FALSE); $type = $types[$conf['type_name']][$conf['group']]; return t('"@s" fieldgroup @name', array('@s' => $context->identifier, '@name' => $type['label'])); }