|
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 } |