Projet

Général

Profil

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

root / drupal7 / modules / node / node.admin.inc @ 01dfd3b5

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

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

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

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

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

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

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

    
417
  return $form;
418
}
419

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

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

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

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

    
477
  $query = db_select('node', 'n')->extend('PagerDefault')->extend('TableSort');
478
  $query->addTag('node_admin_filter');
479
  node_build_filter_query($query);
480

    
481
  if (!user_access('bypass node access')) {
482
    // If the user is able to view their own unpublished nodes, allow them
483
    // to see these in addition to published nodes. Check that they actually
484
    // have some unpublished nodes to view before adding the condition.
485
    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()) {
486
      $query->condition(db_or()
487
        ->condition('n.status', 1)
488
        ->condition('n.nid', $own_unpublished, 'IN')
489
      );
490
    }
491
    else {
492
      // If not, restrict the query to published nodes.
493
      $query->condition('n.status', 1);
494
    }
495
  }
496
  $nids = $query
497
    ->fields('n',array('nid'))
498
    ->limit(50)
499
    ->orderByHeader($header)
500
    ->addTag('node_access')
501
    ->execute()
502
    ->fetchCol();
503
  $nodes = node_load_multiple($nids);
504

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

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

    
599
  $form['pager'] = array('#markup' => theme('pager'));
600
  return $form;
601
}
602

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

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

    
650
    cache_clear_all();
651
  }
652
  else {
653
    // We need to rebuild the form to go to a second step. For example, to
654
    // show the confirmation form for the deletion of nodes.
655
    $form_state['rebuild'] = TRUE;
656
  }
657
}
658

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

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