Code coverage for /20080809/modules/node/content_types.inc

Line #Times calledCode
1
<?php
2
// $Id: content_types.inc,v 1.57 2008/07/16 21:59:27 dries Exp $
3
4
/**
5
 * @file
6
 * Content type editing UI.
7
 */
8
9
/**
10
 * Displays the content type admin overview page.
11
 */
127
function node_overview_types() {
131
  $types = node_get_types();
141
  $names = node_get_types('names');
151
  $header = array(t('Name'), t('Type'), t('Description'), array('data' =>
t('Operations'), 'colspan' => '2'));
161
  $rows = array();
17
181
  foreach ($names as $key => $name) {
191
    $type = $types[$key];
201
    if (node_hook($type, 'form')) {
211
      $type_url_str = str_replace('_', '-', $type->type);
22
      $row = array(
231
        check_plain($name),
241
        check_plain($type->type),
251
        filter_xss_admin($type->description),
261
      );
27
      // Set the edit column.
281
      $row[] = array('data' => l(t('edit'), 'admin/build/node-type/' .
$type_url_str));
29
30
      // Set the delete column.
311
      if ($type->custom) {
321
        $row[] = array('data' => l(t('delete'), 'admin/build/node-type/' .
$type_url_str . '/delete'));
331
      }
34
      else {
350
        $row[] = array('data' => '');
36
      }
371
      $rows[] = $row;
381
    }
391
  }
40
411
  if (empty($rows)) {
420
    $rows[] = array(array('data' => t('No content types available.'),
'colspan' => '5', 'class' => 'message'));
430
  }
44
451
  return theme('table', $header, $rows);
460
}
47
48
/**
49
 * Generates the node type editing form.
50
 */
517
function node_type_form(&$form_state, $type = NULL) {
523
  if (!isset($type->type)) {
530
    $type = new stdClass();
540
    $type->type = $type->name = $type->module = $type->description =
$type->help = '';
550
    $type->min_word_count = 0;
560
    $type->has_title = TRUE;
570
    $type->has_body = TRUE;
580
    $type->title_label = t('Title');
590
    $type->body_label = t('Body');
600
    $type->custom = TRUE;
610
    $type->modified = FALSE;
620
    $type->locked = FALSE;
630
  }
64
653
  $form['#node_type'] = $type; // Make the type object available to
implementations of hook_form_alter.
66
673
  $form['identity'] = array(
683
    '#type' => 'fieldset',
693
    '#title' => t('Identification'),
70
  );
713
  $form['identity']['name'] = array(
723
    '#title' => t('Name'),
733
    '#type' => 'textfield',
743
    '#default_value' => $type->name,
753
    '#description' => t('The human-readable name of this content type. This
text will be displayed as part of the list on the <em>create content</em>
page. It is recommended that this name begin with a capital letter and
contain only letters, numbers, and <strong>spaces</strong>. This name must
be unique.'),
763
    '#required' => TRUE,
77
  );
78
793
  if (!$type->locked) {
803
    $form['identity']['type'] = array(
813
      '#title' => t('Type'),
823
      '#type' => 'textfield',
833
      '#default_value' => $type->type,
843
      '#maxlength' => 32,
853
      '#required' => TRUE,
863
      '#description' => t('The machine-readable name of this content type.
This text will be used for constructing the URL of the <em>create
content</em> page for this content type. This name must contain only
lowercase letters, numbers, and underscores. Underscores will be converted
into hyphens when constructing the URL of the <em>create content</em> page.
This name must be unique.'),
87
    );
883
  }
89
  else {
900
    $form['identity']['type'] = array(
910
      '#type' => 'value',
920
      '#value' => $type->type,
93
    );
940
    $form['identity']['type_display'] = array(
950
      '#title' => t('Type'),
960
      '#type' => 'item',
970
      '#markup' => theme('placeholder', $type->type),
980
      '#description' => t('The machine-readable name of this content type.
This field cannot be modified for system-defined content types.'),
99
    );
100
  }
101
1023
  $form['identity']['description'] = array(
1033
    '#title' => t('Description'),
1043
    '#type' => 'textarea',
1053
    '#default_value' => $type->description,
1063
    '#description' => t('A brief description of this content type. This
text will be displayed as part of the list on the <em>create content</em>
page.'),
107
    );
108
1093
  $form['submission'] = array(
1103
    '#type' => 'fieldset',
1113
    '#title' => t('Submission form settings'),
1123
    '#collapsible' => TRUE,
1133
    '#collapsed' => TRUE,
114
  );
1153
  $form['submission']['title_label'] = array(
1163
    '#title' => t('Title field label'),
1173
    '#type' => 'textfield',
1183
    '#default_value' => $type->title_label,
1193
    '#required' => TRUE,
120
  );
1213
  if (!$type->has_title) {
122
    // Avoid overwriting a content type that intentionally does not have a
123
    // title field.
1240
    $form['submission']['title_label']['#attributes'] = array('disabled' =>
'disabled');
1250
    $form['submission']['title_label']['#description'] = t('This content
type does not have a title field.');
1260
    $form['submission']['title_label']['#required'] = FALSE;
1270
  }
1283
  $form['submission']['body_label'] = array(
1293
    '#title' => t('Body field label'),
1303
    '#type' => 'textfield',
1313
    '#default_value' => isset($type->body_label) ? $type->body_label : '',
1323
    '#description' => t('To omit the body field for this content type,
remove any text and leave this field blank.'),
133
  );
1343
  $form['submission']['min_word_count'] = array(
1353
    '#type' => 'select',
1363
    '#title' => t('Minimum number of words'),
1373
    '#default_value' => $type->min_word_count,
1383
    '#options' => drupal_map_assoc(array(0, 10, 25, 50, 75, 100, 125, 150,
175, 200)),
1393
    '#description' => t('The minimum number of words for the body field to
be considered valid for this content type. This can be useful to rule out
submissions that do not meet the site\'s standards, such as short test
posts.')
1403
  );
1413
  $form['submission']['help']  = array(
1423
    '#type' => 'textarea',
1433
    '#title' => t('Explanation or submission guidelines'),
1443
    '#default_value' => $type->help,
1453
    '#description' => t('This text will be displayed at the top of the
submission form for this content type. It is useful for helping or
instructing your users.')
1463
  );
1473
  $form['workflow'] = array(
1483
    '#type' => 'fieldset',
1493
    '#title' => t('Workflow settings'),
1503
    '#collapsible' => TRUE,
1513
    '#collapsed' => TRUE,
152
  );
1533
  $form['workflow']['node_options'] = array('#type' => 'checkboxes',
1543
    '#title' => t('Default options'),
1553
    '#default_value' => variable_get('node_options_' . $type->type,
array('status', 'promote')),
156
    '#options' => array(
1573
      'status' => t('Published'),
1583
      'promote' => t('Promoted to front page'),
1593
      'sticky' => t('Sticky at top of lists'),
1603
      'revision' => t('Create new revision'),
1613
    ),
1623
    '#description' => t('Users with the <em>administer nodes</em>
permission will be able to override these options.'),
163
  );
164
1653
  $form['old_type'] = array(
1663
    '#type' => 'value',
1673
    '#value' => $type->type,
168
  );
1693
  $form['orig_type'] = array(
1703
    '#type' => 'value',
1713
    '#value' => isset($type->orig_type) ? $type->orig_type : '',
172
  );
1733
  $form['module'] = array(
1743
    '#type' => 'value',
1753
    '#value' => $type->module,
176
  );
1773
  $form['custom'] = array(
1783
    '#type' => 'value',
1793
    '#value' => $type->custom,
180
  );
1813
  $form['modified'] = array(
1823
    '#type' => 'value',
1833
    '#value' => $type->modified,
184
  );
1853
  $form['locked'] = array(
1863
    '#type' => 'value',
1873
    '#value' => $type->locked,
188
  );
189
1903
  $form['submit'] = array(
1913
    '#type' => 'submit',
1923
    '#value' => t('Save content type'),
1933
    '#weight' => 40,
194
  );
195
1963
  if ($type->custom) {
1973
    if (!empty($type->type)) {
1983
      $form['delete'] = array(
1993
        '#type' => 'submit',
2003
        '#value' => t('Delete content type'),
2013
        '#weight' => 45,
202
      );
2033
    }
2043
  }
205
  else {
2060
    $form['reset'] = array(
2070
      '#type' => 'submit',
2080
      '#value' => t('Reset to defaults'),
2090
      '#weight' => 50,
210
    );
211
  }
212
2133
  return $form;
2140
}
215
216
/**
217
 * Implementation of hook_form_validate().
218
 */
2197
function node_type_form_validate($form, &$form_state) {
2201
  $type = new stdClass();
2211
  $type->type = trim($form_state['values']['type']);
2221
  $type->name = trim($form_state['values']['name']);
223
224
  // Work out what the type was before the user submitted this form
2251
  $old_type = trim($form_state['values']['old_type']);
226
2271
  $types = node_get_types('names');
228
2291
  if (!$form_state['values']['locked']) {
2301
    if (isset($types[$type->type]) && $type->type != $old_type) {
2310
      form_set_error('type', t('The machine-readable name %type is already
taken.', array('%type' => $type->type)));
2320
    }
2331
    if (!preg_match('!^[a-z0-9_]+$!', $type->type)) {
2340
      form_set_error('type', t('The machine-readable name must contain only
lowercase letters, numbers, and underscores.'));
2350
    }
236
    // 'theme' conflicts with theme_node_form().
237
    // '0' is invalid, since elsewhere we check it using empty().
2381
    if (in_array($type->type, array('0', 'theme'))) {
2390
      form_set_error('type', t("Invalid machine-readable name. Please enter
a name other than %invalid.", array('%invalid' => $type->type)));
2400
    }
2411
  }
242
2431
  $names = array_flip($types);
244
2451
  if (isset($names[$type->name]) && $names[$type->name] != $old_type) {
2460
    form_set_error('name', t('The human-readable name %name is already
taken.', array('%name' => $type->name)));
2470
  }
2481
}
249
250
/**
251
 * Implementation of hook_form_submit().
252
 */
2537
function node_type_form_submit($form, &$form_state) {
2541
  $op = isset($form_state['values']['op']) ? $form_state['values']['op'] :
'';
255
2561
  $type = new stdClass();
257
2581
  $type->type = trim($form_state['values']['type']);
2591
  $type->name = trim($form_state['values']['name']);
2601
  $type->orig_type = trim($form_state['values']['orig_type']);
2611
  $type->old_type = isset($form_state['values']['old_type']) ?
$form_state['values']['old_type'] : $type->type;
262
2631
  $type->description = $form_state['values']['description'];
2641
  $type->help = $form_state['values']['help'];
2651
  $type->min_word_count = $form_state['values']['min_word_count'];
2661
  $type->title_label = $form_state['values']['title_label'];
2671
  $type->body_label = $form_state['values']['body_label'];
268
269
  // title_label is required in core; has_title will always be true, unless
a
270
  // module alters the title field.
2711
  $type->has_title = ($type->title_label != '');
2721
  $type->has_body = ($type->body_label != '');
273
2741
  $type->module = !empty($form_state['values']['module']) ?
$form_state['values']['module'] : 'node';
2751
  $type->custom = $form_state['values']['custom'];
2761
  $type->modified = TRUE;
2771
  $type->locked = $form_state['values']['locked'];
278
2791
  if ($op == t('Reset to defaults')) {
2800
    node_type_reset($type);
2810
  }
2821
  elseif ($op == t('Delete content type')) {
2830
    $form_state['redirect'] = 'admin/build/node-type/' . str_replace('_',
'-', $type->old_type) . '/delete';
2840
    return;
2850
  }
286
2871
  $status = node_type_save($type);
288
2891
  $variables = $form_state['values'];
290
291
  // Remove everything that's been saved already - whatever's left is
assumed
292
  // to be a persistent variable.
2931
  foreach ($variables as $key => $value) {
2941
    if (isset($type->$key)) {
2951
      unset($variables[$key]);
2961
    }
2971
  }
298
2991
  unset($variables['form_token'], $variables['op'], $variables['submit'],
$variables['delete'], $variables['reset'], $variables['form_id']);
300
301
  // Save or reset persistent variable values.
3021
  foreach ($variables as $key => $value) {
3031
    $variable_new = $key . '_' . $type->type;
3041
    $variable_old = $key . '_' . $type->old_type;
305
3061
    if ($op == t('Reset to defaults')) {
3070
      variable_del($variable_old);
3080
    }
309
    else {
3101
      if (is_array($value)) {
3111
        $value = array_keys(array_filter($value));
3121
      }
3131
      variable_set($variable_new, $value);
314
3151
      if ($variable_new != $variable_old) {
3160
        variable_del($variable_old);
3170
      }
318
    }
3191
  }
320
3211
  node_types_rebuild();
3221
  menu_rebuild();
3231
  $t_args = array('%name' => $type->name);
324
3251
  if ($op == t('Reset to defaults')) {
3260
    drupal_set_message(t('The content type %name has been reset to its
default values.', $t_args));
3270
    return;
3280
  }
329
3301
  if ($status == SAVED_UPDATED) {
3311
    drupal_set_message(t('The content type %name has been updated.',
$t_args));
3321
  }
3330
  elseif ($status == SAVED_NEW) {
3340
    drupal_set_message(t('The content type %name has been added.',
$t_args));
3350
    watchdog('node', 'Added content type %name.', $t_args, WATCHDOG_NOTICE,
l(t('view'), 'admin/build/types'));
3360
  }
337
3381
  $form_state['redirect'] = 'admin/build/types';
3391
  return;
3400
}
341
342
/**
343
 * Implementation of hook_node_type().
344
 */
3457
function node_node_type($op, $info) {
34663
  if ($op != 'delete' && !empty($info->old_type) && $info->old_type !=
$info->type) {
3470
    $update_count = node_type_update_nodes($info->old_type, $info->type);
348
3490
    if ($update_count) {
3500
      drupal_set_message(format_plural($update_count, 'Changed the content
type of 1 post from %old-type to %type.', 'Changed the content type of
@count posts from %old-type to %type.', array('%old-type' =>
$info->old_type, '%type' => $info->type)));
3510
    }
3520
  }
35363
}
354
355
/**
356
 * Resets all of the relevant fields of a module-defined node type to
their
357
 * default values.
358
 *
359
 * @param &$type
360
 *   The node type to reset. The node type is passed back by reference with
its
361
 *   resetted values. If there is no module-defined info for this node
type,
362
 *   then nothing happens.
363
 */
3647
function node_type_reset(&$type) {
3650
  $info_array = module_invoke_all('node_info');
3660
  if (isset($info_array[$type->orig_type])) {
3670
    $info_array[$type->orig_type]['type'] = $type->orig_type;
3680
    $info = _node_type_set_defaults($info_array[$type->orig_type]);
369
3700
    foreach ($info as $field => $value) {
3710
      $type->$field = $value;
3720
    }
3730
  }
3740
}
375
376
/**
377
 * Menu callback; delete a single content type.
378
 */
3797
function node_type_delete_confirm(&$form_state, $type) {
3800
  $form['type'] = array('#type' => 'value', '#value' => $type->type);
3810
  $form['name'] = array('#type' => 'value', '#value' => $type->name);
382
3830
  $message = t('Are you sure you want to delete the content type %type?',
array('%type' => $type->name));
3840
  $caption = '';
385
3860
  $num_nodes = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type =
'%s'", $type->type));
3870
  if ($num_nodes) {
3880
    $caption .= '<p>' . format_plural($num_nodes,
'<strong>Warning:</strong> there is currently 1 %type post on your site. It
may not be able to be displayed or edited correctly, once you have removed
this content type.', '<strong>Warning:</strong> there are currently @count
%type posts on your site. They may not be able to be displayed or edited
correctly, once you have removed this content type.', array('%type' =>
$type->name)) . '</p>';
3890
  }
390
3910
  $caption .= '<p>' . t('This action cannot be undone.') . '</p>';
392
3930
  return confirm_form($form, $message, 'admin/build/types', $caption,
t('Delete'));
3940
}
395
396
/**
397
 * Process content type delete confirm submissions.
398
 */
3997
function node_type_delete_confirm_submit($form, &$form_state) {
4000
  node_type_delete($form_state['values']['type']);
401
4020
  $t_args = array('%name' => $form_state['values']['name']);
4030
  drupal_set_message(t('The content type %name has been deleted.',
$t_args));
4040
  watchdog('menu', 'Deleted content type %name.', $t_args,
WATCHDOG_NOTICE);
405
4060
  node_types_rebuild();
4070
  menu_rebuild();
408
4090
  $form_state['redirect'] = 'admin/build/types';
4100
  return;
4110
}
4127