Commit de84092c authored by gbyte.co's avatar gbyte.co

Fix merge conflicts

parents 9830e2d9 0941e2a5
views.display_extender.simple_sitemap_display_extender:
type: views_display_extender
mapping:
index:
label: 'Index'
type: boolean
variant:
label: 'Sitemap variant'
type: string
priority:
label: 'Priority'
type: string
changefreq:
label: 'Change frequency'
type: string
arguments:
label: 'Indexed arguments'
type: sequence
sequence:
type: string
max_links:
label: 'Max links'
type: integer
/**
* @file
* Views UI helpers for Simple XML Sitemap display extender.
*/
(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'));
};
Drupal.simpleSitemapViewsUi.Checkboxifier.prototype.clickHandler = function () {
this.$button.trigger('click').trigger('submit');
};
Drupal.simpleSitemapViewsUi.Arguments = function ($checkboxes) {
this.$checkboxes = $checkboxes;
this.$checkboxes.on('change', $.proxy(this, 'changeHandler'));
};
Drupal.simpleSitemapViewsUi.Arguments.prototype.changeHandler = function (e) {
var $checkbox = $(e.target), index = this.$checkboxes.index($checkbox);
$checkbox.prop('checked') ? this.check(index) : this.uncheck(index);
};
Drupal.simpleSitemapViewsUi.Arguments.prototype.check = function (index) {
this.$checkboxes.slice(0, index).prop('checked', true);
};
Drupal.simpleSitemapViewsUi.Arguments.prototype.uncheck = function (index) {
this.$checkboxes.slice(index).prop('checked', false);
};
})(jQuery, Drupal);
\ No newline at end of file
name: 'Simple XML Sitemap (Views)'
type: module
description: 'Provides integration of the Simple XML Sitemap module with the Views module.'
configure: simple_sitemap.settings_views
package: SEO
core: 8.x
dependencies:
- simple_sitemap:simple_sitemap
- drupal:views
<?php
/**
* @file
* Install and uninstall hooks for the simple_sitemap_views module.
*/
/**
* Implements hook_install().
*/
function simple_sitemap_views_install() {
// Enable views display extender plugin.
\Drupal::service('simple_sitemap.views')->enable();
}
/**
* Implements hook_uninstall().
*/
function simple_sitemap_views_uninstall() {
// Disable views display extender plugin.
\Drupal::service('simple_sitemap.views')->disable();
}
/**
* Implements hook_schema().
*/
function simple_sitemap_views_schema() {
$schema['simple_sitemap_views'] = [
'description' => 'Index of argument values for view pages.',
'fields' => [
'id' => [
'type' => 'serial',
'not null' => TRUE,
'description' => 'Primary Key: Unique ID for argument values.',
],
'view_id' => [
'type' => 'varchar_ascii',
'not null' => TRUE,
'default' => '',
'length' => 128,
'description' => 'The ID of the view.',
],
'display_id' => [
'type' => 'varchar_ascii',
'not null' => TRUE,
'default' => '',
'length' => 128,
'description' => 'The ID of the view display.',
],
'arguments_ids' => [
'type' => 'varchar',
'not null' => TRUE,
'default' => '',
'length' => 1024,
'description' => 'A string representation of the set of argument identifiers.',
],
'arguments_values' => [
'type' => 'varchar',
'not null' => TRUE,
'default' => '',
'length' => 1024,
'description' => 'A string representation of the set of argument values.',
],
],
'primary key' => ['id'],
'indexes' => [
'view' => ['view_id'],
'display' => ['view_id', 'display_id'],
'arguments_ids' => ['view_id', 'display_id', 'arguments_ids'],
],
];
return $schema;
}
viewsUi:
version: VERSION
js:
js/simple_sitemap.viewsUi.js: {}
dependencies:
- core/jquery
- core/drupal
- core/jquery.once
simple_sitemap.settings_views:
route_name: simple_sitemap.settings_views
title: 'Sitemap views'
base_route: simple_sitemap.settings
weight: 1
<?php
/**
* @file
* Contains simple_sitemap_views.module.
*/
/**
* Implements hook_cron().
*/
function simple_sitemap_views_cron() {
// Create tasks in the garbage collection queue.
\Drupal::service('simple_sitemap.views')->executeGarbageCollection();
}
/**
* Implements hook_simple_sitemap_sitemap_types_alter().
*/
function simple_sitemap_views_simple_sitemap_sitemap_types_alter(array &$sitemap_types) {
// Add a 'views' UrlGenerator plugin to the default hreflang sitemap type.
if (isset($sitemap_types['default_hreflang'])) {
$sitemap_types['default_hreflang']['urlGenerators'][] = 'views';
}
}
simple_sitemap.settings_views:
path: '/admin/config/search/simplesitemap/views'
defaults:
_controller: '\Drupal\simple_sitemap_views\Controller\SimpleSitemapViewsController::content'
_title: 'Simple XML Sitemap Settings'
requirements:
_permission: 'administer sitemap settings'
services:
simple_sitemap.views:
class: Drupal\simple_sitemap_views\SimpleSitemapViews
arguments: ['@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']
tags:
- {name: 'event_subscriber'}
<?php
/**
* @file
* Contains \Drupal\simple_sitemap_views\Controller\SimpleSitemapViewsController.
*/
namespace Drupal\simple_sitemap_views\Controller;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\simple_sitemap_views\SimpleSitemapViews;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Url;
/**
* Controller for Simple XML Sitemap Views admin page.
*/
class SimpleSitemapViewsController extends ControllerBase {
/**
* Views sitemap data.
*
* @var \Drupal\simple_sitemap_views\SimpleSitemapViews
*/
protected $sitemapViews;
/**
* SimpleSitemapViewsController constructor.
*
* @param \Drupal\simple_sitemap_views\SimpleSitemapViews $sitemap_views
* Views sitemap data.
*/
public function __construct(SimpleSitemapViews $sitemap_views) {
$this->sitemapViews = $sitemap_views;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('simple_sitemap.views')
);
}
/**
* Builds a listing of indexed views displays.
*
* @return array
* A render array.
*/
public function content() {
$table = [
'#type' => 'table',
'#header' => [
$this->t('View'),
$this->t('Display'),
$this->t('Arguments'),
$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']),
];
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];
// 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' => [
'display_edit' => [
'title' => $this->t('Edit'),
'url' => $display_edit_url,
],
],
];
}
// Show information about indexed displays.
$build['indexed_displays'] = $table;
return $build;
}
}
<?php
/**
* @file
* Contains views arguments collector.
*/
namespace Drupal\simple_sitemap_views\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\PostResponseEvent;
use Drupal\simple_sitemap_views\SimpleSitemapViews;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Collect information about views arguments.
*/
class ArgumentCollector implements EventSubscriberInterface {
/**
* View entities storage.
*
* @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface
*/
protected $viewStorage;
/**
* Views sitemap data.
*
* @var \Drupal\simple_sitemap_views\SimpleSitemapViews
*/
protected $sitemapViews;
/**
* The currently active route match object.
*
* @var \Drupal\Core\Routing\RouteMatchInterface
*/
protected $routeMatch;
/**
* ArgumentCollector constructor.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* Entity type manager.
* @param \Drupal\simple_sitemap_views\SimpleSitemapViews $sitemap_views
* Views sitemap data.
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
* The currently active route match object.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, SimpleSitemapViews $sitemap_views, RouteMatchInterface $route_match) {
$this->viewStorage = $entity_type_manager->getStorage('view');
$this->sitemapViews = $sitemap_views;
$this->routeMatch = $route_match;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events[KernelEvents::TERMINATE] = 'onTerminate';
return $events;
}
/**
* Collect information about views arguments.
*
* @param \Symfony\Component\HttpKernel\Event\PostResponseEvent $event
* Object of event after a response was sent.
*/
public function onTerminate(PostResponseEvent $event) {
// Only successful requests are interesting.
// Collect information about arguments only if views support is enabled.
if (!$event->getResponse()->isSuccessful() || !$this->sitemapViews->isEnabled()) {
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();
}
}
/**
* Get view arguments from current route.
*
* @return array
* View arguments array.
*/
protected function getViewArgumentsFromRoute() {
// The code of this function is taken in part from the view page controller
// method (Drupal\views\Routing\ViewPageController::handle()).
$route = $this->routeMatch->getRouteObject();
$map = $route->hasOption('_view_argument_map') ? $route->getOption('_view_argument_map') : [];
$args = [];
foreach ($map as $attribute => $parameter_name) {
$parameter_name = isset($parameter_name) ? $parameter_name : $attribute;
if (($arg = $this->routeMatch->getRawParameter($parameter_name)) !== NULL) {
$args[] = $arg;
}
}
return $args;
}
}
<?php
/**
* @file
* Contains queue worker for garbage collection.
*/
namespace Drupal\simple_sitemap_views\Plugin\QueueWorker;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\simple_sitemap_views\SimpleSitemapViews;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Database\Query\Condition;
use Drupal\Core\Queue\QueueWorkerBase;
/**
* Executes garbage collection in the simple_sitemap_views table.
*
* @QueueWorker(
* id = "simple_sitemap.views.garbage_collector",
* title = @Translation("Garbage collection in the simple_sitemap_views table"),
* cron = {"time" = 30}
* )
*/
class GarbageCollector extends QueueWorkerBase implements ContainerFactoryPluginInterface {
/**
* View entities storage.
*
* @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface
*/
protected $viewStorage;
/**
* Views sitemap data.
*
* @var \Drupal\simple_sitemap_views\SimpleSitemapViews
*/
protected $sitemapViews;
/**
* GarbageCollector constructor.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* Entity type manager.
* @param \Drupal\simple_sitemap_views\SimpleSitemapViews $sitemap_views
* Views sitemap data.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, SimpleSitemapViews $sitemap_views) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->viewStorage = $entity_type_manager->getStorage('view');
$this->sitemapViews = $sitemap_views;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager'),
$container->get('simple_sitemap.views')
);
}
/**
* {@inheritdoc}
*/
public function processItem($data) {
$view_id = $data['view_id'];
/** @var \Drupal\views\ViewEntityInterface $view_entity */
$view_entity = $this->viewStorage->load($view_id);
$display_ids = [];
// 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;
}
// 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');
$condition->condition('view_id', $view_id);
$condition->condition('display_id', $display_id);
$condition->condition('arguments_ids', $args_ids, 'NOT IN');
$this->sitemapViews->removeArgumentsFromIndex($condition);
// 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, '>');
$this->sitemapViews->removeArgumentsFromIndex($condition);
}
}
}
// Delete records about view displays that do not exist or are disabled.
if (!empty($display_ids)) {
$condition = new Condition('AND');
$condition->condition('view_id', $view_id);
$condition->condition('display_id', $display_ids, 'NOT IN');
$this->sitemapViews->removeArgumentsFromIndex($condition);
}
// Destroy a view instance.
$view->destroy();
}
// Delete records about the view, if it does not exist, is disabled or it
// does not have a display whose arguments are indexed.
if (empty($display_ids)) {
$condition = new Condition('AND');
$condition->condition('view_id', $view_id);
$this->sitemapViews->removeArgumentsFromIndex($condition);
}
}
}
<?php
/**
* @file
* Contains Views URL generator.
*/
namespace Drupal\simple_sitemap_views\Plugin\simple_sitemap\UrlGenerator;
use Drupal\simple_sitemap\Plugin\simple_sitemap\UrlGenerator\EntityUrlGeneratorBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\simple_sitemap_views\SimpleSitemapViews;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\Core\Database\Query\Condition;
use Drupal\simple_sitemap\Simplesitemap;
use Drupal\simple_sitemap\EntityHelper;
use Drupal\simple_sitemap\Logger;
use Drupal\views\Views;
use Drupal\Core\Url;
/**
* Views URL generator plugin.
*
* @UrlGenerator(
* id = "views",
* label = @Translation("Views URL generator"),
* description = @Translation("Generates URLs for views."),
* )
*/
class ViewsUrlGenerator extends EntityUrlGeneratorBase {
/**
* Views sitemap data.
*
* @var \Drupal\simple_sitemap_views\SimpleSitemapViews
*/
protected $sitemapViews;
/**
* The route provider.
*
* @var \Drupal\Core\Routing\RouteProviderInterface
*/
protected $routeProvider;
/**
* ViewsUrlGenerator constructor.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\simple_sitemap\Simplesitemap $generator
* The simple_sitemap.generator service.
* @param \Drupal\simple_sitemap\Logger $logger
* The simple_sitemap.logger service.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\simple_sitemap\EntityHelper $entity_helper
* The simple_sitemap.entity_helper service.
* @param \Drupal\simple_sitemap_views\SimpleSitemapViews $sitemap_views
* Views sitemap data.
* @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
* The route provider.
*/
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
Simplesitemap $generator,
Logger $logger,
LanguageManagerInterface $language_manager,
EntityTypeManagerInterface $entity_type_manager,
EntityHelper $entity_helper,
SimpleSitemapViews $sitemap_views,
RouteProviderInterface $route_provider
) {
parent::__construct(
$configuration,
$plugin_id,
$plugin_definition,
$generator,
$logger,
$language_manager,
$entity_type_manager,
$entity_helper
);
$this->sitemapViews = $sitemap_views;
$this->routeProvider = $route_provider;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,