SitemapGenerator.php 6.14 KB
Newer Older
1 2 3
<?php
/**
 * @file
gbyte.co's avatar
gbyte.co committed
4
 * Contains \Drupal\simple_sitemap\SitemapGenerator.
5 6 7 8
 *
 * Generates a sitemap for entities and custom links.
 */

gbyte.co's avatar
gbyte.co committed
9
namespace Drupal\simple_sitemap;
10

11
use \XMLWriter;
12 13 14 15 16 17 18 19

/**
 * SitemapGenerator class.
 */
class SitemapGenerator {

  const XML_VERSION = '1.0';
  const ENCODING = 'UTF-8';
20 21
  const XMLNS = 'http://www.sitemaps.org/schemas/sitemap/0.9';
  const XMLNS_XHTML = 'http://www.w3.org/1999/xhtml';
22

23
  private $entityTypes;
24 25
  private $custom;
  private $links;
26
  private $generatingFrom;
27

gbyte.co's avatar
gbyte.co committed
28
  function __construct($from = 'form') {
29
    $this->links = array();
30
    $this->generatingFrom = $from;
31
  }
32

33 34
  public function setEntityTypes($entityTypes) {
    $this->entityTypes = is_array($entityTypes) ? $entityTypes : array();
35 36
  }

37
  public function setCustomLinks($custom) {
38
    $this->custom = is_array($custom) ? $custom : array();
39 40
  }

41
  /**
42
   * Adds all operations to the batch and starts it.
43
   */
44 45 46 47
  public function startBatch() {
    $batch = new Batch($this->generatingFrom);
    $batch->addOperations('custom_paths', $this->batchAddCustomPaths());
    $batch->addOperations('entity_types', $this->batchAddEntityTypePaths());
gbyte.co's avatar
gbyte.co committed
48 49 50 51
    $batch->start();
  }

  /**
52 53 54
   * Returns the custom path generating operation.
   *
   * @return array $operation.
gbyte.co's avatar
gbyte.co committed
55
   */
56
  private function batchAddCustomPaths() {
gbyte.co's avatar
gbyte.co committed
57
    $link_generator = new CustomLinkGenerator();
58
    return $link_generator->getCustomPaths($this->custom);
gbyte.co's avatar
gbyte.co committed
59
  }
60

gbyte.co's avatar
gbyte.co committed
61
  /**
62 63 64 65
   * Collects the entity path generating information from all simeple_sitemap
   * plugins to be added to the batch.
   *
   * @return array $operations.
gbyte.co's avatar
gbyte.co committed
66
   */
67
  private function batchAddEntityTypePaths() {
68
    $operations = [];
69

70 71 72 73 74
    // Menu fix.
    if (isset($this->entityTypes['menu'])) {
      $this->entityTypes['menu_link_content'] = $this->entityTypes['menu'];
      unset ($this->entityTypes['menu']);
    }
75

76 77 78 79 80
    $entity_types = Simplesitemap::getSitemapEntityTypes();
    foreach($entity_types as $entity_type_name => $entity_type) {
      $bundle_entity_type_name = !empty($entity_type->getBundleEntityType()) ? $entity_type->getBundleEntityType() : $entity_type->id();
      if (isset($this->entityTypes[$bundle_entity_type_name])) {
        foreach($this->entityTypes[$bundle_entity_type_name] as $bundle_name => $bundle_settings) {
gbyte.co's avatar
gbyte.co committed
81
          if ($bundle_settings['index']) {
82 83 84 85 86 87 88 89 90 91 92
            $keys = $entity_type->getKeys();
            if ($entity_type_name == 'menu_link_content') {$keys['bundle'] = 'menu_name';} // Menu fix.
            $operations[] = [
              'entity_info' => [
                'bundle_settings' => $bundle_settings,
                'bundle_name' => $bundle_name,
                'bundle_entity_type' => $bundle_entity_type_name,
                'entity_type_name' => $entity_type_name,
                'keys' => $keys,
              ],
            ];
gbyte.co's avatar
gbyte.co committed
93 94
          }
        }
95 96
      }
    }
gbyte.co's avatar
gbyte.co committed
97 98 99 100
    return $operations;
  }

  /**
101 102
   * Wrapper method which takes links along with their options, lets other
   * modules alter the links and then generates and saves the sitemap.
gbyte.co's avatar
gbyte.co committed
103
   *
104 105
   * @param array $links
   *  All links with their multilingual versions and settings.
gbyte.co's avatar
gbyte.co committed
106
   */
107
  public static function generateSitemap($links, $remove_sitemap = FALSE) {
108 109
    // Invoke alter hook.
    \Drupal::moduleHandler()->alter('simple_sitemap_links', $links);
gbyte.co's avatar
gbyte.co committed
110
    $values = array(
111
      'id' => $remove_sitemap ? 1 : db_query('SELECT MAX(id) FROM {simple_sitemap}')->fetchField() + 1,
112
      'sitemap_string' => self::generateSitemapChunk($links),
gbyte.co's avatar
gbyte.co committed
113
      'sitemap_created' => REQUEST_TIME,
gbyte.co's avatar
gbyte.co committed
114
    );
115 116
    if ($remove_sitemap)
      db_truncate('simple_sitemap')->execute();
gbyte.co's avatar
gbyte.co committed
117
    db_insert('simple_sitemap')->fields($values)->execute();
118 119
  }

120
  /**
121
   * Generates and returns the sitemap index for all sitemap chunks.
122
   *
123
   * @param array $sitemap_chunks
124 125 126 127
   *  All sitemap chunks keyed by the chunk ID.
   *
   * @return string sitemap index
   */
128
  public function generateSitemapIndex($sitemap_chunks) {
129 130 131 132 133 134 135
    $writer = new XMLWriter();
    $writer->openMemory();
    $writer->setIndent(TRUE);
    $writer->startDocument(self::XML_VERSION, self::ENCODING);
    $writer->startElement('sitemapindex');
    $writer->writeAttribute('xmlns', self::XMLNS);

136
    foreach ($sitemap_chunks as $chunk_id => $chunk_data) {
137
      $writer->startElement('sitemap');
138 139
      $writer->writeElement('loc', $GLOBALS['base_url'] . '/sitemaps/'
        . $chunk_id . '/' . 'sitemap.xml');
140
      $writer->writeElement('lastmod', date_iso8601($chunk_data->sitemap_created));
141 142 143 144 145 146 147
      $writer->endElement();
    }
    $writer->endElement();
    $writer->endDocument();
    return $writer->outputMemory();
  }

148 149 150 151
  /**
   * Generates and returns a sitemap chunk.
   *
   * @param array $sitemap_links
152
   *  All links with their multilingual versions and settings.
153 154 155
   *
   * @return string sitemap chunk
   */
156 157
  private static function generateSitemapChunk($sitemap_links) {
    $default_language_id = Simplesitemap::getDefaultLangId();
158 159 160 161 162 163 164 165 166

    $writer = new XMLWriter();
    $writer->openMemory();
    $writer->setIndent(TRUE);
    $writer->startDocument(self::XML_VERSION, self::ENCODING);
    $writer->startElement('urlset');
    $writer->writeAttribute('xmlns', self::XMLNS);
    $writer->writeAttribute('xmlns:xhtml', self::XMLNS_XHTML);

167
    foreach ($sitemap_links as $link) {
168 169 170
      $writer->startElement('url');

      // Adding url to standard language.
gbyte.co's avatar
gbyte.co committed
171
      $writer->writeElement('loc', $link['urls'][$default_language_id]);
172

173
      // Adding alternate urls (other languages) if any.
gbyte.co's avatar
gbyte.co committed
174 175
      if (count($link['urls']) > 1) {
        foreach($link['urls'] as $language_id => $localised_url) {
176 177 178 179 180
          $writer->startElement('xhtml:link');
          $writer->writeAttribute('rel', 'alternate');
          $writer->writeAttribute('hreflang', $language_id);
          $writer->writeAttribute('href', $localised_url);
          $writer->endElement();
181 182 183
        }
      }

184
      // Add priority if any.
gbyte.co's avatar
gbyte.co committed
185
      if (isset($link['priority'])) {
186 187 188
        $writer->writeElement('priority', $link['priority']);
      }

189
      // Add lastmod if any.
gbyte.co's avatar
gbyte.co committed
190
      if (isset($link['lastmod'])) {
191 192 193 194
        $writer->writeElement('lastmod', $link['lastmod']);
      }
      $writer->endElement();
    }
gbyte.co's avatar
gbyte.co committed
195
    $writer->endElement();
196 197
    $writer->endDocument();
    return $writer->outputMemory();
198 199
  }
}
200