xmlsitemap_menu.module 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. <?php
  2. /**
  3. * @file
  4. * Main file for XML sitemap menu.
  5. */
  6. /**
  7. * Implements hook_entity_info_alter().
  8. *
  9. * Adds support for the menu link entity if it doesn't already exist.
  10. */
  11. function xmlsitemap_menu_entity_info_alter(&$info) {
  12. if (!isset($info['menu_link'])) {
  13. $info['menu_link'] = array(
  14. 'label' => t('Menu link'),
  15. 'controller class' => 'DrupalDefaultEntityController',
  16. 'base table' => 'menu_links',
  17. 'uri callback' => 'xmlsitemap_menu_menu_link_uri',
  18. 'fieldable' => FALSE,
  19. 'static cache' => TRUE,
  20. 'field cache' => TRUE,
  21. 'entity keys' => array(
  22. 'id' => 'mlid',
  23. 'bundle' => 'menu_name',
  24. 'label' => 'link_title',
  25. 'revision' => '',
  26. ),
  27. 'load hook' => NULL,
  28. 'view modes' => array(),
  29. 'translation' => array(),
  30. 'schema_fields_sql' => array(
  31. 'base table' => drupal_schema_fields_sql('menu_links'),
  32. ),
  33. 'xmlsitemap' => array(
  34. 'process callback' => 'xmlsitemap_menu_xmlsitemap_process_menu_links',
  35. ),
  36. 'bundle label' => t('Menu'),
  37. 'token type' => 'menu_link',
  38. );
  39. foreach (menu_get_menus() as $type => $name) {
  40. $info['menu_link']['bundles'][$type] = array(
  41. 'label' => $name,
  42. 'admin' => array(
  43. 'path' => 'admin/structure/menu/manage/%menu/edit',
  44. 'bundle argument' => 4,
  45. 'real path' => 'admin/structure/menu/manage/' . $type . '/edit',
  46. 'access arguments' => array('administer menus'),
  47. ),
  48. );
  49. }
  50. }
  51. else {
  52. // If the entity type already exists ensure the xmlsitemap is added.
  53. $info['menu_link'] += array(
  54. 'uri callback' => 'xmlsitemap_menu_menu_link_uri',
  55. 'xmlsitemap' => array(
  56. 'process callback' => 'xmlsitemap_menu_xmlsitemap_process_menu_links',
  57. ),
  58. );
  59. if (!isset($info['menu_link']['bundle label'])) {
  60. $info['menu_link']['bundle label'] = t('Menu');
  61. }
  62. }
  63. }
  64. /**
  65. * Entity URI callback.
  66. */
  67. function xmlsitemap_menu_menu_link_uri($menu_item) {
  68. return is_array($menu_item) ? $menu_item['href'] : $menu_item->href;
  69. }
  70. /**
  71. * Implements hook_cron().
  72. *
  73. * Process old menu links not found in the {xmlsitemap} table.
  74. */
  75. function xmlsitemap_menu_cron() {
  76. xmlsitemap_menu_xmlsitemap_index_links(xmlsitemap_var('batch_limit'));
  77. }
  78. /**
  79. * Implements hook_xmlsitemap_index_links().
  80. */
  81. function xmlsitemap_menu_xmlsitemap_index_links($limit) {
  82. if ($menus = xmlsitemap_get_link_type_enabled_bundles('menu_link')) {
  83. $sql = "SELECT ml.mlid FROM {menu_links} ml LEFT JOIN {xmlsitemap} x ON x.type = 'menu' AND ml.mlid = x.id WHERE x.id IS NULL AND ml.menu_name IN (:menus) ORDER BY ml.mlid DESC";
  84. $mlids = db_query_range($sql, 0, $limit, array(':menus' => $menus))->fetchCol();
  85. xmlsitemap_menu_xmlsitemap_process_menu_links($mlids);
  86. }
  87. }
  88. /**
  89. * Process menu sitemap links.
  90. *
  91. * @param array $mlids
  92. * An array of menu link IDs.
  93. */
  94. function xmlsitemap_menu_xmlsitemap_process_menu_links(array $mlids, array $xmlsitemap = array()) {
  95. // Set the global user variable to the anonymous user.
  96. xmlsitemap_switch_user(0);
  97. foreach ($mlids as $mlid) {
  98. $menu_item = menu_link_load($mlid);
  99. if (empty($menu_item)) {
  100. continue;
  101. }
  102. if (!empty($xmlsitemap)) {
  103. $menu_item['xmlsitemap'] = $xmlsitemap;
  104. }
  105. $link = xmlsitemap_menu_create_link($menu_item);
  106. xmlsitemap_link_save($link, array($link['type'] => $menu_item));
  107. }
  108. // Set the global user variable back to the original user.
  109. xmlsitemap_restore_user();
  110. }
  111. /**
  112. * Implements hook_form_FORM_ID_alter().
  113. *
  114. * @see menu_edit_menu()
  115. * @see xmlsitemap_add_link_bundle_settings()
  116. */
  117. function xmlsitemap_menu_form_menu_edit_menu_alter(&$form, $form_state) {
  118. $menu = isset($form['menu_name']['#default_value']) ? $form['menu_name']['#default_value'] : '';
  119. module_load_include('inc', 'xmlsitemap', 'xmlsitemap.admin');
  120. xmlsitemap_add_link_bundle_settings($form, $form_state, 'menu_link', $menu);
  121. }
  122. /**
  123. * Example functions.
  124. *
  125. * Function xmlsitemap_menu_form_menu_overview_form_alter(&$form, $form_state) {
  126. * $form['#submit'][] = 'xmlsitemap_menu_menu_overview_form_submit';
  127. * }
  128. *
  129. * Function xmlsitemap_menu_menu_overview_form_submit($form, $form_state) {
  130. * $mlids = array();
  131. * foreach (element_children($form) as $mlid) {
  132. * if (isset($form[$mlid]['#item'])) {
  133. * $mlids[] = $form[$mlid]['#item']['mlid'];
  134. * }
  135. * }
  136. * xmlsitemap_menu_xmlsitemap_process_menu_links($mlids);
  137. * }
  138. */
  139. /**
  140. * Implements hook_form_FORM_ID_alter().
  141. *
  142. * @see menu_edit_item()
  143. */
  144. function xmlsitemap_menu_form_menu_edit_item_alter(&$form, $form_state) {
  145. $menu_name = $form['parent']['#default_value'];
  146. $menu_name = substr($menu_name, 0, strpos($menu_name, ':'));
  147. // Add the link options.
  148. module_load_include('inc', 'xmlsitemap', 'xmlsitemap.admin');
  149. xmlsitemap_add_form_link_options($form, 'menu_link', $menu_name, $form['mlid']['#value']);
  150. $form['xmlsitemap']['#weight'] = 30;
  151. }
  152. /**
  153. * Implements hook_menu_insert().
  154. */
  155. function xmlsitemap_menu_menu_insert(array $menu) {
  156. if (isset($menu['xmlsitemap'])) {
  157. xmlsitemap_link_bundle_settings_save('menu_link', $menu['menu_name'], $menu['xmlsitemap']);
  158. }
  159. // When menus change, the bundles we defined in
  160. // xmlsitemap_menu_entity_info_alter() change, so we need to clear the cache.
  161. entity_info_cache_clear();
  162. }
  163. /**
  164. * Implements hook_menu_update().
  165. */
  166. function xmlsitemap_menu_menu_update(array $menu) {
  167. if (isset($menu['xmlsitemap'])) {
  168. xmlsitemap_link_bundle_settings_save('menu_link', $menu['menu_name'], $menu['xmlsitemap']);
  169. }
  170. // When menus change, the bundles we defined in
  171. // xmlsitemap_menu_entity_info_alter() change, so we need to clear the cache.
  172. entity_info_cache_clear();
  173. }
  174. /**
  175. * Implements hook_menu_delete().
  176. */
  177. function xmlsitemap_menu_menu_delete(array $menu) {
  178. xmlsitemap_link_bundle_delete('menu_link', $menu['menu_name']);
  179. // When menus change, the bundles we defined in
  180. // xmlsitemap_menu_entity_info_alter() change, so we need to clear the cache.
  181. entity_info_cache_clear();
  182. }
  183. /**
  184. * Implements hook_menu_link_insert().
  185. */
  186. function xmlsitemap_menu_menu_link_insert(array $link) {
  187. $link += array('xmlsitemap' => array());
  188. xmlsitemap_menu_xmlsitemap_process_menu_links(array($link['mlid']), $link['xmlsitemap']);
  189. }
  190. /**
  191. * Implements hook_menu_link_update().
  192. *
  193. * @see hook_menu_link_alter()
  194. */
  195. function xmlsitemap_menu_menu_link_update(array $link) {
  196. // $link += array('xmlsitemap' => array());
  197. // @codingStandardsIgnoreLine
  198. // xmlsitemap_menu_xmlsitemap_process_menu_links(array($link['mlid']), $link['xmlsitemap']);.
  199. }
  200. /**
  201. * Implements hook_menu_link_alter().
  202. *
  203. * We have to use this hook rather than hook_menu_link_update() because this
  204. * hook is not always called if the user does not edit the core menu item
  205. * fields.
  206. *
  207. * @see https://www.drupal.org/node/1013856
  208. */
  209. function xmlsitemap_menu_menu_link_alter(array &$link) {
  210. if (!empty($link['mlid'])) {
  211. $link += array('xmlsitemap' => array());
  212. xmlsitemap_menu_xmlsitemap_process_menu_links(array($link['mlid']), $link['xmlsitemap']);
  213. }
  214. }
  215. /**
  216. * Implements hook_menu_link_delete().
  217. */
  218. function xmlsitemap_menu_menu_link_delete(array $link) {
  219. xmlsitemap_link_delete('menu_link', $link['mlid']);
  220. }
  221. /**
  222. * Create a sitemap link from a menu item.
  223. *
  224. * @param array $menu_item
  225. * A loaded menu item.
  226. */
  227. function xmlsitemap_menu_create_link(array $menu_item) {
  228. if (!isset($menu_item['xmlsitemap'])) {
  229. $menu_item['xmlsitemap'] = array();
  230. if ($menu_item['mlid'] && $link = xmlsitemap_link_load('menu_link', $menu_item['mlid'])) {
  231. $menu_item['xmlsitemap'] = $link;
  232. }
  233. }
  234. $settings = xmlsitemap_link_bundle_load('menu_link', $menu_item['menu_name']);
  235. $menu_item['xmlsitemap'] += array(
  236. 'type' => 'menu_link',
  237. 'id' => $menu_item['mlid'],
  238. 'status' => $settings['status'],
  239. 'status_default' => $settings['status'],
  240. 'status_override' => 0,
  241. 'priority' => $settings['priority'],
  242. 'priority_default' => $settings['priority'],
  243. 'priority_override' => 0,
  244. );
  245. // The following values must always be checked because they are volatile.
  246. $menu_item['xmlsitemap']['loc'] = $menu_item['href'];
  247. $menu_item['xmlsitemap']['subtype'] = $menu_item['menu_name'];
  248. $menu_item['xmlsitemap']['access'] = $menu_item['access'] && !$menu_item['external'] && !$menu_item['hidden'];
  249. $menu_item['xmlsitemap']['language'] = isset($menu_item['options']['langcode']) ? $menu_item['options']['langcode'] : LANGUAGE_NONE;
  250. // Exclude menu items created for nodes that are added by xmlsitemap_node.
  251. if ($menu_item['xmlsitemap']['access'] && $menu_item['router_path'] == 'node/%' && module_exists('xmlsitemap_node')) {
  252. $node = node_load(substr($menu_item['link_path'], 5));
  253. if ($node) {
  254. if (empty($node->xmlsitemap)) {
  255. xmlsitemap_node_create_link($node);
  256. }
  257. if ($node->xmlsitemap['status'] && $node->xmlsitemap['access']) {
  258. $menu_item['xmlsitemap']['status'] = FALSE;
  259. }
  260. }
  261. }
  262. return $menu_item['xmlsitemap'];
  263. }
  264. /**
  265. * Calculate the priority of a menu link based on depth and weight.
  266. */
  267. function xmlsitemap_menu_calculate_priority(array $menu_item) {
  268. $priority = (MENU_MAX_DEPTH - $menu_item['depth'] + 1) / MENU_MAX_DEPTH;
  269. $priority -= (50 + $menu_item['weight']) / (100 * (MENU_MAX_DEPTH + 1));
  270. return $priority;
  271. }
  272. /**
  273. * Internal default variables for template_var().
  274. */
  275. function xmlsitemap_menu_variables() {
  276. $defaults = array();
  277. $menus = array_keys(menu_get_menus());
  278. foreach ($menus as $menu) {
  279. $defaults['xmlsitemap_settings_menu_' . $menu] = array(
  280. 'status' => XMLSITEMAP_STATUS_DEFAULT,
  281. 'priority' => XMLSITEMAP_PRIORITY_DEFAULT,
  282. );
  283. }
  284. return $defaults;
  285. }
  286. /**
  287. * Implements hook_features_pipe_COMPONENT_alter().
  288. *
  289. * Add variables to exported menus.
  290. */
  291. function xmlsitemap_menu_features_pipe_menu_custom_alter(&$pipe, $data, $export) {
  292. if (!empty($data)) {
  293. foreach ($data as $menu_name) {
  294. $pipe['variable'][] = "xmlsitemap_settings_menu_link_{$menu_name}";
  295. }
  296. }
  297. }