[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/modules/node/ -> node.admin.inc (source)

   1  <?php
   2  // $Id: node.admin.inc,v 1.19.2.3 2009/06/08 16:45:34 goba Exp $
   3  
   4  /**
   5   * @file
   6   * Content administration and module settings UI.
   7   */
   8  
   9  /**
  10   * Menu callback; presents general node configuration options.
  11   */
  12  function node_configure() {
  13    $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>';
  14    $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>';
  15  
  16    $form['access'] = array(
  17      '#type' => 'fieldset',
  18      '#title' => t('Node access status'),
  19    );
  20    $form['access']['status'] = array('#value' => $status);
  21    $form['access']['rebuild'] = array(
  22      '#type' => 'submit',
  23      '#value' => t('Rebuild permissions'),
  24      '#submit' => array('node_configure_access_submit'),
  25    );
  26  
  27    $form['default_nodes_main'] = array(
  28      '#type' => 'select', '#title' => t('Number of posts on main page'), '#default_value' => variable_get('default_nodes_main', 10),
  29      '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30)),
  30      '#description' => t('The default maximum number of posts to display per page on overview pages such as the main page.')
  31    );
  32    $form['teaser_length'] = array(
  33      '#type' => 'select', '#title' => t('Length of trimmed posts'), '#default_value' => variable_get('teaser_length', 600),
  34      '#options' => array(
  35        0 => t('Unlimited'),
  36        200 => t('200 characters'),
  37        400 => t('400 characters'),
  38        600 => t('600 characters'),
  39        800 => t('800 characters'),
  40        1000 => t('1000 characters'),
  41        1200 => t('1200 characters'),
  42        1400 => t('1400 characters'),
  43        1600 => t('1600 characters'),
  44        1800 => t('1800 characters'),
  45        2000 => t('2000 characters'),
  46      ),
  47      '#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.")
  48    );
  49  
  50    $form['node_preview'] = array(
  51      '#type' => 'radios',
  52      '#title' => t('Preview post'),
  53      '#default_value' => variable_get('node_preview', 0),
  54      '#options' => array(t('Optional'), t('Required')),
  55      '#description' => t('Must users preview posts before submitting?'),
  56    );
  57  
  58    return system_settings_form($form);
  59  }
  60  
  61  /**
  62   * Form button submit callback.
  63   */
  64  function node_configure_access_submit($form, &$form_state) {
  65    $form_state['redirect'] = 'admin/content/node-settings/rebuild';
  66  }
  67  
  68  /**
  69   * Menu callback: confirm rebuilding of permissions.
  70   */
  71  function node_configure_rebuild_confirm() {
  72    return confirm_form(array(), t('Are you sure you want to rebuild the permissions on site content?'),
  73                    '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'));
  74  }
  75  
  76  /**
  77   * Handler for wipe confirmation
  78   */
  79  function node_configure_rebuild_confirm_submit($form, &$form_state) {
  80    node_access_rebuild(TRUE);
  81    $form_state['redirect'] = 'admin/content/node-settings';
  82  }
  83  
  84  /**
  85   * Implementation of hook_node_operations().
  86   */
  87  function node_node_operations() {
  88    $operations = array(
  89      'publish' => array(
  90        'label' => t('Publish'),
  91        'callback' => 'node_mass_update',
  92        'callback arguments' => array('updates' => array('status' => 1)),
  93      ),
  94      'unpublish' => array(
  95        'label' => t('Unpublish'),
  96        'callback' => 'node_mass_update',
  97        'callback arguments' => array('updates' => array('status' => 0)),
  98      ),
  99      'promote' => array(
 100        'label' => t('Promote to front page'),
 101        'callback' => 'node_mass_update',
 102        'callback arguments' => array('updates' => array('status' => 1, 'promote' => 1)),
 103      ),
 104      'demote' => array(
 105        'label' => t('Demote from front page'),
 106        'callback' => 'node_mass_update',
 107        'callback arguments' => array('updates' => array('promote' => 0)),
 108      ),
 109      'sticky' => array(
 110        'label' => t('Make sticky'),
 111        'callback' => 'node_mass_update',
 112        'callback arguments' => array('updates' => array('status' => 1, 'sticky' => 1)),
 113      ),
 114      'unsticky' => array(
 115        'label' => t('Remove stickiness'),
 116        'callback' => 'node_mass_update',
 117        'callback arguments' => array('updates' => array('sticky' => 0)),
 118      ),
 119      'delete' => array(
 120        'label' => t('Delete'),
 121        'callback' => NULL,
 122      ),
 123    );
 124    return $operations;
 125  }
 126  
 127  /**
 128   * List node administration filters that can be applied.
 129   */
 130  function node_filters() {
 131    // Regular filters
 132    $filters['status'] = array(
 133      'title' => t('status'),
 134      'options' => array(
 135        'status-1' => t('published'),
 136        'status-0' => t('not published'),
 137        'promote-1' => t('promoted'),
 138        'promote-0' => t('not promoted'),
 139        'sticky-1' => t('sticky'),
 140        'sticky-0' => t('not sticky'),
 141      ),
 142    );
 143    // Include translation states if we have this module enabled
 144    if (module_exists('translation')) {
 145      $filters['status']['options'] += array(
 146        'translate-0' => t('Up to date translation'),
 147        'translate-1' => t('Outdated translation'),
 148      );
 149    }
 150  
 151    $filters['type'] = array('title' => t('type'), 'options' => node_get_types('names'));
 152  
 153    // The taxonomy filter
 154    if ($taxonomy = module_invoke('taxonomy', 'form_all', 1)) {
 155      $filters['category'] = array('title' => t('category'), 'options' => $taxonomy);
 156    }
 157    // Language filter if there is a list of languages
 158    if ($languages = module_invoke('locale', 'language_list')) {
 159      $languages = array('' => t('Language neutral')) + $languages;
 160      $filters['language'] = array('title' => t('language'), 'options' => $languages);
 161    }
 162    return $filters;
 163  }
 164  
 165  /**
 166   * Build query for node administration filters based on session.
 167   */
 168  function node_build_filter_query() {
 169    $filters = node_filters();
 170  
 171    // Build query
 172    $where = $args = array();
 173    $join = '';
 174    foreach ($_SESSION['node_overview_filter'] as $index => $filter) {
 175      list($key, $value) = $filter;
 176      switch ($key) {
 177        case 'status':
 178          // Note: no exploitable hole as $key/$value have already been checked when submitted
 179          list($key, $value) = explode('-', $value, 2);
 180          $where[] = 'n.'. $key .' = %d';
 181          break;
 182        case 'category':
 183          $table = "tn$index";
 184          $where[] = "$table.tid = %d";
 185          $join .= "INNER JOIN {term_node} $table ON n.nid = $table.nid ";
 186          break;
 187        case 'type':
 188          $where[] = "n.type = '%s'";
 189          break;
 190        case 'language':
 191          $where[] = "n.language = '%s'";
 192          break;
 193      }
 194      $args[] = $value;
 195    }
 196    $where = count($where) ? 'WHERE '. implode(' AND ', $where) : '';
 197  
 198    return array('where' => $where, 'join' => $join, 'args' => $args);
 199  }
 200  
 201  /**
 202   * Return form for node administration filters.
 203   */
 204  function node_filter_form() {
 205    $session = &$_SESSION['node_overview_filter'];
 206    $session = is_array($session) ? $session : array();
 207    $filters = node_filters();
 208  
 209    $i = 0;
 210    $form['filters'] = array(
 211      '#type' => 'fieldset',
 212      '#title' => t('Show only items where'),
 213      '#theme' => 'node_filters',
 214    );
 215    $form['#submit'][] = 'node_filter_form_submit';
 216    foreach ($session as $filter) {
 217      list($type, $value) = $filter;
 218      if ($type == 'category') {
 219        // Load term name from DB rather than search and parse options array.
 220        $value = module_invoke('taxonomy', 'get_term', $value);
 221        $value = $value->name;
 222      }
 223      else if ($type == 'language') {
 224        $value = empty($value) ? t('Language neutral') : module_invoke('locale', 'language_name', $value);
 225      }
 226      else {
 227        $value = $filters[$type]['options'][$value];
 228      }
 229      if ($i++) {
 230        $form['filters']['current'][] = array('#value' => t('<em>and</em> where <strong>%a</strong> is <strong>%b</strong>', array('%a' => $filters[$type]['title'], '%b' => $value)));
 231      }
 232      else {
 233        $form['filters']['current'][] = array('#value' => t('<strong>%a</strong> is <strong>%b</strong>', array('%a' => $filters[$type]['title'], '%b' => $value)));
 234      }
 235      if (in_array($type, array('type', 'language'))) {
 236        // Remove the option if it is already being filtered on.
 237        unset($filters[$type]);
 238      }
 239    }
 240  
 241    foreach ($filters as $key => $filter) {
 242      $names[$key] = $filter['title'];
 243      $form['filters']['status'][$key] = array('#type' => 'select', '#options' => $filter['options']);
 244    }
 245  
 246    $form['filters']['filter'] = array('#type' => 'radios', '#options' => $names, '#default_value' => 'status');
 247    $form['filters']['buttons']['submit'] = array('#type' => 'submit', '#value' => (count($session) ? t('Refine') : t('Filter')));
 248    if (count($session)) {
 249      $form['filters']['buttons']['undo'] = array('#type' => 'submit', '#value' => t('Undo'));
 250      $form['filters']['buttons']['reset'] = array('#type' => 'submit', '#value' => t('Reset'));
 251    }
 252  
 253    drupal_add_js('misc/form.js', 'core');
 254  
 255    return $form;
 256  }
 257  
 258  /**
 259   * Theme node administration filter form.
 260   *
 261   * @ingroup themeable
 262   */
 263  function theme_node_filter_form($form) {
 264    $output = '';
 265    $output .= '<div id="node-admin-filter">';
 266    $output .= drupal_render($form['filters']);
 267    $output .= '</div>';
 268    $output .= drupal_render($form);
 269    return $output;
 270  }
 271  
 272  /**
 273   * Theme node administration filter selector.
 274   *
 275   * @ingroup themeable
 276   */
 277  function theme_node_filters($form) {
 278    $output = '';
 279    $output .= '<ul class="clear-block">';
 280    if (!empty($form['current'])) {
 281      foreach (element_children($form['current']) as $key) {
 282        $output .= '<li>'. drupal_render($form['current'][$key]) .'</li>';
 283      }
 284    }
 285  
 286    $output .= '<li><dl class="multiselect">'. (!empty($form['current']) ? '<dt><em>'. t('and') .'</em> '. t('where') .'</dt>' : '') .'<dd class="a">';
 287    foreach (element_children($form['filter']) as $key) {
 288      $output .= drupal_render($form['filter'][$key]);
 289    }
 290    $output .= '</dd>';
 291  
 292    $output .= '<dt>'. t('is') .'</dt><dd class="b">';
 293  
 294    foreach (element_children($form['status']) as $key) {
 295      $output .= drupal_render($form['status'][$key]);
 296    }
 297    $output .= '</dd>';
 298  
 299    $output .= '</dl>';
 300    $output .= '<div class="container-inline" id="node-admin-buttons">'. drupal_render($form['buttons']) .'</div>';
 301    $output .= '</li></ul>';
 302  
 303    return $output;
 304  }
 305  
 306  /**
 307   * Process result from node administration filter form.
 308   */
 309  function node_filter_form_submit($form, &$form_state) {
 310    $filters = node_filters();
 311    switch ($form_state['values']['op']) {
 312      case t('Filter'):
 313      case t('Refine'):
 314        if (isset($form_state['values']['filter'])) {
 315          $filter = $form_state['values']['filter'];
 316  
 317          // Flatten the options array to accommodate hierarchical/nested options.
 318          $flat_options = form_options_flatten($filters[$filter]['options']);
 319  
 320          if (isset($flat_options[$form_state['values'][$filter]])) {
 321            $_SESSION['node_overview_filter'][] = array($filter, $form_state['values'][$filter]);
 322          }
 323        }
 324        break;
 325      case t('Undo'):
 326        array_pop($_SESSION['node_overview_filter']);
 327        break;
 328      case t('Reset'):
 329        $_SESSION['node_overview_filter'] = array();
 330        break;
 331    }
 332  }
 333  
 334  /**
 335   * Make mass update of nodes, changing all nodes in the $nodes array
 336   * to update them with the field values in $updates.
 337   *
 338   * IMPORTANT NOTE: This function is intended to work when called
 339   * from a form submit handler. Calling it outside of the form submission
 340   * process may not work correctly.
 341   *
 342   * @param array $nodes
 343   *   Array of node nids to update.
 344   * @param array $updates
 345   *   Array of key/value pairs with node field names and the
 346   *   value to update that field to.
 347   */
 348  function node_mass_update($nodes, $updates) {
 349    // We use batch processing to prevent timeout when updating a large number
 350    // of nodes.
 351    if (count($nodes) > 10) {
 352      $batch = array(
 353        'operations' => array(
 354          array('_node_mass_update_batch_process', array($nodes, $updates))
 355        ),
 356        'finished' => '_node_mass_update_batch_finished',
 357        'title' => t('Processing'),
 358        // We use a single multi-pass operation, so the default
 359        // 'Remaining x of y operations' message will be confusing here.
 360        'progress_message' => '',
 361        'error_message' => t('The update has encountered an error.'),
 362        // The operations do not live in the .module file, so we need to
 363        // tell the batch engine which file to load before calling them.
 364        'file' => drupal_get_path('module', 'node') .'/node.admin.inc',
 365      );
 366      batch_set($batch);
 367    }
 368    else {
 369      foreach ($nodes as $nid) {
 370        _node_mass_update_helper($nid, $updates);
 371      }
 372      drupal_set_message(t('The update has been performed.'));
 373    }
 374  }
 375  
 376  /**
 377   * Node Mass Update - helper function.
 378   */
 379  function _node_mass_update_helper($nid, $updates) {
 380    $node = node_load($nid, NULL, TRUE);
 381    foreach ($updates as $name => $value) {
 382      $node->$name = $value;
 383    }
 384    node_save($node);
 385    return $node;
 386  }
 387  
 388  /**
 389   * Node Mass Update Batch operation
 390   */
 391  function _node_mass_update_batch_process($nodes, $updates, &$context) {
 392    if (!isset($context['sandbox']['progress'])) {
 393      $context['sandbox']['progress'] = 0;
 394      $context['sandbox']['max'] = count($nodes);
 395      $context['sandbox']['nodes'] = $nodes;
 396    }
 397  
 398    // Process nodes by groups of 5.
 399    $count = min(5, count($context['sandbox']['nodes']));
 400    for ($i = 1; $i <= $count; $i++) {
 401      // For each nid, load the node, reset the values, and save it.
 402      $nid = array_shift($context['sandbox']['nodes']);
 403      $node = _node_mass_update_helper($nid, $updates);
 404  
 405      // Store result for post-processing in the finished callback.
 406      $context['results'][] = l($node->title, 'node/'. $node->nid);
 407  
 408      // Update our progress information.
 409      $context['sandbox']['progress']++;
 410    }
 411  
 412    // Inform the batch engine that we are not finished,
 413    // and provide an estimation of the completion level we reached.
 414    if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
 415      $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
 416    }
 417  }
 418  
 419  /**
 420   * Node Mass Update Batch 'finished' callback.
 421   */
 422  function _node_mass_update_batch_finished($success, $results, $operations) {
 423    if ($success) {
 424      drupal_set_message(t('The update has been performed.'));
 425    }
 426    else {
 427      drupal_set_message(t('An error occurred and processing did not complete.'), 'error');
 428      $message = format_plural(count($results), '1 item successfully processed:', '@count items successfully processed:');
 429      $message .= theme('item_list', $results);
 430      drupal_set_message($message);
 431    }
 432  }
 433  
 434  /**
 435   * Menu callback: content administration.
 436   */
 437  function node_admin_content($form_state) {
 438    if (isset($form_state['values']['operation']) && $form_state['values']['operation'] == 'delete') {
 439      return node_multiple_delete_confirm($form_state, array_filter($form_state['values']['nodes']));
 440    }
 441    $form = node_filter_form();
 442  
 443    $form['#theme'] = 'node_filter_form';
 444    $form['admin']  = node_admin_nodes();
 445  
 446    return $form;
 447  }
 448  
 449  /**
 450   * Form builder: Builds the node administration overview.
 451   */
 452  function node_admin_nodes() {
 453  
 454    $filter = node_build_filter_query();
 455  
 456    $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']);
 457  
 458    // Enable language column if locale is enabled or if we have any node with language
 459    $count = db_result(db_query("SELECT COUNT(*) FROM {node} n WHERE language != ''"));
 460    $multilanguage = (module_exists('locale') || $count);
 461  
 462    $form['options'] = array(
 463      '#type' => 'fieldset',
 464      '#title' => t('Update options'),
 465      '#prefix' => '<div class="container-inline">',
 466      '#suffix' => '</div>',
 467    );
 468    $options = array();
 469    foreach (module_invoke_all('node_operations') as $operation => $array) {
 470      $options[$operation] = $array['label'];
 471    }
 472    $form['options']['operation'] = array(
 473      '#type' => 'select',
 474      '#options' => $options,
 475      '#default_value' => 'approve',
 476    );
 477    $form['options']['submit'] = array(
 478      '#type' => 'submit',
 479      '#value' => t('Update'),
 480      '#submit' => array('node_admin_nodes_submit'),
 481    );
 482  
 483    $languages = language_list();
 484    $destination = drupal_get_destination();
 485    $nodes = array();
 486    while ($node = db_fetch_object($result)) {
 487      $nodes[$node->nid] = '';
 488      $options = empty($node->language) ? array() : array('language' => $languages[$node->language]);
 489      $form['title'][$node->nid] = array('#value' => l($node->title, 'node/'. $node->nid, $options) .' '. theme('mark', node_mark($node->nid, $node->changed)));
 490      $form['name'][$node->nid] =  array('#value' => check_plain(node_get_types('name', $node)));
 491      $form['username'][$node->nid] = array('#value' => theme('username', $node));
 492      $form['status'][$node->nid] =  array('#value' => ($node->status ? t('published') : t('not published')));
 493      if ($multilanguage) {
 494        $form['language'][$node->nid] = array('#value' => empty($node->language) ? t('Language neutral') : t($languages[$node->language]->name));
 495      }
 496      $form['operations'][$node->nid] = array('#value' => l(t('edit'), 'node/'. $node->nid .'/edit', array('query' => $destination)));
 497    }
 498    $form['nodes'] = array('#type' => 'checkboxes', '#options' => $nodes);
 499    $form['pager'] = array('#value' => theme('pager', NULL, 50, 0));
 500    $form['#theme'] = 'node_admin_nodes';
 501    return $form;
 502  }
 503  
 504  /**
 505   * Validate node_admin_nodes form submissions.
 506   * 
 507   * Check if any nodes have been selected to perform the chosen
 508   * 'Update option' on.
 509   */
 510  function node_admin_nodes_validate($form, &$form_state) {
 511    $nodes = array_filter($form_state['values']['nodes']);
 512    if (count($nodes) == 0) {
 513      form_set_error('', t('No items selected.'));
 514    }
 515  }
 516  
 517  /**
 518   * Process node_admin_nodes form submissions.
 519   * 
 520   * Execute the chosen 'Update option' on the selected nodes.
 521   */
 522  function node_admin_nodes_submit($form, &$form_state) {
 523    $operations = module_invoke_all('node_operations');
 524    $operation = $operations[$form_state['values']['operation']];
 525    // Filter out unchecked nodes
 526    $nodes = array_filter($form_state['values']['nodes']);
 527    if ($function = $operation['callback']) {
 528      // Add in callback arguments if present.
 529      if (isset($operation['callback arguments'])) {
 530        $args = array_merge(array($nodes), $operation['callback arguments']);
 531      }
 532      else {
 533        $args = array($nodes);
 534      }
 535      call_user_func_array($function, $args);
 536  
 537      cache_clear_all();
 538    }
 539    else {
 540      // We need to rebuild the form to go to a second step.  For example, to
 541      // show the confirmation form for the deletion of nodes.
 542      $form_state['rebuild'] = TRUE;
 543    }
 544  }
 545  
 546  
 547  /**
 548   * Theme node administration overview.
 549   *
 550   * @ingroup themeable
 551   */
 552  function theme_node_admin_nodes($form) {
 553    // If there are rows in this form, then $form['title'] contains a list of
 554    // the title form elements.
 555    $has_posts = isset($form['title']) && is_array($form['title']);
 556    $select_header = $has_posts ? theme('table_select_header_cell') : '';
 557    $header = array($select_header, t('Title'), t('Type'), t('Author'), t('Status'));
 558    if (isset($form['language'])) {
 559      $header[] = t('Language');
 560    }
 561    $header[] = t('Operations');
 562    $output = '';
 563  
 564    $output .= drupal_render($form['options']);
 565    if ($has_posts) {
 566      foreach (element_children($form['title']) as $key) {
 567        $row = array();
 568        $row[] = drupal_render($form['nodes'][$key]);
 569        $row[] = drupal_render($form['title'][$key]);
 570        $row[] = drupal_render($form['name'][$key]);
 571        $row[] = drupal_render($form['username'][$key]);
 572        $row[] = drupal_render($form['status'][$key]);
 573        if (isset($form['language'])) {
 574          $row[] = drupal_render($form['language'][$key]);
 575        }
 576        $row[] = drupal_render($form['operations'][$key]);
 577        $rows[] = $row;
 578      }
 579  
 580    }
 581    else {
 582      $rows[] = array(array('data' => t('No posts available.'), 'colspan' => '6'));
 583    }
 584  
 585    $output .= theme('table', $header, $rows);
 586    if ($form['pager']['#value']) {
 587      $output .= drupal_render($form['pager']);
 588    }
 589  
 590    $output .= drupal_render($form);
 591  
 592    return $output;
 593  }
 594  
 595  function node_multiple_delete_confirm(&$form_state, $nodes) {
 596  
 597    $form['nodes'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
 598    // array_filter returns only elements with TRUE values
 599    foreach ($nodes as $nid => $value) {
 600      $title = db_result(db_query('SELECT title FROM {node} WHERE nid = %d', $nid));
 601      $form['nodes'][$nid] = array(
 602        '#type' => 'hidden',
 603        '#value' => $nid,
 604        '#prefix' => '<li>',
 605        '#suffix' => check_plain($title) ."</li>\n",
 606      );
 607    }
 608    $form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
 609    $form['#submit'][] = 'node_multiple_delete_confirm_submit';
 610    return confirm_form($form,
 611                        t('Are you sure you want to delete these items?'),
 612                        'admin/content/node', t('This action cannot be undone.'),
 613                        t('Delete all'), t('Cancel'));
 614  }
 615  
 616  function node_multiple_delete_confirm_submit($form, &$form_state) {
 617    if ($form_state['values']['confirm']) {
 618      foreach ($form_state['values']['nodes'] as $nid => $value) {
 619        node_delete($nid);
 620      }
 621      drupal_set_message(t('The items have been deleted.'));
 622    }
 623    $form_state['redirect'] = 'admin/content/node';
 624    return;
 625  }
 626  


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7