[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

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

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


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7