'admin/content/types/fields', 'title' => t('Fields'), 'callback' => '_content_admin_type_fields', 'access' => $access, 'type' => MENU_LOCAL_TASK, ); } else { if (arg(0) == 'admin' && arg(1) == 'content' && arg(2) == 'types') { $content_type = content_types(arg(3)); $type = node_get_types('types', $content_type['type']); if (!empty($type) && arg(3) && arg(3) == $content_type['url_str']) { $items[] = array( 'path' => 'admin/content/types/'. $content_type['url_str'] .'/edit', 'title' => t('Edit'), 'callback' => 'drupal_get_form', 'callback arguments' => array('node_type_form', $type), 'type' => MENU_DEFAULT_LOCAL_TASK, ); $items[] = array( 'path' => 'admin/content/types/'. $content_type['url_str'] .'/fields', 'title' => t('Manage fields'), 'callback' => 'drupal_get_form', 'access' => $access, 'callback arguments' => array('content_admin_field_overview_form', $content_type['type']), 'type' => MENU_LOCAL_TASK, 'weight' => 0, ); $items[] = array( 'path' => 'admin/content/types/'. $content_type['url_str'] .'/display', 'title' => t('Display fields'), 'callback' => 'drupal_get_form', 'access' => $access, 'callback arguments' => array('content_admin_display_overview_form', $content_type['type']), 'type' => MENU_LOCAL_TASK, 'weight' => 1, ); $items[] = array( 'path' => 'admin/content/types/'. $content_type['url_str'] .'/add_field', 'title' => t('Add field'), 'callback' => '_content_admin_field_add', 'access' => $access, 'callback arguments' => array($content_type['type']), 'type' => MENU_LOCAL_TASK, 'weight' => 2, ); if (arg(4) == 'fields' && arg(5) && isset($content_type['fields'][arg(5)])) { $items[] = array( 'path' => 'admin/content/types/'. $content_type['url_str'] .'/fields/'. arg(5), 'title' => t($content_type['fields'][arg(5)]['widget']['label']), 'callback' => 'drupal_get_form', 'access' => $access, 'callback arguments' => array('_content_admin_field', $content_type['type'], arg(5)), 'type' => MENU_CALLBACK, ); $items[] = array( 'path' => 'admin/content/types/'. $content_type['url_str'] .'/fields/'. arg(5) .'/remove', 'title' => t('Remove field'), 'callback' => 'drupal_get_form', 'access' => $access, 'callback arguments' => array('_content_admin_field_remove', $content_type['type'], arg(5)), 'type' => MENU_CALLBACK, ); } } } } return $items; } /** * Load data for a node type's fields. * * When loading one of the content.module nodes, we need to let each field handle * its own loading. This can make for a number of queries in some cases, so we * cache the loaded object structure and invalidate it during the update process. */ function content_load($node) { $cid = 'content:'. $node->nid .':'. $node->vid; if ($cached = cache_get($cid, 'cache_content')) { return unserialize($cached->data); } else { $default_additions = _content_field_invoke_default('load', $node); if ($default_additions) { foreach ($default_additions as $key => $value) { $node->$key = $value; } } $additions = _content_field_invoke('load', $node); if ($additions) { foreach ($additions as $key => $value) { $default_additions[$key] = $value; } } cache_set($cid, 'cache_content', serialize($default_additions)); return $default_additions; } } /** * Create fields' form for a content type. * * Each field defines its own component of the content entry form, via its * chosen widget. */ function content_form(&$node) { $form = array(); $type = content_types($node->type); // Set form parameters so we can accept file uploads. if (count($type['fields'])) { $form['#attributes'] = array("enctype" => "multipart/form-data"); } _content_widget_invoke('prepare form values', $node); $form = array_merge($form, _content_widget_invoke('form', $node)); return $form; } /** * Validate form callback to handle node type fields. * * Both widgets and fields have a chance to raise error flags when a node is * being validated. */ function content_validate(&$node) { _content_widget_invoke('validate', $node); _content_widget_invoke('process form values', $node); _content_field_invoke('validate', $node); _content_field_invoke_default('validate', $node); } /** * Submit form callback for node type fields. * * At submit time, the widget does whatever data massaging is necessary so that * the field has the content in the expected format and can commit the changes * to the database. */ function content_submit(&$node) { _content_widget_invoke('submit', $node); _content_widget_invoke('process form values', $node); _content_field_invoke('submit', $node); _content_field_invoke_default('submit', $node); } /** * Insert node type fields. */ function content_insert(&$node) { _content_field_invoke('insert', $node); _content_field_invoke_default('insert', $node); } /** * Update node type fields. */ function content_update(&$node) { _content_field_invoke('update', $node); _content_field_invoke_default('update', $node); cache_clear_all('content:'. $node->nid .':'. $node->vid, 'cache_content'); } /** * Delete node type fields. */ function content_delete(&$node) { $type = content_types($node->type); if (!empty($type['fields'])) { _content_field_invoke('delete', $node); _content_field_invoke_default('delete', $node); } $table = _content_tablename($type['type'], CONTENT_DB_STORAGE_PER_CONTENT_TYPE); if (db_table_exists($table)) { db_query('DELETE FROM {'. $table .'} WHERE nid = %d', $node->nid); } cache_clear_all('content:'. $node->nid, 'cache_content', TRUE); } /** * delete node type fields for a revision. */ function content_delete_revision(&$node) { $type = content_types($node->type); if (!empty($type['fields'])) { _content_field_invoke('delete revision', $node); _content_field_invoke_default('delete revision', $node); } $table = _content_tablename($type['type'], CONTENT_DB_STORAGE_PER_CONTENT_TYPE); if (db_table_exists($table)) { db_query('DELETE FROM {'. $table .'} WHERE vid = %d', $node->vid); } cache_clear_all('content:'. $node->nid .':'. $node->vid, 'cache_content'); } /** * Generate field render arrays. */ function content_view(&$node, $teaser = FALSE, $page = FALSE) { if ($node->in_preview) { _content_widget_invoke('process form values', $node); } $content = _content_field_view($node, $teaser, $page); $node->content = array_merge((array) $node->content, $content); } /** * Implementation of hook_nodeapi(). * * When a revision is deleted, make sure the appropriate cache item is cleared. * @todo: deprecate op==validate & op==submit in favor of form callbacks. */ function content_nodeapi(&$node, $op, $teaser, $page) { switch ($op) { case 'load': return content_load($node); case 'validate': content_validate($node); break; case 'submit': content_submit($node); break; case 'insert': content_insert($node); break; case 'update': content_update($node); break; case 'delete': content_delete($node); break; case 'delete revision': content_delete_revision($node); break; case 'view': content_view($node, $teaser, $page); break; } } /** * Implementation of hook_form_alter(). */ function content_form_alter($form_id, &$form) { if (isset($form['type'])) { $node = $form['#node']; if ($form['type']['#value'] .'_node_form' == $form_id) { $form = array_merge($form, content_form($node)); } } } /** * Make sure that CCK content type info is synched with node type data * any time the content module is enabled. */ function content_enable() { include_once('./'. drupal_get_path('module', 'content') .'/content_admin.inc'); include_once('./'. drupal_get_path('module', 'content') .'/content_crud.inc'); content_types_rebuild(); } /** * Implementation of hook_field(). Handles common field housekeeping. * * This implementation is special, as content.module does not define any field * types. Instead, this function gets called after the type-specific hook, and * takes care of the database interface for field types that do not choose to * do their own storage. */ function content_field($op, &$node, $field, &$node_field, $teaser, $page) { $db_info = content_database_info($field); switch ($op) { case 'load': $column_names = array(); foreach ($db_info['columns'] as $column => $attributes) { $column_names[] = $attributes['column'] .' AS '. $column; } $query = 'SELECT '. implode(', ', $column_names) .' FROM {'. $db_info['table'] .'} WHERE vid = %d'; if ($field['multiple']) { $result = db_query($query .' ORDER BY delta', $node->vid); } else { $result = db_query_range($query, $node->vid, 0, 1); } $additions = array(); while ($value = db_fetch_array($result)) { $additions[$field['field_name']][] = $value; } return $additions; case 'insert': foreach ($node_field as $delta => $item) { $data = array(); $column_names = array(); $column_placeholders = array(); $column_assignments = array(); foreach ($db_info['columns'] as $column => $attributes) { $column_names[] = $attributes['column']; if ($item[$column] == '' && !$attributes['not null'] && !$field['required']) { $column_placeholders[] = '%s'; $column_assignments[] = $attributes['column'] .' = %s'; $item[$column] = 'NULL'; } else { switch ($attributes['type']) { case 'int': case 'mediumint': case 'tinyint': case 'bigint': $column_placeholders[] = '%d'; $column_assignments[] = $attributes['column'] .' = %d'; break; case 'float': $column_placeholders[] = '%f'; $column_assignments[] = $attributes['column'] .' = %f'; break; default: $column_placeholders[] = "'%s'"; $column_assignments[] = $attributes['column'] ." = '%s'"; } } $data[] = $item[$column]; } $data[] = $node->vid; $data[] = $node->nid; if ($field['multiple']) { $data[] = $delta; } if ($field['multiple']) { db_query('INSERT INTO {'. $db_info['table'] .'} ('. implode(', ', $column_names) .', vid, nid, delta) VALUES ('. implode(', ', $column_placeholders) .', %d, %d, %d)', $data); } else { if (db_result(db_query('SELECT COUNT(*) FROM {'. $db_info['table'] .'} WHERE vid = %d AND nid = %d', $node->vid, $node->nid))) { db_query('UPDATE {'. $db_info['table'] .'} SET '. implode(', ', $column_assignments) .' WHERE vid = %d AND nid = %d', $data); } else { db_query('INSERT INTO {'. $db_info['table'] .'} ('. implode(', ', $column_names) .', vid, nid) VALUES ('. implode(', ', $column_placeholders) .', %d, %d)', $data); } } } return; case 'update': if ($field['multiple']) { // Delete and insert, rather than update, in case a field was added. db_query('DELETE FROM {'. $db_info['table'] .'} WHERE vid = %d', $node->vid); } foreach ($node_field as $delta => $item) { $data = array(); $column_names = array(); $column_placeholders = array(); $column_assignments = array(); foreach ($db_info['columns'] as $column => $attributes) { $column_names[] = $attributes['column']; if ($item[$column] == '' && !$attributes['not null'] && !$field['required']) { $column_placeholders[] = '%s'; $column_assignments[] = $attributes['column'] .' = %s'; $item[$column] = 'NULL'; } else { switch ($attributes['type']) { case 'int': case 'mediumint': case 'tinyint': case 'bigint': $column_placeholders[] = '%d'; $column_assignments[] = $attributes['column'] .' = %d'; break; case 'float': $column_placeholders[] = '%f'; $column_assignments[] = $attributes['column'] .' = %f'; break; default: $column_placeholders[] = "'%s'"; $column_assignments[] = $attributes['column'] ." = '%s'"; } } $data[] = $item[$column]; } $data[] = $node->vid; $data[] = $node->nid; if ($field['multiple']) { $data[] = $delta; } if ($field['multiple']) { db_query('INSERT INTO {'. $db_info['table'] .'} ('. implode(', ', $column_names) .', vid, nid, delta) VALUES ('. implode(', ', $column_placeholders) .', %d, %d, %d)', $data); } else { if (db_result(db_query('SELECT COUNT(*) FROM {'. $db_info['table'] .'} WHERE vid = %d AND nid = %d', $node->vid, $node->nid))) { db_query('UPDATE {'. $db_info['table'] .'} SET '. implode(', ', $column_assignments) .' WHERE vid = %d AND nid = %d', $data); } else { db_query('INSERT INTO {'. $db_info['table'] .'} ('. implode(', ', $column_names) .', vid, nid) VALUES ('. implode(', ', $column_placeholders) .', %d, %d)', $data); } } } return; case 'delete': // Delete using nid rather than vid to purge all revisions. db_query('DELETE FROM {'. $db_info['table'] .'} WHERE nid = %d', $node->nid); return; case 'delete revision': db_query('DELETE FROM {'. $db_info['table'] .'} WHERE vid = %d', $node->vid); return; } } /** * Invoke a field hook. * * For each operation, both this function and _content_field_invoke_default() are * called so that the default database handling can occur. */ function _content_field_invoke($op, &$node, $teaser = NULL, $page = NULL) { $type_name = is_string($node) ? $node : (is_array($node) ? $node['type'] : $node->type); $type = content_types($type_name); $field_types = _content_field_types(); $return = array(); if (count($type['fields'])) { foreach ($type['fields'] as $field) { $node_field = isset($node->$field['field_name']) ? $node->$field['field_name'] : array(); $module = $field_types[$field['type']]['module']; $function = $module .'_field'; if (function_exists($function)) { $result = $function($op, $node, $field, $node_field, $teaser, $page); if (is_array($result)) { $return = array_merge($return, $result); } else if (isset($result)) { $return[] = $result; } } // test for values in $node_field in case modules added items on insert if (isset($node->$field['field_name']) || count($node_field)) { $node->$field['field_name'] = $node_field; } } } return $return; } /** * Invoke content.module's version of a field hook. */ function _content_field_invoke_default($op, &$node, $teaser = NULL, $page = NULL) { $type_name = is_string($node) ? $node : (is_array($node) ? $node['type'] : $node->type); $type = content_types($type_name); $return = array(); if (count($type['fields'])) { foreach ($type['fields'] as $field) { $node_field = isset($node->$field['field_name']) ? $node->$field['field_name'] : array(); $db_info = content_database_info($field); if (count($db_info['columns'])) { $result = content_field($op, $node, $field, $node_field, $teaser, $page); if (is_array($result)) { $return = array_merge($return, $result); } else if (isset($result)) { $return[] = $result; } } if (isset($node->$field['field_name'])) { $node->$field['field_name'] = $node_field; } } } return $return; } /** * Format field output based on display settings. */ function _content_field_view(&$node, $teaser = NULL, $page = NULL) { $type_name = is_string($node) ? $node : (is_array($node) ? $node['type'] : $node->type); $type = content_types($type_name); $field_types = _content_field_types(); $context = $teaser ? 'teaser' : 'full'; $return = array(); if (count($type['fields'])) { foreach ($type['fields'] as $field) { $node_field = isset($node->$field['field_name']) ? $node->$field['field_name'] : array(); $formatter = isset($field['display_settings'][$context]['format']) ? $field['display_settings'][$context]['format'] : 'default'; $value = ''; if ($formatter != 'hidden') { if (content_handle('field', 'view', $field) == CONTENT_CALLBACK_CUSTOM) { $module = $field_types[$field['type']]['module']; $function = $module .'_field'; if (function_exists($function)) { $value = $function('view', $node, $field, $node_field, $teaser, $page); } } else { foreach ($node_field as $delta => $item) { $node_field[$delta]['view'] = content_format($field, $item, $formatter, $node); } $value = theme('field', $node, $field, $node_field, $teaser, $page); } } $return[$field['field_name']] = array( '#weight' => $field['widget']['weight'], '#value' => $value, '#access' => $formatter != 'hidden', ); // test for values in $node_field in case modules added items if (isset($node->$field['field_name']) || count($node_field)) { $node->$field['field_name'] = $node_field; } } } return $return; } /** * Invoke a widget hook. */ function _content_widget_invoke($op, &$node) { $type_name = is_string($node) ? $node : (is_array($node) ? $node['type'] : $node->type); $type = content_types($type_name); $widget_types = _content_widget_types(); $return = array(); if (count($type['fields'])) { foreach ($type['fields'] as $field) { $node_field = isset($node->$field['field_name']) ? $node->$field['field_name'] : array(); $module = $widget_types[$field['widget']['type']]['module']; $function = $module .'_widget'; if (function_exists($function)) { // If we're building a node creation form, pre-fill with default values if ($op == 'prepare form values' && empty($node->nid)) { $node_field = array_merge($node_field, content_default_value($node, $field, $node_field)); } $result = $function($op, $node, $field, $node_field); if (is_array($result) && $op == 'form') { $result[$field['field_name']]['#weight'] = $field['widget']['weight']; } if (is_array($result)) { $return = array_merge($return, $result); } else if (isset($result)) { $return[] = $result; } } // test for values in $node_field in case modules added items if (is_object($node) && (isset($node->$field['field_name']) || count($node_field))) { $node->$field['field_name'] = $node_field; } } } return $return; } /** * Return a list of all content types. * * @param $content_type_name * If set, return information on just this type. */ function content_types($type_name = NULL) { // handle type name with either an underscore or a dash $type_name = !empty($type_name) ? str_replace('-', '_', $type_name) : NULL; $info = _content_type_info(); if (isset($type_name)) { if (isset($info['content types'][$type_name])) { return $info['content types'][$type_name]; } else { return NULL; } } return $info['content types']; } /** * Return a list of all fields. * * @param $field_name * If set, return information on just this field. * @param $content_type_name * If set, return information of the field within the context of this content * type. */ function content_fields($field_name = NULL, $content_type_name = NULL) { $info = _content_type_info(); if (isset($field_name)) { if (isset($info['fields'][$field_name])) { if (isset($content_type_name)) { if (isset($info['content types'][$content_type_name]['fields'][$field_name])) { return $info['content types'][$content_type_name]['fields'][$field_name]; } else { return NULL; } } else { return $info['fields'][$field_name]; } } else { return NULL; } } return $info['fields']; } /** * Return a list of field types. */ function _content_field_types() { $info = _content_type_info(); return $info['field types']; } /** * Return a list of widget types. */ function _content_widget_types() { $info = _content_type_info(); return $info['widget types']; } /** * Collate all information on content types, fields, and related structures. * * @param $reset * If TRUE, clear the cache and fetch the information from the database again. */ function _content_type_info($reset = FALSE) { static $info; if ($reset || !isset($info)) { if ($cached = cache_get('content_type_info', 'cache_content')) { $info = unserialize($cached->data); } else { $info = array( 'field types' => array(), 'widget types' => array(), 'fields' => array(), 'content types' => array(), ); foreach (module_list() as $module) { $module_field_types = module_invoke($module, 'field_info'); if ($module_field_types) { foreach ($module_field_types as $name => $field_info) { // Truncate names to match the value that is stored in the database. $db_name = substr($name, 0, 32); $info['field types'][$db_name] = $field_info; $info['field types'][$db_name]['module'] = $module; $info['field types'][$db_name]['formatters'] = array(); } } $module_widgets = module_invoke($module, 'widget_info'); if ($module_widgets) { foreach ($module_widgets as $name => $widget_info) { // Truncate names to match the value that is stored in the database. $db_name = substr($name, 0, 32); $info['widget types'][$db_name] = $widget_info; $info['widget types'][$db_name]['module'] = $module; foreach ($widget_info['field types'] as $delta => $type) { $info['widget types'][$db_name][$delta] = substr($type, 0, 32); } } } } foreach (module_list() as $module) { $module_formatters = module_invoke($module, 'field_formatter_info'); if ($module_formatters) { foreach ($module_formatters as $name => $formatter_info) { foreach ($formatter_info['field types'] as $field_type) { // Truncate names to match the value that is stored in the database. $db_name = substr($field_type, 0, 32); $info['field types'][$db_name]['formatters'][$name] = $formatter_info; $info['field types'][$db_name]['formatters'][$name]['module'] = $module; } } } } $field_result = db_query('SELECT * FROM {node_field}'); while ($field = db_fetch_array($field_result)) { $global_settings = $field['global_settings'] ? unserialize($field['global_settings']) : array(); unset($field['global_settings']); // Preventative error handling for PHP5 if field nodule hasn't created an arrray. if (is_array($global_settings)) { $field = array_merge($field, $global_settings); } $instance_info = db_fetch_array(db_query("SELECT type_name, label FROM {node_field_instance} WHERE field_name = '%s'", $field['field_name'])); $field['widget']['label'] = $instance_info['label']; $field['type_name'] = $instance_info['type_name']; $info['fields'][$field['field_name']] = $field; } $type_result = db_query('SELECT * FROM {node_type} ORDER BY type ASC'); while ($type = db_fetch_array($type_result)) { $type['url_str'] = str_replace('_', '-', $type['type']); $type['fields'] = array(); $field_result = db_query("SELECT * FROM {node_field_instance} nfi WHERE nfi.type_name = '%s' ORDER BY nfi.weight ASC, nfi.label ASC", $type['type']); while ($field = db_fetch_array($field_result)) { // Overwrite global field information with specific information $field = array_merge($info['fields'][$field['field_name']], $field); $widget_settings = $field['widget_settings'] ? unserialize($field['widget_settings']) : array(); unset($field['widget_settings']); $field['widget'] = $widget_settings; $field['widget']['type'] = $field['widget_type']; unset($field['widget_type']); $field['widget']['weight'] = $field['weight']; unset($field['weight']); $field['widget']['label'] = $field['label']; unset($field['label']); $field['widget']['description'] = $field['description']; unset($field['description']); $field['type_name'] = $type['type']; $field['display_settings'] = $field['display_settings'] ? unserialize($field['display_settings']) : array(); $type['fields'][$field['field_name']] = $field; } $info['content types'][$type['type']] = $type; } cache_set('content_type_info', 'cache_content', serialize($info)); } } return $info; } /** * Implementation of hook_node_type() * React to change in node types */ function content_node_type($op, $info) { switch ($op) { case 'insert': include_once('./'. drupal_get_path('module', 'content') .'/content_crud.inc'); content_type_create($info); break; case 'update': include_once('./'. drupal_get_path('module', 'content') .'/content_crud.inc'); content_type_update($info); break; case 'delete': include_once('./'. drupal_get_path('module', 'content') .'/content_crud.inc'); content_type_delete($info); break; } } /** * Clear the cache of content_types; called in several places when content * information is changed. */ function content_clear_type_cache() { // If type type cache needs to be cleared because type information has // changed, the cached node values also need to be emptied so they // don't carry stale values. // TODO see if there is a less destructive way to do this. cache_clear_all('*', 'cache_content', TRUE); _content_type_info(TRUE); if (module_exists('views')) { // Needed because this can be called from .install files include_once('./'. drupal_get_path('module', 'views') .'/views.module'); views_invalidate_cache(); } } /** * Retrieve the database storage location(s) for a field. * * @param $field * The field whose database information is requested. * @return * An array with the keys: * "table": The name of the database table where the field data is stored. * "columns": An array of columns stored for this field. Each is a collection * of information returned from hook_field_settings('database columns'), * with the addition of a "column" attribute which holds the name of the * database column that stores the data. */ function content_database_info($field) { $field_types = _content_field_types(); $module = $field_types[$field['type']]['module']; $columns = module_invoke($module, 'field_settings', 'database columns', $field); $db_info = array(); if ($field['db_storage'] == CONTENT_DB_STORAGE_PER_FIELD) { $db_info['table'] = _content_tablename($field['field_name'], CONTENT_DB_STORAGE_PER_FIELD); } else { $db_info['table'] = _content_tablename($field['type_name'], CONTENT_DB_STORAGE_PER_CONTENT_TYPE); } if (is_array($columns) && count($columns)) { $db_info['columns'] = $columns; foreach ($columns as $column_name => $attributes) { $db_info['columns'][$column_name]['column'] = $field['field_name'] .'_'. $column_name; } } else { $db_info['columns'] = array(); } return $db_info; } /** * Manipulate a 2D array to reverse rows and columns. * * The default data storage for fields is delta first, column names second. * This is sometimes inconvenient for field modules, so this function can be * used to present the data in an alternate format. * * @param $array * The array to be transposed. It must be at least two-dimensional, and * the subarrays must all have the same keys or behavior is undefined. * * @return * The transposed array. */ function content_transpose_array_rows_cols($array) { $result = array(); if (is_array($array)) { foreach ($array as $key1 => $value1) { if (is_array($value1)) { foreach ($value1 as $key2 => $value2) { if (!isset($result[$key2])) { $result[$key2] = array(); } $result[$key2][$key1] = $value2; } } } } return $result; } /** * Format a field item for display. * * @param $field * Either a field array or the name of the field. * @param $item * The field item to be formatted (such as $node->field_foo[0]). * @param $formatter * The name of the formatter to use. * @param $node * Optionally, the containing node object for context purposes. * * @return * A string containing the contents of the field item sanitized for display. * It will have been passed through the necessary check_plain() or check_markup() * functions as necessary. */ function content_format($field, $item, $formatter = 'default', $node = NULL) { if (!is_array($field)) { $field = content_fields($field); } $field_types = _content_field_types(); $formatters = $field_types[$field['type']]['formatters']; if (!isset($formatter, $formatters)) { $formatter = 'default'; } return module_invoke($formatters[$formatter]['module'], 'field_formatter', $field, $item, $formatter, $node); } /** * Format an individual field for display. * * @param $node * The node being displayed (provided for context). * @param $field * The field that is to be displayed (for information about the label, field * type, and so forth). * @param $items * The actual items to theme. This will be a linear array, each element of * which has a "view" property which contains the filtered, formatted contents * of the item. * @param $teaser * Whether the node is being displayed as a teaser or full version. * @param $page * Whether the node is being displayed as a full web page. * * @return * An HTML string containing the fully themed field. */ function theme_field(&$node, &$field, &$items, $teaser, $page) { $label_display = isset($field['display_settings']['label']['format']) ? $field['display_settings']['label']['format'] : 'above'; $label = t($field['widget']['label']); $items_output = ''; foreach ($items as $delta => $item) { if (!empty($item['view']) || $item['view'] === "0") { $items_output .= '
'; if ($label_display == 'inline') { $items_output .= '
'; $items_output .= $label .': 
' ; } $items_output .= $item['view'] .'
'; } } $output = ''; if (!empty($items_output)) { $output .= '
'; if ($label_display == 'above') { $output .= '
'. $label .': 
'; } $output .= '
'. $items_output .'
'; $output .= '
'; } return $output; } /** * Generate a table name for a field or a content type. * * @param $name * The name of the content type or content field * @param $entity * 'field' or 'type' * * @return * A string containing the generated name for the database table */ function _content_tablename($name, $entity, $version = NULL) { if (is_null($version)) { $version = variable_get('content_schema_version', 0); } if ($version < 1003) { $version = 0; } else { $version = 1003; } $name = str_replace('-', '_', $name); switch ("$version-$entity") { case '0-'. CONTENT_DB_STORAGE_PER_CONTENT_TYPE : return "node_$name"; case '0-'. CONTENT_DB_STORAGE_PER_FIELD : return "node_data_$name"; case '1003-'. CONTENT_DB_STORAGE_PER_CONTENT_TYPE : return "content_type_$name"; case '1003-'. CONTENT_DB_STORAGE_PER_FIELD : return "content_$name"; } } /** * Helper function for determining the behaviour of a field or a widget * with respect to a given operation * (currently only used for 'view' field op and 'default value' widegt op) * * @param $entity * 'field' or 'widget' * * @param $op * the name of the operation ('view', 'validate'...) * * @param $field * The field array, including widget info. * @return * CONTENT_CALLBACK_NONE - do nothing for this operation * CONTENT_CALLBACK_CUSTOM - use the module's callback function. * CONTENT_CALLBACK_DEFAULT - use content module default behaviour * */ function content_handle($entity, $op, $field) { $entity_types = ($entity == 'field') ? _content_field_types() : _content_widget_types(); $entity_type = ($entity == 'field') ? $field['type'] : $field['widget']['type']; $module = $entity_types[$entity_type]['module']; if ($op == 'default value' && $module == 'computed_field') { $callback_value = CONTENT_CALLBACK_NONE; } else { $callbacks = module_invoke($module, "{$entity}_settings", 'callbacks', $field); $callback_value = (isset($callbacks[$op])) ? $callbacks[$op] : CONTENT_CALLBACK_DEFAULT; } return $callback_value; } /** * Helper function to return the correct default value for a field. * * @param $node * The node. * * @param $field * The field array. * * @param $items * The value of the field in the node. * * @return * The default value for that field. */ function content_default_value($node, $field, $items) { $widget_types = _content_widget_types(); $module = $widget_types[$field['widget']['type']]['module']; $default_value = array(); if (content_handle('widget', 'default value', $field) == CONTENT_CALLBACK_CUSTOM) { $function = $module .'_widget'; $default_value = $function('default value', $node, $field, $items); } elseif (!empty($field['widget']['default_value_php'])) { ob_start(); $result = eval($field['widget']['default_value_php']); ob_end_clean(); if (is_array($result)) { $default_value = $result; } } elseif (!empty($field['widget']['default_value'])) { $default_value = $field['widget']['default_value']; } return (array) $default_value; }