xmlsitemap.xmlsitemap.inc 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. <?php
  2. /**
  3. * @file
  4. * XML sitemap integration functions for xmlsitemap.module.
  5. */
  6. class XMLSitemapException extends Exception {}
  7. class XMLSitemapGenerationException extends XMLSitemapException {}
  8. /**
  9. * Extended class for writing XML sitemap files.
  10. */
  11. class XMLSitemapWriter extends XMLWriter {
  12. protected $status = TRUE;
  13. protected $uri = NULL;
  14. protected $sitemapElementCount = 0;
  15. protected $linkCountFlush = 500;
  16. protected $sitemap = NULL;
  17. protected $sitemap_page = NULL;
  18. protected $rootElement = 'urlset';
  19. /**
  20. * Constructor.
  21. *
  22. * @param $sitemap
  23. * The sitemap array.
  24. * @param $page
  25. * The current page of the sitemap being generated.
  26. */
  27. function __construct(stdClass $sitemap, $page) {
  28. $this->sitemap = $sitemap;
  29. $this->sitemap_page = $page;
  30. $this->uri = xmlsitemap_sitemap_get_file($sitemap, $page);
  31. $this->openUri($this->uri);
  32. }
  33. public function openUri($uri) {
  34. $return = parent::openUri(drupal_realpath($uri));
  35. if (!$return) {
  36. throw new XMLSitemapGenerationException(t('Could not open file @file for writing.', array('@file' => $uri)));
  37. }
  38. return $return;
  39. }
  40. public function startDocument($version = '1.0', $encoding = 'UTF-8', $standalone = NULL) {
  41. $this->setIndent(FALSE);
  42. parent::startDocument($version, $encoding);
  43. if (variable_get('xmlsitemap_xsl', 1)) {
  44. $this->writeXSL();
  45. }
  46. $this->startElement($this->rootElement, TRUE);
  47. }
  48. /**
  49. * Add the XML stylesheet to the XML page.
  50. */
  51. public function writeXSL() {
  52. $this->writePi('xml-stylesheet', 'type="text/xsl" href="' . url('sitemap.xsl') . '"');
  53. $this->writeRaw(PHP_EOL);
  54. }
  55. /**
  56. * Return an array of attributes for the root element of the XML.
  57. */
  58. public function getRootAttributes() {
  59. $attributes['xmlns'] = 'http://www.sitemaps.org/schemas/sitemap/0.9';
  60. if (variable_get('xmlsitemap_developer_mode', 0)) {
  61. $attributes['xmlns:xsi'] = 'http://www.w3.org/2001/XMLSchema-instance';
  62. $attributes['xsi:schemaLocation'] = 'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd';
  63. }
  64. return $attributes;
  65. }
  66. public function generateXML() {
  67. return xmlsitemap_generate_chunk($this->sitemap, $this, $this->sitemap_page);
  68. }
  69. public function startElement($name, $root = FALSE) {
  70. parent::startElement($name);
  71. if ($root) {
  72. foreach ($this->getRootAttributes() as $name => $value) {
  73. $this->writeAttribute($name, $value);
  74. }
  75. $this->writeRaw(PHP_EOL);
  76. }
  77. }
  78. /**
  79. * Write an full XML sitemap element tag.
  80. *
  81. * @param $name
  82. * The element name.
  83. * @param $element
  84. * An array of the elements properties and values.
  85. */
  86. public function writeSitemapElement($name, array &$element) {
  87. $this->writeElement($name, $element);
  88. $this->writeRaw(PHP_EOL);
  89. // After a certain number of elements have been added, flush the buffer
  90. // to the output file.
  91. $this->sitemapElementCount++;
  92. if (($this->sitemapElementCount % $this->linkCountFlush) == 0) {
  93. $this->flush();
  94. }
  95. }
  96. /**
  97. * Write full element tag including support for nested elements.
  98. *
  99. * @param $name
  100. * The element name.
  101. * @param $content
  102. * The element contents or an array of the elements' sub-elements.
  103. */
  104. public function writeElement($name, $content = '') {
  105. if (is_array($content)) {
  106. $this->startElement($name);
  107. foreach ($content as $sub_name => $sub_content) {
  108. $this->writeElement($sub_name, $sub_content);
  109. }
  110. $this->endElement();
  111. }
  112. else {
  113. parent::writeElement($name, $content);
  114. }
  115. }
  116. /**
  117. * Override of XMLWriter::flush() to track file writing status.
  118. */
  119. public function flush($empty = TRUE) {
  120. $return = parent::flush($empty);
  121. $this->status &= (bool) $return;
  122. return $return;
  123. }
  124. public function getStatus() {
  125. return $this->status;
  126. }
  127. public function getURI() {
  128. return $this->uri;
  129. }
  130. public function getSitemapElementCount() {
  131. return $this->sitemapElementCount;
  132. }
  133. public function endDocument() {
  134. $return = parent::endDocument();
  135. if (!$this->getStatus()) {
  136. throw new XMLSitemapGenerationException(t('Unknown error occurred while writing to file @file.', array('@file' => $this->uri)));
  137. }
  138. //if (xmlsitemap_var('gz')) {
  139. // $file_gz = $file . '.gz';
  140. // file_put_contents($file_gz, gzencode(file_get_contents($file), 9));
  141. //}
  142. return $return;
  143. }
  144. }
  145. class XMLSitemapIndexWriter extends XMLSitemapWriter {
  146. protected $rootElement = 'sitemapindex';
  147. function __construct(stdClass $sitemap, $page = 'index') {
  148. parent::__construct($sitemap, 'index');
  149. }
  150. public function getRootAttributes() {
  151. $attributes['xmlns'] = 'http://www.sitemaps.org/schemas/sitemap/0.9';
  152. if (variable_get('xmlsitemap_developer_mode', 0)) {
  153. $attributes['xmlns:xsi'] = 'http://www.w3.org/2001/XMLSchema-instance';
  154. $attributes['xsi:schemaLocation'] = 'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/siteindex.xsd';
  155. }
  156. return $attributes;
  157. }
  158. public function generateXML() {
  159. $lastmod_format = variable_get('xmlsitemap_lastmod_format', XMLSITEMAP_LASTMOD_MEDIUM);
  160. $url_options = $this->sitemap->uri['options'];
  161. $url_options += array(
  162. 'absolute' => TRUE,
  163. 'base_url' => variable_get('xmlsitemap_base_url', $GLOBALS['base_url']),
  164. 'language' => language_default(),
  165. 'alias' => TRUE,
  166. );
  167. for ($i = 1; $i <= $this->sitemap->chunks; $i++) {
  168. $url_options['query']['page'] = $i;
  169. $element = array(
  170. 'loc' => url('sitemap.xml', $url_options),
  171. // @todo Use the actual lastmod value of the chunk file.
  172. 'lastmod' => gmdate($lastmod_format, REQUEST_TIME),
  173. );
  174. $this->writeSitemapElement('sitemap', $element);
  175. }
  176. }
  177. }
  178. /**
  179. * Implements hook_xmlsitemap_link_info().
  180. */
  181. function xmlsitemap_xmlsitemap_link_info() {
  182. return array(
  183. 'frontpage' => array(
  184. 'label' => t('Frontpage'),
  185. 'xmlsitemap' => array(
  186. 'settings callback' => 'xmlsitemap_link_frontpage_settings',
  187. ),
  188. ),
  189. );
  190. }
  191. /**
  192. * XML sitemap link type settings callback for frontpage link entity.
  193. */
  194. function xmlsitemap_link_frontpage_settings(&$form) {
  195. module_load_include('admin.inc', 'xmlsitemap');
  196. if (user_access('administer site configuration')) {
  197. $form['#description'] = t('The front page path can be changed in the <a href="@url-frontpage">site information configuration</a>.', array('@url-frontpage' => url('admin/config/system/site-information')));
  198. }
  199. $form['xmlsitemap_frontpage_priority'] = array(
  200. '#type' => 'select',
  201. '#title' => t('Priority'),
  202. '#options' => xmlsitemap_get_priority_options(),
  203. '#default_value' => variable_get('xmlsitemap_frontpage_priority', 1.0),
  204. );
  205. $form['xmlsitemap_frontpage_changefreq'] = array(
  206. '#type' => 'select',
  207. '#title' => t('Change frequency'),
  208. '#options' => xmlsitemap_get_changefreq_options(),
  209. '#default_value' => variable_get('xmlsitemap_frontpage_changefreq', XMLSITEMAP_FREQUENCY_DAILY),
  210. );
  211. return $form;
  212. }
  213. /**
  214. * Implements hook_xmlsitemap_link_alter().
  215. */
  216. function xmlsitemap_xmlsitemap_link_alter(&$link) {
  217. // Alter the frontpage priority.
  218. if ($link['type'] == 'frontpage' || $link['loc'] == '' || $link['loc'] == variable_get('site_frontpage', 'node')) {
  219. $link['priority'] = variable_get('xmlsitemap_frontpage_priority', 1.0);
  220. $link['changefreq'] = variable_get('xmlsitemap_frontpage_changefreq', XMLSITEMAP_FREQUENCY_DAILY);
  221. }
  222. }
  223. /**
  224. * Implements hook_xmlsitemap_links().
  225. */
  226. function xmlsitemap_xmlsitemap_links() {
  227. // Frontpage link.
  228. $links[] = array(
  229. 'type' => 'frontpage',
  230. 'id' => 0,
  231. 'loc' => '',
  232. );
  233. return $links;
  234. }
  235. /**
  236. * Implements hook_xmlsitemap_sitemap_operations().
  237. */
  238. function xmlsitemap_xmlsitemap_sitemap_operations() {
  239. $operations['update'] = array(
  240. 'label' => t('Update cached files'),
  241. 'action past' => t('Updated'),
  242. 'callback' => 'xmlsitemap_sitemap_multiple_update',
  243. );
  244. return $operations;
  245. }
  246. /**
  247. * XML sitemap operation callback; regenerate sitemap files using the batch API.
  248. *
  249. * @param $smids
  250. * An array of XML sitemap IDs.
  251. *
  252. * @see xmlsitemap_regenerate_batch()
  253. */
  254. function xmlsitemap_sitemap_multiple_update(array $smids) {
  255. module_load_include('generate.inc', 'xmlsitemap');
  256. $batch = xmlsitemap_regenerate_batch($smids);
  257. batch_set($batch);
  258. }
  259. /**
  260. * Implements hook_query_TAG_alter().
  261. */
  262. function xmlsitemap_query_xmlsitemap_link_bundle_access_alter(QueryAlterableInterface $query) {
  263. if ($query instanceof EntityFieldQuery && $entity = $query->getMetaData('entity')) {
  264. $info = $query->getMetaData('entity_info');
  265. $bundle = $query->getMetaData('bundle');
  266. if (empty($bundle)) {
  267. $bundle = xmlsitemap_get_link_type_enabled_bundles($entity);
  268. }
  269. $query->entityCondition('bundle', $bundle, is_array($bundle) ? 'IN' : '=');
  270. }
  271. }