Commit e617dc00 authored by WalkingDexter's avatar WalkingDexter Committed by atymchuk

Initial commit for views support.

parent 1da98fd4
/**
* @file
* Views UI helpers for Simple XML Sitemap display extender.
*/
(function ($, Drupal) {
Drupal.simpleSitemapViews = {};
Drupal.behaviors.simpleSitemapViewsCheckboxify = {
attach: function attach(context, settings) {
var $button = $('[data-drupal-selector="edit-index-button"]').once('simple-sitemap-views-checkboxify');
if ($button.length) {
new Drupal.simpleSitemapViews.Checkboxifier($button[0]);
}
}
};
Drupal.behaviors.simpleSitemapViewsArguments = {
attach: function attach(context, settings) {
var $arguments = $('.indexed-arguments').once('simple-sitemap-views-arguments');
var $checkboxes = $arguments.find('input[type="checkbox"]');
if ($checkboxes.length) {
new Drupal.simpleSitemapViews.Arguments($checkboxes);
}
}
};
Drupal.simpleSitemapViews.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.simpleSitemapViews.Checkboxifier.prototype.clickHandler = function (e) {
this.$button.trigger('click').trigger('submit');
};
Drupal.simpleSitemapViews.Arguments = function ($checkboxes) {
this.$checkboxes = $checkboxes;
this.$checkboxes.on('change', $.proxy(this, 'changeHandler'));
};
Drupal.simpleSitemapViews.Arguments.prototype.changeHandler = function (e) {
var $checkbox = $(e.target), index = this.$checkboxes.index($checkbox);
$checkbox.prop('checked') ? this.check(index) : this.uncheck(index);
};
Drupal.simpleSitemapViews.Arguments.prototype.check = function (index) {
this.$checkboxes.slice(0, index).prop('checked', true);
};
Drupal.simpleSitemapViews.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_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;
}
views:
version: VERSION
js:
js/simple_sitemap.views.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:
_form: '\Drupal\simple_sitemap_views\Form\SimpleSitemapViewsForm'
_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 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 \Drupal\simple_sitemap_views\Form\SimpleSitemapViewsForm.
*/
namespace Drupal\simple_sitemap_views\Form;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\simple_sitemap\Form\SimplesitemapFormBase;
use Drupal\simple_sitemap_views\SimpleSitemapViews;
use Drupal\simple_sitemap\Form\FormHelper;
use Drupal\Core\Form\FormStateInterface;
use Drupal\simple_sitemap\Simplesitemap;
/**
* Simple XML Sitemap Views settings form.
*/
class SimpleSitemapViewsForm extends SimplesitemapFormBase {
/**
* Views sitemap data.
*
* @var \Drupal\simple_sitemap_views\SimpleSitemapViews
*/
protected $sitemapViews;
/**
* SimpleSitemapViewsForm constructor.
*
* @param \Drupal\simple_sitemap\Simplesitemap $generator
* The simple_sitemap.generator service.
* @param \Drupal\simple_sitemap\Form\FormHelper $form_helper
* Simple XML Sitemap form helper.
* @param \Drupal\simple_sitemap_views\SimpleSitemapViews $sitemap_views
* Views sitemap data.
*/
public function __construct(Simplesitemap $generator, FormHelper $form_helper, SimpleSitemapViews $sitemap_views) {
parent::__construct($generator, $form_helper);
$this->sitemapViews = $sitemap_views;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('simple_sitemap.generator'),
$container->get('simple_sitemap.form_helper'),
$container->get('simple_sitemap.views')
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'simple_sitemap_views_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['simple_sitemap_views']['#prefix'] = $this->getDonationText();
$form['simple_sitemap_views']['views'] = [
'#title' => $this->t('Sitemap views'),
'#type' => 'fieldset',
'#markup' => '<div class="description">' . $this->t('Manage views support.') . '</div>',
];
$form['simple_sitemap_views']['views']['enabled'] = [
'#type' => 'checkbox',
'#title' => $this->t('Enable views support'),
'#description' => $this->t('Sitemap settings for views can be set on the display editing pages.'),
'#default_value' => $this->sitemapViews->isEnabled(),
'#suffix' => $this->getViewsInfo(),
];
$this->formHelper->displayRegenerateNow($form['simple_sitemap_views']['views']);
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$form_state->getValue('enabled') ? $this->sitemapViews->enable() : $this->sitemapViews->disable();
parent::submitForm($form, $form_state);
// Regenerate sitemaps according to user setting.
if ($form_state->getValue('simple_sitemap_regenerate_now')) {
$this->generator->generateSitemap();
}
}
/**
* Returns information about indexed views.
*
* @return string
* An HTML string representing the output.
*/
protected function getViewsInfo() {
$indexed_views = [];
// Collect information about indexed views.
foreach ($this->sitemapViews->getIndexableViews() as $view) {
if (!isset($indexed_views[$view->id()]['label'])) {
$indexed_views[$view->id()]['label'] = $view->storage->label();
}
$indexed_views[$view->id()]['displays'][] = $view->current_display;
// Destroy a view instance.
$view->destroy();
}
// Form the output.
if (empty($indexed_views)) {
$views_info = $this->t('No displays are set to be indexed yet.');
}
else {
$views_info = '';
foreach ($indexed_views as $view_id => $view_info) {
$views_info .= '<div id="indexed-view-displays-' . $view_id . '">';
$views_info .= $this->t("<em>@view_label</em> displays set to be indexed: <em>@display_titles</em>", [
'@view_label' => ucfirst(strtolower($view_info['label'])),
'@display_titles' => implode(', ', $view_info['displays']),
]);
$views_info .= '</div>';
}
}
return $views_info;
}
}
<?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);
}
}
}
This diff is collapsed.
......@@ -14,12 +14,10 @@ simple_sitemap.variants:
route_name: simple_sitemap.settings_variants
title: 'Sitemap variants'
base_route: simple_sitemap.settings
weight: 1
weight: 2
simple_sitemap.settings_custom:
route_name: simple_sitemap.settings_custom
title: 'Custom links'
base_route: simple_sitemap.settings
weight: 2
weight: 3
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment