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

Line #Times calledCode
1
<?php
2
// $Id: node.admin.inc,v 1.24 2008/07/19 19:04:24 dries Exp $
3
4
/**
5
 * @file
6
 * Content administration and module settings UI.
7
 */
8
9
/**
10
 * Menu callback; presents general node configuration options.
11
 */
1291
function node_configure() {
13
  // Only show rebuild button if there are either 0, or 2 or more, rows
14
  // in the {node_access} table, or if there are modules that
15
  // implement hook_node_grants().
160
  if (db_result(db_query('SELECT COUNT(*) FROM {node_access}')) != 1 ||
count(module_implements('node_grants')) > 0) {
170
    $status = '<p>' . t('If the site is experiencing problems with
permissions to content, you may have to rebuild the permissions cache.
Possible causes for permission problems are disabling modules or
configuration changes to permissions. Rebuilding will remove all privileges
to posts, and replace them with permissions based on the current modules
and settings.') . '</p>';
180
    $status .= '<p>' . t('Rebuilding may take some time if there is a lot
of content or complex permission settings. After rebuilding has completed
posts will automatically use the new permissions.') . '</p>';
19
200
    $form['access'] = array(
210
      '#type' => 'fieldset',
220
      '#title' => t('Node access status'),
23
    );
240
    $form['access']['status'] = array('#markup' => $status);
250
    $form['access']['rebuild'] = array(
260
      '#type' => 'submit',
270
      '#value' => t('Rebuild permissions'),
28
    );
290
  }
30
310
  $form['default_nodes_main'] = array(
320
    '#type' => 'select', '#title' => t('Number of posts on main page'),
'#default_value' => variable_get('default_nodes_main', 10),
330
    '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15,
20, 25, 30)),
340
    '#description' => t('The default maximum number of posts to display per
page on overview pages such as the main page.')
350
  );
360
  $form['teaser_length'] = array(
370
    '#type' => 'select', '#title' => t('Length of trimmed posts'),
'#default_value' => variable_get('teaser_length', 600),
380
    '#options' => drupal_map_assoc(array(0, 200, 400, 600, 800, 1000, 1200,
1400, 1600, 1800, 2000), '_node_characters'),
390
    '#description' => t("The maximum number of characters used in the
trimmed version of a post. Drupal will use this setting to determine at
which offset long posts should be trimmed. The trimmed version of a post is
typically used as a teaser when displaying the post on the main page, in
XML feeds, etc. To disable teasers, set to 'Unlimited' . Note that this
setting will only affect new or updated content and will not affect
existing teasers.")
400
  );
41
420
  $form['node_preview'] = array(
430
    '#type' => 'radios',
440
    '#title' => t('Preview post'),
450
    '#default_value' => variable_get('node_preview', 0),
460
    '#options' => array(t('Optional'), t('Required')),
470
    '#description' => t('Must users preview posts before submitting?'),
48
  );
49
500
  $form['#validate'] = array('node_configure_validate');
51
520
  return system_settings_form($form);
530
}
54
55
/**
56
 * Helper function for teaser length choices.
57
 */
5891
function _node_characters($length) {
590
  return ($length == 0) ? t('Unlimited') : format_plural($length, '1
character', '@count characters');
600
}
61
62
/**
63
 * Form validate callback.
64
 */
6591
function node_configure_validate($form, &$form_state) {
660
  if ($form_state['values']['op'] == t('Rebuild permissions')) {
670
    drupal_goto('admin/content/node-settings/rebuild');
680
  }
690
}
70
71
/**
72
 * Menu callback: confirm rebuilding of permissions.
73
 */
7491
function node_configure_rebuild_confirm() {
750
  return confirm_form(array(), t('Are you sure you want to rebuild the
permissions on site content?'),
760
                  'admin/content/node-settings', t('This action rebuilds
all permissions on site content, and may be a lengthy process. This action
cannot be undone.'), t('Rebuild permissions'), t('Cancel'));
770
}
78
79
/**
80
 * Handler for wipe confirmation
81
 */
8291
function node_configure_rebuild_confirm_submit($form, &$form_state) {
830
  node_access_rebuild(TRUE);
840
  $form_state['redirect'] = 'admin/content/node-settings';
850
  return;
860
}
87
88
/**
89
 * Implementation of hook_node_operations().
90
 */
9191
function node_node_operations() {
92
  $operations = array(
93
    'publish' => array(
940
      'label' => t('Publish'),
950
      'callback' => 'node_mass_update',
960
      'callback arguments' => array('updates' => array('status' => 1)),
970
    ),
98
    'unpublish' => array(
990
      'label' => t('Unpublish'),
1000
      'callback' => 'node_mass_update',
1010
      'callback arguments' => array('updates' => array('status' => 0)),
1020
    ),
103
    'promote' => array(
1040
      'label' => t('Promote to front page'),
1050
      'callback' => 'node_mass_update',
1060
      'callback arguments' => array('updates' => array('status' => 1,
'promote' => 1)),
1070
    ),
108
    'demote' => array(
1090
      'label' => t('Demote from front page'),
1100
      'callback' => 'node_mass_update',
1110
      'callback arguments' => array('updates' => array('promote' => 0)),
1120
    ),
113
    'sticky' => array(
1140
      'label' => t('Make sticky'),
1150
      'callback' => 'node_mass_update',
1160
      'callback arguments' => array('updates' => array('status' => 1,
'sticky' => 1)),
1170
    ),
118
    'unsticky' => array(
1190
      'label' => t('Remove stickiness'),
1200
      'callback' => 'node_mass_update',
1210
      'callback arguments' => array('updates' => array('sticky' => 0)),
1220
    ),
123
    'delete' => array(
1240
      'label' => t('Delete'),
1250
      'callback' => NULL,
1260
    ),
1270
  );
1280
  return $operations;
1290
}
130
131
/**
132
 * List node administration filters that can be applied.
133
 */
13491
function node_filters() {
135
  // Regular filters
1360
  $filters['status'] = array(
1370
    'title' => t('status'),
138
    'options' => array(
1390
      'status-1' => t('published'),
1400
      'status-0' => t('not published'),
1410
      'promote-1' => t('promoted'),
1420
      'promote-0' => t('not promoted'),
1430
      'sticky-1' => t('sticky'),
1440
      'sticky-0' => t('not sticky'),
1450
    ),
146
  );
147
  // Include translation states if we have this module enabled
1480
  if (module_exists('translation')) {
1490
    $filters['status']['options'] += array(
1500
      'translate-0' => t('Up to date translation'),
1510
      'translate-1' => t('Outdated translation'),
152
    );
1530
  }
154
1550
  $filters['type'] = array('title' => t('type'), 'options' =>
node_get_types('names'));
156
157
  // The taxonomy filter
1580
  if ($taxonomy = module_invoke('taxonomy', 'form_all', 1)) {
1590
    $filters['category'] = array('title' => t('category'), 'options' =>
$taxonomy);
1600
  }
161
  // Language filter if there is a list of languages
1620
  if ($languages = module_invoke('locale', 'language_list')) {
1630
    $languages = array('' => t('Language neutral')) + $languages;
1640
    $filters['language'] = array('title' => t('language'), 'options' =>
$languages);
1650
  }
1660
  return $filters;
1670
}
168
169
/**
170
 * Build query for node administration filters based on session.
171
 */
17291
function node_build_filter_query() {
1730
  $filters = node_filters();
174
175
  // Build query
1760
  $where = $args = array();
1770
  $join = '';
1780
  foreach ($_SESSION['node_overview_filter'] as $index => $filter) {
1790
    list($key, $value) = $filter;
180
    switch ($key) {
1810
      case 'status':
182
        // Note: no exploitable hole as $key/$value have already been
checked when submitted
1830
        list($key, $value) = explode('-', $value, 2);
1840
        $where[] = 'n.' . $key . ' = %d';
1850
        break;
1860
      case 'category':
1870
        $table = "tn$index";
1880
        $where[] = "$table.tid = %d";
1890
        $join .= "INNER JOIN {term_node} $table ON n.nid = $table.nid ";
1900
        break;
1910
      case 'type':
1920
        $where[] = "n.type = '%s'";
1930
        break;
1940
      case 'language':
1950
        $where[] = "n.language = '%s'";
1960
        break;
1970
    }
1980
    $args[] = $value;
1990
  }
2000
  $where = count($where) ? 'WHERE ' . implode(' AND ', $where) : '';
201
2020
  return array('where' => $where, 'join' => $join, 'args' => $args);
2030
}
204
205
/**
206
 * Return form for node administration filters.
207
 */
20891
function node_filter_form() {
2090
  $session = &$_SESSION['node_overview_filter'];
2100
  $session = is_array($session) ? $session : array();
2110
  $filters = node_filters();
212
2130
  $i = 0;
2140
  $form['filters'] = array(
2150
    '#type' => 'fieldset',
2160
    '#title' => t('Show only items where'),
2170
    '#theme' => 'node_filters',
218
  );
2190
  $form['#submit'][] = 'node_filter_form_submit';
2200
  foreach ($session as $filter) {
2210
    list($type, $value) = $filter;
2220
    if ($type == 'category') {
223
      // Load term name from DB rather than search and parse options
array.
2240
      $value = module_invoke('taxonomy', 'get_term', $value);
2250
      $value = $value->name;
2260
    }
2270
    else if ($type == 'language') {
2280
      $value = empty($value) ? t('Language neutral') :
module_invoke('locale', 'language_name', $value);
2290
    }
230
    else {
2310
      $value = $filters[$type]['options'][$value];
232
    }
2330
    if ($i++) {
2340
      $form['filters']['current'][] = array('#markup' => t('<em>and</em>
where <strong>%a</strong> is <strong>%b</strong>', array('%a' =>
$filters[$type]['title'], '%b' => $value)));
2350
    }
236
    else {
2370
      $form['filters']['current'][] = array('#markup' =>
t('<strong>%a</strong> is <strong>%b</strong>', array('%a' =>
$filters[$type]['title'], '%b' => $value)));
238
    }
2390
    if (in_array($type, array('type', 'language'))) {
240
      // Remove the option if it is already being filtered on.
2410
      unset($filters[$type]);
2420
    }
2430
  }
244
2450
  foreach ($filters as $key => $filter) {
2460
    $names[$key] = $filter['title'];
2470
    $form['filters']['status'][$key] = array('#type' => 'select',
'#options' => $filter['options']);
2480
  }
249
2500
  $form['filters']['filter'] = array('#type' => 'radios', '#options' =>
$names, '#default_value' => 'status');
2510
  $form['filters']['buttons']['submit'] = array('#type' => 'submit',
'#value' => (count($session) ? t('Refine') : t('Filter')));
2520
  if (count($session)) {
2530
    $form['filters']['buttons']['undo'] = array('#type' => 'submit',
'#value' => t('Undo'));
2540
    $form['filters']['buttons']['reset'] = array('#type' => 'submit',
'#value' => t('Reset'));
2550
  }
256
2570
  drupal_add_js('misc/form.js', 'core');
258
2590
  return $form;
2600
}
261
262
/**
263
 * Theme node administration filter form.
264
 *
265
 * @ingroup themeable
266
 */
26791
function theme_node_filter_form($form) {
2680
  $output = '';
2690
  $output .= '<div id="node-admin-filter">';
2700
  $output .= drupal_render($form['filters']);
2710
  $output .= '</div>';
2720
  $output .= drupal_render($form);
2730
  return $output;
2740
}
275
276
/**
277
 * Theme node administration filter selector.
278
 *
279
 * @ingroup themeable
280
 */
28191
function theme_node_filters($form) {
2820
  $output = '';
2830
  $output .= '<ul class="clear-block">';
2840
  if (!empty($form['current'])) {
2850
    foreach (element_children($form['current']) as $key) {
2860
      $output .= '<li>' . drupal_render($form['current'][$key]) . '</li>';
2870
    }
2880
  }
289
2900
  $output .= '<li><dl class="multiselect">' . (!empty($form['current']) ?
'<dt><em>' . t('and') . '</em> ' . t('where') . '</dt>' : '') . '<dd
class="a">';
2910
  foreach (element_children($form['filter']) as $key) {
2920
    $output .= drupal_render($form['filter'][$key]);
2930
  }
2940
  $output .= '</dd>';
295
2960
  $output .= '<dt>' . t('is') . '</dt><dd class="b">';
297
2980
  foreach (element_children($form['status']) as $key) {
2990
    $output .= drupal_render($form['status'][$key]);
3000
  }
3010
  $output .= '</dd>';
302
3030
  $output .= '</dl>';
3040
  $output .= '<div class="container-inline" id="node-admin-buttons">' .
drupal_render($form['buttons']) . '</div>';
3050
  $output .= '</li></ul>';
306
3070
  return $output;
3080
}
309
310
/**
311
 * Process result from node administration filter form.
312
 */
31391
function node_filter_form_submit($form, &$form_state) {
3140
  $filters = node_filters();
3150
  switch ($form_state['values']['op']) {
3160
    case t('Filter'):
3170
    case t('Refine'):
3180
      if (isset($form_state['values']['filter'])) {
3190
        $filter = $form_state['values']['filter'];
320
321
        // Flatten the options array to accommodate hierarchical/nested
options.
3220
        $flat_options =
form_options_flatten($filters[$filter]['options']);
323
3240
        if (isset($flat_options[$form_state['values'][$filter]])) {
3250
          $_SESSION['node_overview_filter'][] = array($filter,
$form_state['values'][$filter]);
3260
        }
3270
      }
3280
      break;
3290
    case t('Undo'):
3300
      array_pop($_SESSION['node_overview_filter']);
3310
      break;
3320
    case t('Reset'):
3330
      $_SESSION['node_overview_filter'] = array();
3340
      break;
3350
  }
3360
}
337
338
/**
339
 * Make mass update of nodes, changing all nodes in the $nodes array
340
 * to update them with the field values in $updates.
341
 *
342
 * IMPORTANT NOTE: This function is intended to work when called
343
 * from a form submit handler. Calling it outside of the form submission
344
 * process may not work correctly.
345
 *
346
 * @param array $nodes
347
 *   Array of node nids to update.
348
 * @param array $updates
349
 *   Array of key/value pairs with node field names and the
350
 *   value to update that field to.
351
 */
35291
function node_mass_update($nodes, $updates) {
353
  // We use batch processing to prevent timeout when updating a large
number
354
  // of nodes.
3550
  if (count($nodes) > 10) {
356
    $batch = array(
357
      'operations' => array(
3580
        array('_node_mass_update_batch_process', array($nodes, $updates))
3590
      ),
3600
      'finished' => '_node_mass_update_batch_finished',
3610
      'title' => t('Processing'),
362
      // We use a single multi-pass operation, so the default
363
      // 'Remaining x of y operations' message will be confusing here.
3640
      'progress_message' => '',
3650
      'error_message' => t('The update has encountered an error.'),
366
      // The operations do not live in the .module file, so we need to
367
      // tell the batch engine which file to load before calling them.
3680
      'file' => drupal_get_path('module', 'node') . '/node.admin.inc',
3690
    );
3700
    batch_set($batch);
3710
  }
372
  else {
3730
    foreach ($nodes as $nid) {
3740
      _node_mass_update_helper($nid, $updates);
3750
    }
3760
    drupal_set_message(t('The update has been performed.'));
377
  }
3780
}
379
380
/**
381
 * Node Mass Update - helper function.
382
 */
38391
function _node_mass_update_helper($nid, $updates) {
3840
  $node = node_load($nid, NULL, TRUE);
3850
  foreach ($updates as $name => $value) {
3860
    $node->$name = $value;
3870
  }
3880
  node_save($node);
3890
  return $node;
3900
}
391
392
/**
393
 * Node Mass Update Batch operation
394
 */
39591
function _node_mass_update_batch_process($nodes, $updates, &$context) {
3960
  if (!isset($context['sandbox']['progress'])) {
3970
    $context['sandbox']['progress'] = 0;
3980
    $context['sandbox']['max'] = count($nodes);
3990
    $context['sandbox']['nodes'] = $nodes;
4000
  }
401
402
  // Process nodes by groups of 5.
4030
  $count = min(5, count($context['sandbox']['nodes']));
4040
  for ($i = 1; $i <= $count; $i++) {
405
    // For each nid, load the node, reset the values, and save it.
4060
    $nid = array_shift($context['sandbox']['nodes']);
4070
    $node = _node_mass_update_helper($nid, $updates);
408
409
    // Store result for post-processing in the finished callback.
4100
    $context['results'][] = l($node->title, 'node/' . $node->nid);
411
412
    // Update our progress information.
4130
    $context['sandbox']['progress']++;
4140
  }
415
416
  // Inform the batch engine that we are not finished,
417
  // and provide an estimation of the completion level we reached.
4180
  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
4190
    $context['finished'] = $context['sandbox']['progress'] /
$context['sandbox']['max'];
4200
  }
4210
}
422
423
/**
424
 * Node Mass Update Batch 'finished' callback.
425
 */
42691
function _node_mass_update_batch_finished($success, $results, $operations)
{
4270
  if ($success) {
4280
    drupal_set_message(t('The update has been performed.'));
4290
  }
430
  else {
4310
    drupal_set_message(t('An error occurred and processing did not
complete.'), 'error');
4320
    $message = format_plural(count($results), '1 item successfully
processed:', '@count items successfully processed:');
4330
    $message .= theme('item_list', $results);
4340
    drupal_set_message($message);
435
  }
4360
}
437
438
/**
439
 * Menu callback: content administration.
440
 */
44191
function node_admin_content($form_state) {
4420
  if (isset($form_state['values']['operation']) &&
$form_state['values']['operation'] == 'delete') {
4430
    return node_multiple_delete_confirm($form_state,
array_filter($form_state['values']['nodes']));
4440
  }
4450
  $form = node_filter_form();
446
4470
  $form['#theme'] = 'node_filter_form';
4480
  $form['admin']  = node_admin_nodes();
449
4500
  return $form;
4510
}
452
453
/**
454
 * Form builder: Builds the node administration overview.
455
 */
45691
function node_admin_nodes() {
457
4580
  $filter = node_build_filter_query();
459
4600
  $result = pager_query(db_rewrite_sql('SELECT n.*, u.name FROM {node} n '
. $filter['join'] . ' INNER JOIN {users} u ON n.uid = u.uid ' .
$filter['where'] . ' ORDER BY n.changed DESC'), 50, 0, NULL,
$filter['args']);
461
462
  // Enable language column if locale is enabled or if we have any node
with language
4630
  $count = db_result(db_query("SELECT COUNT(*) FROM {node} n WHERE language
!= ''"));
4640
  $multilanguage = (module_exists('locale') || $count);
465
4660
  $form['options'] = array(
4670
    '#type' => 'fieldset',
4680
    '#title' => t('Update options'),
4690
    '#prefix' => '<div class="container-inline">',
4700
    '#suffix' => '</div>',
471
  );
4720
  $options = array();
4730
  foreach (module_invoke_all('node_operations') as $operation => $array) {
4740
    $options[$operation] = $array['label'];
4750
  }
4760
  $form['options']['operation'] = array(
4770
    '#type' => 'select',
4780
    '#options' => $options,
4790
    '#default_value' => 'approve',
480
  );
4810
  $form['options']['submit'] = array(
4820
    '#type' => 'submit',
4830
    '#value' => t('Update'),
4840
    '#submit' => array('node_admin_nodes_submit'),
485
  );
486
4870
  $languages = language_list();
4880
  $destination = drupal_get_destination();
4890
  $nodes = array();
4900
  while ($node = db_fetch_object($result)) {
4910
    $nodes[$node->nid] = '';
4920
    $options = empty($node->language) ? array() : array('language' =>
$languages[$node->language]);
4930
    $form['title'][$node->nid] = array('#markup' => l($node->title, 'node/'
. $node->nid, $options) . ' ' . theme('mark', node_mark($node->nid,
$node->changed)));
4940
    $form['name'][$node->nid] =  array('#markup' =>
check_plain(node_get_types('name', $node)));
4950
    $form['username'][$node->nid] = array('#markup' => theme('username',
$node));
4960
    $form['status'][$node->nid] =  array('#markup' => ($node->status ?
t('published') : t('not published')));
4970
    if ($multilanguage) {
4980
      $form['language'][$node->nid] = array('#markup' =>
empty($node->language) ? t('Language neutral') :
t($languages[$node->language]->name));
4990
    }
5000
    $form['operations'][$node->nid] = array('#markup' => l(t('edit'),
'node/' . $node->nid . '/edit', array('query' => $destination)));
5010
  }
5020
  $form['nodes'] = array('#type' => 'checkboxes', '#options' => $nodes);
5030
  $form['pager'] = array('#markup' => theme('pager', NULL, 50, 0));
5040
  $form['#theme'] = 'node_admin_nodes';
5050
  return $form;
5060
}
507
508
/**
509
 * Validate node_admin_nodes form submissions.
510
 *
511
 * Check if any nodes have been selected to perform the chosen
512
 * 'Update option' on.
513
 */
51491
function node_admin_nodes_validate($form, &$form_state) {
5150
  $nodes = array_filter($form_state['values']['nodes']);
5160
  if (count($nodes) == 0) {
5170
    form_set_error('', t('No items selected.'));
5180
  }
5190
}
520
521
/**
522
 * Process node_admin_nodes form submissions.
523
 *
524
 * Execute the chosen 'Update option' on the selected nodes.
525
 */
52691
function node_admin_nodes_submit($form, &$form_state) {
5270
  $operations = module_invoke_all('node_operations');
5280
  $operation = $operations[$form_state['values']['operation']];
529
  // Filter out unchecked nodes
5300
  $nodes = array_filter($form_state['values']['nodes']);
5310
  if ($function = $operation['callback']) {
532
    // Add in callback arguments if present.
5330
    if (isset($operation['callback arguments'])) {
5340
      $args = array_merge(array($nodes), $operation['callback
arguments']);
5350
    }
536
    else {
5370
      $args = array($nodes);
538
    }
5390
    call_user_func_array($function, $args);
540
5410
    cache_clear_all();
5420
  }
543
  else {
544
    // We need to rebuild the form to go to a second step.  For example,
to
545
    // show the confirmation form for the deletion of nodes.
5460
    $form_state['rebuild'] = TRUE;
547
  }
5480
}
549
550
551
/**
552
 * Theme node administration overview.
553
 *
554
 * @ingroup themeable
555
 */
55691
function theme_node_admin_nodes($form) {
557
  // If there are rows in this form, then $form['title'] contains a list
of
558
  // the title form elements.
5590
  $has_posts = isset($form['title']) && is_array($form['title']);
5600
  $select_header = $has_posts ? theme('table_select_header_cell') : '';
5610
  $header = array($select_header, t('Title'), t('Type'), t('Author'),
t('Status'));
5620
  if (isset($form['language'])) {
5630
    $header[] = t('Language');
5640
  }
5650
  $header[] = t('Operations');
5660
  $output = '';
567
5680
  $output .= drupal_render($form['options']);
5690
  if ($has_posts) {
5700
    foreach (element_children($form['title']) as $key) {
5710
      $row = array();
5720
      $row[] = drupal_render($form['nodes'][$key]);
5730
      $row[] = drupal_render($form['title'][$key]);
5740
      $row[] = drupal_render($form['name'][$key]);
5750
      $row[] = drupal_render($form['username'][$key]);
5760
      $row[] = drupal_render($form['status'][$key]);
5770
      if (isset($form['language'])) {
5780
        $row[] = drupal_render($form['language'][$key]);
5790
      }
5800
      $row[] = drupal_render($form['operations'][$key]);
5810
      $rows[] = $row;
5820
    }
583
5840
  }
585
  else {
5860
    $rows[] = array(array('data' => t('No posts available.'), 'colspan' =>
'6'));
587
  }
588
5890
  $output .= theme('table', $header, $rows);
5900
  if ($form['pager']['#markup']) {
5910
    $output .= drupal_render($form['pager']);
5920
  }
593
5940
  $output .= drupal_render($form);
595
5960
  return $output;
5970
}
598
59991
function node_multiple_delete_confirm(&$form_state, $nodes) {
600
6010
  $form['nodes'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree'
=> TRUE);
602
  // array_filter returns only elements with TRUE values
6030
  foreach ($nodes as $nid => $value) {
6040
    $title = db_result(db_query('SELECT title FROM {node} WHERE nid = %d',
$nid));
6050
    $form['nodes'][$nid] = array(
6060
      '#type' => 'hidden',
6070
      '#value' => $nid,
6080
      '#prefix' => '<li>',
6090
      '#suffix' => check_plain($title) . "</li>\n",
610
    );
6110
  }
6120
  $form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
6130
  $form['#submit'][] = 'node_multiple_delete_confirm_submit';
6140
  return confirm_form($form,
6150
                      t('Are you sure you want to delete these items?'),
6160
                      'admin/content/node', t('This action cannot be
undone.'),
6170
                      t('Delete all'), t('Cancel'));
6180
}
619
62091
function node_multiple_delete_confirm_submit($form, &$form_state) {
6210
  if ($form_state['values']['confirm']) {
6220
    foreach ($form_state['values']['nodes'] as $nid => $value) {
6230
      node_delete($nid);
6240
    }
6250
    drupal_set_message(t('The items have been deleted.'));
6260
  }
6270
  $form_state['redirect'] = 'admin/content/node';
6280
  return;
6290
}
63091