...
 
Commits (16)
id: bing
label: 'Bing'
url: http://www.bing.com/ping?sitemap=[sitemap]
status: true
sitemap_variants: { }
id: google
label: 'Google'
url: http://www.google.com/ping?sitemap=[sitemap]
status: true
sitemap_variants: { }
......@@ -11,9 +11,12 @@ simple_sitemap_engines.simple_sitemap_engine.*:
url:
type: string
label: 'Submission URL'
status:
type: boolean
label: 'Enabled'
sitemap_variants:
type: sequence
label: 'Sitemap variants'
sequence:
type: string
label: 'Sitemap variant'
last_submitted:
type: integer
label: 'Last submitted'
......
......@@ -32,8 +32,10 @@ function simple_sitemap_engines_cron() {
$state->set('simple_sitemap_engines_last_submitted', $request_time);
foreach (\Drupal::entityTypeManager()
->getStorage('simple_sitemap_engine')
->loadByProperties(['status' => TRUE]) as $id => $engine) {
$queue->createItem($id);
->loadMultiple() as $id => $engine) {
if (!empty($engine->sitemap_variants)) {
$queue->createItem($id);
}
}
}
}
......
......@@ -54,8 +54,9 @@ class SearchEngineListBuilder extends ConfigEntityListBuilder {
public function buildHeader() {
$header['label'] = $this->t('Name');
$header['url'] = $this->t('Submission URL');
$header['status'] = $this->t('Status');
$header['variants'] = $this->t('Sitemap variants');
$header['last_submitted'] = $this->t('Last submitted');
return $header;
}
......@@ -63,11 +64,11 @@ class SearchEngineListBuilder extends ConfigEntityListBuilder {
* {@inheritdoc}
*/
public function buildRow(EntityInterface $entity) {
/** @var \Drupal\simple_sitemap_engines\Entity\SearchEngine $entity */
/** @var \Drupal\simple_sitemap_engines\Entity\SearchEngine $entity */
$row['label'] = $entity->label();
$row['url'] = $entity->url;
$row['status'] = $entity->status ? $this->t('Enabled') : $this->t('Disabled');
$row['variants'] = implode(', ', $entity->sitemap_variants);
$row['last_submitted'] = $entity->last_submitted
? $this->dateFormatter->format($entity->last_submitted, 'short')
: $this->t('Never');
......
......@@ -25,7 +25,7 @@ use Drupal\Core\Config\Entity\ConfigEntityBase;
* "id",
* "label",
* "url",
* "status",
* "sitemap_variants",
* "last_submitted",
* }
* )
......@@ -57,11 +57,11 @@ class SearchEngine extends ConfigEntityBase {
public $url;
/**
* The search engine enabled state.
* List of sitemap variants to be submitted to this search engine.
*
* @var bool
* @var array
*/
public $status;
public $sitemap_variants;
/**
* Timestamp when the sitemap was last submitted to this search engine.
......
......@@ -8,6 +8,7 @@ use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\simple_sitemap\Form\FormHelper;
use Drupal\simple_sitemap\SimplesitemapManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
......@@ -29,6 +30,13 @@ class SimplesitemapEnginesForm extends ConfigFormBase {
*/
protected $dateFormatter;
/**
* The sitemap manager service.
*
* @var \Drupal\simple_sitemap\SimplesitemapManager
*/
protected $sitemapManager;
/**
* SimplesitemapEnginesForm constructor.
*
......@@ -38,11 +46,14 @@ class SimplesitemapEnginesForm extends ConfigFormBase {
* The entity type manager service.
* @param \Drupal\Core\Datetime\DateFormatter $date_formatter
* The date formatter service.
* @param \Drupal\simple_sitemap\SimplesitemapManager $sitemap_manager
* The sitemap manager service.
*/
public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager, DateFormatter $date_formatter) {
public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager, DateFormatter $date_formatter, SimplesitemapManager $sitemap_manager) {
parent::__construct($config_factory);
$this->entityTypeManager = $entity_type_manager;
$this->dateFormatter = $date_formatter;
$this->sitemapManager = $sitemap_manager;
}
/**
......@@ -52,7 +63,8 @@ class SimplesitemapEnginesForm extends ConfigFormBase {
return new static(
$container->get('config.factory'),
$container->get('entity_type.manager'),
$container->get('date.formatter')
$container->get('date.formatter'),
$container->get('simple_sitemap.manager')
);
}
......@@ -76,21 +88,32 @@ class SimplesitemapEnginesForm extends ConfigFormBase {
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('simple_sitemap_engines.settings');
$engines = $this->entityTypeManager->getStorage('simple_sitemap_engine')->loadMultiple();
// Construct a non-associative array containing the enabled search engines.
$engine_statuses = array_column($engines, 'status', 'id');
$enabled_engines = array_keys(array_filter($engine_statuses));
$variants = array_map(
function ($variant) { return $this->t($variant['label']); },
$this->sitemapManager->getSitemapVariants(NULL, FALSE)
);
$form['engine_group'] = [
$form['#tree'] = TRUE;
$form['engines'] = [
'#type' => 'fieldset',
'#title' => $this->t('Search engines'),
'#markup' => '<div class="description">' . $this->t('Configure sitemap variants to submit to search engines.') . '</div>',
'#prefix' => FormHelper::getDonationText(),
];
$form['engine_group']['engines'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Submit the sitemap to the following engines'),
'#options' => $engines,
'#default_value' => $enabled_engines,
];
foreach ($engines as $engine_id => $engine) {
$form['engines'][$engine_id] = [
'#type' => 'details',
'#title' => $engine->label(),
'#open' => !empty($engine->sitemap_variants) || count($engines) == 1,
];
$form['engines'][$engine_id]['variants'] = [
'#type' => 'select',
'#title' => $this->t('Sitemap variants'),
'#options' => $variants,
'#default_value' => $engine->sitemap_variants,
'#multiple' => TRUE,
];
}
$form['settings'] = [
'#type' => 'fieldset',
......@@ -119,13 +142,14 @@ class SimplesitemapEnginesForm extends ConfigFormBase {
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$engines = $this->entityTypeManager->getStorage('simple_sitemap_engine')->loadMultiple();
foreach ($form_state->getValue('engines') as $engine => $enabled) {
$engines[$engine]->status = (bool) $enabled;
$engines[$engine]->save();
foreach ($engines as $engine_id => $engine) {
$engine->sitemap_variants = $form_state->getValue(['engines', $engine_id, 'variants']);
$engine->save();
}
$config = $this->config('simple_sitemap_engines.settings');
$config->set('enabled', $form_state->getValue('enabled'));
$config->set('submission_interval', $form_state->getValue('submission_interval'));
$config->set('enabled', $form_state->getValue(['settings', 'enabled']));
$config->set('submission_interval', $form_state->getValue(['settings', 'submission_interval']));
$config->save();
}
......
......@@ -96,17 +96,20 @@ class SitemapSubmitter extends QueueWorkerBase implements ContainerFactoryPlugin
/**
* {@inheritdoc}
*/
public function processItem($id) {
public function processItem($engine_id) {
/** @var \Drupal\simple_sitemap_engines\Entity\SearchEngine $engine */
if ($engine = $this->engineStorage->load($id)) {
if ($engine = $this->engineStorage->load($engine_id)) {
// Gather URLs for all sitemap variants.
$sitemap_urls = [];
foreach ($this->sitemapManager->getSitemapTypes() as $type_name => $type_definition) {
$sitemap_generator = $this->sitemapManager->getSitemapGenerator($type_definition['sitemapGenerator']);
$variants = $this->sitemapManager->getSitemapVariants($type_name, FALSE);
if (!empty($variants)) {
// Submit all variants that are enabled for this search engine.
foreach ($variants as $id => $variant) {
$sitemap_urls[$variant['label']] = $sitemap_generator->setSitemapVariant($id)->getSitemapUrl();
if (in_array($id, $engine->sitemap_variants)) {
$sitemap_urls[$variant['label']] = $sitemap_generator->setSitemapVariant($id)->getSitemapUrl();
}
}
}
}
......
......@@ -51,15 +51,11 @@ class SubmitSitemapTest extends KernelTestBase {
$this->engineStorage = \Drupal::entityTypeManager()->getStorage('simple_sitemap_engine');
$this->queue = \Drupal::queue('simple_sitemap_engine_submit');
// Disable all search engines but one so tests will not fail if additional
// search engines are added in the future.
$engines = $this->engineStorage->loadMultiple();
foreach ($engines as $id => $engine) {
if ($id != 'google') {
$engine->status = FALSE;
$engine->save();
}
}
// Set Google to submit the default sitemap variant. Other search engines
// will not submit anything.
$google = $this->engineStorage->load('google');
$google->sitemap_variants = ['default'];
$google->save();
}
/**
......
......@@ -704,3 +704,17 @@ function simple_sitemap_update_8301() {
]
);
}
/**
* Removing unused batch_process_limit key from simple_sitemap.settings
* configuration.
*/
function simple_sitemap_update_8302() {
$settings = \Drupal::service('config.factory')
->getEditable('simple_sitemap.settings');
if (NULL !== $settings->get('batch_process_limit')) {
$settings->clear('batch_process_limit');
$settings->save();
}
}
......@@ -195,11 +195,16 @@ function simple_sitemap_configurable_language_delete(ConfigurableLanguageInterfa
*/
function simple_sitemap_entity_delete(EntityInterface $entity) {
/** @var \Drupal\simple_sitemap\Simplesitemap $generator */
$generator = \Drupal::service('simple_sitemap.generator');
$generator->setVariants(TRUE)->removeEntityInstanceSettings(
$entity->getEntityTypeId(), $entity->id()
);
/** @var \Drupal\simple_sitemap\EntityHelper $entity_helper */
$entity_helper = \Drupal::service('simple_sitemap.entity_helper');
if ($entity_helper->supports($entity->getEntityType())) {
/** @var \Drupal\simple_sitemap\Simplesitemap $generator */
$generator = \Drupal::service('simple_sitemap.generator');
$generator->setVariants(TRUE)->removeEntityInstanceSettings(
$entity->getEntityTypeId(), $entity->id()
);
}
}
/**
......
......@@ -5,6 +5,7 @@ namespace Drupal\simple_sitemap;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Url;
......@@ -105,18 +106,24 @@ class EntityHelper {
* Objects of entity types that can be indexed by the sitemap.
*/
public function getSupportedEntityTypes() {
return array_filter($this->entityTypeManager->getDefinitions(), [$this, 'supports']);
}
/** @var \Drupal\Core\Entity\ContentEntityTypeInterface[] $entity_types */
$entity_types = $this->entityTypeManager->getDefinitions();
foreach ($entity_types as $entity_type_id => $entity_type) {
if (!$entity_type instanceof ContentEntityTypeInterface
|| !method_exists($entity_type, 'getBundleEntityType')
|| !$entity_type->hasLinkTemplate('canonical')) {
unset($entity_types[$entity_type_id]);
}
/**
* Determines if an entity type is supported or not.
*
* @return bool
* TRUE if entity type supported by Simple Sitemap, FALSE if not.
*/
public function supports(EntityTypeInterface $entity_type) {
if (!$entity_type instanceof ContentEntityTypeInterface
|| !method_exists($entity_type, 'getBundleEntityType')
|| !$entity_type->hasLinkTemplate('canonical')) {
return FALSE;
}
return $entity_types;
}
return TRUE;
}
/**
* Checks whether an entity type does not provide bundles.
......
......@@ -408,7 +408,7 @@ class FormHelper {
$this->setEntityTypeId($entity_type_id);
$this->setBundleName($this->entityHelper->getEntityInstanceBundleName($form_entity));
// New menu link's id is '' instead of NULL, hence checking for empty.
$this->setInstanceId(!empty($form_entity->id()) ? $form_entity->id() : NULL);
$this->setInstanceId(!$form_entity->isNew() && !empty($form_entity->id()) ? $form_entity->id() : NULL);
break;
default:
......
......@@ -2,6 +2,7 @@
namespace Drupal\simple_sitemap\Form;
use Drupal\Core\Datetime\DateFormatter;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\simple_sitemap\Simplesitemap;
......@@ -25,18 +26,25 @@ class SimplesitemapSettingsForm extends SimplesitemapFormBase {
*/
protected $db;
/**
* @var \Drupal\Core\Datetime\DateFormatter
*/
protected $dateFormatter;
/**
* SimplesitemapSettingsForm constructor.
* @param \Drupal\simple_sitemap\Simplesitemap $generator
* @param \Drupal\simple_sitemap\Form\FormHelper $form_helper
* @param \Drupal\Core\Language\LanguageManager $language_manager
* @param \Drupal\Core\Database\Connection $database
* @param \Drupal\Core\Datetime\DateFormatter $date_formatter
*/
public function __construct(
Simplesitemap $generator,
FormHelper $form_helper,
LanguageManager $language_manager,
Connection $database
Connection $database,
DateFormatter $date_formatter
) {
parent::__construct(
$generator,
......@@ -44,6 +52,7 @@ class SimplesitemapSettingsForm extends SimplesitemapFormBase {
);
$this->languageManager = $language_manager;
$this->db = $database;
$this->dateFormatter = $date_formatter;
}
/**
......@@ -54,7 +63,8 @@ class SimplesitemapSettingsForm extends SimplesitemapFormBase {
$container->get('simple_sitemap.generator'),
$container->get('simple_sitemap.form_helper'),
$container->get('language_manager'),
$container->get('database')
$container->get('database'),
$container->get('date.formatter')
);
}
......@@ -134,6 +144,7 @@ class SimplesitemapSettingsForm extends SimplesitemapFormBase {
'default_variant' => $this->generator->getSetting('default_variant', NULL),
];
$sitemap_statuses = $this->fetchSitemapInstanceStatuses();
$published_timestamps = $this->fetchSitemapInstancePublishedTimestamps();
foreach ($sitemap_manager->getSitemapTypes() as $type_name => $type_definition) {
if (!empty($variants = $sitemap_manager->getSitemapVariants($type_name, FALSE))) {
$sitemap_generator = $sitemap_manager
......@@ -148,7 +159,7 @@ class SimplesitemapSettingsForm extends SimplesitemapFormBase {
];
$form['simple_sitemap_settings']['status']['types'][$type_name]['table'] = [
'#type' => 'table',
'#header' => [$this->t('Variant'), $this->t('Status'), /*$this->t('Actions')*/],
'#header' => [$this->t('Variant'), $this->t('Status')],
'#attributes' => ['class' => ['form-item', 'clearfix']],
];
foreach ($variants as $variant_name => $variant_definition) {
......@@ -163,19 +174,17 @@ class SimplesitemapSettingsForm extends SimplesitemapFormBase {
$row['status'] = $this->t('generating');
break;
case 1:
$row['status']['data']['#markup'] = $this->t('<a href="@url" target="_blank">published</a>',
['@url' => $sitemap_generator->setSitemapVariant($variant_name)->getSitemapUrl()]
$row['status']['data']['#markup'] = $this->t('<a href="@url" target="_blank">published on @time</a>',
['@url' => $sitemap_generator->setSitemapVariant($variant_name)->getSitemapUrl(), '@time' => $this->dateFormatter->format($published_timestamps[$variant_name])]
);
break;
case 2:
$row['status'] = $this->t('<a href="@url" target="_blank">published</a>, regenerating',
['@url' => $sitemap_generator->setSitemapVariant($variant_name)->getSitemapUrl()]
$row['status'] = $this->t('<a href="@url" target="_blank">published on @time</a>, regenerating',
['@url' => $sitemap_generator->setSitemapVariant($variant_name)->getSitemapUrl(), '@time' => $this->dateFormatter->format($published_timestamps[$variant_name])]
);
break;
}
}
// $row['actions'] = '';
$form['simple_sitemap_settings']['status']['types'][$type_name]['table']['#rows'][$variant_name] = $row;
unset($sitemap_statuses[$variant_name]);
}
......@@ -291,7 +300,7 @@ class SimplesitemapSettingsForm extends SimplesitemapFormBase {
$form['simple_sitemap_settings']['advanced']['remove_duplicates'] = [
'#type' => 'checkbox',
'#title' => $this->t('Exclude duplicate links'),
'#description' => $this->t('Prevent per-sitemap variant duplicate links.<br>Uncheck this to significantly speed up the sitemap generation process on a huge site (more than 20 000 indexed entities).'),
'#description' => $this->t('Prevent per-sitemap variant duplicate links.<br>Unchecking this may help avoiding PHP memory errors on huge sites.'),
'#default_value' => $this->generator->getSetting('remove_duplicates', TRUE),
];
......@@ -299,7 +308,7 @@ class SimplesitemapSettingsForm extends SimplesitemapFormBase {
'#type' => 'number',
'#title' => $this->t('Maximum links in a sitemap'),
'#min' => 1,
'#description' => $this->t('The maximum number of links one sitemap can hold. If more links are generated than set here, a sitemap index will be created and the links split into several sub-sitemaps.<br>50 000 links is the maximum Google will parse per sitemap, but an equally important consideration is generation performance: Splitting sitemaps into chunks <em>greatly</em> increases it.<br>If left blank, all links will be shown on a single sitemap.'),
'#description' => $this->t('The maximum number of links one sitemap can hold. If more links are generated than set here, a sitemap index will be created and the links split into several sub-sitemaps.<br>50 000 links is the maximum Google will parse per sitemap, but choosing a lower value may be needed to avoid PHP memory errors on huge sites.<br>If left blank, all links will be shown on a single sitemap.'),
'#default_value' => $this->generator->getSetting('max_links'),
];
......@@ -324,6 +333,8 @@ class SimplesitemapSettingsForm extends SimplesitemapFormBase {
* 0: Instance is unpublished
* 1: Instance is published
* 2: Instance is published but is being regenerated
*
* @todo Move to SitemapGeneratorBase or DefaultSitemapGenerator so it can be overwritten by sitemap types with custom storages.
*/
protected function fetchSitemapInstanceStatuses() {
$results = $this->db
......@@ -340,6 +351,17 @@ class SimplesitemapSettingsForm extends SimplesitemapFormBase {
return $instances;
}
/**
* @return array
*
* @todo Move to SitemapGeneratorBase or DefaultSitemapGenerator so it can be overwritten by sitemap types with custom storages.
*/
protected function fetchSitemapInstancePublishedTimestamps() {
return $this->db
->query('SELECT type, MAX(sitemap_created) FROM (SELECT sitemap_created, type FROM {simple_sitemap} WHERE status = :status) AS timestamps GROUP BY type', [':status' => 1])
->fetchAllKeyed(0, 1);
}
/**
* {@inheritdoc}
*/
......
......@@ -67,7 +67,7 @@ class SimplesitemapVariantsForm extends SimplesitemapFormBase {
$form_state->setErrorByName('', $this->t("<strong>Line @line</strong>: The variant name cannot be empty.", $placeholders));
}
if (!preg_match('/^[\w-_]+$/', $variant_name)) {
if (!preg_match('/^[\w\-_]+$/', $variant_name)) {
$form_state->setErrorByName('', $this->t("<strong>Line @line</strong>: The variant name <em>@name</em> can only include alphanumeric characters, dashes and underscores.", $placeholders));
}
......
......@@ -39,6 +39,7 @@ class DefaultSitemapGenerator extends SitemapGeneratorBase {
/**
* DefaultSitemapGenerator constructor.
*
* @param array $configuration
* @param string $plugin_id
* @param mixed $plugin_definition
......@@ -108,8 +109,18 @@ class DefaultSitemapGenerator extends SitemapGeneratorBase {
$this->writer->writeGeneratedBy();
$this->writer->startElement('urlset');
$this->addSitemapAttributes();
$this->addLinks($links);
$this->writer->endElement();
$this->writer->endDocument();
return $this->writer->outputMemory();
}
// Add attributes to document.
/**
* Adds attributes to the sitemap.
*/
protected function addSitemapAttributes() {
$attributes = self::$attributes;
if (!$this->isHreflangSitemap()) {
unset($attributes['xmlns:xhtml']);
......@@ -119,68 +130,98 @@ class DefaultSitemapGenerator extends SitemapGeneratorBase {
foreach ($attributes as $name => $value) {
$this->writer->writeAttribute($name, $value);
}
}
// Add URLs to document.
/**
* Adds URL elements to the sitemap.
*
* @param array $links
*/
protected function addLinks(array $links) {
$sitemap_variant = $this->sitemapVariant;
$this->moduleHandler->alter('simple_sitemap_links', $links, $sitemap_variant);
foreach ($links as $link) {
// Add each translation variant URL as location to the sitemap.
foreach ($links as $url_data) {
$this->writer->startElement('url');
$this->writer->writeElement('loc', $link['url']);
// If more than one language is enabled, add all translation variant URLs
// as alternate links to this location turning the sitemap into a hreflang
// sitemap.
if (isset($link['alternate_urls']) && $this->isHreflangSitemap()) {
foreach ($link['alternate_urls'] as $language_id => $alternate_url) {
$this->writer->startElement('xhtml:link');
$this->writer->writeAttribute('rel', 'alternate');
$this->writer->writeAttribute('hreflang', $language_id);
$this->writer->writeAttribute('href', $alternate_url);
$this->writer->endElement();
}
}
$this->addUrl($url_data);
$this->writer->endElement();
}
}
// Add lastmod if any.
if (isset($link['lastmod'])) {
$this->writer->writeElement('lastmod', $link['lastmod']);
}
/**
* Adds a URL element to the sitemap.
*
* @param array $url_data
* The array of properties for this URL.
*/
protected function addUrl(array $url_data) {
$this->writer->writeElement('loc', $url_data['url']);
// If more than one language is enabled, add all translation variant URLs
// as alternate links to this link turning the sitemap into a hreflang
// sitemap.
if (isset($url_data['alternate_urls']) && $this->isHreflangSitemap()) {
$this->addAlternateUrls($url_data['alternate_urls']);
}
// Add changefreq if any.
if (isset($link['changefreq'])) {
$this->writer->writeElement('changefreq', $link['changefreq']);
}
// Add lastmod if any.
if (isset($url_data['lastmod'])) {
$this->writer->writeElement('lastmod', $url_data['lastmod']);
}
// Add priority if any.
if (isset($link['priority'])) {
$this->writer->writeElement('priority', $link['priority']);
}
// Add changefreq if any.
if (isset($url_data['changefreq'])) {
$this->writer->writeElement('changefreq', $url_data['changefreq']);
}
// Add images if any.
if (!empty($link['images'])) {
foreach ($link['images'] as $image) {
$this->writer->startElement('image:image');
$this->writer->writeElement('image:loc', $image['path']);
if (strlen($image['title']) > 0) {
$this->writer->writeElement('image:title', $image['title']);
}
if (strlen($image['alt']) > 0) {
$this->writer->writeElement('image:caption', $image['alt']);
}
$this->writer->endElement();
// Add priority if any.
if (isset($url_data['priority'])) {
$this->writer->writeElement('priority', $url_data['priority']);
}
// Add images if any.
if (!empty($url_data['images'])) {
foreach ($url_data['images'] as $image) {
$this->writer->startElement('image:image');
$this->writer->writeElement('image:loc', $image['path']);
if (strlen($image['title']) > 0) {
$this->writer->writeElement('image:title', $image['title']);
}
if (strlen($image['alt']) > 0) {
$this->writer->writeElement('image:caption', $image['alt']);
}
$this->writer->endElement();
}
}
}
/**
* Adds all translation variant URLs as alternate URLs to a URL.
*
* @param array $alternate_urls
*/
protected function addAlternateUrls(array $alternate_urls) {
foreach ($alternate_urls as $language_id => $alternate_url) {
$this->writer->startElement('xhtml:link');
$this->addAlternateUrl($language_id, $alternate_url);
$this->writer->endElement();
}
$this->writer->endElement();
$this->writer->endDocument();
}
return $this->writer->outputMemory();
/**
* Adds a translation variant URL as alternate URL to a URL.
*
* @param $language_id
* @param $alternate_url
*/
protected function addAlternateUrl($language_id, $alternate_url) {
$this->writer->writeAttribute('rel', 'alternate');
$this->writer->writeAttribute('hreflang', $language_id);
$this->writer->writeAttribute('href', $alternate_url);
}
/**
* Checks if sitemap is hreflang compliant.
*
* @return bool
*/
protected function isHreflangSitemap() {
......
......@@ -214,11 +214,15 @@ abstract class EntityUrlGeneratorBase extends UrlGeneratorBase {
foreach ($entity->getFieldDefinitions() as $field) {
if ($field->getType() === 'image') {
foreach ($entity->get($field->getName())->getValue() as $value) {
$image_data[] = [
'path' => file_create_url(File::load($value['target_id'])->getFileUri()),
'alt' => $value['alt'],
'title' => $value['title'],
] ;
if (!empty($file = File::load($value['target_id']))) {
$image_data[] = [
'path' => $this->replaceBaseUrlWithCustom(
file_create_url($file->getFileUri())
),
'alt' => $value['alt'],
'title' => $value['title'],
];
}
}
}
}
......
......@@ -273,11 +273,11 @@ class QueueWorker {
if ($this->generatorSettings['remove_duplicates'] && !empty($results)) {
$result = $results[key($results)];
if (isset($result['meta']['path'])) {
if (in_array($result['meta']['path'], $this->processedPaths)) {
if (isset($this->processedPaths[$result['meta']['path']])) {
$results = [];
}
else {
$this->processedPaths[] = $result['meta']['path'];
$this->processedPaths[$result['meta']['path']] = TRUE;
}
}
}
......
......@@ -3,6 +3,7 @@
namespace Drupal\Tests\simple_sitemap\Functional;
use Drupal\Core\Url;
use Drupal\node\Entity\Node;
/**
* Tests Simple XML Sitemap functional integration.
......@@ -376,6 +377,20 @@ class SimplesitemapTest extends SimplesitemapTestBase {
$this->assertTrue(empty($result));
}
/**
* Tests that a page does not break if an entity has its id set.
*/
public function testNewEntityWithIdSet() {
$new_node = Node::create([
'nid' => rand(5, 10),
'type' => 'page',
]);
// Assert that the form does not break if an entity has an id but is not
// saved.
// @see https://www.drupal.org/project/simple_sitemap/issues/3079897
\Drupal::service('entity.form_builder')->getForm($new_node);
}
/**
* Test indexing an atomic entity (here: a user)
*/
......