Commit 9e50dec0 authored by WalkingDexter's avatar WalkingDexter Committed by atymchuk

Issue #2834406 by OwilliwO, dksdev01, WalkingDexter, Nuuou, gbyte.co: Add XSL for human readability

parent 6b36a1fc
......@@ -18,8 +18,23 @@
},
"license": "GPL-2.0+",
"minimum-stability": "dev",
"repositories": [
{
"type": "package",
"package": {
"name": "mottie/tablesorter",
"version": "master",
"type": "drupal-library",
"dist": {
"url": "https://github.com/Mottie/tablesorter/archive/master.zip",
"type": "zip"
}
}
}
],
"require": {
"ext-xmlwriter": "*"
"ext-xmlwriter": "*",
"mottie/tablesorter": "master"
},
"extra": {
"drush": {
......@@ -29,4 +44,3 @@
}
}
}
......@@ -4,6 +4,7 @@ cron_generate_interval: 0
generate_duration: 10000
remove_duplicates: true
skip_untranslated: true
xsl: true
base_url: ''
default_variant: 'default'
custom_links_include_images: false
......
......@@ -19,6 +19,9 @@ simple_sitemap.settings:
skip_untranslated:
label: 'Skip untranslated'
type: boolean
xsl:
label: 'Include a stylesheet in the sitemaps for humans'
type: boolean
base_url:
label: 'Base URL'
type: string
......
......@@ -49,3 +49,11 @@ simple_sitemap.settings_variants:
_title: 'Simple XML Sitemap Settings'
requirements:
_permission: 'administer sitemap settings'
simple_sitemap.sitemap_xsl:
path: '/sitemap.xsl'
defaults:
_controller: '\Drupal\simple_sitemap\Controller\SimplesitemapController::getSitemapXsl'
_title: 'Sitemap XSL'
requirements:
_access: 'TRUE'
......@@ -67,4 +67,40 @@ class SimplesitemapController extends ControllerBase {
'X-Robots-Tag' => 'noindex', // Tell search engines not to index the sitemap itself.
]);
}
/**
* Returns the XML stylesheet for sitemap.
*/
public function getSitemapXsl() {
// Read the XSL content from the file.
$module_path = drupal_get_path('module', 'simple_sitemap');
$xsl_content = file_get_contents($module_path . '/xsl/simple_sitemap.xsl');
// Replace custom tokens in the XSL content with appropriate values.
$replacements = [
'[title]' => $this->t('Sitemap file'),
'[generated-by]' => $this->t('Generated by the <a href="@link">Drupal Simple XML sitemap module</a>.', ['@link' => 'https://www.drupal.org/project/simple_sitemap']),
'[number-of-sitemaps]' => $this->t('Number of sitemaps in this index'),
'[sitemap-url]' => $this->t('Sitemap URL'),
'[number-of-urls]' => $this->t('Number of URLs in this sitemap'),
'[url-location]' => $this->t('URL location'),
'[lastmod]' => $this->t('Last modification date'),
'[changefreq]' => $this->t('Change frequency'),
'[priority]' => $this->t('Priority'),
'[translation-set]' => $this->t('Translation set'),
'[images]' => $this->t('Images'),
'[jquery]' => base_path() . 'core/assets/vendor/jquery/jquery.min.js',
'[jquery-tablesorter]' => base_path() . 'libraries/tablesorter/dist/js/jquery.tablesorter.min.js',
'[xsl-js]' => base_path() . $module_path . '/xsl/simple_sitemap.xsl.js',
'[xsl-css]' => base_path() . $module_path . '/xsl/simple_sitemap.xsl.css',
];
$xsl_content = strtr($xsl_content, $replacements);
// Output the XSL content.
$response = new Response($xsl_content);
$response->headers->set('Content-type', 'application/xml; charset=utf-8');
$response->headers->set('X-Robots-Tag', 'noindex, follow');
return $response;
}
}
......@@ -237,6 +237,13 @@ class SimplesitemapSettingsForm extends SimplesitemapFormBase {
],
];
$form['simple_sitemap_settings']['settings']['xsl'] = [
'#type' => 'checkbox',
'#title' => $this->t('Include a stylesheet in the sitemaps for humans'),
'#description' => $this->t('When enabled, this will add formatting and tables with sorting to make it easier to view the XML sitemap data instead of viewing raw XML output. Search engines will ignore this.'),
'#default_value' => $this->generator->getSetting('xsl', TRUE),
];
$form['simple_sitemap_settings']['settings']['languages'] = [
'#type' => 'details',
'#title' => $this->t('Language settings'),
......@@ -363,6 +370,7 @@ class SimplesitemapSettingsForm extends SimplesitemapFormBase {
'cron_generate_interval',
'remove_duplicates',
'skip_untranslated',
'xsl',
'base_url',
'default_variant'] as $setting_name) {
$this->generator->saveSetting($setting_name, $form_state->getValue($setting_name));
......
......@@ -100,6 +100,10 @@ class DefaultSitemapGenerator extends SitemapGeneratorBase {
$this->writer->openMemory();
$this->writer->setIndent(TRUE);
$this->writer->startDocument(self::XML_VERSION, self::ENCODING);
// Add the XML stylesheet to document if necessary.
if ($this->settings['xsl']) {
$this->writer->writeXsl();
}
$this->writer->writeComment(self::GENERATED_BY);
$this->writer->startElement('urlset');
......
......@@ -148,6 +148,10 @@ abstract class SitemapGeneratorBase extends SimplesitemapPluginBase implements S
$this->writer->openMemory();
$this->writer->setIndent(TRUE);
$this->writer->startDocument(self::XML_VERSION, self::ENCODING);
// Add the XML stylesheet to document if necessary.
if ($this->settings['xsl']) {
$this->writer->writeXsl();
}
$this->writer->writeComment(self::GENERATED_BY);
$this->writer->startElement('sitemapindex');
......@@ -300,4 +304,5 @@ abstract class SitemapGeneratorBase extends SimplesitemapPluginBase implements S
$customBaseUrl = $this->settings['base_url'];
return !empty($customBaseUrl) ? $customBaseUrl : $GLOBALS['base_url'];
}
}
......@@ -2,12 +2,20 @@
namespace Drupal\simple_sitemap\Plugin\simple_sitemap\SitemapGenerator;
use XMLWriter;
use Drupal\Core\Url;
/**
* Class SitemapWriter
* @package Drupal\simple_sitemap\Plugin\simple_sitemap\SitemapGenerator
*/
class SitemapWriter extends XMLWriter {
class SitemapWriter extends \XMLWriter {
/**
* Adds the XML stylesheet to the XML page.
*/
public function writeXsl() {
$xsl_url = Url::fromRoute('simple_sitemap.sitemap_xsl')->toString();
$this->writePI('xml-stylesheet', 'type="text/xsl" href="' . $xsl_url . '"');
}
}
......@@ -193,6 +193,7 @@ class QueueWorker {
$this->generatorSettings = [
'base_url' => $this->settings->getSetting('base_url', ''),
'xsl' => $this->settings->getSetting('xsl', TRUE),
'default_variant' => $this->settings->getSetting('default_variant', NULL),
'skip_untranslated' => $this->settings->getSetting('skip_untranslated', FALSE),
'remove_duplicates' => $this->settings->getSetting('remove_duplicates', TRUE),
......
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
xmlns:sitemap="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<xsl:output method="html" encoding="UTF-8" indent="yes"/>
<!-- Root template -->
<xsl:template match="/">
<html>
<head>
<title>[title]</title>
<script type="text/javascript" src="[jquery]"/>
<script type="text/javascript" src="[jquery-tablesorter]"/>
<script type="text/javascript" src="[xsl-js]"/>
<link href="[xsl-css]" type="text/css" rel="stylesheet"/>
</head>
<body>
<h1>[title]</h1>
<xsl:choose>
<xsl:when test="//sitemap:url">
<xsl:call-template name="sitemapTable"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="sitemapIndexTable"/>
</xsl:otherwise>
</xsl:choose>
<div id="footer">
<p>[generated-by]</p>
</div>
</body>
</html>
</xsl:template>
<!-- sitemapIndexTable template -->
<xsl:template name="sitemapIndexTable">
<div id="information">
<p>[number-of-sitemaps]:
<xsl:value-of select="count(sitemap:sitemapindex/sitemap:sitemap)"/>
</p>
</div>
<table class="sitemap index">
<thead>
<tr>
<th>[sitemap-url]</th>
<th>[lastmod]</th>
</tr>
</thead>
<tbody>
<xsl:apply-templates select="sitemap:sitemapindex/sitemap:sitemap"/>
</tbody>
</table>
</xsl:template>
<!-- sitemapTable template -->
<xsl:template name="sitemapTable">
<div id="information">
<p>[number-of-urls]:
<xsl:value-of select="count(sitemap:urlset/sitemap:url)"/>
</p>
</div>
<table class="sitemap">
<thead>
<tr>
<th>[url-location]</th>
<th>[lastmod]</th>
<th>[changefreq]</th>
<th>[priority]</th>
<!-- Show this header only if xhtml:link elements are present -->
<xsl:if test="sitemap:urlset/sitemap:url/xhtml:link">
<th>[translation-set]</th>
</xsl:if>
<!-- Show this header only if image:image elements are present -->
<xsl:if test="sitemap:urlset/sitemap:url/image:image">
<th>[images]</th>
</xsl:if>
</tr>
</thead>
<tbody>
<xsl:apply-templates select="sitemap:urlset/sitemap:url"/>
</tbody>
</table>
</xsl:template>
<!-- sitemap:sitemap template -->
<xsl:template match="sitemap:sitemap">
<tr>
<td>
<xsl:variable name="sitemap_location">
<xsl:value-of select="sitemap:loc"/>
</xsl:variable>
<a href="{$sitemap_location}">
<xsl:value-of select="$sitemap_location"/>
</a>
</td>
<td>
<xsl:value-of select="sitemap:lastmod"/>
</td>
</tr>
</xsl:template>
<!-- sitemap:url template -->
<xsl:template match="sitemap:url">
<tr>
<td>
<xsl:variable name="url_location">
<xsl:value-of select="sitemap:loc"/>
</xsl:variable>
<a href="{$url_location}" rel="nofollow">
<xsl:value-of select="$url_location"/>
</a>
</td>
<td>
<xsl:value-of select="sitemap:lastmod"/>
</td>
<td>
<xsl:value-of select="sitemap:changefreq"/>
</td>
<td>
<xsl:choose>
<!-- If priority is not defined, show the default value of 0.5 -->
<xsl:when test="sitemap:priority">
<xsl:value-of select="sitemap:priority"/>
</xsl:when>
<xsl:otherwise>0.5</xsl:otherwise>
</xsl:choose>
</td>
<!-- Show this column only if xhtml:link elements are present -->
<xsl:if test="/sitemap:urlset/sitemap:url/xhtml:link">
<td>
<xsl:if test="xhtml:link">
<dl class="translation-set">
<xsl:apply-templates select="xhtml:link"/>
</dl>
</xsl:if>
</td>
</xsl:if>
<!-- Show this column only if image:image elements are present -->
<xsl:if test="/sitemap:urlset/sitemap:url/image:image">
<td>
<xsl:if test="image:image">
<ul class="images">
<xsl:apply-templates select="image:image"/>
</ul>
</xsl:if>
</td>
</xsl:if>
</tr>
</xsl:template>
<!-- xhtml:link template -->
<xsl:template match="xhtml:link">
<xsl:variable name="url_language">
<xsl:value-of select="@hreflang"/>
</xsl:variable>
<xsl:variable name="url_location">
<xsl:value-of select="@href"/>
</xsl:variable>
<dt>
<xsl:value-of select="$url_language"/>
</dt>
<dd>
<a href="{$url_location}" rel="nofollow">
<xsl:value-of select="$url_location"/>
</a>
</dd>
</xsl:template>
<!-- image:image template -->
<xsl:template match="image:image">
<xsl:variable name="image_location">
<xsl:value-of select="image:loc"/>
</xsl:variable>
<li>
<a href="{$image_location}" rel="nofollow">
<xsl:value-of select="$image_location"/>
</a>
</li>
</xsl:template>
</xsl:stylesheet>
body {
background-color: #fff;
font-family: Verdana, sans-serif;
font-size: 10pt;
}
h1 {
font-size: 1.25em;
}
table.sitemap {
background-color: #cdcdcd;
margin: 10px 0 15px;
font-size: 8pt;
width: 100%;
text-align: left;
}
table.sitemap thead tr th,
table.sitemap tfoot tr th {
background-color: #e6eeee;
border: 1px solid #fff;
font-size: 8pt;
padding: 3px;
}
table.sitemap thead tr .tablesorter-header:not(.sorter-false) {
cursor: pointer;
}
table.sitemap thead tr .tablesorter-header .tablesorter-header-inner {
position: relative;
display: inline-block;
padding-right: 15px;
}
table.sitemap tbody td {
color: #3d3d3d;
padding: 3px;
background-color: #fff;
vertical-align: top;
}
table.sitemap tbody .odd td {
background-color: #efefef;
}
table.sitemap thead tr .tablesorter-headerAsc,
table.sitemap thead tr .tablesorter-headerDesc {
background-color: #5050d3;
color: #fff;
font-style: italic;
}
table.sitemap thead tr .tablesorter-headerAsc .tablesorter-header-inner:after {
content: '\25b2';
position:absolute;
right: 0;
}
table.sitemap thead tr .tablesorter-headerDesc .tablesorter-header-inner:after {
content: '\25bc';
position:absolute;
right: 0;
}
table.sitemap tbody tr dl.translation-set {
padding: 0;
margin: 0;
}
table.sitemap tbody tr dl.translation-set dt {
text-transform: uppercase;
float: left;
padding: 0;
margin: 0 5px 0 0;
}
table.sitemap tbody tr dl.translation-set dt:after {
content: ":";
}
table.sitemap tbody tr dl.translation-set dd {
padding: 0;
margin: 0;
}
table.sitemap tbody tr ul.images {
list-style: none;
padding: 0;
margin: 0;
}
/**
* @file
* JavaScript file for sitemap.
*/
(function ($) {
'use strict';
$.tablesorter.addParser({
// Set a unique id.
id: 'changefreq',
is: function (s) {
return false;
},
format: function (s) {
switch (s) {
case 'always':
return 0;
case 'hourly':
return 1;
case 'daily':
return 2;
case 'weekly':
return 3;
case 'monthly':
return 4;
case 'yearly':
return 5;
default:
return 6;
}
},
type: 'numeric'
});
$(document).ready(function () {
// Set some location variables.
var $h1 = $('h1');
$h1.text($h1.text() + ': ' + location);
document.title = $h1.text();
var $table = $('table');
var options = {widgets: ['zebra']};
if ($table.hasClass('index')) {
// Options for sitemap index table.
options.sortList = [[0, 0]];
}
else {
// Options for sitemap table.
options.sortList = [[3, 0]];
options.headers = {
2: {sorter: 'changefreq'},
4: {sorter: false },
5: {sorter: false }
};
}
$table.tablesorter(options);
});
})(jQuery);
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