Commit 3f2f5845 authored by gbyte.co's avatar gbyte.co

Adding sitemap lastmod info in sitemap index, improving code documentation.

parent a7ec2d2e
......@@ -2,7 +2,7 @@
/**
* @file
* Module install functions creating a database table.
* Module install and update procedures.
*/
/**
......@@ -19,11 +19,17 @@ function simplesitemap_schema() {
'not null' => TRUE,
),
'sitemap_string' => array(
'description' => 'XML sitemap string.',
'description' => 'XML sitemap chunk string.',
'type' => 'text',
'size' => 'big',
'not null' => TRUE,
),
'generated' => array(
'description' => 'Timestamp of sitemap chunk generation.',
'type' => 'int',
'default' => 0,
'not null' => TRUE,
),
),
'primary key' => array('id'),
);
......@@ -62,7 +68,8 @@ function simplesitemap_update_8102() {
$entity_types['taxonomy_vocabulary'] = $entity_types['taxonomy_term'];
unset($entity_types['taxonomy_term']);
}
\Drupal::service('config.factory')->getEditable('simplesitemap.settings')->set('entity_types', $entity_types)->save();
\Drupal::service('config.factory')->getEditable('simplesitemap.settings')
->set('entity_types', $entity_types)->save();
}
/**
......@@ -88,5 +95,19 @@ function simplesitemap_update_8104() {
'size' => 'small',
'not null' => TRUE,
));
\Drupal::service('config.factory')->getEditable('simplesitemap.settings')
->set('settings', array('max_links' => 2000))->save();
return t('Before the sitemap can be accessed, it must be regenerated manually or via cron run.');
}
/**
* Modifying database structure to accommodate sitemap chunk timestamps.
*/
function simplesitemap_update_8105() {
db_add_field('simplesitemap', 'generated', array(
'description' => 'Timestamp of sitemap chunk generation.',
'type' => 'int',
'default' => 0,
'not null' => TRUE,
));
}
......@@ -9,6 +9,8 @@ use Drupal\simplesitemap\SitemapGenerator;
/**
* Implements hook_form_alter.
*
* Adds sitemap settings to entity types that are supported via plugins.
*/
function simplesitemap_form_alter(&$form, $form_state, $form_id) {
......@@ -63,15 +65,16 @@ function simplesitemap_form_alter(&$form, $form_state, $form_id) {
/**
* Form submission handler called in hook_form_alter.
*
* todo: use $form_state->getValue() instead $form array
*/
function simplesitemap_entity_form_submit($form, &$form_state) {
$sitemap = new Simplesitemap;
$values = $form_state->getValues();
// Only make changes in DB if sitemap settings actually changed.
if ($form['simplesitemap']['simplesitemap_index_content']['#default_value'] != $form['simplesitemap']['simplesitemap_index_content']['#value'] || $form['simplesitemap']['simplesitemap_priority']['#default_value'] != $form['simplesitemap']['simplesitemap_priority']['#value']) {
if ($values['simplesitemap_index_content'] != $form['simplesitemap']['simplesitemap_index_content']['#default_value']
|| $values['simplesitemap_priority'] != $form['simplesitemap']['simplesitemap_priority']['#default_value']) {
$form_entity = Simplesitemap::get_form_entity($form_state);
$entity_type_id = $form_entity->getEntityTypeId();
......@@ -80,7 +83,6 @@ function simplesitemap_entity_form_submit($form, &$form_state) {
// Get current entity type sitemap settings.
$entity_types = $sitemap->get_entity_types();
$values = $form_state->getValues();
$entity_types[$entity_type_id][$bundle_name]['index'] = $values['simplesitemap_index_content'];
$entity_types[$entity_type_id][$bundle_name]['priority'] = $values['simplesitemap_priority'];
......@@ -89,7 +91,7 @@ function simplesitemap_entity_form_submit($form, &$form_state) {
}
// Regenerate sitemaps according to user setting.
if ($form['simplesitemap']['simplesitemap_rebuild_now']['#value']) {
if ($values['simplesitemap_rebuild_now']) {
$sitemap->generate_sitemap();
}
}
......@@ -99,13 +101,15 @@ function simplesitemap_entity_form_submit($form, &$form_state) {
*/
function simplesitemap_cron() {
// Regenerate sitemaps for all languages and save them into strings for performance reasons (pseudo caching).
// Regenerate sitemap for all languages.
$sitemap = new Simplesitemap;
$sitemap->generate_sitemap();
}
/**
* Implements hook_entity_bundle_delete().
*
* Removes settings of the removed bundle.
*/
function simplesitemap_entity_bundle_delete($entity_type_id, $bundle) {
$sitemap = new Simplesitemap;
......@@ -115,7 +119,8 @@ function simplesitemap_entity_bundle_delete($entity_type_id, $bundle) {
if (isset($entity_types[$bundle_entity_type_id][$bundle])) {
unset($entity_types[$bundle_entity_type_id][$bundle]);
$sitemap->save_entity_types($entity_types);
drupal_set_message(t("You may want to <a href='@url'>rebuild</a> your XML sitemap now. Otherwise it will be rebuilt on the next cron run.", array('@url' => $GLOBALS['base_url'] . '/admin/config/search/simplesitemap')));
drupal_set_message(t("You may want to <a href='@url'>rebuild</a> your XML sitemap now.
Otherwise it will be rebuilt on the next cron run.",
array('@url' => $GLOBALS['base_url'] . '/admin/config/search/simplesitemap')));
}
}
......@@ -16,6 +16,12 @@ class SimplesitemapController {
/**
* Returns the whole sitemap, a requested sitemap chunk, or the sitemap index file.
*
* @param int $sitemap_id
* Id of the sitemap chunk.
*
* @return object Response
* Returns an XML response.
*/
public function get_sitemap($sitemap_id = NULL) {
......
......@@ -114,6 +114,8 @@ class SimplesitemapCustomLinksForm extends ConfigFormBase {
}
$sitemap->save_custom_links($custom_link_config);
parent::submitForm($form, $form_state);
// Regenerate sitemaps according to user setting.
if ($form_state->getValue('simplesitemap_rebuild_now')) {
$sitemap->generate_sitemap();
......
......@@ -89,6 +89,7 @@ class SimplesitemapSettingsForm extends ConfigFormBase {
$settings = $sitemap->get_settings();
$settings['max_links'] = $form_state->getValue('max_links');
$sitemap->save_settings($settings);
parent::submitForm($form, $form_state);
}
public function rebuild_sitemap(array &$form, FormStateInterface $form_state) {
......
......@@ -15,6 +15,14 @@ use Drupal\Core\Url;
*/
class CustomLinkGenerator {
/**
* Returns an array of all urls of the custom paths.
*
* @param array $custom_paths
* @param array $languages
* Array of Drupal language objects.
* @return array $urls
*/
public function get_custom_links($custom_paths, $languages) {
$links = array();
foreach($custom_paths as $i => $custom_path) {
......
......@@ -11,7 +11,8 @@
namespace Drupal\simplesitemap\LinkGenerators;
/**
* EntityLinkGenerator abstract class.
* EntityLinkGenerator class.
* @abstract
*/
abstract class EntityLinkGenerator {
......@@ -34,6 +35,14 @@ abstract class EntityLinkGenerator {
return $this->entity_links;
}
/**
* Gets lastmod date for an entity.
*
* @param string $entity_type
* @param int $id
* ID of the entity.
* @return string lastmod date or NULL if none.
*/
private function get_lastmod($entity_type, $id) {
switch ($entity_type) {
case 'node_type':
......@@ -48,5 +57,16 @@ abstract class EntityLinkGenerator {
return isset($lastmod[0]) ? date_iso8601($lastmod[0]) : NULL;
}
/**
* Returns an array of all urls to this bundle.
*
* @param string $bundle
* Machine name of the bundle, eg. 'page'.
* @param array $languages
* Array of Drupal language objects.
* @return array $urls
*
* @abstract
*/
abstract function get_entity_bundle_links($bundle, $languages);
}
......@@ -18,6 +18,9 @@ use Drupal\Core\Url;
*/
class menu extends EntityLinkGenerator {
/**
* {@inheritdoc}
*/
function get_entity_bundle_links($bundle, $languages) {
$routes = db_query("SELECT mlid, route_name, route_parameters FROM {menu_tree} WHERE menu_name = :menu_name and enabled = 1", array(':menu_name' => $bundle))
->fetchAllAssoc('mlid');
......
......@@ -25,9 +25,13 @@ use Drupal\Core\Url;
*/
class node_type extends EntityLinkGenerator {
/**
* {@inheritdoc}
*/
function get_entity_bundle_links($bundle, $languages) {
$results = db_query("SELECT nid FROM {node_field_data} WHERE status = 1 AND type = :type", array(':type' => $bundle))
->fetchAllAssoc('nid');
$urls = array();
foreach ($results as $id => $changed) {
foreach($languages as $language) {
......
......@@ -18,8 +18,10 @@ use Drupal\Core\Url;
*/
class taxonomy_vocabulary extends EntityLinkGenerator {
/**
* {@inheritdoc}
*/
function get_entity_bundle_links($bundle, $languages) {
$results = db_query("SELECT tid FROM {taxonomy_term_field_data} WHERE vid = :vid", array(':vid' => $bundle))
->fetchAllAssoc('tid');
......
......@@ -8,6 +8,8 @@ namespace Drupal\simplesitemap;
/**
* Simplesitemap class.
*
* Main module class.
*/
class Simplesitemap {
......@@ -20,6 +22,12 @@ class Simplesitemap {
$this->initialize();
}
/**
* Returns an the form entity object.
*
* @param object $form_state
* @return object $entity or FALSE if non-existent.
*/
public static function get_form_entity($form_state) {
if (!is_null($form_state->getFormObject())
&& method_exists($form_state->getFormObject(), 'getEntity')) {
......@@ -29,6 +37,12 @@ class Simplesitemap {
return FALSE;
}
/**
* Returns path of a sitemap plugin.
*
* @param string $entity_type_name
* @return string $class_path or FALSE if non-existent.
*/
public static function get_plugin_path($entity_type_name) {
$class_path = drupal_get_path('module', 'simplesitemap')
. '/' . self::SITEMAP_PLUGIN_PATH . '/' . $entity_type_name . '.php';
......@@ -45,26 +59,38 @@ class Simplesitemap {
// Get sitemap from database.
private function get_sitemap_from_db() {
//todo: update for chunked sitemaps
$result = db_query("SELECT id, sitemap_string FROM {simplesitemap}")->fetchAllAssoc('id');
foreach ($result as $sitemap_id => $sitemap) {
$this->sitemap[$sitemap_id] = $sitemap->sitemap_string;
$this->sitemap = db_query("SELECT * FROM {simplesitemap}")->fetchAllAssoc('id');
}
}
// Get sitemap settings from configuration storage.
/**
* Gets sitemap settings from configuration storage.
*/
private function get_config_from_db() {
$this->config = \Drupal::config('simplesitemap.settings');
}
/**
* Saves entity type sitemap settings to db.
*
* @param array $entity_types
*/
public function save_entity_types($entity_types) {
$this->save_config('entity_types', $entity_types);
}
/**
* Saves the sitemap custom links settings to db.
*
* @param array $custom_links
*/
public function save_custom_links($custom_links) {
$this->save_config('custom', $custom_links);
}
/**
* Saves other sitemap settings to db.
*
* @param array $settings
*/
public function save_settings($settings) {
$this->save_config('settings', $settings);
}
......@@ -75,6 +101,17 @@ class Simplesitemap {
$this->initialize();
}
/**
* Returns the whole sitemap, a requested sitemap chunk,
* or the sitemap index file.
*
* @param int $sitemap_id
*
* @return string $sitemap
* If no sitemap id provided, either a sitemap index is returned, or the
* whole sitemap, if the amount of links does not exceed the max links setting.
* If a sitemap id is provided, a sitemap chunk is returned.
*/
public function get_sitemap($sitemap_id = NULL) {
if (empty($this->sitemap)) {
$this->generate_sitemap();
......@@ -89,16 +126,19 @@ class Simplesitemap {
// Return sitemap if there is only one chunk.
else {
return $this->sitemap[0];
return $this->sitemap[0]->sitemap_string;
}
}
// Return specific sitemap chunk.
else {
return $this->sitemap[$sitemap_id];
return $this->sitemap[$sitemap_id]->sitemap_string;
}
}
/**
* Generates the sitemap for all languages and saves it to the db.
*/
public function generate_sitemap() {
$generator = new SitemapGenerator();
$generator->set_custom_links($this->config->get('custom'));
......@@ -110,38 +150,53 @@ class Simplesitemap {
array('@url' => $GLOBALS['base_url'] . '/sitemap.xml')));
}
/**
* Saves the sitemap to the db.
*/
private function save_sitemap() {
db_truncate('simplesitemap')->execute();
$values = array();
foreach($this->sitemap as $sitemap_id => $sitemap_string) {
foreach($this->sitemap as $chunk_id => $chunk_data) {
$values[] = array(
'id' => $sitemap_id,
'sitemap_string' => $sitemap_string,
//todo: add 'changed' info in new column?
'id' => $chunk_id,
'sitemap_string' => $chunk_data->sitemap_string,
'generated' => $chunk_data->generated,
);
}
$query = db_insert('simplesitemap')->fields(array('id', 'sitemap_string'));
$query = db_insert('simplesitemap')
->fields(array('id', 'sitemap_string', 'generated'));
foreach ($values as $record) {
$query->values($record);
}
$query->execute();
}
/**
* Gets the sitemap index.
*/
private function get_sitemap_index() {
$generator = new SitemapGenerator();
return $generator->generate_sitemap_index($this->sitemap);
}
/**
* Gets the sitemap entity type settings.
*/
public function get_entity_types() {
return $this->config->get('entity_types');
}
/**
* Gets the sitemap custom links settings.
*/
public function get_custom_links() {
return $this->config->get('custom');
}
/**
* Gets other sitemap settings.
*/
public function get_settings() {
return $this->config->get('settings');
}
......
......@@ -36,6 +36,11 @@ class SitemapGenerator {
$this->links = array();
}
/**
* Gets the values needed to display the priority dropdown setting.
*
* @return array $options
*/
public static function get_priority_select_values() {
$options = array();
foreach(range(0, self::PRIORITY_HIGHEST) as $value) {
......@@ -53,23 +58,46 @@ class SitemapGenerator {
$this->custom = is_array($custom) ? $custom : array();
}
/**
* Generates and returns the sitemap.
*
* @param int $max_links
* This number dictates how many sitemap chunks are to be created.
*
* @return array $sitemaps.
*/
public function generate_sitemap($max_links = NULL) {
$this->generate_custom_links();
$this->generate_entity_links();
$timestamp = time();
$sitemaps = array();
if (!empty($max_links) && count($this->links) > 0) {
foreach(array_chunk($this->links, $max_links) as $sitemap_id => $sitemap_links) {
$sitemaps[] = $this->generate_sitemap_chunk($sitemap_links);
$sitemaps[] = (object)[
'sitemap_string' => $this->generate_sitemap_chunk($sitemap_links),
'generated' => $timestamp,
];
}
}
else {
$sitemaps[] = $this->generate_sitemap_chunk($this->links);
$sitemaps[] = (object)[
'sitemap_string' => $this->generate_sitemap_chunk($this->links),
'generated' => $timestamp,
];
}
return $sitemaps;
}
/**
* Generates and returns the sitemap index.
*
* @param array $sitemap
* All sitemap chunks keyed by the chunk ID.
*
* @return string sitemap index
*/
public function generate_sitemap_index($sitemap) {
$writer = new XMLWriter();
$writer->openMemory();
......@@ -78,10 +106,11 @@ class SitemapGenerator {
$writer->startElement('sitemapindex');
$writer->writeAttribute('xmlns', self::XMLNS);
foreach ($sitemap as $sitemap_id => $sitemap_string) {
foreach ($sitemap as $chunk_id => $chunk_data) {
$writer->startElement('sitemap');
$writer->writeElement('loc', $GLOBALS['base_url'] . '/sitemaps/' . $sitemap_id . '/' . 'sitemap.xml');
//todo: lastmod
$writer->writeElement('loc', $GLOBALS['base_url'] . '/sitemaps/'
. $chunk_id . '/' . 'sitemap.xml');
$writer->writeElement('lastmod', date_iso8601($chunk_data->generated));
$writer->endElement();
}
$writer->endElement();
......@@ -89,6 +118,14 @@ class SitemapGenerator {
return $writer->outputMemory();
}
/**
* Generates and returns a sitemap chunk.
*
* @param array $sitemap_links
* All links with their translation and settings.
*
* @return string sitemap chunk
*/
private function generate_sitemap_chunk($sitemap_links) {
$writer = new XMLWriter();
......@@ -105,7 +142,7 @@ class SitemapGenerator {
// Adding url to standard language.
$writer->writeElement('loc', $link['url'][$this->default_language_id]);
// Adding alternate urls (other languages).
// Adding alternate urls (other languages) if any.
if (count($link['url']) > 1) {
foreach($link['url'] as $language_id => $localised_url) {
$writer->startElement('xhtml:link');
......@@ -116,12 +153,12 @@ class SitemapGenerator {
}
}
// Add priority.
// Add priority if any.
if (!is_null($link['priority'])) {
$writer->writeElement('priority', $link['priority']);
}
// Add lastmod.
// Add lastmod if any.
if (!is_null($link['lastmod'])) {
$writer->writeElement('lastmod', $link['lastmod']);
}
......@@ -131,14 +168,18 @@ class SitemapGenerator {
return $writer->outputMemory();
}
// Add custom links.
/**
* Gets custom links.
*/
private function generate_custom_links() {
$link_generator = new CustomLinkGenerator();
$links = $link_generator->get_custom_links($this->custom , $this->languages);
$this->links = array_merge($this->links, $links);
}
// Add entity type links.
/**
* Gets entity type links.
*/
private function generate_entity_links() {
foreach($this->entity_types as $entity_type => $bundles) {
$class_path = Simplesitemap::get_plugin_path($entity_type);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment