t('Fields'), 'page callback' => 'term_fields_admin', 'description' => t('An overview of term fields.'), 'access arguments' => array('administer term fields'), 'type' => MENU_LOCAL_TASK, 'file' => 'term_fields.admin.inc' ); $items['admin/content/taxonomy/term_fields/new'] = array( 'title' => t('New Field'), 'page callback' => 'drupal_get_form', 'page arguments' => array('term_fields_admin_new'), 'description' => t('Form used to create new term fields.'), 'access arguments' => array('administer term fields'), 'type' => MENU_LOCAL_TASK, 'file' => 'term_fields.admin.inc' ); $items['admin/content/taxonomy/term_fields/settings'] = array( 'title' => t('Settings'), 'page callback' => 'drupal_get_form', 'page arguments' => array('term_fields_admin_settings'), 'description' => t('Form used to change settings.'), 'access arguments' => array('administer term fields'), 'type' => MENU_LOCAL_TASK, 'file' => 'term_fields.admin.inc' ); $items['admin/content/taxonomy/term_fields/edit/%fid'] = array( 'title' => t('Edit Field'), 'page callback' => 'drupal_get_form', 'page arguments' => array('term_fields_admin_edit', 5), 'description' => t('Form used to edit term fields.'), 'access arguments' => array('administer term fields'), 'type' => MENU_CALLBACK, 'file' => 'term_fields.admin.inc' ); $items['admin/content/taxonomy/term_fields/delete/%fid'] = array( 'title' => t('Delete Field'), 'page callback' => 'drupal_get_form', 'page arguments' => array('term_fields_admin_delete', 5), 'description' => t('Form used to delete term fields.'), 'access arguments' => array('administer term fields'), 'type' => MENU_CALLBACK, 'file' => 'term_fields.admin.inc' ); return $items; } /** * Implementation of hook_perm(). */ function term_fields_perm() { return array('administer term fields'); } /** * Implementation of hook_form_alter(). */ function term_fields_form_alter(&$form, &$form_state, $form_id) { // we don't want our form to appear on the deletion confirmation screen if ($_POST['op'] == 'Delete') { return; } // shortcuts $tid = $form['tid']['#value']; $vid = $form['vid']['#value']; switch ($form_id) { case 'taxonomy_form_term': // make the initial fieldset $form['fields'] = array( '#type' => 'fieldset', '#title' => 'Term Fields', '#collapsed' => TRUE, '#collapsible' => TRUE, '#weight' => 1 ); // get all fields for this vocabulary $sql = 'SELECT * FROM {term_fields} WHERE vid = %d ORDER BY weight'; $result = db_query($sql, $vid); $fields = array(); while ($data = db_fetch_object($result)) { $fields[$data->fid]['title'] = $data->title; $fields[$data->fid]['description'] = $data->description; $fields[$data->fid]['type'] = $data->type; $fields[$data->fid]['options'] = $data->options; } if (!empty($fields)) { // render the fields foreach ($fields as $fid => $attribute) { $sql = 'SELECT %s FROM {term_fields_term} WHERE tid = %d'; $value = db_result(db_query($sql, $fid, $tid)); // some values are going to be conditional based on the data type switch ($attribute['type']) { case 'textfield': $form['fields'][$fid] = array( '#type' => $attribute['type'], '#size' => 30, '#max_length' => 100, '#default_value' => $value ? $value : NULL, '#description' => $attribute['description'] ); break; case 'textarea': $form['fields'][$fid] = array( '#type' => $attribute['type'], '#rows' => 5, '#cols' => 60, '#default_value' => $value ? $value : NULL, '#description' => $attribute['description'] ); break; case 'numeric': $form['fields'][$fid] = array( '#type' => 'textfield', '#size' => 2, '#default_value' => $value ? $value : NULL, '#description' => $attribute['description'] ); break; case 'select': $options = unserialize($attribute['options']); $options = array('' => '') + $options; $form['fields'][$fid] = array( '#type' => 'select', '#options' => $options, '#default_value' => $value || $value == 0 ? $value : NULL, '#description' => $attribute['description'] ); break; case 'date': $default_value = date_parse($value); $form['fields'][$fid] = array( '#type' => $attribute['type'], '#default_value' => $default_value ? $default_value : NULL, '#element_validate' => array('term_fields_date_validate'), '#description' => $attribute['description'] ); } // these fields will always be the same $form['fields'][$fid]['#title'] = $attribute['title'] . ' (' . $fid . ')'; $form['fields'][$fid]['#description'] = $attribute['description']; // we're going to make some alterations to any date fields that exist $form['#after_build'] = array('term_fields_alter_date'); } } else { $form['fields']['empty'] = array( '#type' => 'item', '#value' => t('There are no fields defined for the vocabulary that this term is a part of.') ); } $form['submit']['#weight'] = 10; $form['delete']['#weight'] = 10; } } /** * Implementation of hook_taxonomy(). */ function term_fields_taxonomy($op, $type, $form_values) { // shortcuts $tid = $form_values['tid']; $vid = $form_values['vid']; switch($type) { case 'term': // get all fields IDs used by this vocabulary $fids = term_fields_get_fids($vid); if (!empty($fids)) { // map field values $values = array(); foreach ($fids as $fid) { $value = $form_values[$fid]; if (!is_array($value)) { $values[$fid] = $value; } else { // this is a date field $values[$fid] = $value['year'] . '-' . $value['month'] . '-' . $value['day']; } } // some simple clean up and validation foreach ($values as $fid => $value) { $sql = "SELECT type, options FROM {term_fields} WHERE fid = '%s'"; $record = db_fetch_object(db_query($sql, $fid)); switch ($record->type) { case 'numeric': if (!is_numeric($value) && $value != '') { drupal_set_message(t('!fid must be numeric. This field was not set.', array('!fid' => $fid)), 'error'); unset($values[$fid]); } break; case 'select': $options = unserialize($options); } } // if there's no values to set then we need to get out of here // the exception being if the term is being deleted if ($op != 'delete' && count($values) == 0) { break; } switch ($op) { case 'insert': term_fields_term_create_record($tid, $values); break; case 'update': // see if theres a record for this term already. // if so, update it. if not, insert a new record $sql = 'SELECT tid FROM {term_fields_term} WHERE tid = %d'; $result = db_query($sql, $tid); if (term_fields_fetch_fields($result)) { // update the existing record term_fields_term_update_record($tid, $values); } else { // insert a new record term_fields_term_create_record($tid, $values); } break; case 'delete': db_query('DELETE FROM {term_fields_term} WHERE tid = %d', $tid); } } break; case 'vocabulary': switch ($op) { case 'delete': $fids = term_fields_get_fids($vid); if (!empty($fids)) { foreach ($fids as $fid) { db_query('ALTER TABLE {term_fields_term} DROP %s', $fid); } db_query('DELETE FROM {term_fields} WHERE vid = %d', $vid); } } } } /** * Retrieve a single field value given a term ID and field ID. */ function term_fields_get_field($tid, $fid) { $sql = "SELECT %s FROM {term_fields_term} WHERE tid = %d"; return db_result(db_query($sql, $fid, $tid)); } /** * Retrieve an array of fields from a given term, keyed by field ID. */ function term_fields_get_fields($term) { $fids = term_fields_get_fids($term->vid); $field_list = implode(',', $fids); $sql = 'SELECT ' . $field_list . ' FROM {term_fields_term} WHERE tid = %d'; $result = db_query($sql, $term->tid); return db_fetch_array($result); } /** * Retrieve a term object like taxonomy_get_term(), but with fields. */ function term_fields_get_term($tid) { $term = taxonomy_get_term($tid); $fields = term_fields_get_fields($term); $term->fields = $fields; return $term; } /** * Implementation of hook_views_api(). */ function term_fields_views_api() { return array( 'api' => 2, 'path' => drupal_get_path('module', 'term_fields') . '/views' ); } /** * Get a list of field IDs */ function term_fields_get_fids($vid = NULL) { if ($vid) { $sql = 'SELECT fid FROM {term_fields} WHERE vid = %d'; $result = db_query($sql, $vid); } else { $sql = 'SELECT fid FROM {term_fields}'; $result = db_query($sql); } while ($data = db_fetch_object($result)) { $fields[] = $data->fid; } return $fields; } /** * Get all values from rows in the term_fields table. */ function term_fields_get_rows($vid = NULL) { if ($vid) { $sql = 'SELECT * FROM {term_fields} WHERE vid = %d'; } else { $sql = 'SELECT * FROM {term_fields}'; } $result = db_query($sql); $rows = array(); while ($data = db_fetch_object($result)) { $fid = $data->fid; unset($data->fid); $rows[$fid] = $data; } return $rows; } /** * Get all values from a single row in the term_fields table. */ function term_fields_get_row($fid) { $sql = "SELECT * FROM {term_fields} WHERE fid = '%s'"; return db_fetch_object(db_query($sql)); } /** * Check a string to make sure all the characters are acceptable. */ function term_fields_check_acceptable($string, $acceptable = 'abcdefghijklmnopqrstuvwxyz1234567890_') { $string = str_split($string); $acceptable = str_split($acceptable); foreach ($string as $character) { if (!in_array(strtolower($character), $acceptable)) { return FALSE; } } return TRUE; } /** * Insert a record in the term_field_term table. */ function term_fields_term_create_record($tid, $values) { // create a comma separted list of fields to be used in the query $fields = array_keys($values); $field_list = implode(', ', $fields); // create a list of place holders so db_query() can do it's thing $placeholders = ''; foreach ($values as $value) { $placeholders = $placeholders . (is_numeric($value) ? "%d, " : "'%s', "); } $placeholders = rtrim($placeholders, ', '); // put the term id at the beginning of the array array_unshift($values, $tid); // go go go $sql = 'INSERT INTO {term_fields_term} (tid, ' . $field_list . ') VALUES (%d, ' . $placeholders . ')'; db_query($sql, $values); } /** * Update an existing record in the term_fields_term table. */ function term_fields_term_update_record($tid, $values) { // create a list of fields and their respective placeholders for db_query() $placeholders = ''; foreach ($values as $fid => $value) { $placeholders = $placeholders . $fid . ' = ' . (is_numeric($value) ? "%d, " : "'%s', "); } $placeholders = rtrim($placeholders, ', '); // add the tid on to the end of the array array_push($values, $tid); // construct and execute $sql = 'UPDATE {term_fields_term} SET ' . $placeholders . ' WHERE tid = %d'; db_query($sql, $values); } /** * #after_build function to pop a blank value to the top of date fields */ function term_fields_alter_date($form, $form_element) { $sql = "SELECT fid FROM {term_fields} WHERE type = '%s' AND vid = %d"; $result = db_query($sql, 'date', $form['vid']['#value']); if (db_affected_rows()) { $date_ids = array(); while ($data = db_fetch_object($result)) { $date_ids[] = $data->fid; } foreach ($date_ids as $did) { // add blank values to each select list $blank = array(0 => ''); $form['fields'][$did]['year']['#options'] = $blank + $form['fields'][$did]['year']['#options']; $form['fields'][$did]['month']['#options'] = $blank + $form['fields'][$did]['month']['#options']; $form['fields'][$did]['day']['#options'] = $blank + $form['fields'][$did]['day']['#options']; // give titles to each list $form['fields'][$did]['year']['#title'] = t('Year'); $form['fields'][$did]['month']['#title'] = t('Month'); $form['fields'][$did]['day']['#title'] = t('Day'); } } return $form; } /** * Validator for date fields. */ function term_fields_date_validate($element, &$form_state) { $year = $element['year']['#value']; $month = $element['month']['#value']; $day = $element['day']['#value']; // we allow the user to unset date fields by leaving all fields (day, month AND year) blank // they can only have either all 3 of them set, or all 3 of them unset if (empty($year) || empty($month) || empty($day)) { if (!(empty($year) && empty($month) && empty($day))) { form_set_error($element['#name'], t("A value must be specified for month, day and year. If you want to make this field blank, unset all three fields.")); } } } /** * Loader function for fid argument. */ function fid_load($fid) { if ($fid) { $fids = term_fields_get_fids(); if (in_array($fid, $fids)) { return $fid; } } return FALSE; } /** * Helper function to modify the datetime object in the database to whatever format the user chooses. */ function term_fields_format_date($date) { $format = variable_get('term_fields_date_format', 'd/m/Y'); $format_custom = variable_get('term_fields_date_format_custom', ''); if (!empty($date) && $date != "0000-00-00 00:00:00") { $datetime = date_create($date); if ($format_custom) { $date = date_format($datetime, $format_custom); } else { $date = date_format($datetime, $format); } return $date; } else { return ''; } } /** * Helper function to determine if there are any fields defined, and return them * in an array usable by theme_table if so. */ function term_fields_fetch_fields($result) { $rows = array(); while ($data = db_fetch_object($result)) { $rows[$data->fid]['title'] = $data->title . ' (' . $data->fid . ')'; $rows[$data->fid]['vocab'] = $data->name; $rows[$data->fid]['desc'] = $data->description; $rows[$data->fid]['edit'] = l(t('Edit'), 'admin/content/taxonomy/term_fields/edit/' . $data->fid); } return !empty($rows) ? $rows : 0; } /** * Implementation of hook_token_values(). */ function term_fields_token_values($type, $object = NULL, $options = array()) { if ($type == 'taxonomy') { $term = $object; $tokens = array(); $fields = term_fields_get_rows(); foreach ($fields as $fid => $field) { if ($field->type != 'textarea' && $field->type != 'date') { $value = term_fields_get_field($term->tid, $fid); $tokens['field-' . $fid] = check_plain($value); $tokens['field-' . $fid . '-raw'] = $value; } } return $tokens; } } /** * Implementation of hook_token_list(). */ function term_fields_token_list($type = 'all') { if ($type == 'taxonomy' || $type == 'all') { $tokens = array(); $fields = term_fields_get_rows(); foreach ($fields as $fid => $field) { if ($field->type != 'textarea' && $field->type != 'date') { $tokens['term_fields']['field-' . $fid] = t($field->description); $tokens['term_fields']['field-' . $fid . '-raw'] = t($field->description . ' - *RAW*'); } } return $tokens; } }