xmlsitemap_node.module 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. <?php
  2. // $Id: xmlsitemap_node.module,v 1.33 2010/01/24 04:31:32 davereid Exp $
  3. /**
  4. * Implements hook_cron().
  5. *
  6. * Process old nodes not found in the {xmlsitemap} table.
  7. */
  8. function xmlsitemap_node_cron() {
  9. xmlsitemap_node_xmlsitemap_index_links(xmlsitemap_var('batch_limit'));
  10. }
  11. /**
  12. * Implements hook_xmlsitemap_index_links().
  13. */
  14. function xmlsitemap_node_xmlsitemap_index_links($limit) {
  15. if ($types = xmlsitemap_node_get_types()) {
  16. $nids = db_query_range("SELECT n.nid FROM {node} n LEFT JOIN {xmlsitemap} x ON x.type = 'node' AND n.nid = x.id WHERE x.id IS NULL AND n.type IN (:types) ORDER BY n.nid DESC", 0, $limit, array(':types' => $types));
  17. foreach ($nids as $nid) {
  18. $node = node_load($nid, NULL, TRUE);
  19. $link = xmlsitemap_node_create_link($node);
  20. xmlsitemap_save_link($link);
  21. }
  22. }
  23. }
  24. /**
  25. * Implements hook_nodeapi().
  26. */
  27. function xmlsitemap_node_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  28. switch ($op) {
  29. case 'load':
  30. if ($data = xmlsitemap_load_link(array('type' => 'node', 'id' => $node->nid))) {
  31. return array('xmlsitemap' => $data);
  32. }
  33. break;
  34. case 'insert':
  35. $link = xmlsitemap_node_create_link($node);
  36. xmlsitemap_save_link($link);
  37. break;
  38. case 'update':
  39. $link = xmlsitemap_node_create_link($node);
  40. if (!empty($node->revision)) {
  41. // Update the change frequency.
  42. xmlsitemap_recalculate_changefreq($link);
  43. }
  44. xmlsitemap_save_link($link);
  45. break;
  46. case 'delete':
  47. xmlsitemap_delete_link(array('type' => 'node', 'id' => $node->nid));
  48. break;
  49. }
  50. }
  51. /**
  52. * Implements hook_comment().
  53. */
  54. function xmlsitemap_node_comment($comment, $op) {
  55. switch ($op) {
  56. case 'delete':
  57. case 'publish':
  58. case 'unpublish':
  59. $comment = (object) $comment;
  60. if ($node = node_load($comment->nid, NULL, TRUE)) {
  61. $link = xmlsitemap_node_create_link($node);
  62. if ($op == 'publish') {
  63. xmlsitemap_recalculate_changefreq($link);
  64. }
  65. xmlsitemap_save_link($link);
  66. }
  67. break;
  68. }
  69. }
  70. /**
  71. * Implements hook_node_type().
  72. */
  73. function xmlsitemap_node_node_type($op, $info) {
  74. if ($op == 'delete') {
  75. variable_del('xmlsitemap_node_status_' . $info->type);
  76. variable_del('xmlsitemap_node_priority_' . $info->type);
  77. //xmlsitemap_delete_link(array('type' => 'node', 'subtype' => $info->type));
  78. }
  79. }
  80. /**
  81. * Implements hook_form_FORM_ID_alter().
  82. *
  83. * Show a summary of content types on the XML sitemap settings page.
  84. */
  85. function xmlsitemap_node_form_xmlsitemap_settings_form_alter(&$form, $form_state) {
  86. $type = array(
  87. 'type' => 'node',
  88. 'title' => t('Content types'),
  89. 'item_title' => t('Content type'),
  90. 'access' => user_access('administer content types'),
  91. );
  92. $node_types = node_type_get_names();
  93. foreach ($node_types as $node_type => $node_type_name) {
  94. $node_types[$node_type] = array(
  95. 'name' => drupal_ucfirst($node_type_name),
  96. 'link' => 'admin/content/node-type/' . str_replace('_', '-', $node_type),
  97. 'status' => variable_get('xmlsitemap_node_status_' . $node_type, 0),
  98. 'priority' => variable_get('xmlsitemap_node_priority_' . $node_type, 0.5),
  99. );
  100. }
  101. xmlsitemap_add_form_type_summary($form, $type, $node_types);
  102. $form['node']['#weight'] = 30;
  103. }
  104. /**
  105. * Implements hook_form_FORM_ID_alter().
  106. *
  107. * @see node_type_form()
  108. * @see xmlsitemap_add_form_type_options()
  109. */
  110. function xmlsitemap_node_form_node_type_form_alter(&$form, $form_state) {
  111. $node_type = isset($form['#node_type']->type) ? $form['#node_type']->type : '';
  112. module_load_include('inc', 'xmlsitemap', 'xmlsitemap.admin');
  113. $options = array(
  114. 'status' => variable_get('xmlsitemap_node_status_' . $node_type, 0),
  115. 'priority' => variable_get('xmlsitemap_node_priority_' . $node_type, 0.5),
  116. );
  117. xmlsitemap_add_form_type_options($form, 'node', $options);
  118. $form['xmlsitemap']['#attached']['js']['vertical-tabs'] = drupal_get_path('module', 'xmlsitemap_node') . '/xmlsitemap_node.js';
  119. // Add our submit handler before node_type_form_submit() so we can compare
  120. // the old and new values.
  121. array_unshift($form['#submit'], 'xmlsitemap_node_type_form_submit');
  122. }
  123. function xmlsitemap_node_type_form_submit($form, $form_state) {
  124. $node_type = $form_state['values']['old_type'];
  125. $new_status = $form_state['values']['xmlsitemap_node_status'];
  126. $new_priority = $form_state['values']['xmlsitemap_node_priority'];
  127. $new_type = $form_state['values']['type'];
  128. if ($new_status != variable_get('xmlsitemap_node_status_' . $node_type, 0)) {
  129. xmlsitemap_update_links(array('status' => $new_status), array('type' => 'node', 'subtype' => $node_type, 'status_override' => 0));
  130. }
  131. if ($new_priority != variable_get('xmlsitemap_node_priority_' . $node_type, 0.5)) {
  132. xmlsitemap_update_links(array('priority' => $new_priority), array('type' => 'node', 'subtype' => $node_type, 'priority_override' => 0));
  133. }
  134. if ($node_type != $new_type) {
  135. xmlsitemap_update_links(array('subtype' => $new_type), array('type' => 'node', 'subtype' => $node_type));
  136. }
  137. }
  138. /**
  139. * Implements hook_form_alter().
  140. *
  141. * Add the XML sitemap individual link options for a node.
  142. *
  143. * @see xmlsitemap_add_form_link_options()
  144. */
  145. function xmlsitemap_node_form_alter(&$form, $form_state, $form_id) {
  146. if (!empty($form['#node_edit_form'])) {
  147. $node = clone $form['#node'];
  148. if (!isset($node->nid)) {
  149. // Handle new nodes that do not have a value for nid yet.
  150. $node->nid = NULL;
  151. }
  152. $link = xmlsitemap_node_create_link($node);
  153. // Add the link options.
  154. module_load_include('inc', 'xmlsitemap', 'xmlsitemap.admin');
  155. xmlsitemap_add_form_link_options($form, $link);
  156. $form['xmlsitemap']['#access'] |= user_access('administer nodes');
  157. $form['xmlsitemap']['#weight'] = 30;
  158. if (user_access('administer content types')) {
  159. $form['xmlsitemap']['#description'] = t('The default XML sitemap settings for this content type can be changed <a href="@link-type">here</a>.', array('@link-type' => url('admin/content/node-type/' . $node->type, array('query' => drupal_get_destination()))));
  160. }
  161. //// The following values should not exist for new nodes.
  162. //if ($node->nid) {
  163. // $form['xmlsitemap']['lastmod'] = array(
  164. // '#type' => 'value',
  165. // '#value' => $node->xmlsitemap['lastmod'],
  166. // );
  167. // $form['xmlsitemap']['changefreq'] = array(
  168. // '#type' => 'value',
  169. // '#value' => $node->xmlsitemap['changefreq'],
  170. // );
  171. // $form['xmlsitemap']['changecount'] = array(
  172. // '#type' => 'value',
  173. // '#value' => $node->xmlsitemap['changecount'],
  174. // );
  175. //}
  176. }
  177. }
  178. /**
  179. * Implements hook_xmlsitemap_links().
  180. */
  181. function xmlsitemap_node_xmlsitemap_links($offset = 0, $limit = 0) {
  182. $links = array();
  183. if ($types = xmlsitemap_node_get_types()) {
  184. $sql = "SELECT n.nid FROM {node} n WHERE n.nid > :offset AND n.type IN (:types) ORDER BY n.nid";
  185. $args = array(':offset' => $offset, ':types' => $types);
  186. $nids = ($limit ? db_query_range($sql, 0, $limit, $args) : db_query($sql, $args));
  187. foreach ($nids as $nid) {
  188. $node = node_load($nid, NULL, TRUE);
  189. $links[] = xmlsitemap_node_create_link($node);
  190. }
  191. }
  192. return $links;
  193. }
  194. /**
  195. * Implements hook_xmlsitemap_links_batch_info().
  196. */
  197. function xmlsitemap_node_xmlsitemap_links_batch_info() {
  198. $types = xmlsitemap_node_get_types();
  199. return array(
  200. 'max' => $types ? db_query("SELECT COUNT(n.nid) FROM {node} n WHERE n.type IN (:types)", array(':types' => $types))->fetchField() : 0,
  201. );
  202. }
  203. /**
  204. * Implements hook_xmlsitemap_link_info().
  205. */
  206. function xmlsitemap_node_xmlsitemap_link_info() {
  207. return array(
  208. 'node' => array(
  209. 'purge' => TRUE,
  210. 'table' => 'node',
  211. 'id' => 'nid',
  212. 'subtype' => 'type',
  213. 'subtypes' => xmlsitemap_node_get_types(),
  214. ),
  215. );
  216. }
  217. /**
  218. * Fetch an array of node types to be included in the sitemap.
  219. */
  220. function xmlsitemap_node_get_types() {
  221. $node_types = array_keys(node_type_get_names());
  222. foreach ($node_types as $index => $node_type) {
  223. if (!variable_get('xmlsitemap_node_status_' . $node_type, 0)) {
  224. unset($node_types[$index]);
  225. }
  226. }
  227. return $node_types;
  228. }
  229. /**
  230. * Implements hook_content_extra_fields().
  231. *
  232. * This is so that the XML sitemap fieldset is sortable on the node edit form.
  233. */
  234. function xmlsitemap_node_content_extra_fields() {
  235. $extras['xmlsitemap'] = array(
  236. 'label' => t('XML sitemap'),
  237. 'description' => t('XML sitemap module form.'),
  238. 'weight' => 30,
  239. );
  240. return $extras;
  241. }
  242. /**
  243. * Fetch all the timestamps for when a node was changed.
  244. *
  245. * @param $node
  246. * A node object.
  247. * @return
  248. * An array of UNIX timestamp integers.
  249. */
  250. function xmlsitemap_node_get_timestamps($node) {
  251. static $timestamps = array();
  252. if (!isset($timestamps[$node->nid])) {
  253. $timestamps[$node->nid] = db_query("SELECT c.timestamp FROM {comments} c WHERE c.nid = %d AND c.status = %d UNION ALL SELECT nr.timestamp FROM {node_revisions} nr WHERE nr.nid = %d", $node->nid, COMMENT_PUBLISHED, $node->nid)->fetchCol();
  254. }
  255. return $timestamps[$node->nid];
  256. }
  257. /**
  258. * Create a sitemap link from a node.
  259. *
  260. * The link will be saved as $node->xmlsitemap.
  261. *
  262. * @param $node
  263. * A node object.
  264. */
  265. function xmlsitemap_node_create_link(&$node) {
  266. if (!isset($node->xmlsitemap)) {
  267. $node->xmlsitemap = array();
  268. }
  269. $node->xmlsitemap += array(
  270. 'type' => 'node',
  271. 'id' => $node->nid,
  272. 'subtype' => $node->type,
  273. 'loc' => 'node/'. $node->nid,
  274. 'status' => variable_get('xmlsitemap_node_status_' . $node->type, 0),
  275. 'status_default' => variable_get('xmlsitemap_node_status_' . $node->type, 0),
  276. 'status_override' => 0,
  277. 'priority' => variable_get('xmlsitemap_node_priority_' . $node->type, 0.5),
  278. 'priority_default' => variable_get('xmlsitemap_node_priority_' . $node->type, 0.5),
  279. 'priority_override' => 0,
  280. 'changefreq' => $node->nid ? xmlsitemap_calculate_changefreq(xmlsitemap_node_get_timestamps($node)) : 0,
  281. 'changecount' => $node->nid ? count(xmlsitemap_node_get_timestamps($node)) - 1 : 0,
  282. );
  283. // The following values must always be checked because they are volatile.
  284. $node->xmlsitemap['lastmod'] = isset($node->changed) ? $node->changed : REQUEST_TIME;
  285. $node->xmlsitemap['access'] = $node->nid ? (bool) node_access('view', $node, drupal_anonymous_user()) : 1;
  286. $node->xmlsitemap['language'] = isset($node->language) ? $node->language : LANGUAGE_NONE;
  287. return $node->xmlsitemap;
  288. }
  289. /**
  290. * Internal default variables for xmlsitemap_node_var().
  291. */
  292. function xmlsitemap_node_variables() {
  293. $defaults = array();
  294. $node_types = array_keys(node_type_get_names());
  295. foreach ($node_types as $node_type) {
  296. $defaults['xmlsitemap_node_priority_' . $node_type] = 0.5;
  297. $defaults['xmlsitemap_node_status_' . $node_type] = 0;
  298. // @todo Remove the variable.
  299. $defaults['xmlsitemap_node_update_' . $node_type] = NULL;
  300. }
  301. return $defaults;
  302. }
  303. ///**
  304. // * Internal implementation of variable_get().
  305. // */
  306. //function xmlsitemap_node_var($name, $default = NULL) {
  307. // static $defaults;
  308. // if (!isset($defaults)) {
  309. // $defaults = xmlsitemap_node_variables();
  310. // }
  311. //
  312. // $name = 'xmlsitemap_node_'. $name;
  313. //
  314. // // @todo Remove when stable.
  315. // if (!isset($defaults[$name])) {
  316. // trigger_error(t('Default variable for %variable not found.', array('%variable' => $name)));
  317. // }
  318. //
  319. // return variable_get($name, isset($default) || !isset($defaults[$name]) ? $default : $defaults[$name]);
  320. //}