diff --git a/composer.json b/composer.json index 4c97a1ed78c308f0552a8eeee812d534e727a887..890143f36f5f6953bc213d70ac497f63f47649ba 100644 --- a/composer.json +++ b/composer.json @@ -163,7 +163,7 @@ "drupal/search_api_db": "1.18", "drupal/simple_gmap": "3.0", "drupal/simple_megamenu": "1.0-beta3", - "drupal/simple_sitemap": "3.7", + "drupal/simple_sitemap": "3.8", "drupal/simplesamlphp_auth": "3.1", "drupal/smtp": "1.0-rc4", "drupal/social_media": "1.8", diff --git a/composer.lock b/composer.lock index bc5f31f8fe3aa468ccc236aaf77942dbc772d29e..4d49cf69874c982d0ad99aebc00236c0bba4ac70 100644 --- a/composer.lock +++ b/composer.lock @@ -7340,17 +7340,17 @@ }, { "name": "drupal/simple_sitemap", - "version": "3.7.0", + "version": "3.8.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/simple_sitemap.git", - "reference": "8.x-3.7" + "reference": "8.x-3.8" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/simple_sitemap-8.x-3.7.zip", - "reference": "8.x-3.7", - "shasum": "7b23930cc71d37f332c1e836bc18c29ed2ae8cde" + "url": "https://ftp.drupal.org/files/projects/simple_sitemap-8.x-3.8.zip", + "reference": "8.x-3.8", + "shasum": "55252af261fbd7b18c230ab429eb7d8b92f4c66a" }, "require": { "drupal/core": "^8 || ^9", @@ -7359,8 +7359,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-3.7", - "datestamp": "1592298918", + "version": "8.x-3.8", + "datestamp": "1605141357", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -7382,6 +7382,10 @@ "homepage": "https://www.drupal.org/u/gbyte.co", "email": "contact@gbyte.co", "role": "Maintainer" + }, + { + "name": "gbyte", + "homepage": "https://www.drupal.org/user/2381352" } ], "description": "Creates a standard conform hreflang XML sitemap of the site content and provides a framework for developing other sitemap types.", diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 3b22bd086d84e357ed003ade49c145ac7222b588..35095aa591ae875c568b78a4895a53534b852cdb 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -7565,18 +7565,18 @@ }, { "name": "drupal/simple_sitemap", - "version": "3.7.0", - "version_normalized": "3.7.0.0", + "version": "3.8.0", + "version_normalized": "3.8.0.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/simple_sitemap.git", - "reference": "8.x-3.7" + "reference": "8.x-3.8" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/simple_sitemap-8.x-3.7.zip", - "reference": "8.x-3.7", - "shasum": "7b23930cc71d37f332c1e836bc18c29ed2ae8cde" + "url": "https://ftp.drupal.org/files/projects/simple_sitemap-8.x-3.8.zip", + "reference": "8.x-3.8", + "shasum": "55252af261fbd7b18c230ab429eb7d8b92f4c66a" }, "require": { "drupal/core": "^8 || ^9", @@ -7585,8 +7585,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-3.7", - "datestamp": "1592298918", + "version": "8.x-3.8", + "datestamp": "1605141357", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -7609,6 +7609,10 @@ "homepage": "https://www.drupal.org/u/gbyte.co", "email": "contact@gbyte.co", "role": "Maintainer" + }, + { + "name": "gbyte", + "homepage": "https://www.drupal.org/user/2381352" } ], "description": "Creates a standard conform hreflang XML sitemap of the site content and provides a framework for developing other sitemap types.", diff --git a/web/modules/simple_sitemap/modules/simple_sitemap_engines/simple_sitemap_engines.info.yml b/web/modules/simple_sitemap/modules/simple_sitemap_engines/simple_sitemap_engines.info.yml index 0ef2cb06a95c64eefd16105a25306f79d4adf3be..39730416e38e4edc00ee61200043ad74a9760b9b 100644 --- a/web/modules/simple_sitemap/modules/simple_sitemap_engines/simple_sitemap_engines.info.yml +++ b/web/modules/simple_sitemap/modules/simple_sitemap_engines/simple_sitemap_engines.info.yml @@ -8,7 +8,7 @@ core_version_requirement: ^8 || ^9 dependencies: - simple_sitemap:simple_sitemap -# Information added by Drupal.org packaging script on 2020-06-16 -version: '8.x-3.7' +# Information added by Drupal.org packaging script on 2020-11-12 +version: '8.x-3.8' project: 'simple_sitemap' -datestamp: 1592298876 +datestamp: 1605141361 diff --git a/web/modules/simple_sitemap/modules/simple_sitemap_engines/src/Controller/SearchEngineListBuilder.php b/web/modules/simple_sitemap/modules/simple_sitemap_engines/src/Controller/SearchEngineListBuilder.php index 8ce2b2fc10584b09b0e690f5ad2b9866930c1d1f..3d7da378687fa4e25a352d8691bf18b3d3304aac 100644 --- a/web/modules/simple_sitemap/modules/simple_sitemap_engines/src/Controller/SearchEngineListBuilder.php +++ b/web/modules/simple_sitemap/modules/simple_sitemap_engines/src/Controller/SearchEngineListBuilder.php @@ -78,9 +78,10 @@ public function buildRow(EntityInterface $entity) { public function render() { return ['simple_sitemap_engines' => [ + '#type' => 'details', + '#open' => TRUE, '#prefix' => FormHelper::getDonationText(), '#title' => $this->t('Submission status'), - '#type' => 'fieldset', 'table' => parent::render(), '#description' => $this->t('Submission settings can be configured <a href="@url">here</a>.', ['@url' => $GLOBALS['base_url'] . '/admin/config/search/simplesitemap/engines/settings']), ]]; diff --git a/web/modules/simple_sitemap/modules/simple_sitemap_views/config/schema/simple_sitemap_views.views.schema.yml b/web/modules/simple_sitemap/modules/simple_sitemap_views/config/schema/simple_sitemap_views.views.schema.yml index 99a96c90fef280c3af5653e9f31ae11ffa6de42d..10c9e5965af5b3478e78ad05eb77253d4c3ba7ad 100644 --- a/web/modules/simple_sitemap/modules/simple_sitemap_views/config/schema/simple_sitemap_views.views.schema.yml +++ b/web/modules/simple_sitemap/modules/simple_sitemap_views/config/schema/simple_sitemap_views.views.schema.yml @@ -1,12 +1,18 @@ views.display_extender.simple_sitemap_display_extender: type: views_display_extender + mapping: + variants: + type: sequence + label: 'Variants' + sequence: + type: simple_sitemap_views_variant_settings + +simple_sitemap_views_variant_settings: + type: mapping mapping: index: label: 'Index' type: boolean - variant: - label: 'Sitemap variant' - type: string priority: label: 'Priority' type: string diff --git a/web/modules/simple_sitemap/modules/simple_sitemap_views/js/simple_sitemap.viewsUi.js b/web/modules/simple_sitemap/modules/simple_sitemap_views/js/simple_sitemap.viewsUi.js index 503eee1fdb2749f8946747b8dd8b2d9386ac4ca0..a6ca3d83f2712b09dfc17fd4191d3c5b2b833968 100755 --- a/web/modules/simple_sitemap/modules/simple_sitemap_views/js/simple_sitemap.viewsUi.js +++ b/web/modules/simple_sitemap/modules/simple_sitemap_views/js/simple_sitemap.viewsUi.js @@ -6,35 +6,20 @@ (function ($, Drupal) { Drupal.simpleSitemapViewsUi = {}; - Drupal.behaviors.simpleSitemapViewsUiCheckboxify = { - attach: function attach() { - var $button = $('[data-drupal-selector="edit-index-button"]').once('simple-sitemap-views-ui-checkboxify'); - if ($button.length) { - new Drupal.simpleSitemapViewsUi.Checkboxifier($button); - } - } - }; - Drupal.behaviors.simpleSitemapViewsUiArguments = { attach: function attach() { var $arguments = $('.indexed-arguments').once('simple-sitemap-views-ui-arguments'); - var $checkboxes = $arguments.find('input[type="checkbox"]'); - if ($checkboxes.length) { - new Drupal.simpleSitemapViewsUi.Arguments($checkboxes); - } - } - }; - Drupal.simpleSitemapViewsUi.Checkboxifier = function ($button) { - this.$button = $button; - this.$parent = this.$button.parent('div.simple-sitemap-views-index'); - this.$input = this.$parent.find('input:checkbox'); - this.$button.hide(); - this.$input.on('click', $.proxy(this, 'clickHandler')); - }; + if ($arguments.length) { + $arguments.each(function () { + var $checkboxes = $(this).find('input[type="checkbox"]'); - Drupal.simpleSitemapViewsUi.Checkboxifier.prototype.clickHandler = function () { - this.$button.trigger('click').trigger('submit'); + if ($checkboxes.length) { + new Drupal.simpleSitemapViewsUi.Arguments($checkboxes); + } + }); + } + } }; Drupal.simpleSitemapViewsUi.Arguments = function ($checkboxes) { @@ -55,4 +40,4 @@ this.$checkboxes.slice(index).prop('checked', false); }; -})(jQuery, Drupal); \ No newline at end of file +})(jQuery, Drupal); diff --git a/web/modules/simple_sitemap/modules/simple_sitemap_views/simple_sitemap_views.info.yml b/web/modules/simple_sitemap/modules/simple_sitemap_views/simple_sitemap_views.info.yml index 11e2a8680e4c34d8b851b0f97ce1279e8202e8aa..25dc95007d6929b9f420527a1c7d1d79baacad4c 100644 --- a/web/modules/simple_sitemap/modules/simple_sitemap_views/simple_sitemap_views.info.yml +++ b/web/modules/simple_sitemap/modules/simple_sitemap_views/simple_sitemap_views.info.yml @@ -9,7 +9,7 @@ dependencies: - simple_sitemap:simple_sitemap - drupal:views -# Information added by Drupal.org packaging script on 2020-06-16 -version: '8.x-3.7' +# Information added by Drupal.org packaging script on 2020-11-12 +version: '8.x-3.8' project: 'simple_sitemap' -datestamp: 1592298876 +datestamp: 1605141361 diff --git a/web/modules/simple_sitemap/modules/simple_sitemap_views/simple_sitemap_views.install b/web/modules/simple_sitemap/modules/simple_sitemap_views/simple_sitemap_views.install index 44b34e1bfd8a3abb06650cc0237ea61540a13a1e..ab4320f40e892625430cf95529fea12e19bd19cc 100755 --- a/web/modules/simple_sitemap/modules/simple_sitemap_views/simple_sitemap_views.install +++ b/web/modules/simple_sitemap/modules/simple_sitemap_views/simple_sitemap_views.install @@ -71,3 +71,40 @@ function simple_sitemap_views_schema() { ]; return $schema; } + +/** + * Update views display extender config. + */ +function simple_sitemap_views_update_8301() { + $config_factory = \Drupal::configFactory(); + $display_extender_name = 'simple_sitemap_display_extender'; + + // Find all views configs. + foreach ($config_factory->listAll('views.view.') as $view_config_name) { + $view = $config_factory->getEditable($view_config_name); + $changed = FALSE; + + // Go through each display on each view. + $displays = $view->get('display'); + foreach ($displays as $display_name => $display) { + if (isset($display['display_options']['display_extenders'][$display_extender_name])) { + $options = $display['display_options']['display_extenders'][$display_extender_name]; + + if (!isset($options['variants']) && isset($options['variant'])) { + $variant = $options['variant']; + unset($options['variant']); + + // Update display extender config. + $key = "display.$display_name.display_options.display_extenders.$display_extender_name"; + $options = ['variants' => [$variant => $options]]; + $view->set($key, $options); + $changed = TRUE; + } + } + } + + if ($changed) { + $view->save(TRUE); + } + } +} diff --git a/web/modules/simple_sitemap/modules/simple_sitemap_views/simple_sitemap_views.services.yml b/web/modules/simple_sitemap/modules/simple_sitemap_views/simple_sitemap_views.services.yml index f01cceb37ec69de699ebc5a42fb8e35bf73b89e9..e9402ce2ce0dc43dffbdcaa9070c799e93283085 100755 --- a/web/modules/simple_sitemap/modules/simple_sitemap_views/simple_sitemap_views.services.yml +++ b/web/modules/simple_sitemap/modules/simple_sitemap_views/simple_sitemap_views.services.yml @@ -1,7 +1,7 @@ services: simple_sitemap.views: class: Drupal\simple_sitemap_views\SimpleSitemapViews - arguments: ['@entity_type.manager', '@config.factory', '@queue', '@database'] + arguments: ['@simple_sitemap.manager', '@entity_type.manager', '@config.factory', '@queue', '@database'] simple_sitemap.views.argument_collector: class: Drupal\simple_sitemap_views\EventSubscriber\ArgumentCollector arguments: ['@entity_type.manager', '@simple_sitemap.views', '@current_route_match'] diff --git a/web/modules/simple_sitemap/modules/simple_sitemap_views/src/Controller/SimpleSitemapViewsController.php b/web/modules/simple_sitemap/modules/simple_sitemap_views/src/Controller/SimpleSitemapViewsController.php index cb6e8728a92a0de54036d5b44573d308999c7c8b..508e865c4e5be5e3854d57c4dcd9bce0b359a5af 100644 --- a/web/modules/simple_sitemap/modules/simple_sitemap_views/src/Controller/SimpleSitemapViewsController.php +++ b/web/modules/simple_sitemap/modules/simple_sitemap_views/src/Controller/SimpleSitemapViewsController.php @@ -51,7 +51,7 @@ public function content() { '#header' => [ $this->t('View'), $this->t('Display'), - $this->t('Arguments'), + $this->t('Variants'), $this->t('Operations'), ], '#empty' => $this->t('No view displays are set to be indexed yet. <a href="@url">Edit a view.</a>', ['@url' => $GLOBALS['base_url'] . '/admin/structure/views']), @@ -60,15 +60,17 @@ public function content() { foreach ($this->sitemapViews->getIndexableViews() as $index => $view) { $table[$index]['view'] = ['#markup' => $view->storage->label()]; $table[$index]['display'] = ['#markup' => $view->display_handler->display['display_title']]; - // Determine whether view display arguments are indexed. - $arguments_status = $this->sitemapViews->getIndexableArguments($view) ? $this->t('Yes') : $this->t('No'); - $table[$index]['arguments'] = ['#markup' => $arguments_status]; + + $variants = $this->sitemapViews->getIndexableVariants($view); + $variants = implode(', ', array_keys($variants)); + $table[$index]['variants'] = ['#markup' => $variants]; // Link to view display edit form. $display_edit_url = Url::fromRoute('entity.view.edit_display_form', [ 'view' => $view->id(), 'display_id' => $view->current_display, ]); + $table[$index]['operations'] = [ '#type' => 'operations', '#links' => [ diff --git a/web/modules/simple_sitemap/modules/simple_sitemap_views/src/EventSubscriber/ArgumentCollector.php b/web/modules/simple_sitemap/modules/simple_sitemap_views/src/EventSubscriber/ArgumentCollector.php index f33ef222ea5c1194145a6215aef4fa5def480182..fc63255faea12541171d991a310a996531574549 100755 --- a/web/modules/simple_sitemap/modules/simple_sitemap_views/src/EventSubscriber/ArgumentCollector.php +++ b/web/modules/simple_sitemap/modules/simple_sitemap_views/src/EventSubscriber/ArgumentCollector.php @@ -56,7 +56,6 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager, Sim */ public static function getSubscribedEvents() { $events[KernelEvents::TERMINATE] = 'onTerminate'; - return $events; } @@ -73,16 +72,16 @@ public function onTerminate(PostResponseEvent $event) { return; } - // Get view ID from route. $view_id = $this->routeMatch->getParameter('view_id'); /** @var \Drupal\views\ViewEntityInterface $view_entity */ if ($view_id && $view_entity = $this->viewStorage->load($view_id)) { - // Get display ID from route. $display_id = $this->routeMatch->getParameter('display_id'); + // Get a set of view arguments and try to add them to the index. $view = $view_entity->getExecutable(); $args = $this->getViewArgumentsFromRoute(); $this->sitemapViews->addArgumentsToIndex($view, $args, $display_id); + // Destroy a view instance. $view->destroy(); } @@ -103,11 +102,12 @@ protected function getViewArgumentsFromRoute() { $args = []; foreach ($map as $attribute => $parameter_name) { $parameter_name = isset($parameter_name) ? $parameter_name : $attribute; - if (($arg = $this->routeMatch->getRawParameter($parameter_name)) !== NULL) { + $arg = $this->routeMatch->getRawParameter($parameter_name); + + if ($arg !== NULL) { $args[] = $arg; } } - return $args; } diff --git a/web/modules/simple_sitemap/modules/simple_sitemap_views/src/Plugin/QueueWorker/GarbageCollector.php b/web/modules/simple_sitemap/modules/simple_sitemap_views/src/Plugin/QueueWorker/GarbageCollector.php index 91a6b284f95f3839ac0a215ef3c860ff0fc4c685..5643b72ff0dc32c4dd7094df7aee8094c368bee3 100755 --- a/web/modules/simple_sitemap/modules/simple_sitemap_views/src/Plugin/QueueWorker/GarbageCollector.php +++ b/web/modules/simple_sitemap/modules/simple_sitemap_views/src/Plugin/QueueWorker/GarbageCollector.php @@ -79,19 +79,33 @@ public function processItem($data) { // Check that the view exists and it is enabled. if ($view_entity && $view_entity->status()) { $view = $view_entity->getExecutable(); + foreach ($this->sitemapViews->getRouterDisplayIds($view_entity) as $display_id) { // Ensure the display was correctly set. // Check that the display is enabled. if (!$view->setDisplay($display_id) || !$view->display_handler->isEnabled()) { continue; } + + $variants = $this->sitemapViews->getIndexableVariants($view); + $variants = array_keys($variants); + + $args_ids = []; + foreach ($variants as $variant) { + $variant_args_ids = $this->sitemapViews->getIndexableArguments($view, $variant); + + if (count($variant_args_ids) > count($args_ids)) { + $args_ids = $variant_args_ids; + } + } + // Check that the display has indexable arguments. - $args_ids = $this->sitemapViews->getIndexableArguments($view); if (empty($args_ids)) { continue; } $display_ids[] = $display_id; + // Delete records about sets of arguments that are no longer indexed. $args_ids = $this->sitemapViews->getArgumentsStringVariations($args_ids); $condition = new Condition('AND'); @@ -100,13 +114,26 @@ public function processItem($data) { $condition->condition('arguments_ids', $args_ids, 'NOT IN'); $this->sitemapViews->removeArgumentsFromIndex($condition); + $max_links = 0; + foreach ($variants as $variant) { + $settings = $this->sitemapViews->getSitemapSettings($view, $variant); + $variant_max_links = is_numeric($settings['max_links']) ? $settings['max_links'] : 0; + + if ($variant_max_links == 0) { + $max_links = 0; + break; + } + elseif ($variant_max_links > $max_links) { + $max_links = $variant_max_links; + } + } + // Check if the records limit for display is exceeded. - $settings = $this->sitemapViews->getSitemapSettings($view); - $max_links = is_numeric($settings['max_links']) ? $settings['max_links'] : 0; if ($max_links > 0) { $condition = new Condition('AND'); $condition->condition('view_id', $view_id); $condition->condition('display_id', $display_id); + // Delete records that exceed the limit. if ($index_id = $this->sitemapViews->getIndexIdByPosition($max_links, $condition)) { $condition->condition('id', $index_id, '>'); @@ -114,6 +141,7 @@ public function processItem($data) { } } } + // Delete records about view displays that do not exist or are disabled. if (!empty($display_ids)) { $condition = new Condition('AND'); @@ -121,6 +149,7 @@ public function processItem($data) { $condition->condition('display_id', $display_ids, 'NOT IN'); $this->sitemapViews->removeArgumentsFromIndex($condition); } + // Destroy a view instance. $view->destroy(); } diff --git a/web/modules/simple_sitemap/modules/simple_sitemap_views/src/Plugin/simple_sitemap/UrlGenerator/ViewsUrlGenerator.php b/web/modules/simple_sitemap/modules/simple_sitemap_views/src/Plugin/simple_sitemap/UrlGenerator/ViewsUrlGenerator.php index 76ee0461e291e2fd226e8ece0eb6e87a25b66854..16f50c6036e9bc42984afaa396307f20f67e4eca 100755 --- a/web/modules/simple_sitemap/modules/simple_sitemap_views/src/Plugin/simple_sitemap/UrlGenerator/ViewsUrlGenerator.php +++ b/web/modules/simple_sitemap/modules/simple_sitemap_views/src/Plugin/simple_sitemap/UrlGenerator/ViewsUrlGenerator.php @@ -116,9 +116,9 @@ public function getDataSets() { // Get data sets. foreach ($this->sitemapViews->getIndexableViews() as $view) { - $settings = $this->sitemapViews->getSitemapSettings($view); - if ($settings['variant'] != $this->sitemapVariant) { - // Destroy a view instance. + $settings = $this->sitemapViews->getSitemapSettings($view, $this->sitemapVariant); + + if (empty($settings)) { $view->destroy(); continue; } @@ -131,17 +131,20 @@ public function getDataSets() { $data_sets[] = $base_data_set + ['arguments' => NULL]; // Process indexed arguments. - if ($args_ids = $this->sitemapViews->getIndexableArguments($view)) { + if ($args_ids = $this->sitemapViews->getIndexableArguments($view, $this->sitemapVariant)) { + $args_ids = $this->sitemapViews->getArgumentsStringVariations($args_ids); + // Form the condition according to the variants of the // indexable arguments. - $args_ids = $this->sitemapViews->getArgumentsStringVariations($args_ids); $condition = new Condition('AND'); $condition->condition('view_id', $view->id()); $condition->condition('display_id', $view->current_display); $condition->condition('arguments_ids', $args_ids, 'IN'); + // Get the arguments values from the index. $max_links = is_numeric($settings['max_links']) ? $settings['max_links'] : NULL; $indexed_arguments = $this->sitemapViews->getArgumentsFromIndex($condition, $max_links, TRUE); + // Add the arguments values for processing. foreach ($indexed_arguments as $index_id => $arguments_info) { $data_sets[] = $base_data_set + [ @@ -150,6 +153,7 @@ public function getDataSets() { ]; } } + // Destroy a view instance. $view->destroy(); } @@ -179,7 +183,7 @@ protected function processDataSet($data_set) { } // Trying to get the sitemap settings. - $settings = $this->sitemapViews->getSitemapSettings($view); + $settings = $this->sitemapViews->getSitemapSettings($view, $this->sitemapVariant); if (empty($settings)) { throw new \UnexpectedValueException('Failed to get the sitemap settings.'); } @@ -191,13 +195,16 @@ protected function processDataSet($data_set) { if (is_array($args)) { $params = array_merge([$view_id, $display_id], $args); $view_result = call_user_func_array('views_get_view_result', $params); + // Do not include paths on which the view returns an empty result. if (empty($view_result)) { throw new \UnexpectedValueException('The view returned an empty result.'); } + // Remove empty arguments from URL. $this->cleanRouteParameters($url, $args); } + $path = $url->getInternalPath(); // Destroy a view instance. $view->destroy(); @@ -243,11 +250,13 @@ protected function processDataSet($data_set) { */ protected function cleanRouteParameters(Url $url, array $args) { $parameters = $url->getRouteParameters(); + // Check that the number of params does not match the number of arguments. if (count($parameters) != count($args)) { $route_name = $url->getRouteName(); $route = $this->routeProvider->getRouteByName($route_name); $variables = $route->compile()->getVariables(); + // Remove params that are not present in the arguments. foreach ($variables as $variable_name) { if (empty($args)) { @@ -257,6 +266,7 @@ protected function cleanRouteParameters(Url $url, array $args) { array_shift($args); } } + // Set new route params. $url->setRouteParameters($parameters); } diff --git a/web/modules/simple_sitemap/modules/simple_sitemap_views/src/Plugin/views/display_extender/SimpleSitemapDisplayExtender.php b/web/modules/simple_sitemap/modules/simple_sitemap_views/src/Plugin/views/display_extender/SimpleSitemapDisplayExtender.php index 0ffa6db3f427a1d4c093a1f6a83bc55952a62062..accb215f2f4478b35f8ae05902ebc6c2bd6d00ad 100755 --- a/web/modules/simple_sitemap/modules/simple_sitemap_views/src/Plugin/views/display_extender/SimpleSitemapDisplayExtender.php +++ b/web/modules/simple_sitemap/modules/simple_sitemap_views/src/Plugin/views/display_extender/SimpleSitemapDisplayExtender.php @@ -39,6 +39,13 @@ class SimpleSitemapDisplayExtender extends DisplayExtenderPluginBase { */ protected $sitemapManager; + /** + * The sitemap variants. + * + * @var array + */ + protected $variants = []; + /** * Constructs the plugin. * @@ -57,6 +64,7 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition parent::__construct($configuration, $plugin_id, $plugin_definition); $this->formHelper = $form_helper; $this->sitemapManager = $sitemap_manager; + $this->variants = $sitemap_manager->getSitemapVariants(NULL, FALSE); } /** @@ -87,12 +95,7 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o */ protected function defineOptions() { $options = parent::defineOptions(); - $options['index'] = ['default' => 0]; - $options['variant'] = ['default' => NULL]; - $options['priority'] = ['default' => 0.5]; - $options['changefreq'] = ['default' => '']; - $options['arguments'] = ['default' => []]; - $options['max_links'] = ['default' => 100]; + $options['variants'] = ['default' => []]; return $options; } @@ -101,92 +104,81 @@ protected function defineOptions() { */ public function buildOptionsForm(&$form, FormStateInterface $form_state) { if ($this->hasSitemapSettings() && $form_state->get('section') == 'simple_sitemap') { - $form['#title'] .= $this->t('Simple XML Sitemap settings for this display'); - $settings = $this->getSitemapSettings(); + $arguments_options = $this->getArgumentsOptions(); - // The index section. - $form['index'] = [ - '#prefix' => '<div class="simple-sitemap-views-index">', - '#suffix' => '</div>', - ]; - // Add a checkbox for JS users, which will have behavior attached to it - // so it can replace the button. - $form['index']['index'] = [ - '#type' => 'checkbox', - '#title' => $this->t('Index this display'), - '#default_value' => $settings['index'], - ]; - // Then add the button itself. - $form['index']['index_button'] = [ - '#limit_validation_errors' => [], - '#type' => 'submit', - '#value' => $this->t('Index this display'), - '#submit' => [[$this, 'displaySitemapSettingsForm']], + $form['variants'] = [ + '#type' => 'container', + '#tree' => TRUE, ]; - // Show the whole form only if indexing is checked. - if ($this->options['index']) { - // Main settings fieldset. - $form['main'] = [ - '#type' => 'fieldset', - '#title' => $this->t('Main settings'), + foreach ($this->variants as $variant => $definition) { + $settings = $this->getSitemapSettings($variant); + $variant_form = &$form['variants'][$variant]; + + $variant_form = [ + '#type' => 'details', + '#title' => '<em>' . $definition['label'] . '</em>', + '#open' => (bool) $settings['index'], ]; - // The sitemap variant. - $form['main']['variant'] = [ - '#type' => 'select', - '#title' => $this->t('Sitemap variant'), - '#description' => $this->t('The sitemap variant this display is to be indexed in.'), - '#options' => $this->formHelper->getVariantSelectValues(), - '#default_value' => $this->formHelper->getVariantSelectValuesDefault($settings['variant']), - '#required' => TRUE, + + $variant_form['index'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Index this display in variant <em>@variant_label</em>', [ + '@variant_label' => $definition['label'], + ]), + '#default_value' => $settings['index'], + ]; + + $states = [ + 'visible' => [ + ':input[name="variants[' . $variant . '][index]"]' => ['checked' => TRUE], + ], ]; + // The sitemap priority. - $form['main']['priority'] = [ + $variant_form['priority'] = [ '#type' => 'select', '#title' => $this->t('Priority'), '#description' => $this->t('The priority this display will have in the eyes of search engine bots.'), '#default_value' => $settings['priority'], '#options' => $this->formHelper->getPrioritySelectValues(), + '#states' => $states, ]; + // The sitemap change frequency. - $form['main']['changefreq'] = [ + $variant_form['changefreq'] = [ '#type' => 'select', '#title' => $this->t('Change frequency'), '#description' => $this->t('The frequency with which this display changes. Search engine bots may take this as an indication of how often to index it.'), '#default_value' => $settings['changefreq'], '#options' => $this->formHelper->getChangefreqSelectValues(), + '#states' => $states, ]; - // Argument settings fieldset. - $form['arguments'] = [ - '#type' => 'fieldset', - '#title' => $this->t('Argument settings'), + // Arguments to index. + $variant_form['arguments'] = [ + '#type' => 'checkboxes', + '#title' => $this->t('Indexed arguments'), + '#options' => $arguments_options, + '#default_value' => $settings['arguments'], + '#attributes' => ['class' => ['indexed-arguments']], + '#access' => !empty($arguments_options), + '#states' => $states, + ]; + + // Max links with arguments. + $variant_form['max_links'] = [ + '#type' => 'number', + '#title' => $this->t('Maximum display variations'), + '#description' => $this->t('The maximum number of link variations to be indexed for this display. If left blank, each argument will create link variations for this display. Use with caution, as a large number of argument values​can significantly increase the number of sitemap links.'), + '#default_value' => $settings['max_links'], + '#min' => 1, + '#access' => !empty($arguments_options), + '#states' => $states, ]; - // Get view arguments options. - if ($arguments_options = $this->getArgumentsOptions()) { - // Indexed arguments element. - $form['arguments']['arguments'] = [ - '#type' => 'checkboxes', - '#title' => $this->t('Indexed arguments'), - '#options' => $arguments_options, - '#default_value' => $settings['arguments'], - '#attributes' => ['class' => ['indexed-arguments']], - ]; - // Max links with arguments. - $form['arguments']['max_links'] = [ - '#type' => 'number', - '#title' => $this->t('Maximum display variations'), - '#description' => $this->t('The maximum number of link variations to be indexed for this display. If left blank, each argument will create link variations for this display. Use with caution, as a large number of argument values​can significantly increase the number of sitemap links.'), - '#default_value' => $settings['max_links'], - '#min' => 1, - ]; - } - else { - $form['arguments']['#description'] = $this->t('This display has no arguments.'); - } } - // Attaching script to form. + $form['#title'] .= $this->t('Simple XML Sitemap settings for this display'); $form['#attached']['library'][] = 'simple_sitemap_views/viewsUi'; } } @@ -196,11 +188,13 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { */ public function validateOptionsForm(&$form, FormStateInterface $form_state) { if ($this->hasSitemapSettings() && $form_state->get('section') == 'simple_sitemap') { - // Validate indexed arguments. - $arguments = $form_state->getValue('arguments', []); - $errors = $this->validateIndexedArguments($arguments); - foreach ($errors as $message) { - $form_state->setError($form['arguments']['arguments'], $message); + foreach (array_keys($this->variants) as $variant) { + $arguments = $form_state->getValue(['variants', $variant, 'arguments'], []); + $errors = $this->validateIndexedArguments($arguments); + + foreach ($errors as $message) { + $form_state->setError($form['variants'][$variant]['arguments'], $message); + } } } } @@ -210,12 +204,16 @@ public function validateOptionsForm(&$form, FormStateInterface $form_state) { */ public function submitOptionsForm(&$form, FormStateInterface $form_state) { if ($this->hasSitemapSettings() && $form_state->get('section') == 'simple_sitemap') { - $values = $form_state->cleanValues()->getValues(); - $values['arguments'] = isset($values['arguments']) ? array_filter($values['arguments']) : []; - // Save sitemap settings. - foreach ($values as $key => $value) { - if (array_key_exists($key, $this->options)) { - $this->options[$key] = $value; + $variants = $form_state->getValue('variants'); + $this->options['variants'] = []; + + // Save settings for each variant. + foreach (array_keys($this->variants) as $variant) { + $settings = $variants[$variant] + $this->getSitemapSettings($variant); + + if ($settings['index']) { + $settings['arguments'] = array_filter($settings['arguments']); + $this->options['variants'][$variant] = $settings; } } } @@ -225,16 +223,18 @@ public function submitOptionsForm(&$form, FormStateInterface $form_state) { * {@inheritdoc} */ public function validate() { - $errors = parent::validate(); + $errors = [parent::validate()]; // Validate the argument options relative to the // current state of the view argument handlers. if ($this->hasSitemapSettings()) { - $settings = $this->getSitemapSettings(); - $result = $this->validateIndexedArguments($settings['arguments']); - $errors = array_merge($errors, $result); + foreach (array_keys($this->variants) as $variant) { + $settings = $this->getSitemapSettings($variant); + $errors[] = $this->validateIndexedArguments($settings['arguments']); + } } - return $errors; + + return array_merge([], ...$errors); } /** @@ -246,48 +246,48 @@ public function optionsSummary(&$categories, &$options) { 'title' => $this->t('Simple XML Sitemap'), 'column' => 'second', ]; + + $included_variants = []; + foreach (array_keys($this->variants) as $variant) { + $settings = $this->getSitemapSettings($variant); + + if ($settings['index']) { + $included_variants[] = $variant; + } + } + $options['simple_sitemap'] = [ + 'title' => NULL, 'category' => 'simple_sitemap', - 'title' => $this->t('Status'), - 'value' => $this->isIndexingEnabled() ? $this->t('Included in sitemap') : $this->t('Excluded from sitemap'), + 'value' => $included_variants ? $this->t('Included in sitemap variants: @variants', [ + '@variants' => implode(', ', $included_variants), + ]) : $this->t('Excluded from all sitemap variants'), ]; } } /** - * Displays the sitemap settings form. + * Gets the sitemap settings. * - * @param array $form - * The form structure. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * Current form state. - */ - public function displaySitemapSettingsForm(array $form, FormStateInterface $form_state) { - // Update index option. - $this->options['index'] = empty($this->options['index']); - - // Rebuild settings form. - /** @var \Drupal\views_ui\ViewUI $view */ - $view = $form_state->get('view'); - $display_handler = $view->getExecutable()->display_handler; - $extender_options = $display_handler->getOption('display_extenders'); - if (isset($extender_options[$this->pluginId])) { - $extender_options[$this->pluginId] = $this->options; - $display_handler->setOption('display_extenders', $extender_options); - } - $view->cacheSet(); - $form_state->set('rerender', TRUE); - $form_state->setRebuild(); - } - - /** - * Get sitemap settings configuration for this display. + * @param string $variant + * The name of the sitemap variant. * * @return array * The sitemap settings. */ - public function getSitemapSettings() { - return $this->options; + public function getSitemapSettings($variant) { + $settings = [ + 'index' => 0, + 'priority' => 0.5, + 'changefreq' => '', + 'arguments' => [], + 'max_links' => 100, + ]; + + if (isset($this->options['variants'][$variant])) { + $settings = $this->options['variants'][$variant] + $settings; + } + return $settings; } /** @@ -300,17 +300,6 @@ public function hasSitemapSettings() { return $this->displayHandler instanceof DisplayRouterInterface; } - /** - * Identify whether or not the current display indexing is enabled. - * - * @return bool - * Indexing is enabled (TRUE) or not (FALSE). - */ - public function isIndexingEnabled() { - $settings = $this->getSitemapSettings(); - return !empty($settings['index']); - } - /** * Returns available view arguments options. * @@ -318,9 +307,9 @@ public function isIndexingEnabled() { * View arguments labels keyed by argument ID. */ protected function getArgumentsOptions() { - $arguments_options = []; - // Get view argument handlers. $arguments = $this->displayHandler->getHandlers('argument'); + $arguments_options = []; + /** @var \Drupal\views\Plugin\views\argument\ArgumentPluginBase $argument */ foreach ($arguments as $id => $argument) { $arguments_options[$id] = $argument->adminLabel(); diff --git a/web/modules/simple_sitemap/modules/simple_sitemap_views/src/SimpleSitemapViews.php b/web/modules/simple_sitemap/modules/simple_sitemap_views/src/SimpleSitemapViews.php index d7cf0db54df3e3b7e760a5f485a035742126f163..7fae9b93cddb167d3f3ee2b9cd7add0809071d60 100755 --- a/web/modules/simple_sitemap/modules/simple_sitemap_views/src/SimpleSitemapViews.php +++ b/web/modules/simple_sitemap/modules/simple_sitemap_views/src/SimpleSitemapViews.php @@ -3,6 +3,7 @@ namespace Drupal\simple_sitemap_views; use Drupal\simple_sitemap_views\Plugin\views\display_extender\SimpleSitemapDisplayExtender; +use Drupal\simple_sitemap\SimplesitemapManager; use Drupal\Core\Database\Query\ConditionInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Config\ConfigFactoryInterface; @@ -29,6 +30,13 @@ class SimpleSitemapViews { */ const PLUGIN_ID = 'simple_sitemap_display_extender'; + /** + * Simple XML Sitemap manager. + * + * @var \Drupal\simple_sitemap\SimplesitemapManager + */ + protected $sitemapManager; + /** * View entities storage. * @@ -60,6 +68,8 @@ class SimpleSitemapViews { /** * SimpleSitemapViews constructor. * + * @param \Drupal\simple_sitemap\SimplesitemapManager $sitemap_manager + * Simple XML Sitemap manager. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * The entity type manager. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory @@ -70,11 +80,13 @@ class SimpleSitemapViews { * The current active database's master connection. */ public function __construct( + SimplesitemapManager $sitemap_manager, EntityTypeManagerInterface $entity_type_manager, ConfigFactoryInterface $config_factory, QueueFactory $queue_factory, Connection $database ) { + $this->sitemapManager = $sitemap_manager; $this->viewStorage = $entity_type_manager->getStorage('view'); $this->configFactory = $config_factory; $this->queueFactory = $queue_factory; @@ -90,7 +102,6 @@ public function __construct( public function isEnabled() { // Support enabled when views display extender is enabled. $enabled = Views::getEnabledDisplayExtenders(); - return isset($enabled[self::PLUGIN_ID]); } @@ -127,49 +138,59 @@ public function disable() { } /** - * Get sitemap settings for view display. + * Gets the sitemap settings for view display. * * @param \Drupal\views\ViewExecutable $view * A view executable instance. + * @param string $variant + * The name of the sitemap variant. * @param string|null $display_id - * The display id. If empty uses the preselected display. + * The display id. If empty uses the current display. * * @return array|null * The sitemap settings if the display is indexed, NULL otherwise. */ - public function getSitemapSettings(ViewExecutable $view, $display_id = NULL) { + public function getSitemapSettings(ViewExecutable $view, $variant, $display_id = NULL) { // Ensure the display was correctly set. if (!$view->setDisplay($display_id)) { return NULL; } - // Get the list of extenders. + $extenders = $view->display_handler->getExtenders(); $extender = isset($extenders[self::PLUGIN_ID]) ? $extenders[self::PLUGIN_ID] : NULL; + // Retrieve the sitemap settings from the extender. - if ($extender instanceof SimpleSitemapDisplayExtender && $extender->hasSitemapSettings() && $extender->isIndexingEnabled()) { - return $extender->getSitemapSettings(); - } + if ($extender instanceof SimpleSitemapDisplayExtender && $extender->hasSitemapSettings()) { + $settings = $extender->getSitemapSettings($variant); + if ($settings['index']) { + return $settings; + } + } return NULL; } /** - * Get indexable arguments for view display. + * Gets the indexable arguments for view display. * * @param \Drupal\views\ViewExecutable $view * A view executable instance. + * @param string $variant + * The name of the sitemap variant. * @param string|null $display_id - * The display id. If empty uses the preselected display. + * The display id. If empty uses the current display. * * @return array * Indexable arguments identifiers. */ - public function getIndexableArguments(ViewExecutable $view, $display_id = NULL) { + public function getIndexableArguments(ViewExecutable $view, $variant, $display_id = NULL) { + $settings = $this->getSitemapSettings($view, $variant, $display_id); $indexable_arguments = []; - $settings = $this->getSitemapSettings($view, $display_id); - if ($settings && !empty($settings['arguments']) && is_array($settings['arguments'])) { - // Find indexable arguments. + + // Find indexable arguments. + if ($settings && !empty($settings['arguments'])) { $arguments = array_keys($view->display_handler->getHandlers('argument')); + foreach ($arguments as $argument_id) { if (empty($settings['arguments'][$argument_id])) { break; @@ -177,7 +198,6 @@ public function getIndexableArguments(ViewExecutable $view, $display_id = NULL) $indexable_arguments[] = $argument_id; } } - return $indexable_arguments; } @@ -189,37 +209,69 @@ public function getIndexableArguments(ViewExecutable $view, $display_id = NULL) * @param array $args * Array of arguments to add to the index. * @param string|null $display_id - * The display id. If empty uses the preselected display. + * The display id. If empty uses the current display. * * @return bool * TRUE if the arguments are added to the index, FALSE otherwise. */ public function addArgumentsToIndex(ViewExecutable $view, array $args, $display_id = NULL) { + $variants = $this->sitemapManager->getSitemapVariants(NULL, FALSE); + + foreach (array_keys($variants) as $variant) { + $result = $this->addArgumentsToIndexByVariant($view, $variant, $args, $display_id); + + if ($result) { + return $result; + } + } + return FALSE; + } + + /** + * Adds view arguments to the index by the sitemap variant. + * + * @param \Drupal\views\ViewExecutable $view + * A view executable instance. + * @param string $variant + * The name of the sitemap variant. + * @param array $args + * Array of arguments to add to the index. + * @param string|null $display_id + * The display id. If empty uses the current display. + * + * @return bool + * TRUE if the arguments are added to the index, FALSE otherwise. + */ + public function addArgumentsToIndexByVariant(ViewExecutable $view, $variant, array $args, $display_id = NULL) { // An array of arguments to be added to the index can not be empty. // Also ensure the display was correctly set. if (empty($args) || !$view->setDisplay($display_id)) { return FALSE; } + // Check that indexing of at least one argument is enabled. - $indexable_arguments = $this->getIndexableArguments($view); + $indexable_arguments = $this->getIndexableArguments($view, $variant); if (empty($indexable_arguments)) { return FALSE; } + // Check that the number of identifiers is equal to the number of values. $args_ids = array_slice($indexable_arguments, 0, count($args)); if (count($args_ids) != count($args)) { return FALSE; } + // Check that the current number of rows in the index does not // exceed the specified number. $condition = new Condition('AND'); $condition->condition('view_id', $view->id()); $condition->condition('display_id', $view->current_display); - $settings = $this->getSitemapSettings($view); + $settings = $this->getSitemapSettings($view, $variant); $max_links = is_numeric($settings['max_links']) ? $settings['max_links'] : 0; if ($max_links > 0 && $this->getArgumentsFromIndexCount($condition) >= $max_links) { return FALSE; } + // Convert the set of identifiers and a set of values to string. $args_ids = $this->convertArgumentsArrayToString($args_ids); $args_values = $this->convertArgumentsArrayToString($args); @@ -229,12 +281,14 @@ public function addArgumentsToIndex(ViewExecutable $view, array $args, $display_ if ($this->getArgumentsFromIndexCount($condition)) { return FALSE; } + // Check that the view result is not empty for this set of arguments. $params = array_merge([$view->id(), $view->current_display], $args); $view_result = call_user_func_array('views_get_view_result', $params); if (empty($view_result)) { return FALSE; } + // Add a set of arguments to the index. $options = ['return' => Database::RETURN_AFFECTED]; $query = $this->database->insert('simple_sitemap_views', $options); @@ -244,7 +298,6 @@ public function addArgumentsToIndex(ViewExecutable $view, array $args, $display_ 'arguments_ids' => $args_ids, 'arguments_values' => $args_values, ]); - return (bool) $query->execute(); } @@ -264,23 +317,22 @@ public function addArgumentsToIndex(ViewExecutable $view, array $args, $display_ * An array with information about the indexed arguments. */ public function getArgumentsFromIndex(ConditionInterface $condition = NULL, $limit = NULL, $convert = FALSE) { - // Select the rows from the index table. $query = $this->database->select('simple_sitemap_views', 'ssv'); $query->addField('ssv', 'id'); $query->addField('ssv', 'view_id'); $query->addField('ssv', 'display_id'); $query->addField('ssv', 'arguments_values', 'arguments'); - // Add conditions if necessary. + if (!empty($condition)) { $query->condition($condition); } - // Limit results if necessary. if (!empty($limit)) { $query->range(0, $limit); } + $rows = $query->execute()->fetchAll(); - // Form the result. $arguments = []; + foreach ($rows as $row) { $arguments[$row->id] = [ 'view_id' => $row->view_id, @@ -288,7 +340,6 @@ public function getArgumentsFromIndex(ConditionInterface $condition = NULL, $lim 'arguments' => $convert ? $this->convertArgumentsStringToArray($row->arguments) : $row->arguments, ]; } - return $arguments; } @@ -303,12 +354,10 @@ public function getArgumentsFromIndex(ConditionInterface $condition = NULL, $lim */ public function getArgumentsFromIndexCount(ConditionInterface $condition = NULL) { $query = $this->database->select('simple_sitemap_views', 'ssv'); - // Add conditions if necessary. + if (!empty($condition)) { $query->condition($condition); } - - // Get the number of rows from the index table. return $query->countQuery()->execute()->fetchField(); } @@ -326,13 +375,13 @@ public function getArgumentsFromIndexCount(ConditionInterface $condition = NULL) public function getIndexIdByPosition($position, ConditionInterface $condition = NULL) { $query = $this->database->select('simple_sitemap_views', 'ssv'); $query->addField('ssv', 'id'); - // Add conditions if necessary. + if (!empty($condition)) { $query->condition($condition); } + $query->orderBy('id', 'ASC'); $query->range($position - 1, 1); - return $query->execute()->fetchField(); } @@ -366,11 +415,12 @@ public function removeArgumentsFromIndex(ConditionInterface $condition = NULL) { */ public function getRouterDisplayIds(ViewEntityInterface $view_entity) { $display_plugins = $this->getRouterDisplayPluginIds(); + $filter_callback = function (array $display) use ($display_plugins) { return !empty($display['display_plugin']) && in_array($display['display_plugin'], $display_plugins); }; - $displays = array_filter($view_entity->get('display'), $filter_callback); + $displays = array_filter($view_entity->get('display'), $filter_callback); return array_keys($displays); } @@ -385,11 +435,13 @@ public function getIndexableViews() { if (!$this->isEnabled()) { return []; } + // Load views with display plugins that use the route. $query = $this->viewStorage->getQuery(); $query->condition('status', TRUE); $query->condition("display.*.display_plugin", $this->getRouterDisplayPluginIds(), 'IN'); $view_ids = $query->execute(); + // If there are no such views, then return an empty array. if (empty($view_ids)) { return []; @@ -400,6 +452,7 @@ public function getIndexableViews() { foreach ($this->viewStorage->loadMultiple($view_ids) as $view_entity) { foreach ($this->getRouterDisplayIds($view_entity) as $display_id) { $view = Views::executableFactory()->get($view_entity); + // Ensure the display was correctly set. if (!$view->setDisplay($display_id)) { $view->destroy(); @@ -407,30 +460,58 @@ public function getIndexableViews() { } // Check that the display is enabled and indexed. - if ($view->display_handler->isEnabled() && $this->getSitemapSettings($view)) { + if ($view->display_handler->isEnabled() && $this->getIndexableVariants($view)) { $indexable_views[] = $view; } } } - return $indexable_views; } + /** + * Returns an array of indexable sitemap variants for view display. + * + * @param \Drupal\views\ViewExecutable $view + * A view executable instance. + * @param string|null $display_id + * The display id. If empty uses the current display. + * + * @return array + * An array of sitemap variants. + */ + public function getIndexableVariants(ViewExecutable $view, $display_id = NULL) { + // Ensure the display was correctly set. + if (!$view->setDisplay($display_id)) { + return []; + } + + $variants = $this->sitemapManager->getSitemapVariants(NULL, FALSE); + foreach (array_keys($variants) as $variant) { + if (!$this->getSitemapSettings($view, $variant)) { + unset($variants[$variant]); + } + } + return $variants; + } + /** * Creates tasks in the garbage collection queue. */ public function executeGarbageCollection() { // The task queue of garbage collection in the arguments index. $queue = $this->queueFactory->get('simple_sitemap.views.garbage_collector'); + // Check that the queue is empty. if ($queue->numberOfItems()) { return; } + // Get identifiers of indexed views. $query = $this->database->select('simple_sitemap_views', 'ssv'); $query->addField('ssv', 'view_id'); $query->distinct(); $result = $query->execute()->fetchCol(); + // Create a garbage collection tasks. foreach ($result as $view_id) { $queue->createItem(['view_id' => $view_id]); @@ -448,11 +529,11 @@ public function executeGarbageCollection() { */ public function getArgumentsStringVariations(array $args) { $variations = []; + for ($length = 1; $length <= count($args); $length++) { $args_slice = array_slice($args, 0, $length); $variations[] = $this->convertArgumentsArrayToString($args_slice); } - return $variations; } @@ -490,16 +571,17 @@ protected function convertArgumentsStringToArray($args) { */ protected function getRouterDisplayPluginIds() { static $plugin_ids = []; + if (empty($plugin_ids)) { - // Get all display plugins that use the route. $display_plugins = Views::pluginManager('display')->getDefinitions(); + + // Get all display plugins that use the route. foreach ($display_plugins as $plugin_id => $definition) { if (!empty($definition['uses_route'])) { $plugin_ids[$plugin_id] = $plugin_id; } } } - return $plugin_ids; } diff --git a/web/modules/simple_sitemap/modules/simple_sitemap_views/tests/modules/simple_sitemap_views_test/config/install/views.view.simple_sitemap_views_test_view.yml b/web/modules/simple_sitemap/modules/simple_sitemap_views/tests/modules/simple_sitemap_views_test/config/install/views.view.simple_sitemap_views_test_view.yml index d4dfae2f2fc659ff00135bd2bd2a589bc5c8b831..acd3a247c8cf608f6fc8162fbcb6b73e77dc6ca8 100644 --- a/web/modules/simple_sitemap/modules/simple_sitemap_views/tests/modules/simple_sitemap_views_test/config/install/views.view.simple_sitemap_views_test_view.yml +++ b/web/modules/simple_sitemap/modules/simple_sitemap_views/tests/modules/simple_sitemap_views_test/config/install/views.view.simple_sitemap_views_test_view.yml @@ -262,14 +262,15 @@ display: display_options: display_extenders: simple_sitemap_display_extender: - index: true - variant: default - priority: '0.5' - changefreq: '' - arguments: - type: type - title: title - max_links: 2 + variants: + default: + index: true + priority: '0.5' + changefreq: '' + arguments: + type: type + title: title + max_links: 2 path: simple-sitemap-views-test-view rendering_language: en cache_metadata: diff --git a/web/modules/simple_sitemap/modules/simple_sitemap_views/tests/modules/simple_sitemap_views_test/simple_sitemap_views_test.info.yml b/web/modules/simple_sitemap/modules/simple_sitemap_views/tests/modules/simple_sitemap_views_test/simple_sitemap_views_test.info.yml index 46a2a9cb6d926eb5ca8ca85702244824fbe90fe3..d6410836c0b3631fac8a3453b25d57cde04d9784 100644 --- a/web/modules/simple_sitemap/modules/simple_sitemap_views/tests/modules/simple_sitemap_views_test/simple_sitemap_views_test.info.yml +++ b/web/modules/simple_sitemap/modules/simple_sitemap_views/tests/modules/simple_sitemap_views_test/simple_sitemap_views_test.info.yml @@ -7,7 +7,7 @@ core_version_requirement: ^8 || ^9 dependencies: - simple_sitemap:simple_sitemap_views -# Information added by Drupal.org packaging script on 2020-06-16 -version: '8.x-3.7' +# Information added by Drupal.org packaging script on 2020-11-12 +version: '8.x-3.8' project: 'simple_sitemap' -datestamp: 1592298876 +datestamp: 1605141361 diff --git a/web/modules/simple_sitemap/modules/simple_sitemap_views/tests/src/Functional/SimpleSitemapViewsTest.php b/web/modules/simple_sitemap/modules/simple_sitemap_views/tests/src/Functional/SimpleSitemapViewsTest.php index e3ffc43181ea9d1d68a21e6ac15a13e90af281f3..36f8035f1213920ff9a85f59b486fa18a73e4a74 100644 --- a/web/modules/simple_sitemap/modules/simple_sitemap_views/tests/src/Functional/SimpleSitemapViewsTest.php +++ b/web/modules/simple_sitemap/modules/simple_sitemap_views/tests/src/Functional/SimpleSitemapViewsTest.php @@ -42,7 +42,7 @@ public function testIndexableViews() { $this->assertTrue($test_view_exists); // Check the indexing status of the arguments. - $indexable_arguments = $this->sitemapViews->getIndexableArguments($this->testView); + $indexable_arguments = $this->sitemapViews->getIndexableArguments($this->testView, $this->sitemapVariant); $this->assertContains('type', $indexable_arguments); $this->assertContains('title', $indexable_arguments); $this->assertNotContains('nid', $indexable_arguments); diff --git a/web/modules/simple_sitemap/modules/simple_sitemap_views/tests/src/Functional/SimpleSitemapViewsTestBase.php b/web/modules/simple_sitemap/modules/simple_sitemap_views/tests/src/Functional/SimpleSitemapViewsTestBase.php index 3dae919d914b80c4414924d894d8f212e4943cc1..4d3888d78d1eba502d92c6115f592f6b8bbf8d00 100644 --- a/web/modules/simple_sitemap/modules/simple_sitemap_views/tests/src/Functional/SimpleSitemapViewsTestBase.php +++ b/web/modules/simple_sitemap/modules/simple_sitemap_views/tests/src/Functional/SimpleSitemapViewsTestBase.php @@ -40,6 +40,13 @@ abstract class SimpleSitemapViewsTestBase extends SimplesitemapTestBase { */ protected $testView; + /** + * The sitemap variant. + * + * @var string + */ + protected $sitemapVariant; + /** * {@inheritdoc} */ @@ -48,6 +55,7 @@ protected function setUp() { $this->sitemapViews = $this->container->get('simple_sitemap.views'); $this->cron = $this->container->get('cron'); + $this->sitemapVariant = 'default'; $this->testView = Views::getView('simple_sitemap_views_test_view'); $this->testView->setDisplay('page_1'); diff --git a/web/modules/simple_sitemap/simple_sitemap.api.php b/web/modules/simple_sitemap/simple_sitemap.api.php index 15593722d108a2fc51da0cd427781df8c380045c..4a8f55e4f18c4b0dc6baf77891329fce56774aa6 100644 --- a/web/modules/simple_sitemap/simple_sitemap.api.php +++ b/web/modules/simple_sitemap/simple_sitemap.api.php @@ -33,9 +33,7 @@ function hook_simple_sitemap_links_alter(array &$links, $sitemap_variant) { // If this 'loc' URL points to a non-german site, make sure to remove // its german alternate URL. else { - if ($link['alternate_urls']['de']) { - unset($links[$key]['alternate_urls']['de']); - } + unset($links[$key]['alternate_urls']['de']); } } } diff --git a/web/modules/simple_sitemap/simple_sitemap.info.yml b/web/modules/simple_sitemap/simple_sitemap.info.yml index ad557ba9d413da56ad6d05f84e64844e18708fa5..87aa33a8d28998535d4c75c61711b301f76d4042 100644 --- a/web/modules/simple_sitemap/simple_sitemap.info.yml +++ b/web/modules/simple_sitemap/simple_sitemap.info.yml @@ -6,7 +6,7 @@ package: SEO core: 8.x core_version_requirement: ^8 || ^9 -# Information added by Drupal.org packaging script on 2020-06-16 -version: '8.x-3.7' +# Information added by Drupal.org packaging script on 2020-11-12 +version: '8.x-3.8' project: 'simple_sitemap' -datestamp: 1592298876 +datestamp: 1605141361 diff --git a/web/modules/simple_sitemap/simple_sitemap.module b/web/modules/simple_sitemap/simple_sitemap.module index edf3b81a871638609de4b3a5c52f657c737bd752..dacec83fb36cb515f4fa8b4440fa08d9e445be35 100644 --- a/web/modules/simple_sitemap/simple_sitemap.module +++ b/web/modules/simple_sitemap/simple_sitemap.module @@ -33,6 +33,8 @@ function simple_sitemap_help($route_name, RouteMatchInterface $route_match) { * @param $form * @param \Drupal\Core\Form\FormStateInterface $form_state * @param $form_id + * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException + * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ function simple_sitemap_form_alter(&$form, FormStateInterface $form_state, $form_id) { @@ -80,6 +82,9 @@ function simple_sitemap_form_alter(&$form, FormStateInterface $form_state, $form * * @param $form * @param \Drupal\Core\Form\FormStateInterface $form_state + * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException + * @throws \Drupal\Component\Plugin\Exception\PluginException + * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ function simple_sitemap_entity_form_submit($form, FormStateInterface &$form_state) { @@ -94,7 +99,6 @@ function simple_sitemap_entity_form_submit($form, FormStateInterface &$form_stat // Fix for values appearing in a sub array on a commerce product entity. $values = isset($values['simple_sitemap']) ? $values['simple_sitemap'] : $values; - // Only make changes in DB if sitemap settings actually changed. if ($f->valuesChanged($form, $values)) { /** @var \Drupal\simple_sitemap\Simplesitemap $generator */ @@ -113,16 +117,12 @@ function simple_sitemap_entity_form_submit($form, FormStateInterface &$form_stat $generator->setVariants($variant); switch ($f->getEntityCategory()) { - case 'bundle': $generator->setBundleSettings($f->getEntityTypeId(), $f->getBundleName(), $settings); - if (empty($settings['index'])) { - $generator->removeEntityInstanceSettings($f->getEntityTypeId(), $f->getInstanceId()); - } break; case 'instance': - if (!$f->entityIsNew()) { + if (!$f->entityIsNew()) { // Make sure the entity is saved first for multi-step forms, see https://www.drupal.org/project/simple_sitemap/issues/3080510. $generator->setEntityInstanceSettings($f->getEntityTypeId(), $f->getInstanceId(), $settings); } break; @@ -211,6 +211,8 @@ function simple_sitemap_entity_delete(EntityInterface $entity) { * * @param string $entity_type_id * @param string $bundle + * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException + * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ function simple_sitemap_entity_bundle_delete($entity_type_id, $bundle) { @@ -225,6 +227,8 @@ function simple_sitemap_entity_bundle_delete($entity_type_id, $bundle) { * Removes settings for the removed menu. * * @param \Drupal\system\MenuInterface $menu + * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException + * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ function simple_sitemap_menu_delete(MenuInterface $menu) { diff --git a/web/modules/simple_sitemap/simple_sitemap.services.yml b/web/modules/simple_sitemap/simple_sitemap.services.yml index 1e28807b4a1ab76624eb14c6ce80b24a5b125ab5..1b6ce081ef8f3b4540a339d04e2d619d4816895b 100644 --- a/web/modules/simple_sitemap/simple_sitemap.services.yml +++ b/web/modules/simple_sitemap/simple_sitemap.services.yml @@ -40,6 +40,7 @@ services: - '@state' - '@simple_sitemap.queue' - '@simple_sitemap.logger' + - '@module_handler' simple_sitemap.queue: class: Drupal\simple_sitemap\Queue\SimplesitemapQueue diff --git a/web/modules/simple_sitemap/src/Form/FormHelper.php b/web/modules/simple_sitemap/src/Form/FormHelper.php index c0d3d56ec657425266a74bfdff3f01eadbdd355e..ca0e69e1a0bc4a2115770872f665a96421831af3 100644 --- a/web/modules/simple_sitemap/src/Form/FormHelper.php +++ b/web/modules/simple_sitemap/src/Form/FormHelper.php @@ -126,8 +126,10 @@ public function __construct( public function processForm(FormStateInterface $form_state) { $this->formState = $form_state; $this->cleanUpFormInfo(); - $this->getEntityDataFromFormEntity(); - $this->negotiateSettings(); + + if ($this->getEntityDataFromFormEntity()) { + $this->negotiateSettings(); + } return $this->supports(); } @@ -204,18 +206,18 @@ public function getInstanceId() { */ protected function supports() { - // Do not alter the form if user lacks certain permissions. - if (!$this->currentUser->hasPermission('administer sitemap settings')) { + // Do not alter the form if it is irrelevant to sitemap generation. + if (empty($this->getEntityCategory())) { return FALSE; } - // Do not alter the form if it is irrelevant to sitemap generation. - elseif (empty($this->getEntityCategory())) { + // Do not alter the form if user lacks certain permissions. + if (!$this->currentUser->hasPermission('administer sitemap settings')) { return FALSE; } // Do not alter the form if entity is not enabled in sitemap settings. - elseif (!$this->generator->entityTypeIsEnabled($this->getEntityTypeId())) { + if (!$this->generator->entityTypeIsEnabled($this->getEntityTypeId())) { return FALSE; } @@ -401,7 +403,11 @@ protected function getEntityDataFromFormEntity() { } // Menu fix. - $this->setEntityCategory(NULL === $this->getEntityCategory() && $entity_type_id === 'menu' ? 'bundle' : $this->getEntityCategory()); + $this->setEntityCategory( + NULL === $this->getEntityCategory() && $entity_type_id === 'menu' + ? 'bundle' + : $this->getEntityCategory() + ); switch ($this->getEntityCategory()) { case 'bundle': @@ -469,6 +475,8 @@ public function cleanUpFormInfo() { * * @return bool * TRUE if simple_sitemap form values have been altered by the user. + * + * @todo Make it work with variants. */ public function valuesChanged($form, array $values) { // foreach (self::$valuesToCheck as $field_name) { @@ -480,7 +488,6 @@ public function valuesChanged($form, array $values) { // // return FALSE; - //todo return TRUE; } diff --git a/web/modules/simple_sitemap/src/Plugin/simple_sitemap/SitemapGenerator/DefaultSitemapGenerator.php b/web/modules/simple_sitemap/src/Plugin/simple_sitemap/SitemapGenerator/DefaultSitemapGenerator.php index 1c95134a430d2dcb7304d8cc5d3fcb9319593752..abf6e39e6d02d20881bafb2a7a8c6e8adc6dc467 100755 --- a/web/modules/simple_sitemap/src/Plugin/simple_sitemap/SitemapGenerator/DefaultSitemapGenerator.php +++ b/web/modules/simple_sitemap/src/Plugin/simple_sitemap/SitemapGenerator/DefaultSitemapGenerator.php @@ -2,8 +2,6 @@ namespace Drupal\simple_sitemap\Plugin\simple_sitemap\SitemapGenerator; -use Symfony\Component\DependencyInjection\ContainerInterface; - /** * Class DefaultSitemapGenerator * @package Drupal\simple_sitemap\Plugin\simple_sitemap\SitemapGenerator @@ -83,8 +81,6 @@ protected function addSitemapAttributes() { * @param array $links */ protected function addLinks(array $links) { - $sitemap_variant = $this->sitemapVariant; - $this->moduleHandler->alter('simple_sitemap_links', $links, $sitemap_variant); foreach ($links as $url_data) { $this->writer->startElement('url'); $this->addUrl($url_data); diff --git a/web/modules/simple_sitemap/src/Plugin/simple_sitemap/SitemapGenerator/SitemapGeneratorBase.php b/web/modules/simple_sitemap/src/Plugin/simple_sitemap/SitemapGenerator/SitemapGeneratorBase.php index 7ca401fb6e59732803197f12cd43903dc64edd54..da9704f695212bd080d9629f8c17acc550808023 100644 --- a/web/modules/simple_sitemap/src/Plugin/simple_sitemap/SitemapGenerator/SitemapGeneratorBase.php +++ b/web/modules/simple_sitemap/src/Plugin/simple_sitemap/SitemapGenerator/SitemapGeneratorBase.php @@ -3,7 +3,6 @@ namespace Drupal\simple_sitemap\Plugin\simple_sitemap\SitemapGenerator; use Drupal\Core\Url; -use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl; use Drupal\simple_sitemap\Plugin\simple_sitemap\SimplesitemapPluginBase; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Database\Connection; @@ -346,16 +345,41 @@ public function getSitemapUrl($delta = NULL) { } /** + * Determines if the sitemap is to be a multilingual sitemap based on several + * factors. + * + * A hreflang/multilingual sitemap is only wanted if there are indexable + * languages available and if there is a language negotiation method enabled + * that is based on URL discovery. Any other language negotiation methods + * should be irrelevant, as a sitemap can only use URLs to guide to the + * correct language. + * + * @see https://www.drupal.org/project/simple_sitemap/issues/3154570#comment-13730522 + * * @return bool */ public static function isMultilingualSitemap() { + if (!\Drupal::moduleHandler()->moduleExists('language')) { + return FALSE; + } + + /** @var \Drupal\language\LanguageNegotiatorInterface $language_negotiator */ + $language_negotiator = \Drupal::service('language_negotiator'); + + $url_negotiation_method_enabled = FALSE; + foreach ($language_negotiator->getNegotiationMethods(LanguageInterface::TYPE_URL) as $method) { + if ($language_negotiator->isNegotiationMethodEnabled($method['id'])) { + $url_negotiation_method_enabled = TRUE; + break; + } + } + $has_multiple_indexable_languages = count( array_diff_key(\Drupal::languageManager()->getLanguages(), \Drupal::service('simple_sitemap.generator')->getSetting('excluded_languages', [])) ) > 1; - return $has_multiple_indexable_languages - && \Drupal::service('language_negotiator')->isNegotiationMethodEnabled(LanguageNegotiationUrl::METHOD_ID); + return $url_negotiation_method_enabled && $has_multiple_indexable_languages; } } diff --git a/web/modules/simple_sitemap/src/Plugin/simple_sitemap/SitemapGenerator/SitemapWriter.php b/web/modules/simple_sitemap/src/Plugin/simple_sitemap/SitemapGenerator/SitemapWriter.php index 36b52dbeea0ea9882d823ce38da088e3b876ea37..bfec3e9c30b1f0b0c1974caf50051408e222342b 100644 --- a/web/modules/simple_sitemap/src/Plugin/simple_sitemap/SitemapGenerator/SitemapWriter.php +++ b/web/modules/simple_sitemap/src/Plugin/simple_sitemap/SitemapGenerator/SitemapWriter.php @@ -2,7 +2,7 @@ namespace Drupal\simple_sitemap\Plugin\simple_sitemap\SitemapGenerator; -use Drupal\Core\Routing\RouteProvider; +use Drupal\Core\Routing\RouteProviderInterface; /** * Class SitemapWriter @@ -19,7 +19,7 @@ class SitemapWriter extends \XMLWriter { */ protected $routeProvider; - public function __construct(RouteProvider $route_provider) { + public function __construct(RouteProviderInterface $route_provider) { $this->routeProvider = $route_provider; } @@ -27,13 +27,21 @@ public function __construct(RouteProvider $route_provider) { * Adds the XML stylesheet to the XML page. */ public function writeXsl() { - // Use this instead of URL::fromRoute() to avoid creating a URL with the + // Using this instead of URL::fromRoute() to avoid creating a path with the // subdomain from which creation was triggered which might lead to a CORS // problem. See https://www.drupal.org/project/simple_sitemap/issues/3131672. $xsl_url = $this->routeProvider ->getRouteByName('simple_sitemap.sitemap_xsl') ->getPath(); + // The above workaround however generates an incorrect path when the site is + // located in a subdirectory, which is why the following logic adds the base + // path of the installation. + // See https://www.drupal.org/project/simple_sitemap/issues/3154494. + // All of this seems to be an over engineered way of writing 'sitemap.xsl', + // but may be useful in cases where another module alters the routes. + $xsl_url = base_path() . ltrim($xsl_url, '/'); + $this->writePI('xml-stylesheet', 'type="text/xsl" href="' . $xsl_url . '"'); } diff --git a/web/modules/simple_sitemap/src/Plugin/simple_sitemap/UrlGenerator/CustomUrlGenerator.php b/web/modules/simple_sitemap/src/Plugin/simple_sitemap/UrlGenerator/CustomUrlGenerator.php old mode 100755 new mode 100644 index 2bb641f80ba63768b1da5c683579e248bc6829da..0c31d784c3f0c913a3aefac6bfcb4e367bf8589f --- a/web/modules/simple_sitemap/src/Plugin/simple_sitemap/UrlGenerator/CustomUrlGenerator.php +++ b/web/modules/simple_sitemap/src/Plugin/simple_sitemap/UrlGenerator/CustomUrlGenerator.php @@ -113,7 +113,7 @@ protected function processDataSet($data_set) { return FALSE; } - $url_object = Url::fromUserInput($data_set['path'], ['absolute' => TRUE]); + $url_object = Url::fromUserInput($data_set['path'])->setAbsolute(); $path = $url_object->getInternalPath(); $entity = $this->entityHelper->getEntityFromUrlObject($url_object); @@ -133,7 +133,7 @@ protected function processDataSet($data_set) { ]; // Additional info useful in hooks. - if (NULL !== $entity) { + if (!empty($entity)) { $path_data['meta']['entity_info'] = [ 'entity_type' => $entity->getEntityTypeId(), 'id' => $entity->id(), diff --git a/web/modules/simple_sitemap/src/Plugin/simple_sitemap/UrlGenerator/EntityMenuLinkContentUrlGenerator.php b/web/modules/simple_sitemap/src/Plugin/simple_sitemap/UrlGenerator/EntityMenuLinkContentUrlGenerator.php old mode 100755 new mode 100644 index 921bfba00471a39768dd5cc415ef047e46fe252e..ca136153672718aab164c2e7081288509ee66779 --- a/web/modules/simple_sitemap/src/Plugin/simple_sitemap/UrlGenerator/EntityMenuLinkContentUrlGenerator.php +++ b/web/modules/simple_sitemap/src/Plugin/simple_sitemap/UrlGenerator/EntityMenuLinkContentUrlGenerator.php @@ -129,7 +129,7 @@ protected function processDataSet($data_set) { return FALSE; } - $url_object = $data_set->getUrlObject(); + $url_object = $data_set->getUrlObject()->setAbsolute(); // Do not include external paths. if ($url_object->isExternal()) { @@ -174,8 +174,6 @@ protected function processDataSet($data_set) { } } - $url_object->setOption('absolute', TRUE); - $entity = $this->entityHelper->getEntityFromUrlObject($url_object); $path_data = [ diff --git a/web/modules/simple_sitemap/src/Plugin/simple_sitemap/UrlGenerator/EntityUrlGenerator.php b/web/modules/simple_sitemap/src/Plugin/simple_sitemap/UrlGenerator/EntityUrlGenerator.php old mode 100755 new mode 100644 index efa2abfe6c720fd2572bab1c71eec59c6eae5608..7889994f8704b0c9fa2271045c6b63428083e677 --- a/web/modules/simple_sitemap/src/Plugin/simple_sitemap/UrlGenerator/EntityUrlGenerator.php +++ b/web/modules/simple_sitemap/src/Plugin/simple_sitemap/UrlGenerator/EntityUrlGenerator.php @@ -142,28 +142,21 @@ protected function processDataSet($data_set) { return FALSE; } - $entity_id = $entity->id(); - $entity_type_name = $entity->getEntityTypeId(); - $entity_settings = $this->generator ->setVariants($this->sitemapVariant) - ->getEntityInstanceSettings($entity_type_name, $entity_id); + ->getEntityInstanceSettings($entity->getEntityTypeId(), $entity->id()); if (empty($entity_settings['index'])) { return FALSE; } - $url_object = $entity->toUrl(); + $url_object = $entity->toUrl()->setAbsolute(); // Do not include external paths. if (!$url_object->isRouted()) { return FALSE; } - $path = $url_object->getInternalPath(); - - $url_object->setOption('absolute', TRUE); - return [ 'url' => $url_object, 'lastmod' => method_exists($entity, 'getChangedTime') ? date('c', $entity->getChangedTime()) : NULL, @@ -175,12 +168,32 @@ protected function processDataSet($data_set) { // Additional info useful in hooks. 'meta' => [ - 'path' => $path, + 'path' => $url_object->getInternalPath(), 'entity_info' => [ - 'entity_type' => $entity_type_name, - 'id' => $entity_id, + 'entity_type' => $entity->getEntityTypeId(), + 'id' => $entity->id(), ], ] ]; } + + /** + * @inheritdoc + * + * Make sure to clear entity cache so it does not build up resulting in a + * constant increase of memory. + * + * See https://www.drupal.org/project/simple_sitemap/issues/3170261. + */ + public function generate($data_set) { + $result = parent::generate($data_set); + + $storage = $this->entityTypeManager->getStorage($data_set['entity_type']); + if (method_exists($storage, 'resetCache')) { + $storage->resetCache([$data_set['id']]); + } + + return $result; + } + } diff --git a/web/modules/simple_sitemap/src/Plugin/simple_sitemap/UrlGenerator/EntityUrlGeneratorBase.php b/web/modules/simple_sitemap/src/Plugin/simple_sitemap/UrlGenerator/EntityUrlGeneratorBase.php old mode 100755 new mode 100644 index 7ef4e9e2e33c1f2e092b8fef23372640a54e50c2..8dd8e4281237bbc386cdc5077b13d81b832bc8e0 --- a/web/modules/simple_sitemap/src/Plugin/simple_sitemap/UrlGenerator/EntityUrlGeneratorBase.php +++ b/web/modules/simple_sitemap/src/Plugin/simple_sitemap/UrlGenerator/EntityUrlGeneratorBase.php @@ -4,7 +4,7 @@ use Drupal\simple_sitemap\Plugin\simple_sitemap\SitemapGenerator\SitemapGeneratorBase; use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\Core\Entity\ContentEntityBase; +use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Url; use Drupal\file\Entity\File; use Drupal\simple_sitemap\EntityHelper; @@ -110,9 +110,9 @@ protected function getUrlVariants(array $path_data, Url $url_object) { $alternate_urls = $this->getAlternateUrlsForDefaultLanguage($url_object); } elseif ($this->settings['skip_untranslated'] - && ($entity = $this->entityHelper->getEntityFromUrlObject($url_object)) instanceof ContentEntityBase) { + && ($entity = $this->entityHelper->getEntityFromUrlObject($url_object)) instanceof ContentEntityInterface) { - /** @var ContentEntityBase $entity */ + /** @var ContentEntityInterface $entity */ $translation_languages = $entity->getTranslationLanguages(); if (isset($translation_languages[Language::LANGCODE_NOT_SPECIFIED]) || isset($translation_languages[Language::LANGCODE_NOT_APPLICABLE])) { @@ -149,7 +149,7 @@ protected function getAlternateUrlsForDefaultLanguage(Url $url_object) { $alternate_urls = []; if ($url_object->access($this->anonUser)) { $alternate_urls[$this->defaultLanguageId] = $this->replaceBaseUrlWithCustom($url_object - ->setOption('language', $this->languages[$this->defaultLanguageId])->toString() + ->setAbsolute()->setOption('language', $this->languages[$this->defaultLanguageId])->toString() ); } @@ -157,11 +157,11 @@ protected function getAlternateUrlsForDefaultLanguage(Url $url_object) { } /** - * @param \Drupal\Core\Entity\ContentEntityBase $entity + * @param \Drupal\Core\Entity\ContentEntityInterface $entity * @param \Drupal\Core\Url $url_object * @return array */ - protected function getAlternateUrlsForTranslatedLanguages(ContentEntityBase $entity, Url $url_object) { + protected function getAlternateUrlsForTranslatedLanguages(ContentEntityInterface $entity, Url $url_object) { $alternate_urls = []; /** @var Language $language */ @@ -169,7 +169,7 @@ protected function getAlternateUrlsForTranslatedLanguages(ContentEntityBase $ent if (!isset($this->settings['excluded_languages'][$language->getId()]) || $language->isDefault()) { if ($entity->getTranslation($language->getId())->access('view', $this->anonUser)) { $alternate_urls[$language->getId()] = $this->replaceBaseUrlWithCustom($url_object - ->setOption('language', $language)->toString() + ->setAbsolute()->setOption('language', $language)->toString() ); } } @@ -188,7 +188,7 @@ protected function getAlternateUrlsForAllLanguages(Url $url_object) { foreach ($this->languages as $language) { if (!isset($this->settings['excluded_languages'][$language->getId()]) || $language->isDefault()) { $alternate_urls[$language->getId()] = $this->replaceBaseUrlWithCustom($url_object - ->setOption('language', $language)->toString() + ->setAbsolute()->setOption('language', $language)->toString() ); } } @@ -215,11 +215,11 @@ public function generate($data_set) { } /** - * @param \Drupal\Core\Entity\ContentEntityBase $entity + * @param \Drupal\Core\Entity\ContentEntityInterface $entity * * @return array */ - protected function getEntityImageData(ContentEntityBase $entity) { + protected function getEntityImageData(ContentEntityInterface $entity) { $image_data = []; foreach ($entity->getFieldDefinitions() as $field) { if ($field->getType() === 'image') { diff --git a/web/modules/simple_sitemap/src/Queue/QueueWorker.php b/web/modules/simple_sitemap/src/Queue/QueueWorker.php index 0f01394a80cc11cffdf3b4349889b56a71be58ed..562ef91d40241076bf173b110409ad56f88b7f68 100644 --- a/web/modules/simple_sitemap/src/Queue/QueueWorker.php +++ b/web/modules/simple_sitemap/src/Queue/QueueWorker.php @@ -3,13 +3,13 @@ namespace Drupal\simple_sitemap\Queue; use Drupal\Component\Utility\Timer; +use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\simple_sitemap\Plugin\simple_sitemap\SitemapGenerator\SitemapGeneratorBase; use Drupal\simple_sitemap\SimplesitemapSettings; use Drupal\simple_sitemap\SimplesitemapManager; use Drupal\Core\State\StateInterface; use Drupal\simple_sitemap\Logger; - class QueueWorker { use BatchTrait; @@ -46,6 +46,11 @@ class QueueWorker { */ protected $logger; + /** + * @var \Drupal\Core\Extension\ModuleHandlerInterface + */ + protected $moduleHandler; + /** * @var string|null */ @@ -61,6 +66,11 @@ class QueueWorker { */ protected $results = []; + /** + * @var array + */ + protected $processedResults = []; + /** * @var array */ @@ -93,35 +103,20 @@ class QueueWorker { * @param \Drupal\Core\State\StateInterface $state * @param \Drupal\simple_sitemap\Queue\SimplesitemapQueue $element_queue * @param \Drupal\simple_sitemap\Logger $logger + * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */ public function __construct(SimplesitemapSettings $settings, SimplesitemapManager $manager, StateInterface $state, SimplesitemapQueue $element_queue, - Logger $logger) { + Logger $logger, + ModuleHandlerInterface $module_handler) { $this->settings = $settings; $this->manager = $manager; $this->state = $state; $this->queue = $element_queue; $this->logger = $logger; - } - - /** - * @return $this - */ - public function deleteQueue() { - $this->queue->deleteQueue(); - SitemapGeneratorBase::purgeSitemapVariants(NULL, 'unpublished'); - $this->variantProcessedNow = NULL; - $this->generatorProcessedNow = NULL; - $this->results = []; - $this->processedPaths = []; - $this->state->set('simple_sitemap.queue_items_initial_amount', 0); - $this->state->delete('simple_sitemap.queue_stashed_results'); - $this->elementsTotal = NULL; - $this->elementsRemaining = NULL; - - return $this; + $this->moduleHandler = $module_handler; } /** @@ -305,23 +300,32 @@ protected function removeDuplicates(&$results) { */ protected function generateVariantChunksFromResults($complete = FALSE) { if (!empty($this->results)) { - $generator = $this->manager->getSitemapGenerator($this->generatorProcessedNow) - ->setSitemapVariant($this->variantProcessedNow) - ->setSettings($this->generatorSettings); + $processed_results = $this->results; + $this->moduleHandler->alter('simple_sitemap_links', $processed_results, $this->variantProcessedNow); + $this->processedResults = array_merge($this->processedResults, $processed_results); + $this->results = []; + } - if (empty($this->maxLinks) || $complete) { - $generator->generate($this->results); - $this->results = []; - } - else { - foreach (array_chunk($this->results, $this->maxLinks, TRUE) as $chunk_links) { - if (count($chunk_links) === $this->maxLinks || $complete) { - $generator->generate($chunk_links); - $this->results = array_diff_key($this->results, $chunk_links); - } + if (empty($this->processedResults)) { + return; + } + + $generator = $this->manager->getSitemapGenerator($this->generatorProcessedNow) + ->setSitemapVariant($this->variantProcessedNow) + ->setSettings($this->generatorSettings); + + if (!empty($this->maxLinks)) { + foreach (array_chunk($this->processedResults, $this->maxLinks, TRUE) as $chunk_links) { + if ($complete || count($chunk_links) === $this->maxLinks) { + $generator->generate($chunk_links); + $this->processedResults = array_diff_key($this->processedResults, $chunk_links); } } } + else { + $generator->generate($this->processedResults); + $this->processedResults = []; + } } protected function publishCurrentVariant() { @@ -334,23 +338,45 @@ protected function publishCurrentVariant() { } } + protected function resetWorker() { + $this->results = []; + $this->processedPaths = []; + $this->processedResults = []; + $this->variantProcessedNow = NULL; + $this->generatorProcessedNow = NULL; + $this->elementsTotal = NULL; + $this->elementsRemaining = NULL; + } + + /** + * @return $this + */ + public function deleteQueue() { + $this->queue->deleteQueue(); + SitemapGeneratorBase::purgeSitemapVariants(NULL, 'unpublished'); + $this->state->set('simple_sitemap.queue_items_initial_amount', 0); + $this->state->delete('simple_sitemap.queue_stashed_results'); + $this->resetWorker(); + + return $this; + } + protected function stashResults() { $this->state->set('simple_sitemap.queue_stashed_results', [ 'variant' => $this->variantProcessedNow, 'generator' => $this->generatorProcessedNow, 'results' => $this->results, + 'processed_results' => $this->processedResults, 'processed_paths' => $this->processedPaths, ]); - $this->results = []; - $this->processedPaths = []; - $this->generatorProcessedNow = NULL; - $this->variantProcessedNow = NULL; + $this->resetWorker(); } protected function unstashResults() { if (NULL !== $results = $this->state->get('simple_sitemap.queue_stashed_results')) { $this->state->delete('simple_sitemap.queue_stashed_results'); $this->results = !empty($results['results']) ? $results['results'] : []; + $this->processedResults = !empty($results['processed_results']) ? $results['processed_results'] : []; $this->processedPaths = !empty($results['processed_paths']) ? $results['processed_paths'] : []; $this->variantProcessedNow = $results['variant']; $this->generatorProcessedNow = $results['generator']; @@ -381,7 +407,9 @@ public function getQueuedElementCount($force_recount = FALSE) { * @return int */ public function getStashedResultCount() { - return count($this->state->get('simple_sitemap.queue_stashed_results', ['results' => []])['results']); + $results = $this->state->get('simple_sitemap.queue_stashed_results', []); + return (!empty($results['results']) ? count($results['results']) : 0) + + (!empty($results['processed_results']) ? count($results['processed_results']) : 0); } /** diff --git a/web/modules/simple_sitemap/src/Simplesitemap.php b/web/modules/simple_sitemap/src/Simplesitemap.php index eed94bffd9466bc0bf24369132e8c4cb09a4a2ef..a3782eda4633f4d217906bacf714a4934a9abc7b 100644 --- a/web/modules/simple_sitemap/src/Simplesitemap.php +++ b/web/modules/simple_sitemap/src/Simplesitemap.php @@ -466,8 +466,19 @@ public function setBundleSettings($entity_type_id, $bundle_name = NULL, $setting } $bundle_settings->save(); + if (empty($entity_ids = $this->entityHelper->getEntityInstanceIds($entity_type_id, $bundle_name))) { + return $this; + } + + // Delete all entity overrides in case bundle indexation is disabled. + if (empty($settings['index'])) { + $this->removeEntityInstanceSettings($entity_type_id, $entity_ids); + + return $this; + } + // Delete entity overrides which are identical to new bundle settings. - $entity_ids = $this->entityHelper->getEntityInstanceIds($entity_type_id, $bundle_name); + // todo Enclose into some sensible method. $query = $this->db->select('simple_sitemap_entity_overrides', 'o') ->fields('o', ['id', 'inclusion_settings']) ->condition('o.entity_type', $entity_type_id) @@ -491,6 +502,8 @@ public function setBundleSettings($entity_type_id, $bundle_name = NULL, $setting } } if (!empty($delete_instances)) { + + // todo Use removeEntityInstanceSettings() instead. $this->db->delete('simple_sitemap_entity_overrides') ->condition('id', $delete_instances, 'IN') ->execute(); @@ -522,7 +535,6 @@ public function setBundleSettings($entity_type_id, $bundle_name = NULL, $setting * entity type does not exist. */ public function getBundleSettings($entity_type_id = NULL, $bundle_name = NULL, $supplement_defaults = TRUE, $multiple_variants = FALSE) { - $bundle_name = NULL !== $bundle_name ? $bundle_name : $entity_type_id; $all_bundle_settings = []; @@ -595,8 +607,9 @@ public function removeBundleSettings($entity_type_id = NULL, $bundle_name = NULL ->getEditable("simple_sitemap.bundle_settings.$variant.$entity_type_id.$bundle_name")->delete(); } - $entity_ids = $this->entityHelper->getEntityInstanceIds($entity_type_id, $bundle_name); - $this->removeEntityInstanceSettings($entity_type_id, (empty($entity_ids) ? NULL : $entity_ids)); + if (!empty($entity_ids = $this->entityHelper->getEntityInstanceIds($entity_type_id, $bundle_name))) { + $this->removeEntityInstanceSettings($entity_type_id, $entity_ids); + } } else { foreach ($variants as $variant) { diff --git a/web/modules/simple_sitemap/src/SimplesitemapManager.php b/web/modules/simple_sitemap/src/SimplesitemapManager.php index 6a48d5cd71b9d6884041c7df5fea3b99b52f9694..a2fe3f50e5184afd1e38f9b7f9043d933d9181d8 100644 --- a/web/modules/simple_sitemap/src/SimplesitemapManager.php +++ b/web/modules/simple_sitemap/src/SimplesitemapManager.php @@ -135,20 +135,22 @@ public function getSitemapTypes() { */ public function getSitemapVariants($sitemap_type = NULL, $attach_type_info = TRUE) { if (NULL === $sitemap_type) { - $variants = []; + $variants_by_type = []; foreach ($this->configFactory->listAll('simple_sitemap.variants.') as $config_name) { - $config_name_parts = explode('.', $config_name); - $saved_variants = $this->configFactory->get($config_name)->get('variants'); - $saved_variants = $attach_type_info ? $this->attachSitemapTypeToVariants($saved_variants, $config_name_parts[2]) : $saved_variants; - $variants = array_merge($variants, (is_array($saved_variants) ? $saved_variants : [])); + $variants = !empty($variants = $this->configFactory->get($config_name)->get('variants')) ? $variants : []; + $variants = $attach_type_info ? $this->attachSitemapTypeToVariants($variants, explode('.', $config_name)[2]) : $variants; + $variants_by_type[] = $variants; } + $variants = array_merge([], ...$variants_by_type); } else { - $variants = $this->configFactory->get("simple_sitemap.variants.$sitemap_type")->get('variants'); - $variants = is_array($variants) ? $variants : []; + $variants = !empty($variants = $this->configFactory->get("simple_sitemap.variants.$sitemap_type")->get('variants')) ? $variants : []; $variants = $attach_type_info ? $this->attachSitemapTypeToVariants($variants, $sitemap_type) : $variants; } - array_multisort(array_column($variants, "weight"), SORT_ASC, $variants); + + // Sort variants by weight. + $variant_weights = array_column($variants, 'weight'); + array_multisort($variant_weights, SORT_ASC, $variants); return $variants; } diff --git a/web/modules/simple_sitemap/tests/src/Functional/SimplesitemapTest.php b/web/modules/simple_sitemap/tests/src/Functional/SimplesitemapTest.php index d5e18d76b497301eedc8da1072312e789f594275..1b2ad00a51ad65c000ab49e8443fdabf6c4d06ec 100644 --- a/web/modules/simple_sitemap/tests/src/Functional/SimplesitemapTest.php +++ b/web/modules/simple_sitemap/tests/src/Functional/SimplesitemapTest.php @@ -344,13 +344,7 @@ public function testSetEntityInstanceSettings() { $this->assertSession()->responseContains('<option value="never" selected="selected">never</option>'); // Test database changes. - $result = $this->database->select('simple_sitemap_entity_overrides', 'o') - ->fields('o', ['inclusion_settings']) - ->condition('o.entity_type', 'node') - ->condition('o.entity_id', $this->node->id()) - ->execute() - ->fetchField(); - $this->assertNotEmpty($result); + $this->assertEquals(1, $this->getOverridesCount('node', $this->node->id())); $this->generator->setBundleSettings('node', 'page', ['priority' => 0.1, 'changefreq' => 'never']) ->generateSitemap(QueueWorker::GENERATE_TYPE_BACKEND); @@ -370,13 +364,47 @@ public function testSetEntityInstanceSettings() { // Test if entity override has been removed from database after its equal to // its bundle settings. - $result = $this->database->select('simple_sitemap_entity_overrides', 'o') + $this->assertEquals(0, $this->getOverridesCount('node', $this->node->id())); + + // Assert that creating a new content type doesn't remove the overrides. + $this->drupalGet('node/' . $this->node->id() . '/edit'); + $this->submitForm(['index_default_node_settings' => 0], 'Save'); + $this->assertEquals(1, $this->getOverridesCount('node', $this->node->id())); + // Create a new content type. + $this->drupalGet('admin/structure/types/add'); + $this->submitForm([ + 'name' => 'simple_sitemap_type', + 'type' => 'simple_sitemap_type', + 'index_default_node_settings' => 0, + ], 'Save content type'); + // The entity override from the other content type should not be affected. + $this->assertEquals(1, $this->getOverridesCount('node', $this->node->id())); + + // Assert that removing the other content type doesn't remove the overrides. + $this->drupalGet('admin/structure/types/manage/simple_sitemap_type/delete'); + $this->submitForm([], 'Delete'); + $this->assertEquals(1, $this->getOverridesCount('node', $this->node->id())); + } + + /** + * Returns the number of entity overrides for the given entity type/ID. + * + * @param string $entity_type_id + * The entity type ID. + * @param string $entity_id + * The entity ID. + * + * @return int + * The number of overrides for the given entity type ID and entity ID. + */ + protected function getOverridesCount($entity_type_id, $entity_id) { + return $this->database->select('simple_sitemap_entity_overrides', 'o') ->fields('o', ['inclusion_settings']) - ->condition('o.entity_type', 'node') - ->condition('o.entity_id', $this->node->id()) + ->condition('o.entity_type', $entity_type_id) + ->condition('o.entity_id', $entity_id) + ->countQuery() ->execute() ->fetchField(); - $this->assertEmpty($result); } /** @@ -384,7 +412,7 @@ public function testSetEntityInstanceSettings() { */ public function testNewEntityWithIdSet() { $new_node = Node::create([ - 'nid' => rand(5, 10), + 'nid' => mt_rand(5, 10), 'type' => 'page', ]); // Assert that the form does not break if an entity has an id but is not