node.module 48.8 KB
Newer Older
Dries's avatar
 
Dries committed
1
<?php
2
// $Id$
Dries's avatar
 
Dries committed
3

4 5
define('NODE_NEW_LIMIT', time() - 30 * 24 * 60 * 60);

Dries's avatar
 
Dries committed
6
function node_help($section = 'admin/help#node') {
Dries's avatar
 
Dries committed
7
  global $mod;
Dries's avatar
 
Dries committed
8
  $output = '';
9 10 11

  switch ($section) {

Dries's avatar
 
Dries committed
12
    case 'admin/help#node':
Dries's avatar
 
Dries committed
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
      $output .= t("
      <h3>Nodes</h3>
      <p>The core of the Drupal system is the node. All of the contents of the system are placed in nodes, or extensions of nodes.
      A base node contains:<dl>
      <dt>A Title</dt><dd>Up to 128 characters of text that titles the node.</dd>
      <dt>A Teaser</dt><dd>A small block of text that is meant to get you interested in the rest of node. Drupal will automatically pull a small amount of the body of the node to make the teaser (To configure how long the teaser will be <a href=\"%teaser\">click here</a>). The teaser can be changed if you don't like what Drupal grabs.</dd>
      <dt>The Body</dt><dd>The main text that comprises your content.</dd>
      <dt>A Type</dt><dd>What kind of node is this? Blog, book, forum, comment, unextended, etc.</dd>
      <dt>An Author</dt><dd>The author's name. It will either be \"anonymous\" or a valid user. You <i>cannot</i> set it to an arbitrary value.</dd>
      <dt>Authored on</dt><dd>The date the node was written.</dd>
      <dt>Changed</dt><dd>The last time this node was changed.</dd>
      <dt>Static on front page</dt><dd>The front page is configured to show the teasers from only a few of the total nodes you have on your site (To configure how many teasers <a href=\"%teaser\">click here</a>), but if you think a node is important enough that you want it to stay on the front page enable this.</dd>
      <dt>Allow user comments</dt><dd>A node can have comments. These comments can be written by other users (Read-write), or only by admins (Read-only).</dd>
      <dt>Revisions</dt><dd>Drupal has a revision system so that you can \"roll back\" to an older version of a post if the new version is not what you want.</dd>
      <dt>Promote to front page</dt><dd>To get people to look at the new stuff on your site you can choose to move it to the front page.</dd>
      <dt>In moderation queue</dt><dd>Drupal has a moderation system. If it is active, a node is in one of three states: approved and published, approved and unpublished, and awaiting approval. If you are moderating a node it should be in the moderation queue.</dd>
      <dt>Votes</dt><dd>If you are moderating a node this counts how many votes the node has gotten. Once a node gets a certain number of vote it will either be approved or dropped.
      <dt>Score</dt><dd>The score of the node is gotten by the votes it is given.</dd>
      <dt>Users</dt><dd>The list of users who have voted on a moderated node.</dd>
      <dt>Published</dt><dd>When using Drupal's moderation system a node remains unpublished -- unavaliable to non-moderators -- until it is marked Published.</dd></dl>
      <p>Now that you know what is in a node, here are some of the types of nodes available.</p>", array("%teaser" => url("admin/system/modules/node")));
Dries's avatar
 
Dries committed
34

Dries's avatar
 
Dries committed
35
      if ($mod == 'admin') {
Dries's avatar
 
Dries committed
36
        foreach (node_list() as $type) {
Dries's avatar
 
Dries committed
37
          $output .= '<h3>'. t('Node type: %module', array('%module' => node_invoke($type, 'node_name'))). '</h3>';
38
          $output .= implode("\n", module_invoke_all('help', 'node/add#'. $type));
39
        }
Dries's avatar
 
Dries committed
40
      }
41 42
      break;

Dries's avatar
 
Dries committed
43
    case 'admin/system/modules#description':
Dries's avatar
 
Dries committed
44
      $output = t('The core that allows content to be submitted to the site.');
45 46
      break;
    case 'admin/system/modules/node':
Dries's avatar
 
Dries committed
47
      $output = t('Settings for the core of Drupal. Almost everything is a node so these settings will affect most of the site.');
48 49
      break;
    case 'admin/node':
Dries's avatar
 
Dries committed
50
      $output = t("Below is a list of all of the nodes in your site. Other forms of content are listed elsewhere (e.g. <a href=\"%comments\">comments</a>).<br />Clicking a title views that node, while clicking an author's name edits their user information.<br />Other node-related tasks are available from the menu on the left.", array('%comments' => url('admin/comment')));
51 52
      break;
    case 'admin/node/search':
Dries's avatar
 
Dries committed
53
      $output = t("Enter a simple pattern to search for a post. This can include the wildcard character *.<br />For example, a search for \"br*\" might return \"bread bakers\", \"our daily bread\" and \"brenda\".");
54 55
      break;
    case 'admin/node/settings':
Dries's avatar
 
Dries committed
56
      $output = t('This page lets you set the defaults used during creation of nodes for all the different node types.<br /><strong>comment:</strong> Read/write setting for comments.<br /><strong>publish:</strong> Is this node publicly viewable, has it been published?<br /><strong>promote:</strong> Is this node to be promoted to the front page?<br /><strong>moderate:</strong> Does this node need approval before it can be viewed?<br /><strong>static:</strong> Is this node always visible on the front page?<br /><strong>revision:</strong> Will this node go into the revision system allowing multiple versions to be saved?');
57 58
      break;

Dries's avatar
 
Dries committed
59
  }
Dries's avatar
 
Dries committed
60 61

  return $output;
Dries's avatar
 
Dries committed
62 63
}

64
function node_cron() {
Dries's avatar
 
Dries committed
65
  db_query('DELETE FROM {history} WHERE timestamp < %d', NODE_NEW_LIMIT);
66 67
}

Dries's avatar
 
Dries committed
68
function node_help_page() {
Dries's avatar
 
Dries committed
69
  print theme('page', node_help());
Dries's avatar
 
Dries committed
70 71 72
}


Dries's avatar
 
Dries committed
73 74 75 76
/*
** Accepts a DB result object which can be used to fetch node objects.
** Returns an HTML list suitable as content for a block.
*/
Dries's avatar
 
Dries committed
77 78
function node_title_list($result, $title = NULL) {
  while ($node = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
79
    $number = module_invoke('comment', 'num_all', $node->nid);
80
    $items[] = l($node->title, "node/view/$node->nid", array('title' => format_plural($number, '1 comment', '%count comments')));
Dries's avatar
 
Dries committed
81 82
  }

Dries's avatar
 
Dries committed
83
  return theme('node_list', $items, $title);
Dries's avatar
 
Dries committed
84 85
}

Dries's avatar
 
Dries committed
86
function theme_node_list($items, $title = NULL) {
Dries's avatar
 
Dries committed
87
  return theme('item_list', $items, $title);
Dries's avatar
 
Dries committed
88 89
}

Dries's avatar
 
Dries committed
90 91 92 93 94
// Update the 'last viewed' timestamp of the specified node for current user.
function node_tag_new($nid) {
  global $user;

  if ($user->uid) {
Dries's avatar
 
Dries committed
95
    $result = db_query('SELECT timestamp FROM {history} WHERE uid = %d AND nid = %d', $user->uid, $nid);
Dries's avatar
 
Dries committed
96
    if (db_fetch_object($result)) {
Dries's avatar
 
Dries committed
97
      db_query('UPDATE {history} SET timestamp = %d WHERE uid = %d AND nid = %d', time(), $user->uid, $nid);
Dries's avatar
 
Dries committed
98 99
    }
    else {
Dries's avatar
 
Dries committed
100
      db_query('INSERT INTO {history} (uid, nid, timestamp) VALUES (%d, %d, %d)', $user->uid, $nid, time());
Dries's avatar
 
Dries committed
101 102 103 104 105 106 107 108 109 110 111
    }
  }
}

/*
** Retrieves the timestamp at which the current user last viewed the
** specified node.
*/
function node_last_viewed($nid) {
  global $user;

Dries's avatar
 
Dries committed
112
  $history = db_fetch_object(db_query("SELECT timestamp FROM {history} WHERE uid = '$user->uid' AND nid = %d", $nid));
113
  return ($history->timestamp ? $history->timestamp : NODE_NEW_LIMIT);
Dries's avatar
 
Dries committed
114 115 116
}

/**
Dries's avatar
 
Dries committed
117 118
 * Determines whether the supplied timestamp is newer than the user's last view
 * of a given node
Dries's avatar
 
Dries committed
119
 *
120 121
 * @param $nid node-id whose history supplies the 'last viewed' timestamp
 * @param $timestamp time which is compared against node's 'last viewed'
Dries's avatar
 
Dries committed
122 123
 *   timestamp
 */
Dries's avatar
 
Dries committed
124 125 126 127
function node_is_new($nid, $timestamp) {
  global $user;
  static $cache;

Dries's avatar
Dries committed
128
  if (!isset($cache[$nid])) {
Dries's avatar
 
Dries committed
129
    if ($user->uid) {
Dries's avatar
 
Dries committed
130
      $history = db_fetch_object(db_query('SELECT timestamp FROM {history} WHERE uid = %d AND nid = %d', $user->uid, $nid));
Dries's avatar
 
Dries committed
131 132 133 134 135 136 137
      $cache[$nid] = $history->timestamp ? $history->timestamp : 0;
    }
    else {
      $cache[$nid] = time();
    }
  }

138
  return ($timestamp > $cache[$nid] && $timestamp > NODE_NEW_LIMIT);
Dries's avatar
 
Dries committed
139 140
}

Dries's avatar
 
Dries committed
141 142
function node_teaser($body) {

Dries's avatar
 
Dries committed
143
  $size = variable_get('teaser_length', 600);
Dries's avatar
 
Dries committed
144 145 146 147 148 149 150 151 152

  /*
  ** If the size is zero, teasers are disabled so we
  ** return the entire body.
  */

  if ($size == 0) {
    return $body;
  }
Dries's avatar
 
Dries committed
153 154

  /*
Dries's avatar
 
Dries committed
155
  ** If a valid delimiter has been specified, use it to
Dries's avatar
 
Dries committed
156 157
  ** chop of the teaser.  The delimiter can be outside
  ** the allowed range but no more than a factor two.
Dries's avatar
 
Dries committed
158 159
  */

Dries's avatar
 
Dries committed
160
  $delimiter = strpos($body, '<!--break-->');
Dries's avatar
 
Dries committed
161
  if ($delimiter > 0) {
Dries's avatar
 
Dries committed
162 163 164
    return substr($body, 0, $delimiter);
  }

Dries's avatar
 
Dries committed
165 166 167 168 169 170 171 172
  /*
  ** If we have a short body, return the entire body:
  */

  if (strlen($body) < $size) {
    return $body;
  }

Dries's avatar
 
Dries committed
173 174 175 176
  /*
  ** In some cases no delimiter has been specified (eg.
  ** when posting using the Blogger API) in which case
  ** we try to split at paragraph boundaries.
Dries's avatar
 
Dries committed
177 178
  */

Dries's avatar
 
Dries committed
179
  if ($length = strpos($body, '</p>', $size)) {
Dries's avatar
 
Dries committed
180
    return substr($body, 0, $length + 4);
Dries's avatar
 
Dries committed
181 182
  }

Dries's avatar
 
Dries committed
183
  if ($length = strpos($body, '<br />', $size)) {
Dries's avatar
 
Dries committed
184
    return substr($body, 0, $length);
Dries's avatar
 
Dries committed
185 186
  }

Dries's avatar
 
Dries committed
187
  if ($length = strpos($body, '<br>', $size)) {
Dries's avatar
 
Dries committed
188 189 190
    return substr($body, 0, $length);
  }

191
  if ($length = strpos($body, "\n", $size)) {
Dries's avatar
 
Dries committed
192
    return substr($body, 0, $length);
Dries's avatar
 
Dries committed
193 194
  }

Dries's avatar
 
Dries committed
195
  /*
Dries's avatar
 
Dries committed
196
  ** When even the first paragraph is too long, try to
Dries's avatar
 
Dries committed
197
  ** split at the end of the next sentence.
Dries's avatar
 
Dries committed
198 199
  */

Dries's avatar
 
Dries committed
200
  if ($length = strpos($body, '. ', $size)) {
Dries's avatar
 
Dries committed
201 202 203
    return substr($body, 0, $length + 1);
  }

Dries's avatar
 
Dries committed
204
  if ($length = strpos($body, '! ', $size)) {
Dries's avatar
 
Dries committed
205 206 207
    return substr($body, 0, $length + 1);
  }

Dries's avatar
 
Dries committed
208
  if ($length = strpos($body, '? ', $size)) {
Dries's avatar
 
Dries committed
209 210 211 212 213 214
    return substr($body, 0, $length + 1);
  }

  /*
  ** Nevermind, we split it the hard way ...
  */
Dries's avatar
 
Dries committed
215

Dries's avatar
 
Dries committed
216
  return substr($body, 0, $size);
Dries's avatar
 
Dries committed
217 218
}

Dries's avatar
 
Dries committed
219

220
/**
Dries's avatar
 
Dries committed
221 222 223 224 225 226 227 228
 * Determines the module that defines the node type of the given node.
 *
 * @param &$node
 *   Either a node object, node array, or a string containing the node type.
 * @return
 *   A string containing the name of the defining module.
 */
function node_get_module_name($node) {
Dries's avatar
 
Dries committed
229
  if (is_array($node)) {
Dries's avatar
 
Dries committed
230 231
    if ($pos = strpos($node['type'], '/')) {
      return substr($node['type'], 0, $pos);
232 233
    }
    else {
Dries's avatar
 
Dries committed
234
      return $node['type'];
Dries's avatar
 
Dries committed
235
    }
Dries's avatar
 
Dries committed
236 237
  }
  else if (is_object($node)) {
Dries's avatar
 
Dries committed
238
    if ($pos = strpos($node->type, '/')) {
Dries's avatar
 
Dries committed
239
      return substr($node->type, 0, $pos);
240 241
    }
    else {
Dries's avatar
 
Dries committed
242 243
      return $node->type;
    }
Dries's avatar
 
Dries committed
244 245
  }
  else if (is_string($node)) {
Dries's avatar
 
Dries committed
246
    if ($pos = strpos($node, '/')) {
Dries's avatar
 
Dries committed
247
      return substr($node, 0, $pos);
248 249
    }
    else {
Dries's avatar
 
Dries committed
250 251
      return $node;
    }
Dries's avatar
 
Dries committed
252
  }
Dries's avatar
 
Dries committed
253
}
Dries's avatar
 
Dries committed
254

255
/**
Dries's avatar
 
Dries committed
256 257 258
 * Get a list of all the defined node types.
 *
 * @return
Dries's avatar
 
Dries committed
259
 *   An list of all node types.
Dries's avatar
 
Dries committed
260 261 262 263
 */
function node_list() {
  $types = array();
  foreach (module_list() as $module) {
Dries's avatar
 
Dries committed
264 265
    if (module_hook($module, 'node_name')) {
      $module_types = module_invoke($module, 'node_types');
Dries's avatar
 
Dries committed
266 267
      if ($module_types) {
        foreach ($module_types as $type) {
Dries's avatar
 
Dries committed
268
          $types[] = $type;
Dries's avatar
 
Dries committed
269
        }
270 271
      }
      else {
Dries's avatar
 
Dries committed
272
        $types[] = $module;
Dries's avatar
 
Dries committed
273 274 275 276
      }
    }
  }
  return $types;
Dries's avatar
 
Dries committed
277
}
Dries's avatar
 
Dries committed
278

279
/**
Dries's avatar
 
Dries committed
280 281 282 283 284 285 286 287 288 289
 * Determine whether a node hook exists.
 *
 * @param &$node
 *   Either a node object, node array, or a string containing the node type.
 * @param $hook
 *   A string containing the name of the hook.
 * @return
 *   TRUE iff the $hook exists in the node type of $node.
 */
function node_hook(&$node, $hook) {
290
  $function = node_get_module_name($node) ."_$hook";
Dries's avatar
 
Dries committed
291 292 293 294

  return function_exists($function);
}

295
/**
Dries's avatar
 
Dries committed
296 297 298 299 300 301 302 303 304 305 306 307
 * Invoke a node hook.
 *
 * @param &$node
 *   Either a node object, node array, or a string containing the node type.
 * @param $hook
 *   A string containing the name of the hook.
 * @param $a2, $a3, $a4
 *   Arguments to pass on to the hook, after the $node argument.
 * @return
 *   The returned value of the invoked hook is returned.
 */
function node_invoke(&$node, $hook, $a2 = NULL, $a3 = NULL, $a4 = NULL) {
308
  $function = node_get_module_name($node) ."_$hook";
Dries's avatar
 
Dries committed
309 310

  if (function_exists($function)) {
Dries's avatar
 
Dries committed
311
    return ($function($node, $a2, $a3, $a4));
Dries's avatar
 
Dries committed
312 313 314
  }
}

Dries's avatar
 
Dries committed
315 316 317
function node_invoke_nodeapi(&$node, $op, $arg = 0) {
  $return = array();
  foreach (module_list() as $name) {
Dries's avatar
 
Dries committed
318
    $function = $name .'_nodeapi';
Dries's avatar
 
Dries committed
319 320 321 322 323 324 325 326 327 328
    if (function_exists($function)) {
      $result = $function($node, $op, $arg);
      if (isset($result)) {
        $return = array_merge($return, $result);
      }
    }
  }
  return $return;
}

Dries's avatar
 
Dries committed
329
function node_load($conditions, $revision = -1) {
Dries's avatar
 
Dries committed
330 331 332 333 334 335

  /*
  ** Turn the conditions into a query:
  */

  foreach ($conditions as $key => $value) {
Dries's avatar
 
Dries committed
336
    $cond[] = 'n.'. check_query($key) ." = '". check_query($value) ."'";
Dries's avatar
 
Dries committed
337 338 339 340 341 342
  }

  /*
  ** Retrieve the node:
  */

Dries's avatar
 
Dries committed
343
  $node = db_fetch_object(db_query('SELECT n.*, u.uid, u.name, u.data FROM {node} n INNER JOIN {users} u ON u.uid = n.uid WHERE '. implode(' AND ', $cond)));
Dries's avatar
 
Dries committed
344
  $node = drupal_unpack($node);
Dries's avatar
 
Dries committed
345 346

  /*
Dries's avatar
 
Dries committed
347
  ** Unserialize the revisions and user data fields:
Dries's avatar
 
Dries committed
348 349 350 351 352 353 354 355 356 357 358
  */

  if ($node->revisions) {
    $node->revisions = unserialize($node->revisions);
  }

  /*
  ** Call the node specific callback (if any) and piggy-back the
  ** results to the node or overwrite some values:
  */

Dries's avatar
 
Dries committed
359
  if ($extra = node_invoke($node, 'load')) {
Dries's avatar
 
Dries committed
360 361 362 363 364
    foreach ($extra as $key => $value) {
      $node->$key = $value;
    }
  }

Dries's avatar
 
Dries committed
365 366 367 368
  /*
  ** Return the desired revision
  */
  if ($revision != -1 && isset($node->revisions[$revision])) {
Dries's avatar
 
Dries committed
369
    $node = $node->revisions[$revision]['node'];
Dries's avatar
 
Dries committed
370 371
  }

Dries's avatar
 
Dries committed
372 373 374
  return $node;
}

375
function node_save($node) {
Dries's avatar
 
Dries committed
376

377 378 379
  /*
  ** Fetch fields to save to node table:
  */
Dries's avatar
 
Dries committed
380
  $fields = node_invoke_nodeapi($node, 'fields');
Dries's avatar
 
Dries committed
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399

  /*
  ** Serialize the revisions field:
  */

  if ($node->revisions) {
    $node->revisions = serialize($node->revisions);
  }

  /*
  ** Apply filters to some default node fields:
  */

  if (empty($node->nid)) {

    /*
    ** Insert a new node:
    */

Dries's avatar
 
Dries committed
400
    // Set some required fields:
401 402 403
    if (!$node->created) {
      $node->created = time();
    }
Dries's avatar
 
Dries committed
404
    $node->changed = time();
Dries's avatar
 
Dries committed
405
    $node->nid = db_next_id('{node}_nid');
Dries's avatar
 
Dries committed
406

Dries's avatar
 
Dries committed
407
    // Prepare the query:
Dries's avatar
 
Dries committed
408 409 410
    foreach ($node as $key => $value) {
      if (in_array($key, $fields)) {
        $k[] = check_query($key);
Dries's avatar
 
Dries committed
411 412
        $v[] = $value;
        $s[] = "'%s'";
Dries's avatar
 
Dries committed
413 414 415
      }
    }

Dries's avatar
 
Dries committed
416
    $keysfmt = implode(', ', $s);
Dries's avatar
 
Dries committed
417 418 419
    // need to quote the placeholders for the values
    $valsfmt = "'". implode("', '", $s) ."'";

Dries's avatar
 
Dries committed
420
    // Insert the node into the database:
Dries's avatar
 
Dries committed
421
    db_query("INSERT INTO {node} (". implode(", ", $k) .") VALUES(". implode(", ", $s) .")", $v);
Dries's avatar
 
Dries committed
422

Dries's avatar
 
Dries committed
423
    // Call the node specific callback (if any):
Dries's avatar
 
Dries committed
424 425
    node_invoke($node, 'insert');
    node_invoke_nodeapi($node, 'insert');
Dries's avatar
 
Dries committed
426 427 428 429 430 431 432
  }
  else {

    /*
    ** Update an existing node:
    */

Dries's avatar
 
Dries committed
433
    // Set some required fields:
Dries's avatar
 
Dries committed
434 435
    $node->changed = time();

Dries's avatar
 
Dries committed
436
    // Prepare the query:
Dries's avatar
 
Dries committed
437 438
    foreach ($node as $key => $value) {
      if (in_array($key, $fields)) {
Dries's avatar
 
Dries committed
439 440
        $q[] = check_query($key) ." = '%s'";
        $v[] = $value;
Dries's avatar
 
Dries committed
441 442 443
      }
    }

Dries's avatar
 
Dries committed
444
    // Update the node in the database:
Dries's avatar
 
Dries committed
445
    db_query("UPDATE {node} SET ". implode(', ', $q) ." WHERE nid = '$node->nid'", $v);
Dries's avatar
 
Dries committed
446

Dries's avatar
 
Dries committed
447
    // Call the node specific callback (if any):
Dries's avatar
 
Dries committed
448 449
    node_invoke($node, 'update');
    node_invoke_nodeapi($node, 'update');
Dries's avatar
 
Dries committed
450 451
  }

Dries's avatar
 
Dries committed
452
  /*
Dries's avatar
 
Dries committed
453 454
  ** Clear the cache so an anonymous poster can see the node being
  ** added or updated.
Dries's avatar
 
Dries committed
455 456 457 458
  */

  cache_clear_all();

Dries's avatar
 
Dries committed
459 460 461 462 463 464 465 466
  /*
  ** Return the node ID:
  */

  return $node->nid;

}

Dries's avatar
 
Dries committed
467
function node_view($node, $main = 0, $page = 0) {
Dries's avatar
 
Dries committed
468

Dries's avatar
 
Dries committed
469
  $node = array2object($node);
Dries's avatar
 
Dries committed
470

Dries's avatar
 
Dries committed
471 472
  /*
  ** Remove the delimiter (if any) that seperates the teaser from the
Dries's avatar
Dries committed
473
  ** body. TODO: this strips legitimate uses of '<!--break-->' also.
Dries's avatar
 
Dries committed
474 475
  */

Dries's avatar
 
Dries committed
476
  $node->body = str_replace('<!--break-->', '', $node->body);
Dries's avatar
 
Dries committed
477

Dries's avatar
 
Dries committed
478
  /*
Dries's avatar
 
Dries committed
479
  ** The 'view' hook can be implemented to overwrite the default function
Dries's avatar
 
Dries committed
480 481 482
  ** to display nodes.
  */

Dries's avatar
 
Dries committed
483 484
  if (node_hook($node, 'view')) {
    return node_invoke($node, 'view', $main, $page);
Dries's avatar
 
Dries committed
485 486 487 488 489 490 491
  }
  else {

    /*
    ** Default behavior:
    */

Dries's avatar
 
Dries committed
492
    return theme('node', node_prepare($node, $main), $main, $page);
Dries's avatar
 
Dries committed
493 494
  }
}
Dries's avatar
 
Dries committed
495

Dries's avatar
 
Dries committed
496 497 498
function node_prepare($node, $main = 0) {
  if ($main == 0) {
    $node->body = check_output($node->body);
Dries's avatar
 
Dries committed
499 500 501
  }
  else {
    $node->teaser = check_output($node->teaser);
Dries's avatar
 
Dries committed
502
  }
Dries's avatar
 
Dries committed
503
  return $node;
Dries's avatar
 
Dries committed
504 505
}

Dries's avatar
 
Dries committed
506 507
function node_show($node, $cid) {

Dries's avatar
 
Dries committed
508
  if (node_access('view', $node)) {
Dries's avatar
 
Dries committed
509

Dries's avatar
 
Dries committed
510
    $output = node_view($node, 0, 1);
Dries's avatar
 
Dries committed
511

Dries's avatar
 
Dries committed
512
    if (function_exists('comment_render') && $node->comment) {
Dries's avatar
 
Dries committed
513
      $output .= comment_render($node, $cid);
Dries's avatar
 
Dries committed
514
    }
Dries's avatar
 
Dries committed
515 516 517 518 519 520

    /*
    ** Update the history table, stating that this user viewed this node.
    */

    node_tag_new($node->nid);
Dries's avatar
 
Dries committed
521 522

    return $output;
Dries's avatar
 
Dries committed
523
  }
Dries's avatar
 
Dries committed
524 525 526
  else {
    drupal_set_message(message_access());
  }
Dries's avatar
 
Dries committed
527 528
}

Dries's avatar
 
Dries committed
529 530
function node_access($op, $node = 0) {

Dries's avatar
 
Dries committed
531
  if (user_access('administer nodes')) {
Dries's avatar
 
Dries committed
532
    return 1;
Dries's avatar
 
Dries committed
533 534
  }

Dries's avatar
 
Dries committed
535 536 537
  /*
  ** Convert the node to an object if necessary:
  */
Dries's avatar
 
Dries committed
538

Dries's avatar
 
Dries committed
539
  $node = array2object($node);
Dries's avatar
 
Dries committed
540

Dries's avatar
 
Dries committed
541 542
  // Can't use node_invoke:
  // the access hook takes the $op parameter before the $node parameter.
Dries's avatar
 
Dries committed
543
  return module_invoke(node_get_module_name($node), 'access', $op, $node);
Dries's avatar
 
Dries committed
544 545
}

Dries's avatar
 
Dries committed
546
function node_perm() {
Dries's avatar
 
Dries committed
547
  return array('administer nodes', 'access content');
Dries's avatar
 
Dries committed
548 549
}

Dries's avatar
 
Dries committed
550 551
function node_search($keys) {

Kjartan's avatar
Kjartan committed
552 553 554
  // Return the results of performing a search using the indexed search
  // for this particular type of node.
  //
Dries's avatar
 
Dries committed
555
  // Pass an array to the 'do_search' function which dictates what it
Kjartan's avatar
Kjartan committed
556 557 558 559 560 561 562 563
  // will search through, and what it will search for
  //
  // "keys"'s value is the keywords entered by the user
  //
  // "type"'s value is used to identify the node type in the search
  // index.
  //
  // "select"'s value is used to relate the data from the specific nodes
Dries's avatar
 
Dries committed
564
  // table to the data that the search_index table has in it, and the the
Kjartan's avatar
Kjartan committed
565 566
  // do_search functino will rank it.
  //
Dries's avatar
 
Dries committed
567
  // The select must always provide the following fields - lno, title,
Kjartan's avatar
Kjartan committed
568 569
  // created, uid, name, count
  //
Dries's avatar
 
Dries committed
570
  $find = do_search(array('keys' => $keys, 'type' => 'node', 'select' => "select s.lno as lno, n.title as title, n.created as created, u.uid as uid, u.name as name, s.count as count FROM {search_index} s, {node} n INNER JOIN {users} u ON n.uid = u.uid WHERE s.lno = n.nid AND s.type = 'node' AND s.word like '%' AND n.status = 1"));
Dries's avatar
 
Dries committed
571

Dries's avatar
 
Dries committed
572
  return array(t('Matching nodes ranked in order of relevance'), $find);
Dries's avatar
 
Dries committed
573 574
}

575
function node_settings() {
Dries's avatar
 
Dries committed
576 577 578
  $output .= form_select(t('Number of posts on main page'), 'default_nodes_main', variable_get('default_nodes_main', 10), array(1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 =>  5, 6 => 6, 7 => 7, 8 => 8, 9 => 9, 10 => 10, 15 => 15, 20 => 20, 25 => 25, 30 => 30), t('The default maximum number of posts to display per page on overview pages such as the main page.'));
  $output .= form_select(t('Length of trimmed posts'), 'teaser_length', variable_get('teaser_length', 600), array(0 => t('Unlimited'), 200 => t('200 characters'), 400 => t('400 characters'), 600 => t('600 characters'), 800 => t('800 characters'), 1000 => t('1000 characters'), 1200 => t('1200 characters'), 1400 => t('1400 characters'), 1600 => t('1600 characters'), 1800 => t('1800 characters'), 2000 => t('2000 characters')), 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'."));
  $output .= form_radios(t('Preview post'), 'node_preview', variable_get('node_preview', 0), array(t('Optional'), t('Required')), t('Must users preview posts before submitting?'));
Dries's avatar
 
Dries committed
579

Dries's avatar
 
Dries committed
580 581 582
  return $output;
}

Dries's avatar
 
Dries committed
583
function node_comment_mode($nid) {
Dries's avatar
 
Dries committed
584 585
  static $comment_mode;
  if (!isset($comment_mode[$nid])) {
Dries's avatar
 
Dries committed
586
    $comment_mode[$nid] = db_result(db_query('SELECT comment FROM {node} WHERE nid = %d', $nid));
Dries's avatar
 
Dries committed
587 588
  }
  return $comment_mode[$nid];
Dries's avatar
 
Dries committed
589 590
}

591
function node_link($type, $node = 0, $main = 0) {
Dries's avatar
 
Dries committed
592

Dries's avatar
 
Dries committed
593 594
  $links = array();

Dries's avatar
 
Dries committed
595
  if ($type == 'node') {
Kjartan's avatar
Kjartan committed
596 597 598
    if ($node->links) {
      $links = $node->links;
    }
Dries's avatar
 
Dries committed
599

Dries's avatar
 
Dries committed
600
    if ($main == 1 && $node->teaser && strlen($node->teaser) != strlen($node->body)) {
Dries's avatar
 
Dries committed
601
      $links[] = l(t('read more'), "node/view/$node->nid", array('title' => t('Read the rest of this posting.'), 'class' => 'read-more'));
Dries's avatar
 
Dries committed
602
    }
Dries's avatar
 
Dries committed
603

Dries's avatar
 
Dries committed
604 605
    if (user_access('administer nodes')) {
      $links[] = l(t('administer'), "admin/node/edit/$node->nid", array('title' => t('Administer this node.')));
Dries's avatar
 
Dries committed
606 607
    }

Dries's avatar
 
Dries committed
608 609
    if (user_access('administer nodes') && $node->revisions) {
      $links[] = l(t('revisions'), "node/revisions/$node->nid", array('title' => t('Administer revisions.')));
Dries's avatar
 
Dries committed
610
    }
Dries's avatar
 
Dries committed
611 612
  }

Dries's avatar
 
Dries committed
613 614
  if ($type == 'system') {
    menu('node/add', t('create content'), 'node_page', 1, MENU_HIDE_NOCHILD);
Dries's avatar
 
Dries committed
615

Dries's avatar
 
Dries committed
616 617 618 619 620 621
    if (user_access('administer nodes')) {
      menu('admin/node', t('content'), 'node_admin');
      menu('admin/node/search', t('search'), 'node_admin', 8);
      menu('admin/node/help', t('help'), 'node_help_page', 9);
      menu('admin/node/edit', t('edit post'), 'node_admin', 0, MENU_HIDE);
      menu('admin/node/settings', t('settings'), 'node_admin', 8);
Dries's avatar
 
Dries committed
622
    }
Dries's avatar
 
Dries committed
623

Dries's avatar
 
Dries committed
624 625
    if (user_access('access content')) {
      menu('node', t('content'), 'node_page', 0, MENU_HIDE);
Dries's avatar
 
Dries committed
626
    }
Dries's avatar
 
Dries committed
627 628
  }

Dries's avatar
 
Dries committed
629
  return $links;
Dries's avatar
 
Dries committed
630 631
}

Dries's avatar
 
Dries committed
632
function node_admin_edit($node) {
Dries's avatar
 
Dries committed
633

Dries's avatar
 
Dries committed
634
  if (is_numeric($node)) {
Dries's avatar
 
Dries committed
635
    $node = node_load(array('nid' => $node));
Dries's avatar
 
Dries committed
636
  }
Dries's avatar
 
Dries committed
637

Dries's avatar
 
Dries committed
638
  $output .= node_form($node);
Dries's avatar
 
Dries committed
639

Dries's avatar
 
Dries committed
640
  /*
Dries's avatar
 
Dries committed
641
  ** Display the node form extensions:
Dries's avatar
 
Dries committed
642
  */
643
  $output .= implode("\n", module_invoke_all('node_link', $node));
Dries's avatar
Dries committed
644

Dries's avatar
 
Dries committed
645
  return $output;
Dries's avatar
 
Dries committed
646 647 648

}

Dries's avatar
 
Dries committed
649
function node_admin_nodes() {
Dries's avatar
 
Dries committed
650
  $filters = array(
Dries's avatar
 
Dries committed
651 652 653 654 655 656
    array(t('View posts that are new or updated'), 'ORDER BY n.changed DESC'),
    array(t('View posts that need approval'), 'WHERE n.status = 0 OR n.moderate = 1 ORDER BY n.changed DESC'),
    array(t('View posts that are promoted'), 'WHERE n.status = 1 AND n.promote = 1 ORDER BY n.changed DESC'),
    array(t('View posts that are not promoted'), 'WHERE n.status = 1 AND n.promote = 0 ORDER BY n.changed DESC'),
    array(t('View posts that are static'), 'WHERE n.status = 1 AND n.static = 1 ORDER BY n.changed DESC'),
    array(t('View posts that are unpublished'), 'WHERE n.status = 0 AND n.moderate = 0 ORDER BY n.changed DESC')
Dries's avatar
 
Dries committed
657 658 659
   );

  $operations = array(
Dries's avatar
 
Dries committed
660 661 662 663 664
    array(t('Approve the selected posts'), 'UPDATE {node} SET status = 1, moderate = 0 WHERE nid = %d'),
    array(t('Promote the selected posts'), 'UPDATE {node} SET status = 1, promote = 1 WHERE nid = %d'),
    array(t('Make the selected posts static'), 'UPDATE {node} SET status = 1, static = 1 WHERE nid = %d'),
    array(t('Demote the selected posts'), 'UPDATE {node} SET promote = 0 WHERE nid = %d'),
    array(t('Unpublish the selected posts'), 'UPDATE {node} SET status = 0 WHERE nid = %d')
Dries's avatar
 
Dries committed
665
  );
Dries's avatar
 
Dries committed
666

Dries's avatar
 
Dries committed
667 668 669 670
  /*
  ** Handle operations:
  */

Dries's avatar
 
Dries committed
671 672
  if (empty($_SESSION['node_overview_filter'])) {
    $_SESSION['node_overview_filter'] = 0;
Dries's avatar
 
Dries committed
673 674
  }

Dries's avatar
 
Dries committed
675 676
  if (isset($_POST['edit']['filter'])) {
    $_SESSION['node_overview_filter'] = $_POST['edit']['filter'];
Dries's avatar
 
Dries committed
677 678
  }

Dries's avatar
 
Dries committed
679 680 681
  if (isset($_POST['edit']['operation'])) {
    $operation = $operations[$_POST['edit']['operation']][1];
    foreach ($_POST['edit']['status'] as $nid => $value) {
Dries's avatar
 
Dries committed
682
      if ($value) {
Dries's avatar
Dries committed
683
        db_query($operation, $nid);
Dries's avatar
 
Dries committed
684 685 686
      }
    }

Dries's avatar
 
Dries committed
687
    drupal_set_message(t('the update has been performed.'));
Dries's avatar
 
Dries committed
688 689
  }

Dries's avatar
 
Dries committed
690
  $filter = $_SESSION['node_overview_filter'];
Dries's avatar
Dries committed
691

Dries's avatar
 
Dries committed
692 693 694 695 696 697 698 699
  /*
  ** Render filter form:
  */

  $options = array();
  foreach ($filters as $key => $value) {
    $options[] = $value[0];
  }
Dries's avatar
 
Dries committed
700

Dries's avatar
 
Dries committed
701 702
  $form  = form_select(NULL, 'filter', $filter, $options);
  $form .= form_submit(t('Go'));
Dries's avatar
 
Dries committed
703

Dries's avatar
 
Dries committed
704
  $output .= '<h3>'. t('Filter options') .'</h3>';
Dries's avatar
 
Dries committed
705 706 707 708 709 710 711 712 713 714 715
  $output .= "<div class=\"container-inline\">$form</div>";

  /*
  ** Render operations form:
  */

  $options = array();
  foreach ($operations as $key => $value) {
    $options[] = $value[0];
  }

Dries's avatar
 
Dries committed
716 717
  $form = form_select(NULL, 'operation', 0, $options);
  $form .= form_submit(t('Go'));
Dries's avatar
 
Dries committed
718

Dries's avatar
 
Dries committed
719
  $output .= '<h3>'. t('Update options') .'</h3>';
Dries's avatar
 
Dries committed
720 721 722 723 724 725
  $output .= "<div class=\"container-inline\">$form</div>";

  /*
  ** Overview table:
  */

Dries's avatar
 
Dries committed
726 727
  $result = pager_query('SELECT n.*, u.name, u.uid FROM {node} n INNER JOIN {users} u ON n.uid = u.uid '. $filters[$filter][1], 50);
  $header = array(NULL, t('title'), t('type'), t('author'), t('status'), array('data' => t('operations'), 'colspan' => 2));
Dries's avatar
 
Dries committed
728

Dries's avatar
 
Dries committed
729
  while ($node = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
730
    $rows[] = array(form_checkbox(NULL, "status][$node->nid", 1, 0), l($node->title, "node/view/$node->nid") .' '. (node_is_new($node->nid, $node->changed) ? theme_mark() : ''), node_invoke($node, 'node_name'), format_name($node), ($node->status ? t('published') : t('not published')), l(t('edit node'), "admin/node/edit/$node->nid"), l(t('delete node'), "admin/node/delete/$node->nid"));
Dries's avatar
 
Dries committed
731
  }
Dries's avatar
 
Dries committed
732

Dries's avatar
 
Dries committed
733 734
  if ($pager = theme('pager', NULL, 50, 0)) {
    $rows[] = array(array('data' => $pager, 'colspan' => 7));
Dries's avatar
 
Dries committed
735
  }
Dries's avatar
 
Dries committed
736

Dries's avatar
 
Dries committed
737 738
  $output .= '<h3>'. $filters[$filter][0] .'</h3>';
  $output .= theme('table', $header, $rows);
Dries's avatar
 
Dries committed
739
  return form($output);
Dries's avatar
Dries committed
740 741
}

742
function node_admin_settings($edit) {
Dries's avatar
 
Dries committed
743
  $op = $_POST['op'];
Kjartan's avatar
Kjartan committed
744

Dries's avatar
 
Dries committed
745
  if ($op == t('Save configuration')) {
746 747 748 749 750 751 752
    /*
    ** Save the configuration options:
    */

    foreach ($edit as $name => $value) {
      variable_set($name, $value);
    }
Dries's avatar
 
Dries committed
753
    drupal_set_message(t('the content settings have been saved.'));
754 755
  }

Dries's avatar
 
Dries committed
756
  if ($op == t('Reset to defaults')) {
757 758 759 760 761 762 763
    /*
    ** Reset the configuration options to their default value:
    */

    foreach ($edit as $name => $value) {
      variable_del($name);
    }
Dries's avatar
 
Dries committed
764
    drupal_set_message(t('the content settings have been reset to their default values.'));
765 766
  }

Dries's avatar
 
Dries committed
767
  $header = array_merge(array(t('type')), array_keys(node_invoke_nodeapi($node, 'settings')));
Dries's avatar
 
Dries committed
768
  foreach (node_list() as $type) {
Dries's avatar
 
Dries committed
769 770
    $node->type = $type;
    $cols = array();
Dries's avatar
 
Dries committed
771 772
    foreach (node_invoke_nodeapi($node, 'settings') as $setting) {
      $cols[] = array('data' => $setting, 'align' => 'center', 'width' => 55);
773
    }
Dries's avatar
 
Dries committed
774
    $rows[] = array_merge(array(node_invoke($node, 'node_name')), $cols);
775
  }
Kjartan's avatar
Kjartan committed
776

Dries's avatar
 
Dries committed
777
  $output .= theme('table', $header, $rows);
778

779
  /* This is an idea for the future.
Dries's avatar
 
Dries committed
780
  foreach (node_list() as $type) {
Dries's avatar
 
Dries committed
781
    $node->type = $type;
Kjartan's avatar
Kjartan committed
782

Dries's avatar
 
Dries committed
783 784
      // Create theme('table', ) data:
      $header = array_keys(node_invoke_nodeapi($node, 'settings'));
785
      $cols = array();
Dries's avatar
 
Dries committed
786 787
      foreach (node_invoke_nodeapi($node, 'settings') as $setting) {
        $cols[] = array('data' => $setting, 'align' => 'center', 'width' => 75);
788 789
      }

Dries's avatar
 
Dries committed
790 791 792
      $output .= '<h2>'. node_invoke($node, 'node_name') .'</h2>';
      $output .= theme('table', $header, array($cols));
      $output .= '<br /><br />';
793 794
    }
  }
795
  */
796

Dries's avatar
 
Dries committed
797 798
  $output .= form_submit(t('Save configuration'));
  $output .= form_submit(t('Reset to defaults'));
Kjartan's avatar
Kjartan committed
799

Dries's avatar
 
Dries committed
800
  return form($output);
801 802 803

}

Dries's avatar
 
Dries committed
804 805
function node_revision_overview($nid) {

Dries's avatar
 
Dries committed
806 807
  if (user_access('administer nodes')) {
    $node = node_load(array('nid' => $nid));
Dries's avatar
 
Dries committed
808 809

    if ($node->revisions) {
Dries's avatar
 
Dries committed
810
      $header = array(t('older revisions'), array('colspan' => '3', 'data' => t('operations')));
Dries's avatar
 
Dries committed
811 812

      foreach ($node->revisions as $key => $revision) {
Dries's avatar
 
Dries committed
813
        $rows[] = array(t('revision #%r revised by %u on %d', array('%r' => $key, '%u' => format_name(user_load(array('uid' => $revision['uid']))), '%d' => format_date($revision['timestamp'], 'small'))) . ($revision['history'] ? '<br /><small>'. $revision['history'] .'</small>' : ''), l(t('view'), "node/view/$node->nid", array(), "revision=$key"), l(t('rollback'), "node/rollback-revision/$node->nid/$key"), l(t('delete'), "node/delete-revision/$node->nid/$key"));
Dries's avatar
 
Dries committed
814
      }
Dries's avatar
 
Dries committed
815
      $output .= theme('table', $header, $rows);
Dries's avatar
 
Dries committed
816 817 818 819 820 821 822
    }
  }

  return $output;
}


Dries's avatar
 
Dries committed
823 824 825 826 827
/*
** Return the revision with the specified revision number.
*/

function node_revision_load($node, $revision) {
Dries's avatar
 
Dries committed
828
  return $node->revisions[$revision]['node'];
Dries's avatar
 
Dries committed
829 830 831 832 833 834
}

/*
** Create and return a new revision of the given node.
*/

Dries's avatar
 
Dries committed
835 836 837
function node_revision_create($node) {
  global $user;

Dries's avatar
 
Dries committed
838 839 840 841 842
  /*
  ** 'revision' is the name of the field used to indicicate that we
  ** have to create a new revision of a node.
  */

Dries's avatar
 
Dries committed
843
  if ($node->nid && $node->revision) {
Dries's avatar
 
Dries committed
844
    $prev = node_load(array('nid' => $node->nid));
Dries's avatar
 
Dries committed
845 846
    $node->revisions = $prev->revisions;
    unset($prev->revisions);
Dries's avatar
 
Dries committed
847
    $node->revisions[] = array('uid' => $user->uid, 'timestamp' => time(), 'node' => $prev, 'history' => $node->history);
Dries's avatar
 
Dries committed
848 849 850 851 852
  }

  return $node;
}

Dries's avatar
 
Dries committed
853 854 855
/*
** Roll-back to the revision with the specified revision number.
*/
Dries's avatar
 
Dries committed
856

Dries's avatar
 
Dries committed
857
function node_revision_rollback($nid, $revision) {
Dries's avatar
 
Dries committed
858
  global $user;
Dries's avatar
 
Dries committed
859

Dries's avatar
 
Dries committed
860 861
  if (user_access('administer nodes')) {
    $node = node_load(array('nid' => $nid));
Dries's avatar
 
Dries committed
862

Dries's avatar
 
Dries committed
863 864 865
    /*
    ** Extract the specified revision:
    */
Dries's avatar
 
Dries committed
866