Project

General

Profile

Paste
Download (15.2 KB) Statistics
| Branch: | Revision:

root / drupal7 / modules / node / content_types.inc @ b0dc3a2e

1
<?php
2

    
3
/**
4
 * @file
5
 * Content type editing user interface.
6
 */
7

    
8
/**
9
 * Displays the content type admin overview page.
10
 */
11
function node_overview_types() {
12
  $types = node_type_get_types();
13
  $names = node_type_get_names();
14
  $field_ui = module_exists('field_ui') && user_access('administer fields');
15
  $header = array(t('Name'), array('data' => t('Operations'), 'colspan' => $field_ui ? '4' : '2'));
16
  $rows = array();
17

    
18
  foreach ($names as $key => $name) {
19
    $type = $types[$key];
20
    if (node_hook($type->type, 'form')) {
21
      $type_url_str = str_replace('_', '-', $type->type);
22
      $row = array(theme('node_admin_overview', array('name' => $name, 'type' => $type)));
23
      // Set the edit column.
24
      $row[] = array('data' => l(t('edit'), 'admin/structure/types/manage/' . $type_url_str));
25

    
26
      if ($field_ui) {
27
        // Manage fields.
28
        $row[] = array('data' => l(t('manage fields'), 'admin/structure/types/manage/' . $type_url_str . '/fields'));
29

    
30
        // Display fields.
31
        $row[] = array('data' => l(t('manage display'), 'admin/structure/types/manage/' . $type_url_str . '/display'));
32
      }
33

    
34
      // Set the delete column.
35
      if ($type->custom) {
36
        $row[] = array('data' => l(t('delete'), 'admin/structure/types/manage/' . $type_url_str . '/delete'));
37
      }
38
      else {
39
        $row[] = array('data' => '');
40
      }
41

    
42
      $rows[] = $row;
43
    }
44
  }
45

    
46
  $build['node_table'] = array(
47
    '#theme' => 'table',
48
    '#header' => $header,
49
    '#rows' => $rows,
50
    '#empty' => t('No content types available. <a href="@link">Add content type</a>.', array('@link' => url('admin/structure/types/add'))),
51
  );
52

    
53
  return $build;
54
}
55

    
56
/**
57
 * Returns HTML for a node type description for the content type admin overview page.
58
 *
59
 * @param $variables
60
 *   An associative array containing:
61
 *   - name: The human-readable name of the content type.
62
 *   - type: An object containing the 'type' (machine name) and 'description' of
63
 *     the content type.
64
 *
65
 * @ingroup themeable
66
 */
67
function theme_node_admin_overview($variables) {
68
  $name = $variables['name'];
69
  $type = $variables['type'];
70

    
71
  $output = check_plain($name);
72
  $output .= ' <small>' . t('(Machine name: @type)', array('@type' => $type->type)) . '</small>';
73
  $output .= '<div class="description">' . filter_xss_admin($type->description) . '</div>';
74
  return $output;
75
}
76

    
77
/**
78
 * Form constructor for the node type editing form.
79
 *
80
 * @param $type
81
 *   (optional) An object representing the node type, when editing an existing
82
 *   node type.
83
 *
84
 * @see node_type_form_validate()
85
 * @see node_type_form_submit()
86
 * @ingroup forms
87
 */
88
function node_type_form($form, &$form_state, $type = NULL) {
89
  if (!isset($type->type)) {
90
    // This is a new type. Node module managed types are custom and unlocked.
91
    $type = node_type_set_defaults(array('custom' => 1, 'locked' => 0));
92
  }
93

    
94
  // Make the type object available to implementations of hook_form_alter.
95
  $form['#node_type'] = $type;
96

    
97
  $form['name'] = array(
98
    '#title' => t('Name'),
99
    '#type' => 'textfield',
100
    '#default_value' => $type->name,
101
    '#description' => t('The human-readable name of this content type. This text will be displayed as part of the list on the <em>Add new content</em> page. It is recommended that this name begin with a capital letter and contain only letters, numbers, and spaces. This name must be unique.'),
102
    '#required' => TRUE,
103
    '#size' => 30,
104
  );
105

    
106
  $form['type'] = array(
107
    '#type' => 'machine_name',
108
    '#default_value' => $type->type,
109
    '#maxlength' => 32,
110
    '#disabled' => $type->locked,
111
    '#machine_name' => array(
112
      'exists' => 'node_type_load',
113
    ),
114
    '#description' => t('A unique machine-readable name for this content type. It must only contain lowercase letters, numbers, and underscores. This name will be used for constructing the URL of the %node-add page, in which underscores will be converted into hyphens.', array(
115
      '%node-add' => t('Add new content'),
116
    )),
117
  );
118

    
119
  $form['description'] = array(
120
    '#title' => t('Description'),
121
    '#type' => 'textarea',
122
    '#default_value' => $type->description,
123
    '#description' => t('Describe this content type. The text will be displayed on the <em>Add new content</em> page.'),
124
  );
125

    
126
  $form['additional_settings'] = array(
127
    '#type' => 'vertical_tabs',
128
    '#attached' => array(
129
      'js' => array(drupal_get_path('module', 'node') . '/content_types.js'),
130
    ),
131
  );
132

    
133
  $form['submission'] = array(
134
    '#type' => 'fieldset',
135
    '#title' => t('Submission form settings'),
136
    '#collapsible' => TRUE,
137
    '#group' => 'additional_settings',
138
  );
139
  $form['submission']['title_label'] = array(
140
    '#title' => t('Title field label'),
141
    '#type' => 'textfield',
142
    '#default_value' => $type->title_label,
143
    '#required' => TRUE,
144
  );
145
  if (!$type->has_title) {
146
    // Avoid overwriting a content type that intentionally does not have a
147
    // title field.
148
    $form['submission']['title_label']['#attributes'] = array('disabled' => 'disabled');
149
    $form['submission']['title_label']['#description'] = t('This content type does not have a title field.');
150
    $form['submission']['title_label']['#required'] = FALSE;
151
  }
152
  $form['submission']['node_preview'] = array(
153
    '#type' => 'radios',
154
    '#title' => t('Preview before submitting'),
155
    '#default_value' => variable_get('node_preview_' . $type->type, DRUPAL_OPTIONAL),
156
    '#options' => array(
157
      DRUPAL_DISABLED => t('Disabled'),
158
      DRUPAL_OPTIONAL => t('Optional'),
159
      DRUPAL_REQUIRED => t('Required'),
160
    ),
161
  );
162
  $form['submission']['help']  = array(
163
    '#type' => 'textarea',
164
    '#title' => t('Explanation or submission guidelines'),
165
    '#default_value' => $type->help,
166
    '#description' => t('This text will be displayed at the top of the page when creating or editing content of this type.'),
167
  );
168
  $form['workflow'] = array(
169
    '#type' => 'fieldset',
170
    '#title' => t('Publishing options'),
171
    '#collapsible' => TRUE,
172
    '#collapsed' => TRUE,
173
    '#group' => 'additional_settings',
174
  );
175
  $form['workflow']['node_options'] = array('#type' => 'checkboxes',
176
    '#title' => t('Default options'),
177
    '#default_value' => variable_get('node_options_' . $type->type, array('status', 'promote')),
178
    '#options' => array(
179
      'status' => t('Published'),
180
      'promote' => t('Promoted to front page'),
181
      'sticky' => t('Sticky at top of lists'),
182
      'revision' => t('Create new revision'),
183
    ),
184
    '#description' => t('Users with the <em>Administer content</em> permission will be able to override these options.'),
185
  );
186
  $form['display'] = array(
187
    '#type' => 'fieldset',
188
    '#title' => t('Display settings'),
189
    '#collapsible' => TRUE,
190
    '#collapsed' => TRUE,
191
    '#group' => 'additional_settings',
192
  );
193
  $form['display']['node_submitted'] = array(
194
    '#type' => 'checkbox',
195
    '#title' => t('Display author and date information.'),
196
    '#default_value' => variable_get('node_submitted_' . $type->type, TRUE),
197
    '#description' => t('Author username and publish date will be displayed.'),
198
  );
199
  $form['old_type'] = array(
200
    '#type' => 'value',
201
    '#value' => $type->type,
202
  );
203
  $form['orig_type'] = array(
204
    '#type' => 'value',
205
    '#value' => isset($type->orig_type) ? $type->orig_type : '',
206
  );
207
  $form['base'] = array(
208
    '#type' => 'value',
209
    '#value' => $type->base,
210
  );
211
  $form['custom'] = array(
212
    '#type' => 'value',
213
    '#value' => $type->custom,
214
  );
215
  $form['modified'] = array(
216
    '#type' => 'value',
217
    '#value' => $type->modified,
218
  );
219
  $form['locked'] = array(
220
    '#type' => 'value',
221
    '#value' => $type->locked,
222
  );
223

    
224
  $form['actions'] = array('#type' => 'actions');
225
  $form['actions']['submit'] = array(
226
    '#type' => 'submit',
227
    '#value' => t('Save content type'),
228
    '#weight' => 40,
229
  );
230

    
231
  if ($type->custom) {
232
    if (!empty($type->type)) {
233
      $form['actions']['delete'] = array(
234
        '#type' => 'submit',
235
        '#value' => t('Delete content type'),
236
        '#weight' => 45,
237
      );
238
    }
239
  }
240

    
241
  return $form;
242
}
243

    
244
/**
245
 * Helper function for teaser length choices.
246
 */
247
function _node_characters($length) {
248
  return ($length == 0) ? t('Unlimited') : format_plural($length, '1 character', '@count characters');
249
}
250

    
251
/**
252
 * Form validation handler for node_type_form().
253
 *
254
 * @see node_type_form_submit()
255
 */
256
function node_type_form_validate($form, &$form_state) {
257
  $type = new stdClass();
258
  $type->type = $form_state['values']['type'];
259
  $type->name = trim($form_state['values']['name']);
260

    
261
  // Work out what the type was before the user submitted this form
262
  $old_type = $form_state['values']['old_type'];
263

    
264
  $types = node_type_get_names();
265

    
266
  if (!$form_state['values']['locked']) {
267
    // 'theme' conflicts with theme_node_form().
268
    // '0' is invalid, since elsewhere we check it using empty().
269
    if (in_array($type->type, array('0', 'theme'))) {
270
      form_set_error('type', t("Invalid machine-readable name. Enter a name other than %invalid.", array('%invalid' => $type->type)));
271
    }
272
  }
273

    
274
  $names = array_flip($types);
275

    
276
  if (isset($names[$type->name]) && $names[$type->name] != $old_type) {
277
    form_set_error('name', t('The human-readable name %name is already taken.', array('%name' => $type->name)));
278
  }
279
}
280

    
281
/**
282
 * Form submission handler for node_type_form().
283
 *
284
 * @see node_type_form_validate()
285
 */
286
function node_type_form_submit($form, &$form_state) {
287
  $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
288

    
289
  $type = node_type_set_defaults();
290

    
291
  $type->type = $form_state['values']['type'];
292
  $type->name = trim($form_state['values']['name']);
293
  $type->orig_type = trim($form_state['values']['orig_type']);
294
  $type->old_type = isset($form_state['values']['old_type']) ? $form_state['values']['old_type'] : $type->type;
295

    
296
  $type->description = $form_state['values']['description'];
297
  $type->help = $form_state['values']['help'];
298
  $type->title_label = $form_state['values']['title_label'];
299
  // title_label is required in core; has_title will always be true, unless a
300
  // module alters the title field.
301
  $type->has_title = ($type->title_label != '');
302

    
303
  $type->base = !empty($form_state['values']['base']) ? $form_state['values']['base'] : 'node_content';
304
  $type->custom = $form_state['values']['custom'];
305
  $type->modified = TRUE;
306
  $type->locked = $form_state['values']['locked'];
307
  if (isset($form['#node_type']->module)) {
308
    $type->module = $form['#node_type']->module;
309
  }
310

    
311
  if ($op == t('Delete content type')) {
312
    $form_state['redirect'] = 'admin/structure/types/manage/' . str_replace('_', '-', $type->old_type) . '/delete';
313
    return;
314
  }
315

    
316
  $variables = $form_state['values'];
317

    
318
  // Remove everything that's been saved already - whatever's left is assumed
319
  // to be a persistent variable.
320
  foreach ($variables as $key => $value) {
321
    if (isset($type->$key)) {
322
      unset($variables[$key]);
323
    }
324
  }
325

    
326
  unset($variables['form_token'], $variables['op'], $variables['submit'], $variables['delete'], $variables['reset'], $variables['form_id'], $variables['form_build_id']);
327

    
328
  // Save or reset persistent variable values.
329
  foreach ($variables as $key => $value) {
330
    $variable_new = $key . '_' . $type->type;
331
    $variable_old = $key . '_' . $type->old_type;
332

    
333
    if (is_array($value)) {
334
      $value = array_keys(array_filter($value));
335
    }
336
    variable_set($variable_new, $value);
337

    
338
    if ($variable_new != $variable_old) {
339
      variable_del($variable_old);
340
    }
341
  }
342

    
343
  // Saving the content type after saving the variables allows modules to act
344
  // on those variables via hook_node_type_insert().
345
  $status = node_type_save($type);
346

    
347
  node_types_rebuild();
348
  menu_rebuild();
349
  $t_args = array('%name' => $type->name);
350

    
351
  if ($status == SAVED_UPDATED) {
352
    drupal_set_message(t('The content type %name has been updated.', $t_args));
353
  }
354
  elseif ($status == SAVED_NEW) {
355
    node_add_body_field($type);
356
    drupal_set_message(t('The content type %name has been added.', $t_args));
357
    watchdog('node', 'Added content type %name.', $t_args, WATCHDOG_NOTICE, l(t('view'), 'admin/structure/types'));
358
  }
359

    
360
  $form_state['redirect'] = 'admin/structure/types';
361
  return;
362
}
363

    
364
/**
365
 * Implements hook_node_type_insert().
366
 */
367
function node_node_type_insert($info) {
368
  if (!empty($info->old_type) && $info->old_type != $info->type) {
369
    $update_count = node_type_update_nodes($info->old_type, $info->type);
370

    
371
    if ($update_count) {
372
      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)));
373
    }
374
  }
375
}
376

    
377
/**
378
 * Implements hook_node_type_update().
379
 */
380
function node_node_type_update($info) {
381
  if (!empty($info->old_type) && $info->old_type != $info->type) {
382
    $update_count = node_type_update_nodes($info->old_type, $info->type);
383

    
384
    if ($update_count) {
385
      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)));
386
    }
387
  }
388
}
389

    
390
/**
391
 * Resets relevant fields of a module-defined node type to their default values.
392
 *
393
 * @param $type
394
 *   The node type to reset. The node type is passed back by reference with its
395
 *   resetted values. If there is no module-defined info for this node type,
396
 *   then nothing happens.
397
 */
398
function node_type_reset($type) {
399
  $info_array = module_invoke_all('node_info');
400
  if (isset($info_array[$type->orig_type])) {
401
    $info_array[$type->orig_type]['type'] = $type->orig_type;
402
    $info = node_type_set_defaults($info_array[$type->orig_type]);
403

    
404
    foreach ($info as $field => $value) {
405
      $type->$field = $value;
406
    }
407
  }
408
}
409

    
410
/**
411
 * Menu callback; delete a single content type.
412
 *
413
 * @ingroup forms
414
 */
415
function node_type_delete_confirm($form, &$form_state, $type) {
416
  $form['type'] = array('#type' => 'value', '#value' => $type->type);
417
  $form['name'] = array('#type' => 'value', '#value' => $type->name);
418

    
419
  $message = t('Are you sure you want to delete the content type %type?', array('%type' => $type->name));
420
  $caption = '';
421

    
422
  $num_nodes = db_query("SELECT COUNT(*) FROM {node} WHERE type = :type", array(':type' => $type->type))->fetchField();
423
  if ($num_nodes) {
424
    $caption .= '<p>' . format_plural($num_nodes, '%type is used by 1 piece of content on your site. If you remove this content type, you will not be able to edit the %type content and it may not display correctly.', '%type is used by @count pieces of content on your site. If you remove %type, you will not be able to edit the %type content and it may not display correctly.', array('%type' => $type->name)) . '</p>';
425
  }
426

    
427
  $caption .= '<p>' . t('This action cannot be undone.') . '</p>';
428

    
429
  return confirm_form($form, $message, 'admin/structure/types', $caption, t('Delete'));
430
}
431

    
432
/**
433
 * Process content type delete confirm submissions.
434
 *
435
 * @see node_type_delete_confirm()
436
 */
437
function node_type_delete_confirm_submit($form, &$form_state) {
438
  node_type_delete($form_state['values']['type']);
439

    
440
  variable_del('node_preview_' . $form_state['values']['type']);
441
  $t_args = array('%name' => $form_state['values']['name']);
442
  drupal_set_message(t('The content type %name has been deleted.', $t_args));
443
  watchdog('node', 'Deleted content type %name.', $t_args, WATCHDOG_NOTICE);
444

    
445
  node_types_rebuild();
446
  menu_rebuild();
447

    
448
  $form_state['redirect'] = 'admin/structure/types';
449
  return;
450
}