Projet

Général

Profil

Paste
Télécharger (23,2 ko) Statistiques
| Branche: | Révision:

root / drupal7 / modules / node / node.admin.inc @ 76597ebf

1
<?php
2

    
3
/**
4
 * @file
5
 * Content administration and module settings UI.
6
 */
7

    
8
/**
9
 * Menu callback: confirm rebuilding of permissions.
10
 *
11
 * @see node_configure_rebuild_confirm_submit()
12
 * @see node_menu()
13
 * @ingroup forms
14
 */
15
function node_configure_rebuild_confirm() {
16
  return confirm_form(array(), t('Are you sure you want to rebuild the permissions on site content?'),
17
                  'admin/reports/status', 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'));
18
}
19

    
20
/**
21
 * Handler for wipe confirmation
22
 *
23
 * @see node_configure_rebuild_confirm()
24
 */
25
function node_configure_rebuild_confirm_submit($form, &$form_state) {
26
  node_access_rebuild(TRUE);
27
  $form_state['redirect'] = 'admin/reports/status';
28
}
29

    
30
/**
31
 * Implements hook_node_operations().
32
 */
33
function node_node_operations() {
34
  $operations = array(
35
    'publish' => array(
36
      'label' => t('Publish selected content'),
37
      'callback' => 'node_mass_update',
38
      'callback arguments' => array('updates' => array('status' => NODE_PUBLISHED)),
39
    ),
40
    'unpublish' => array(
41
      'label' => t('Unpublish selected content'),
42
      'callback' => 'node_mass_update',
43
      'callback arguments' => array('updates' => array('status' => NODE_NOT_PUBLISHED)),
44
    ),
45
    'promote' => array(
46
      'label' => t('Promote selected content to front page'),
47
      'callback' => 'node_mass_update',
48
      'callback arguments' => array('updates' => array('status' => NODE_PUBLISHED, 'promote' => NODE_PROMOTED)),
49
    ),
50
    'demote' => array(
51
      'label' => t('Demote selected content from front page'),
52
      'callback' => 'node_mass_update',
53
      'callback arguments' => array('updates' => array('promote' => NODE_NOT_PROMOTED)),
54
    ),
55
    'sticky' => array(
56
      'label' => t('Make selected content sticky'),
57
      'callback' => 'node_mass_update',
58
      'callback arguments' => array('updates' => array('status' => NODE_PUBLISHED, 'sticky' => NODE_STICKY)),
59
    ),
60
    'unsticky' => array(
61
      'label' => t('Make selected content not sticky'),
62
      'callback' => 'node_mass_update',
63
      'callback arguments' => array('updates' => array('sticky' => NODE_NOT_STICKY)),
64
    ),
65
    'delete' => array(
66
      'label' => t('Delete selected content'),
67
      'callback' => NULL,
68
    ),
69
  );
70
  return $operations;
71
}
72

    
73
/**
74
 * List node administration filters that can be applied.
75
 *
76
 * @return
77
 *   An associative array of filters.
78
 */
79
function node_filters() {
80
  // Regular filters
81
  $filters['status'] = array(
82
    'title' => t('status'),
83
    'options' => array(
84
      '[any]' => t('any'),
85
      'status-1' => t('published'),
86
      'status-0' => t('not published'),
87
      'promote-1' => t('promoted'),
88
      'promote-0' => t('not promoted'),
89
      'sticky-1' => t('sticky'),
90
      'sticky-0' => t('not sticky'),
91
    ),
92
  );
93
  // Include translation states if we have this module enabled
94
  if (module_exists('translation')) {
95
    $filters['status']['options'] += array(
96
      'translate-0' => t('Up to date translation'),
97
      'translate-1' => t('Outdated translation'),
98
    );
99
  }
100

    
101
  $filters['type'] = array(
102
    'title' => t('type'),
103
    'options' => array(
104
      '[any]' => t('any'),
105
    ) + node_type_get_names(),
106
  );
107

    
108
  // Language filter if there is a list of languages
109
  if ($languages = module_invoke('locale', 'language_list')) {
110
    $languages = array(LANGUAGE_NONE => t('Language neutral')) + $languages;
111
    $filters['language'] = array(
112
      'title' => t('language'),
113
      'options' => array(
114
        '[any]' => t('any'),
115
      ) + $languages,
116
    );
117
  }
118
  return $filters;
119
}
120

    
121
/**
122
 * Applies filters for node administration filters based on session.
123
 *
124
 * @param $query
125
 *   A SelectQuery to which the filters should be applied.
126
 */
127
function node_build_filter_query(SelectQueryInterface $query) {
128
  // Build query
129
  $filter_data = isset($_SESSION['node_overview_filter']) ? $_SESSION['node_overview_filter'] : array();
130
  foreach ($filter_data as $index => $filter) {
131
    list($key, $value) = $filter;
132
    switch ($key) {
133
      case 'status':
134
        // Note: no exploitable hole as $key/$value have already been checked when submitted
135
        list($key, $value) = explode('-', $value, 2);
136
      case 'type':
137
      case 'language':
138
        $query->condition('n.' . $key, $value);
139
        break;
140
    }
141
  }
142
}
143

    
144
/**
145
 * Returns the node administration filters form array to node_admin_content().
146
 *
147
 * @see node_admin_nodes()
148
 * @see node_admin_nodes_submit()
149
 * @see node_admin_nodes_validate()
150
 * @see node_filter_form_submit()
151
 * @see node_multiple_delete_confirm()
152
 * @see node_multiple_delete_confirm_submit()
153
 *
154
 * @ingroup forms
155
 */
156
function node_filter_form() {
157
  $session = isset($_SESSION['node_overview_filter']) ? $_SESSION['node_overview_filter'] : array();
158
  $filters = node_filters();
159

    
160
  $i = 0;
161
  $form['filters'] = array(
162
    '#type' => 'fieldset',
163
    '#title' => t('Show only items where'),
164
    '#theme' => 'exposed_filters__node',
165
  );
166
  foreach ($session as $filter) {
167
    list($type, $value) = $filter;
168
    if ($type == 'term') {
169
      // Load term name from DB rather than search and parse options array.
170
      $value = module_invoke('taxonomy', 'term_load', $value);
171
      $value = $value->name;
172
    }
173
    elseif ($type == 'language') {
174
      $value = $value == LANGUAGE_NONE ? t('Language neutral') : module_invoke('locale', 'language_name', $value);
175
    }
176
    else {
177
      $value = $filters[$type]['options'][$value];
178
    }
179
    $t_args = array('%property' => $filters[$type]['title'], '%value' => $value);
180
    if ($i++) {
181
      $form['filters']['current'][] = array('#markup' => t('and where %property is %value', $t_args));
182
    }
183
    else {
184
      $form['filters']['current'][] = array('#markup' => t('where %property is %value', $t_args));
185
    }
186
    if (in_array($type, array('type', 'language'))) {
187
      // Remove the option if it is already being filtered on.
188
      unset($filters[$type]);
189
    }
190
  }
191

    
192
  $form['filters']['status'] = array(
193
    '#type' => 'container',
194
    '#attributes' => array('class' => array('clearfix')),
195
    '#prefix' => ($i ? '<div class="additional-filters">' . t('and where') . '</div>' : ''),
196
  );
197
  $form['filters']['status']['filters'] = array(
198
    '#type' => 'container',
199
    '#attributes' => array('class' => array('filters')),
200
  );
201
  foreach ($filters as $key => $filter) {
202
    $form['filters']['status']['filters'][$key] = array(
203
      '#type' => 'select',
204
      '#options' => $filter['options'],
205
      '#title' => $filter['title'],
206
      '#default_value' => '[any]',
207
    );
208
  }
209

    
210
  $form['filters']['status']['actions'] = array(
211
    '#type' => 'actions',
212
    '#attributes' => array('class' => array('container-inline')),
213
  );
214
  $form['filters']['status']['actions']['submit'] = array(
215
    '#type' => 'submit',
216
    '#value' => count($session) ? t('Refine') : t('Filter'),
217
  );
218
  if (count($session)) {
219
    $form['filters']['status']['actions']['undo'] = array('#type' => 'submit', '#value' => t('Undo'));
220
    $form['filters']['status']['actions']['reset'] = array('#type' => 'submit', '#value' => t('Reset'));
221
  }
222

    
223
  drupal_add_js('misc/form.js');
224

    
225
  return $form;
226
}
227

    
228
/**
229
 * Form submission handler for node_filter_form().
230
 *
231
 * @see node_admin_content()
232
 * @see node_admin_nodes()
233
 * @see node_admin_nodes_submit()
234
 * @see node_admin_nodes_validate()
235
 * @see node_filter_form()
236
 * @see node_multiple_delete_confirm()
237
 * @see node_multiple_delete_confirm_submit()
238
 */
239
function node_filter_form_submit($form, &$form_state) {
240
  $filters = node_filters();
241
  switch ($form_state['values']['op']) {
242
    case t('Filter'):
243
    case t('Refine'):
244
      // Apply every filter that has a choice selected other than 'any'.
245
      foreach ($filters as $filter => $options) {
246
        if (isset($form_state['values'][$filter]) && $form_state['values'][$filter] != '[any]') {
247
          // Flatten the options array to accommodate hierarchical/nested options.
248
          $flat_options = form_options_flatten($filters[$filter]['options']);
249
          // Only accept valid selections offered on the dropdown, block bad input.
250
          if (isset($flat_options[$form_state['values'][$filter]])) {
251
            $_SESSION['node_overview_filter'][] = array($filter, $form_state['values'][$filter]);
252
          }
253
        }
254
      }
255
      break;
256
    case t('Undo'):
257
      array_pop($_SESSION['node_overview_filter']);
258
      break;
259
    case t('Reset'):
260
      $_SESSION['node_overview_filter'] = array();
261
      break;
262
  }
263
}
264

    
265
/**
266
 * Make mass update of nodes, changing all nodes in the $nodes array
267
 * to update them with the field values in $updates.
268
 *
269
 * IMPORTANT NOTE: This function is intended to work when called from a form
270
 * submission handler. Calling it outside of the form submission process may not
271
 * work correctly.
272
 *
273
 * @param array $nodes
274
 *   Array of node nids to update.
275
 * @param array $updates
276
 *   Array of key/value pairs with node field names and the value to update that
277
 *   field to.
278
 */
279
function node_mass_update($nodes, $updates) {
280
  // We use batch processing to prevent timeout when updating a large number
281
  // of nodes.
282
  if (count($nodes) > 10) {
283
    $batch = array(
284
      'operations' => array(
285
        array('_node_mass_update_batch_process', array($nodes, $updates))
286
      ),
287
      'finished' => '_node_mass_update_batch_finished',
288
      'title' => t('Processing'),
289
      // We use a single multi-pass operation, so the default
290
      // 'Remaining x of y operations' message will be confusing here.
291
      'progress_message' => '',
292
      'error_message' => t('The update has encountered an error.'),
293
      // The operations do not live in the .module file, so we need to
294
      // tell the batch engine which file to load before calling them.
295
      'file' => drupal_get_path('module', 'node') . '/node.admin.inc',
296
    );
297
    batch_set($batch);
298
  }
299
  else {
300
    foreach ($nodes as $nid) {
301
      _node_mass_update_helper($nid, $updates);
302
    }
303
    drupal_set_message(t('The update has been performed.'));
304
  }
305
}
306

    
307
/**
308
 * Updates individual nodes when fewer than 10 are queued.
309
 *
310
 * @param $nid
311
 *   ID of node to update.
312
 * @param $updates
313
 *   Associative array of updates.
314
 *
315
 * @return object
316
 *   An updated node object.
317
 *
318
 * @see node_mass_update()
319
 */
320
function _node_mass_update_helper($nid, $updates) {
321
  $node = node_load($nid, NULL, TRUE);
322
  // For efficiency manually save the original node before applying any changes.
323
  $node->original = clone $node;
324
  foreach ($updates as $name => $value) {
325
    $node->$name = $value;
326
  }
327
  node_save($node);
328
  return $node;
329
}
330

    
331
/**
332
 * Executes a batch operation for node_mass_update().
333
 *
334
 * @param array $nodes
335
 *   An array of node IDs.
336
 * @param array $updates
337
 *   Associative array of updates.
338
 * @param array $context
339
 *   An array of contextual key/values.
340
 */
341
function _node_mass_update_batch_process($nodes, $updates, &$context) {
342
  if (!isset($context['sandbox']['progress'])) {
343
    $context['sandbox']['progress'] = 0;
344
    $context['sandbox']['max'] = count($nodes);
345
    $context['sandbox']['nodes'] = $nodes;
346
  }
347

    
348
  // Process nodes by groups of 5.
349
  $count = min(5, count($context['sandbox']['nodes']));
350
  for ($i = 1; $i <= $count; $i++) {
351
    // For each nid, load the node, reset the values, and save it.
352
    $nid = array_shift($context['sandbox']['nodes']);
353
    $node = _node_mass_update_helper($nid, $updates);
354

    
355
    // Store result for post-processing in the finished callback.
356
    $context['results'][] = l($node->title, 'node/' . $node->nid);
357

    
358
    // Update our progress information.
359
    $context['sandbox']['progress']++;
360
  }
361

    
362
  // Inform the batch engine that we are not finished,
363
  // and provide an estimation of the completion level we reached.
364
  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
365
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
366
  }
367
}
368

    
369
/**
370
 * Menu callback: Reports the status of batch operation for node_mass_update().
371
 *
372
 * @param bool $success
373
 *   A boolean indicating whether the batch mass update operation successfully
374
 *   concluded.
375
 * @param int $results
376
 *   The number of nodes updated via the batch mode process.
377
 * @param array $operations
378
 *   An array of function calls (not used in this function).
379
 */
380
function _node_mass_update_batch_finished($success, $results, $operations) {
381
  if ($success) {
382
    drupal_set_message(t('The update has been performed.'));
383
  }
384
  else {
385
    drupal_set_message(t('An error occurred and processing did not complete.'), 'error');
386
    $message = format_plural(count($results), '1 item successfully processed:', '@count items successfully processed:');
387
    $message .= theme('item_list', array('items' => $results));
388
    drupal_set_message($message);
389
  }
390
}
391

    
392
/**
393
 * Page callback: Form constructor for the content administration form.
394
 *
395
 * @see node_admin_nodes()
396
 * @see node_admin_nodes_submit()
397
 * @see node_admin_nodes_validate()
398
 * @see node_filter_form()
399
 * @see node_filter_form_submit()
400
 * @see node_menu()
401
 * @see node_multiple_delete_confirm()
402
 * @see node_multiple_delete_confirm_submit()
403
 * @ingroup forms
404
 */
405
function node_admin_content($form, $form_state) {
406
  if (isset($form_state['values']['operation']) && $form_state['values']['operation'] == 'delete') {
407
    return node_multiple_delete_confirm($form, $form_state, array_filter($form_state['values']['nodes']));
408
  }
409
  $form['filter'] = node_filter_form();
410
  $form['#submit'][] = 'node_filter_form_submit';
411
  $form['admin'] = node_admin_nodes();
412

    
413
  return $form;
414
}
415

    
416
/**
417
 * Form builder: Builds the node administration overview.
418
 *
419
 * @see node_admin_nodes_submit()
420
 * @see node_admin_nodes_validate()
421
 * @see node_filter_form()
422
 * @see node_filter_form_submit()
423
 * @see node_multiple_delete_confirm()
424
 * @see node_multiple_delete_confirm_submit()
425
 *
426
 * @ingroup forms
427
 */
428
function node_admin_nodes() {
429
  $admin_access = user_access('administer nodes');
430

    
431
  // Build the 'Update options' form.
432
  $form['options'] = array(
433
    '#type' => 'fieldset',
434
    '#title' => t('Update options'),
435
    '#attributes' => array('class' => array('container-inline')),
436
    '#access' => $admin_access,
437
  );
438
  $options = array();
439
  foreach (module_invoke_all('node_operations') as $operation => $array) {
440
    $options[$operation] = $array['label'];
441
  }
442
  $form['options']['operation'] = array(
443
    '#type' => 'select',
444
    '#title' => t('Operation'),
445
    '#title_display' => 'invisible',
446
    '#options' => $options,
447
    '#default_value' => 'approve',
448
  );
449
  $form['options']['submit'] = array(
450
    '#type' => 'submit',
451
    '#value' => t('Update'),
452
    '#validate' => array('node_admin_nodes_validate'),
453
    '#submit' => array('node_admin_nodes_submit'),
454
  );
455

    
456
  // Enable language column if translation module is enabled or if we have any
457
  // node with language.
458
  $multilanguage = (module_exists('translation') || db_query_range("SELECT 1 FROM {node} WHERE language <> :language", 0, 1, array(':language' => LANGUAGE_NONE))->fetchField());
459

    
460
  // Build the sortable table header.
461
  $header = array(
462
    'title' => array('data' => t('Title'), 'field' => 'n.title'),
463
    'type' => array('data' => t('Type'), 'field' => 'n.type'),
464
    'author' => t('Author'),
465
    'status' => array('data' => t('Status'), 'field' => 'n.status'),
466
    'changed' => array('data' => t('Updated'), 'field' => 'n.changed', 'sort' => 'desc')
467
  );
468
  if ($multilanguage) {
469
    $header['language'] = array('data' => t('Language'), 'field' => 'n.language');
470
  }
471
  $header['operations'] = array('data' => t('Operations'));
472

    
473
  $query = db_select('node', 'n')->extend('PagerDefault')->extend('TableSort');
474
  $query->addTag('node_admin_filter');
475
  node_build_filter_query($query);
476

    
477
  if (!user_access('bypass node access')) {
478
    // If the user is able to view their own unpublished nodes, allow them
479
    // to see these in addition to published nodes. Check that they actually
480
    // have some unpublished nodes to view before adding the condition.
481
    if (user_access('view own unpublished content') && $own_unpublished = db_query('SELECT nid FROM {node} WHERE uid = :uid AND status = :status', array(':uid' => $GLOBALS['user']->uid, ':status' => 0))->fetchCol()) {
482
      $query->condition(db_or()
483
        ->condition('n.status', 1)
484
        ->condition('n.nid', $own_unpublished, 'IN')
485
      );
486
    }
487
    else {
488
      // If not, restrict the query to published nodes.
489
      $query->condition('n.status', 1);
490
    }
491
  }
492
  $nids = $query
493
    ->fields('n',array('nid'))
494
    ->limit(50)
495
    ->orderByHeader($header)
496
    ->addTag('node_access')
497
    ->execute()
498
    ->fetchCol();
499
  $nodes = node_load_multiple($nids);
500

    
501
  // Prepare the list of nodes.
502
  $languages = language_list();
503
  $destination = drupal_get_destination();
504
  $options = array();
505
  foreach ($nodes as $node) {
506
    $langcode = entity_language('node', $node);
507
    $l_options = $langcode != LANGUAGE_NONE && isset($languages[$langcode]) ? array('language' => $languages[$langcode]) : array();
508
    $options[$node->nid] = array(
509
      'title' => array(
510
        'data' => array(
511
          '#type' => 'link',
512
          '#title' => $node->title,
513
          '#href' => 'node/' . $node->nid,
514
          '#options' => $l_options,
515
          '#suffix' => ' ' . theme('mark', array('type' => node_mark($node->nid, $node->changed))),
516
        ),
517
      ),
518
      'type' => check_plain(node_type_get_name($node)),
519
      'author' => theme('username', array('account' => $node)),
520
      'status' => $node->status ? t('published') : t('not published'),
521
      'changed' => format_date($node->changed, 'short'),
522
    );
523
    if ($multilanguage) {
524
      if ($langcode == LANGUAGE_NONE || isset($languages[$langcode])) {
525
        $options[$node->nid]['language'] = $langcode == LANGUAGE_NONE ? t('Language neutral') : t($languages[$langcode]->name);
526
      }
527
      else {
528
        $options[$node->nid]['language'] = t('Undefined language (@langcode)', array('@langcode' => $langcode));
529
      }
530
    }
531
    // Build a list of all the accessible operations for the current node.
532
    $operations = array();
533
    if (node_access('update', $node)) {
534
      $operations['edit'] = array(
535
        'title' => t('edit'),
536
        'href' => 'node/' . $node->nid . '/edit',
537
        'query' => $destination,
538
      );
539
    }
540
    if (node_access('delete', $node)) {
541
      $operations['delete'] = array(
542
        'title' => t('delete'),
543
        'href' => 'node/' . $node->nid . '/delete',
544
        'query' => $destination,
545
      );
546
    }
547
    $options[$node->nid]['operations'] = array();
548
    if (count($operations) > 1) {
549
      // Render an unordered list of operations links.
550
      $options[$node->nid]['operations'] = array(
551
        'data' => array(
552
          '#theme' => 'links__node_operations',
553
          '#links' => $operations,
554
          '#attributes' => array('class' => array('links', 'inline')),
555
        ),
556
      );
557
    }
558
    elseif (!empty($operations)) {
559
      // Render the first and only operation as a link.
560
      $link = reset($operations);
561
      $options[$node->nid]['operations'] = array(
562
        'data' => array(
563
          '#type' => 'link',
564
          '#title' => $link['title'],
565
          '#href' => $link['href'],
566
          '#options' => array('query' => $link['query']),
567
        ),
568
      );
569
    }
570
  }
571

    
572
  // Only use a tableselect when the current user is able to perform any
573
  // operations.
574
  if ($admin_access) {
575
    $form['nodes'] = array(
576
      '#type' => 'tableselect',
577
      '#header' => $header,
578
      '#options' => $options,
579
      '#empty' => t('No content available.'),
580
    );
581
  }
582
  // Otherwise, use a simple table.
583
  else {
584
    $form['nodes'] = array(
585
      '#theme' => 'table',
586
      '#header' => $header,
587
      '#rows' => $options,
588
      '#empty' => t('No content available.'),
589
    );
590
  }
591

    
592
  $form['pager'] = array('#markup' => theme('pager'));
593
  return $form;
594
}
595

    
596
/**
597
 * Validate node_admin_nodes form submissions.
598
 *
599
 * Checks whether any nodes have been selected to perform the chosen 'Update
600
 * option' on.
601
 *
602
 * @see node_admin_nodes()
603
 * @see node_admin_nodes_submit()
604
 * @see node_filter_form()
605
 * @see node_filter_form_submit()
606
 * @see node_multiple_delete_confirm()
607
 * @see node_multiple_delete_confirm_submit()
608
 */
609
function node_admin_nodes_validate($form, &$form_state) {
610
  // Error if there are no items to select.
611
  if (!is_array($form_state['values']['nodes']) || !count(array_filter($form_state['values']['nodes']))) {
612
    form_set_error('', t('No items selected.'));
613
  }
614
}
615

    
616
/**
617
 * Process node_admin_nodes form submissions.
618
 *
619
 * Executes the chosen 'Update option' on the selected nodes.
620
 *
621
 * @see node_admin_nodes()
622
 * @see node_admin_nodes_validate()
623
 * @see node_filter_form()
624
 * @see node_filter_form_submit()
625
 * @see node_multiple_delete_confirm()
626
 * @see node_multiple_delete_confirm_submit()
627
 */
628
function node_admin_nodes_submit($form, &$form_state) {
629
  $operations = module_invoke_all('node_operations');
630
  $operation = $operations[$form_state['values']['operation']];
631
  // Filter out unchecked nodes
632
  $nodes = array_filter($form_state['values']['nodes']);
633
  if ($function = $operation['callback']) {
634
    // Add in callback arguments if present.
635
    if (isset($operation['callback arguments'])) {
636
      $args = array_merge(array($nodes), $operation['callback arguments']);
637
    }
638
    else {
639
      $args = array($nodes);
640
    }
641
    call_user_func_array($function, $args);
642

    
643
    cache_clear_all();
644
  }
645
  else {
646
    // We need to rebuild the form to go to a second step. For example, to
647
    // show the confirmation form for the deletion of nodes.
648
    $form_state['rebuild'] = TRUE;
649
  }
650
}
651

    
652
/**
653
 * Multiple node deletion confirmation form for node_admin_content().
654
 *
655
 * @see node_admin_nodes()
656
 * @see node_admin_nodes_submit()
657
 * @see node_admin_nodes_validate()
658
 * @see node_filter_form()
659
 * @see node_filter_form_submit()
660
 * @see node_multiple_delete_confirm_submit()
661
 * @ingroup forms
662
 */
663
function node_multiple_delete_confirm($form, &$form_state, $nodes) {
664
  $form['nodes'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
665
  // array_filter returns only elements with TRUE values
666
  foreach ($nodes as $nid => $value) {
667
    $title = db_query('SELECT title FROM {node} WHERE nid = :nid', array(':nid' => $nid))->fetchField();
668
    $form['nodes'][$nid] = array(
669
      '#type' => 'hidden',
670
      '#value' => $nid,
671
      '#prefix' => '<li>',
672
      '#suffix' => check_plain($title) . "</li>\n",
673
    );
674
  }
675
  $form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
676
  $form['#submit'][] = 'node_multiple_delete_confirm_submit';
677
  $confirm_question = format_plural(count($nodes),
678
                                  'Are you sure you want to delete this item?',
679
                                  'Are you sure you want to delete these items?');
680
  return confirm_form($form,
681
                    $confirm_question,
682
                    'admin/content', t('This action cannot be undone.'),
683
                    t('Delete'), t('Cancel'));
684
}
685

    
686
/**
687
 * Form submission handler for node_multiple_delete_confirm().
688
 *
689
 * @see node_admin_nodes()
690
 * @see node_admin_nodes_submit()
691
 * @see node_admin_nodes_validate()
692
 * @see node_filter_form()
693
 * @see node_filter_form_submit()
694
 * @see node_multiple_delete_confirm()
695
 */
696
function node_multiple_delete_confirm_submit($form, &$form_state) {
697
  if ($form_state['values']['confirm']) {
698
    node_delete_multiple(array_keys($form_state['values']['nodes']));
699
    cache_clear_all();
700
    $count = count($form_state['values']['nodes']);
701
    watchdog('content', 'Deleted @count posts.', array('@count' => $count));
702
    drupal_set_message(format_plural($count, 'Deleted 1 post.', 'Deleted @count posts.'));
703
  }
704
  $form_state['redirect'] = 'admin/content';
705
}