Commit da42cb77 authored by Mike Rockétt's avatar Mike Rockétt 💬
Browse files

0.3.0-beta

- alter stylesheet
- use separate class-loader
- separate methods to traits
- bind options to module-config, instead of page-fields
- use stylesheet by default
- add debug trait
- remove gitignore stuff we don't need
parent 2fd035f6
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache
*.sublime-workspace
sftp-config.json
Package Control.last-run
Package Control.ca-list
Package Control.ca-bundle
Package Control.system-ca-bundle
Package Control.cache/
Package Control.ca-certs/
Package Control.merged-ca-bundle
Package Control.user-ca-bundle
oscrypto-ca-bundle.crt
bh_unicode_properties.cache
GitHub.sublime-settings
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
Desktop.ini
$RECYCLE.BIN/
*.cab
*.msi
*.msm
*.msp
*.lnk
.phpintel/
\ No newline at end of file
<?php
wire('classLoader')->addNamespace('Rockett\Sitemap', __DIR__ . '/src/Sitemap');
wire('classLoader')->addNamespace('Rockett\Traits', __DIR__ . '/src/Traits');
\ No newline at end of file
{
"title": "Sitemap",
"version": "0.2.4",
"version": "0.3.0",
"author": "Mike Rockett",
"summary": "Renders a sitemap for your ProcessWire powered site. Supports multi-language, multi-site, and image sub-elements. Adapted from MarkupSitemapXML.",
"href": "http://github.com/rockettpw/markup-sitemap",
......
This diff is collapsed.
......@@ -10,27 +10,24 @@
* @license MIT
*/
wire('classLoader')->addNamespace('Rockett\Utilities', __DIR__ . '/src/Utilities');
require_once __DIR__ . '/ClassLoader.php';
use Rockett\Utilities\Fields;
use Rockett\Traits\FieldsTrait as BuildsFields;
class MarkupSitemapConfig extends ModuleConfig
{
use Fields;
use BuildsFields;
/**
* Get the default system fields created by the module
* Get default condifguration, automatically passed to input fields.
* @return array
*/
public static function getDefaultFields()
public function getDefaults()
{
return [
'sitemap_fieldset',
'sitemap_priority',
'sitemap_ignore_images',
'sitemap_ignore_page',
'sitemap_ignore_children',
'sitemap_fieldset_END',
// This has been turned on by default due to the fact that
// the default XML output is not rendered properly (not sure why)
'sitemap_stylesheet' => true,
];
}
......@@ -50,52 +47,11 @@ class MarkupSitemapConfig extends ModuleConfig
$templates[] = $template;
}
// If saving ...
if ($this->input->post->submit_save_module) {
// Remove sitemap cache
if ($this->removeSitemapCache()) {
$this->message($this->_('Removed sitemap cache'));
}
// Add/remove sitemap fields from templates
$includedTemplates = (array) $this->input->post->sitemap_include_templates;
foreach ($templates as $template) {
if (in_array($template->name, $includedTemplates)) {
if ($template->hasField('sitemap_fieldset')) {
continue;
} else {
$sitemapFields = self::getDefaultFields();
unset($sitemapFields[count($sitemapFields) - 1]);
foreach ($this->fields as $sitemapField) {
if (preg_match('%^sitemap_.*%Uis', $sitemapField->name)
&& !in_array($sitemapField->name, self::getDefaultFields())) {
array_push($sitemapFields, $sitemapField->name);
}
}
array_push($sitemapFields, 'sitemap_fieldset_END');
foreach ($sitemapFields as $templateField) {
if ($template->id === $this->pages->get(1)->template->id
&& in_array($templateField, ['sitemap_ignore_page',
'sitemap_ignore_children'])) {
continue;
}
$template->fields->add($this->fields->get($templateField));
}
$template->fields->save();
}
} else {
if ($template->hasField('sitemap_fieldset')) {
foreach ($template->fields as $templateField) {
if (in_array($templateField->name, self::getDefaultFields())) {
$template->fields->remove($templateField);
}
}
$template->fields->save();
} else {
continue;
}
}
}
}
// If saving, remove the sitemap cache to effect
// possible changes in configuration.
$this->input->post->submit_save_module &&
$this->removeSitemapCache() &&
$this->message($this->_('Removed sitemap cache'));
// Start inputfields
$inputfields = parent::getInputfields();
......@@ -104,10 +60,9 @@ class MarkupSitemapConfig extends ModuleConfig
$includeTemplatesField = $this->buildInputField('AsmSelect', [
'name+id' => 'sitemap_include_templates',
'label' => 'Templates with sitemap options',
'description' => $this->_('Select which templates (and, therefore, all pages assigned to those templates) can have individual sitemap options. These options allow you to set which pages and, optionally, their children should be excluded from the sitemap when it is rendered; define which page’s images should not be included in the sitemap (provided that image fields have been added below); and set an optional priority for each page.'),
'notes' => '**Please use with caution:** If you remove any templates from this list, any sitemap options saved for pages using those templates will be discarded when you save this configuration as the fields are completely removed from the assigned templates. Also note that the home page cannot be excluded from the sitemap. As such, the applicable options will not be available for the home page.',
'description' => $this->_('Select which templates (and, therefore, all pages assigned to those templates) can have individual sitemap options. These options (shown in the Settings tab of the page editor) allow you to set which pages and, optionally, their children should be excluded from the sitemap when it is rendered; define which page’s images should not be included in the sitemap (provided that image fields have been added below); and, lastly, set an optional priority for each page.'),
'notes' => $this->_("**Removal/Restoration:** Removing a template from this list will not delete any page options applicable to it. However, they will also not be read when rendering the sitemap. As such, when restoring a template to this list after having removed it, any previous options saved for a page that uses this template will be used when rendering the sitemap. The only time sitemap options are deleted is when either the page in question is completely deleted after having been trashed, or when the module is uninstalled.\n\n**A note about the home Page: ** This page cannot be excluded from the sitemap. As such, the applicable exclusion options will not be available when editing it."),
'icon' => 'cubes',
'collapsed' => Inputfield::collapsedBlank,
]);
foreach ($templates as $template) {
$includeTemplatesField->addOption($template->name, $template->get('label|name'));
......@@ -121,6 +76,7 @@ class MarkupSitemapConfig extends ModuleConfig
'label' => $this->_('Image fields'),
'description' => $this->_('If you’d like to include images in your sitemap (for somewhat enhanced Google Images support), specify the image fields you’d like MarkupSitemap to traverse and include. The sitemap will include images for every page that uses the field(s) you select below, except for pages that are set to not have their images included.'),
'icon' => 'image',
'collapsed' => Inputfield::collapsedBlank,
]);
foreach ($imageFields as $field) {
$imageFieldsField->addOption($field->name, "{$field->get('label|name')} (used in {$field->numFieldgroups()} templates)");
......@@ -128,17 +84,35 @@ class MarkupSitemapConfig extends ModuleConfig
$inputfields->add($imageFieldsField);
}
// Add the default-language iso text field
if ($this->siteUsesLanguageSupportPageNames()) {
$inputfields->add($this->buildInputField('Text', [
'name+id' => 'sitemap_default_iso',
'label' => $this->_('ISO code for default language'),
'description' => $this->_('If you’ve set your home page to not include a language ISO (default language name) via LanguageSupportPageNames **and** your home page’s default language name is empty, then you can set an ISO code here for the default language that will appear in the sitemap. This will prevent the sitemap from containing `hreflang="home"` for all default-language URLs.'),
'notes' => $this->_('Note that if your home page has a name for the default language, then this option will not take any effect.'),
'placeholder' => $this->_('Example: en'),
'icon' => 'language',
'collapsed' => Inputfield::collapsedBlank,
]));
}
// Create the stylesheet fieldset
$stylesheetFieldset = $this->buildInputField('Fieldset', [
'label' => $this->_('Stylesheet'),
'collapsed' => Inputfield::collapsedBlank,
'icon' => 'css3',
]);
// Add the stylesheet checkbox
$inputfields->add($this->buildInputField('Checkbox', [
$stylesheetFieldset->add($this->buildInputField('Checkbox', [
'name+id' => 'sitemap_stylesheet',
'label' => $this->_('Sitemap Stylesheet'),
'label2' => $this->_('Add a stylesheet to the sitemap'),
'icon' => 'css3',
'columnWidth' => '35%',
// 'label' => $this->_('Sitemap Stylesheet'),
'label' => $this->_('Add a stylesheet to the sitemap'),
]));
// Add the custom stylesheet text field
$inputfields->add($this->buildInputField('Text', [
$stylesheetFieldset->add($this->buildInputField('Text', [
'name+id' => 'sitemap_stylesheet_custom',
'label' => $this->_('Custom Stylesheet'),
'description' => $this->_('If you would like to use your own stylesheet, enter the absolute URL to its file here.'),
......@@ -146,23 +120,11 @@ class MarkupSitemapConfig extends ModuleConfig
'showIf' => 'sitemap_stylesheet=1',
'notes' => $this->_('The default stylesheet is located at **assets/sitemap-stylesheet.xsl** in the module’s directory. If you leave this field blank or your input is not a valid URL, the default will be used.'),
'icon' => 'file-o',
'columnWidth' => '65%',
'collapsed' => Inputfield::collapsedBlank,
]));
// Add the default-language iso text field
if ($this->siteUsesLanguageSupportPageNames()) {
$inputfields->add($this->buildInputField('Text', [
'name+id' => 'sitemap_default_iso',
'label' => $this->_('ISO code for default language'),
'description' => $this->_('If you’ve set your home page to not include a language ISO (default language name) via LanguageSupportPageNames **and** your home page’s default language name is empty, then you can set an ISO code here for the default language that will appear in the sitemap. This will prevent the sitemap from containing `hreflang="home"` for all default-language URLs.'),
'notes' => $this->_('Note that if your home page has a name for the default language, then this option will not take any effect.'),
'placeholder' => $this->_('en'),
'icon' => 'language',
'collapsed' => Inputfield::collapsedBlank,
]));
}
$this->config->scripts->add($this->urls->httpSiteModules . 'MarkupSitemap/assets/scripts/config.js');
// Add the stylesheet fieldset to the inputfields
$inputfields->add($stylesheetFieldset);
// Add the support-development markup field
$supportText = $this->wire('sanitizer')->entitiesMarkdown($this->_('Sitemap is proudly [open-source](http://opensource.com/resources/what-open-source) and is [free to use](https://en.wikipedia.org/wiki/Free_software) for personal and commercial projects. Please consider [making a small donation](https://rockett.pw/donate) in support of the development of MarkupSitemap and other modules.'), ['fullMarkdown' => true]);
......@@ -174,6 +136,8 @@ class MarkupSitemapConfig extends ModuleConfig
'collapsed' => Inputfield::collapsedYes,
]));
$this->config->scripts->add($this->urls->httpSiteModules . 'MarkupSitemap/assets/scripts/config.js');
return $inputfields;
}
......@@ -183,9 +147,8 @@ class MarkupSitemapConfig extends ModuleConfig
*/
protected function removeSitemapCache()
{
$cachePath = $this->config->paths->cache . 'MarkupCache/MarkupSitemap';
try {
$cachePath = $this->config->paths->cache . 'MarkupCache/MarkupSitemap';
$removed = (bool) CacheFile::removeAll($cachePath, true);
} catch (\Exception $e) {
$removed = false;
......
## Sitemap for ProcessWire
![Shield: Version = 0.2.4-beta](https://img.shields.io/badge/version-0.2.4_beta-orange.svg?style=flat-square) ![Shield: Version = 0.2.4](https://img.shields.io/badge/requires_ProcessWire-2.8+-green.svg?style=flat-square) ![Shield: License = MIT](https://img.shields.io/github/license/rockettpw/markup-sitemap.svg?style=flat-square)
![Shield: Tagged Release](https://img.shields.io/github/release/rockettpw/markup-sitemap.svg?maxAge=7200&style=flat-square) ![Shield: Status Beta](https://img.shields.io/badge/status-beta-orange.svg?style=flat-square) ![Shield: Requires ProcessWire Versions](https://img.shields.io/badge/requires-ProcessWire--2.8.16/3.0.16+-green.svg?style=flat-square) ![Shield: License = MIT](https://img.shields.io/github/license/rockettpw/markup-sitemap.svg?style=flat-square)
An upgrade to MarkupSitemapXML by Pete, MarkupSitemap adds multi-language support using the built-in LanguageSupportPageNames. Where multi-language pages are available, they are added to the sitemap by means of an alternate link in that page’s `<url>`. Support for listing images in the sitemap on a page-by-page basis and using a sitemap stylesheet are also added.
......
......@@ -17,6 +17,7 @@
<xsl:if test="sitemap:sitemapindex">Index</xsl:if>
</title>
<link rel="stylesheet" href="https://unpkg.com/tachyons@4.6.1/css/tachyons.min.css"/>
<style>td{vertical-align:top}</style>
</head>
<body class="ph3 pb3 mid-gray">
<header class="mw8 pv4 center">
......@@ -111,17 +112,14 @@
<xsl:template match="sitemap:urlset">
<div class="mw8 center">
<div class="overflow-auto">
<table class="w-100 f6 b--silver ba bw1" cellspacing="0">
<thead class="bg-silver">
<table class="w-100 f6 b--light-silver ba bw1" cellspacing="0">
<thead class="bg-light-silver">
<tr>
<th class="pa3 fw6 tl dark-gray" style="width:60px"></th>
<th class="pa3 fw6 tl dark-gray">URL</th>
<xsl:if test="sitemap:url/sitemap:changefreq">
<th class="pa3 fw6 tr dark-gray" style="width:130px">Change Freq.</th>
</xsl:if>
<xsl:if test="sitemap:url/sitemap:priority">
<th class="pa3 fw6 tr dark-gray" style="width:90px">Priority</th>
</xsl:if>
<xsl:if test="sitemap:url/sitemap:lastmod">
<th class="pa3 fw6 tr dark-gray" style="width:200px">Last Modified</th>
</xsl:if>
......@@ -141,16 +139,20 @@
</td>
<td class="pa3 bb b--silver">
<p>
<a href="{$loc}" class="link blue">
<a href="{$loc}" class="f5 link blue b">
<xsl:value-of select="sitemap:loc"/>
</a>
<xsl:if test="sitemap:priority">
<small class="dib ml2 mr2 ph1 pv1 tracked lh-solid white bg-light-blue br-pill">
Priority: <xsl:value-of select="sitemap:priority"/>
</small>
</xsl:if>
</p>
<xsl:apply-templates select="xhtml:*"/>
<xsl:apply-templates select="image:*"/>
<xsl:apply-templates select="video:*"/>
</td>
<xsl:apply-templates select="sitemap:changefreq"/>
<xsl:apply-templates select="sitemap:priority"/>
<xsl:if test="sitemap:lastmod">
<td class="pa3 tr bb b--silver">
<xsl:value-of select="concat(substring(sitemap:lastmod, 0, 11), concat(' ', substring(sitemap:lastmod, 12, 5)), concat(' ', substring(sitemap:lastmod, 20, 6)))"/>
......@@ -184,19 +186,19 @@
</a>
<xsl:if test="@hreflang">
<small class="dib mr2 ph1 pv1 tracked lh-solid white bg-silver br-pill">
<small class="dib mr2 ph1 pv1 tracked lh-solid white bg-green br-pill">
<xsl:value-of select="@hreflang"/>
</small>
</xsl:if>
<xsl:if test="@rel">
<small class="dib mr2 ph2 pv1 tracked lh-solid white bg-silver br-pill">
<small class="dib mr2 ph2 pv1 tracked lh-solid white bg-light-silver br-pill">
<xsl:value-of select="@rel"/>
</small>
</xsl:if>
<xsl:if test="@media">
<small class="dib mr2 ph2 pv1 tracked lh-solid white bg-silver br-pill">
<small class="dib mr2 ph2 pv1 tracked lh-solid white bg-light-silver br-pill">
<xsl:value-of select="@media"/>
</small>
</xsl:if>
......@@ -218,7 +220,7 @@
</a>
<xsl:if test="image:license">
<small>
<a href="{$license_loc}" class="dib mr2 ph2 pv1 tracked lh-solid link white bg-silver hover-bg-blue br-pill">license</a>
<a href="{$license_loc}" class="dib mr2 ph2 pv1 tracked lh-solid link white bg-light-silver hover-bg-blue br-pill">license</a>
</small>
</xsl:if>
<xsl:if test="image:caption">
......@@ -256,7 +258,7 @@
</xsl:choose>
</a>
<small>
<a href="{$thumb_loc}" class="dib mr2 ph2 pv1 tracked lh-solid link white bg-silver hover-bg-blue br-pill">thumb</a>
<a href="{$thumb_loc}" class="dib mr2 ph2 pv1 tracked lh-solid link white bg-light-silver hover-bg-blue br-pill">thumb</a>
</small>
<xsl:if test="video:title">
<span class="i gray">
......
<?php
/**
* Sitemap builder trait. Contains all methods needed for
* putting a new sitemap together.
*
* @author Mike Rockett
* @license MIT
*/
namespace Rockett\Traits;
use Rockett\Sitemap\Elements\Url;
use Rockett\Sitemap\Elements\Urlset;
use Rockett\Sitemap\Output;
use Rockett\Sitemap\SubElements\Image;
use Rockett\Sitemap\SubElements\Link;
trait BuilderTrait
{
/**
* Current UrlSet
*
* @var Urlset
*/
protected $urlSet;
/**
* Add alternative languges, including current.
* @param Page $page
* @param Url $url
*/
protected function addAltLanguages($page, $url)
{
foreach ($this->languages as $altLanguage) {
if ($this->pageLanguageInvalid($altLanguage, $page)) {
continue;
}
if ($altLanguage->isDefault()
&& $this->pages->get(1)->name === 'home'
&& !$this->modules->LanguageSupportPageNames->useHomeSegment
&& !empty($this->sitemap_default_iso)) {
$languageIsoName = $this->sitemap_default_iso;
} else {
$languageIsoName = $this->pages->get(1)->localName($altLanguage);
}
$url->addSubElement(new Link($languageIsoName, $page->localHttpUrl($altLanguage)));
}
}
/**
* Generate an image tag for the current image in the loop
* @param Pageimage $image
* @param Language $language
* @return Image
*/
protected function addImage($image, $language = null)
{
$locImage = new Image($image->httpUrl);
foreach (self::IMAGE_FIELDS as $imageMetaMethod => $imageMetaValues) {
foreach (explode('|', $imageMetaValues) as $imageMetaValue) {
if ($language != null && !$language->isDefault() && $image->{"$imageMetaValue{$language->id}"}) {
$imageMetaValue .= $language->id;
}
if ($image->$imageMetaValue) {
if ($imageMetaMethod === 'License') {
// Skip invalid licence URLs
if (!filter_var($image->$imageMetaValue, FILTER_VALIDATE_URL)) {
continue;
}
}
$locImage->{"set{$imageMetaMethod}"}($image->$imageMetaValue);
}
}
}
return $locImage;
}
/**
* Add images to the current Url
* @param Url $url
* @param Language $language
*/
protected function addImages($page, $url, $language = null)
{
// Loop through declared image fields and skip non image fields
if ($this->sitemap_image_fields) {
foreach ($this->sitemap_image_fields as $imageFieldName) {
$page->of(false);
$imageField = $page->$imageFieldName;
if ($imageField) {
foreach ($imageField as $image) {
if ($image instanceof Pageimage) {
$url->addSubElement($this->addImage($image, $language));
}
}
}
}
}
}
/**
* Recursively add pages in each language with
* alternate language and image sub-elements.
* @param $page
* @return void
*/
protected function addPages($page)
{
// Get the saved options for this page
$pageSitemapOptions = $this->modules->getConfig($this, "o{$page->id}");
// If the page is viewable and not excluded or we’re working with the root page,
// begin generating the sitemap by adding pages recursively. (Root is always added.)
if ($page->viewable() && ($page->path === '/' || !$pageSitemapOptions['excludes']['page'])) {
// If language support is enabled, then we need to loop through each language
// to generate <loc> for each language with all alternates, including the
// current language. Then add image references with multi-language support.
if ($this->siteUsesLanguageSupportPageNames()) {
foreach ($this->languages as $language) {
if ($this->pageLanguageInvalid($language, $page) || !$page->viewable($language)) {
continue;
}
$url = new Url($page->localHttpUrl($language));
$url->setLastMod(date('c', $page->modified));
$this->addAltLanguages($page, $url);
if ($pageSitemapOptions['priority']) {
$url->setPriority($this->formatPriorityFloat($pageSitemapOptions['priority']));
}
if (!$pageSitemapOptions['excludes']['images']) {
$this->addImages($page, $url, $language);
}
$this->urlSet->addUrl($url);
}
} else {
// If multi-language support is not enabled, then we only need to
// add the current URL to a new <loc>, along with images.
$url = new Url($page->httpUrl);
$url->setLastMod(date('c', $page->modified));
if ($pageSitemapOptions['priority']) {
$url->setPriority($this->formatPriorityFloat($pageSitemapOptions['priority']));
}
if (!$pageSitemapOptions['excludes']['images']) {
$this->addImages($page, $url);
}
$this->urlSet->addUrl($url);
}
}
// Check for children, if allowed
// * Recursive process
if (!$pageSitemapOptions['excludes']['children']) {
$children = $page->children($this->selector);
if (count($children)) {
foreach ($children as $child) {
$this->addPages($child);
}
}
}
}
/**
* Build a new sitemap (called when cache doesn't have one or we're debugging)
* @return string
*/
protected function buildNewSitemap($rootPage)
{
$this->urlSet = new Urlset();
$this->addPages($this->pages->get($rootPage));
$sitemapOutput = new Output();
if ($this->sitemap_stylesheet) {
$sitemapOutput->addProcessingInstruction(
'xml-stylesheet',
'type="text/xsl" href="' . $this->getStylesheetUrl() . '"'
);
}
return $sitemapOutput->setIndented(true)->getOutput($this->urlSet);
}
/**
* If using a stylesheet, return its absolute Url\
* @return string
*/
protected function getStylesheetUrl()
{
if ($this->sitemap_stylesheet_custom
&& filter_var($this->sitemap_stylesheet_custom, FILTER_VALIDATE_URL)) {
return $this->sitemap_stylesheet_custom;
}
return $stylesheetPath = $this->urls->httpSiteModules . 'MarkupSitemap/assets/sitemap-stylesheet.xsl';
}
}
<?php
/**
* Debug trait. Used to dump things
* during debugging.
*
* @author Mike Rockett
* @license MIT
*/
namespace Rockett\Traits;
trait DebugTrait
{
/**
* Dump vars and die.
*
* @param mixed $mixed The vars to dump
* @return void
*/
protected function dd()
{
$this->dump(func_get_args()) && die;
}
/**
* Dump vars.
*
* @param mixed $mixed The vars to dump
* @return void
*/
protected function dump()
{
$this->header();
array_map(
function ($mixed) {
var_dump($mixed);
}, func_get_args()
);
return true;
}
/**
* Prepare the content-type header
*
* @return void
*/
protected function header()
{
$header = 'Content-Type: text/plain';
if (!$this->headerPrepared($header)) {
header($header);
$this->timestamp = -microtime(true);
}
}
/**
* Determine if a header has been prepared.
*
* @param $header
* @return bool