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

init

parents
{
"title": "Sitemap",
"summary": "Renders a sitemap for your ProcessWire powered site. Supports multi-language and multi-site. Adapted from MarkupSitemapXML.",
"version": "0.1.0",
"permanent": false,
"autoload": true,
"singular": true
}
\ No newline at end of file
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Thepixeldeveloper\Sitemap\Output;
use Thepixeldeveloper\Sitemap\Subelements\Link;
use Thepixeldeveloper\Sitemap\Url;
use Thepixeldeveloper\Sitemap\Urlset;
class MarkupSitemap extends WireData implements Module
{
/**
* LanguageSupport module name
*/
const LANGUAGE_SUPPORT_PAGE_NAMES_MODULE = 'LanguageSupportPageNames';
/**
* MarkupCache module name
*/
const MARKUP_CACHE_MODULE = 'MarkupCache';
/**
* MultiSite module name
*/
const MULTI_SITE_MODULE = 'MultiSite';
/**
* Sitemap URI
*/
const SITEMAP_URI = '/sitemap.xml';
/**
* Language
* @var string
*/
protected $lang = '';
/**
* Current request URI
* @var string
*/
protected $requestUri = '';
/**
* Page selector
* @var string
*/
protected $selector = '';
/**
* Subdomain (multi-site support)
* @var string
*/
protected $subdomain = '';
/**
* This UrlSet
* @var Urlset
*/
protected $urlSet;
/**
* Install module
* @return void
*/
public function ___install()
{
$this->createField('FieldsetOpen', 'sitemap_fieldset', [
'label' => $this->_('XML Sitemap'),
'description' => 'These options are specific to MarkupSitemap, and allow you to select whether or not this Page (and, optionally, its children) should be rendered in the sitemap.',
'icon' => 'sitemap',
'collapsed' => Inputfield::collapsedBlank,
], true);
$this->createField('FieldsetClose', 'sitemap_fieldset_END', [
'label' => $this->_('Close XML Sitemap'),
], true);
$this->createField('Checkbox', 'sitemap_ignore_page', [
'label' => $this->_('Exclude Page'),
'label2' => $this->_('Exclude this Page from being rendered in the XML sitemap'),
], true);
$this->createField('Checkbox', 'sitemap_ignore_children', [
'label' => $this->_('Exclude Children'),
'label2' => $this->_('Exclude this Page’s children from being rendered in the XML sitemap'),
'notes' => $this->_('This option is independent of the option above which, if not checked, means that only this page’s children will be excluded when this option is checked.'),
], true);
}
/**
* Uninstall module
* @return void
*/
public function ___uninstall()
{
$fields = $this->fields;
foreach (MarkupSitemapConfig::getDefaultFields() as $fieldName) {
foreach ($this->templates as $template) {
if (!$template->hasField($fieldName)) {
continue;
}
$templateFields = $template->fields;
$templateFields->remove($fieldName);
$templateFields->save();
}
$field = $fields->get($fieldName);
$field->flags = Field::flagSystemOverride;
$field->flags = 0;
$fields->delete($field);
}
}
/**
* Class constructor
*/
public function __construct()
{
$this->requestUri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : null;
}
/**
* Initiate the module
* @return void
*/
public function init()
{
// If the request is valid (/sitemap.xml)...
if ($this->isValidRequest()) {
// Add the relevant page hooks for multi-language support
// as these are not bootstrapped at the 404 event (for some reason...)
if ($this->modules->isInstalled(self::LANGUAGE_SUPPORT_PAGE_NAMES_MODULE)) {
foreach (['localHttpUrl', 'localName'] as $pageHook) {
$pageHookFunction = 'hookPage' . ucfirst($pageHook);
$this->addHook("Page::{$pageHook}", null, function ($event) use ($pageHookFunction) {
$this->modules->{self::LANGUAGE_SUPPORT_PAGE_NAMES_MODULE}->{$pageHookFunction}($event);
});
}
}
// Add the hook to process and render the sitemap.
$this->addHookBefore('ProcessPageView::pageNotFound', $this, 'render');
}
// Add a hook that moves the XML Sitemap fields to the Settings tab
$this->addHookAfter('ProcessPageEdit::buildForm', $this, 'moveSitemapFields');
}
/**
* Move sitemap fields
* @param HookEvent $event
*/
public function moveSitemapFields(HookEvent $event)
{
// Get the form
$form = $event->return;
// Loop through the sitemap fields and move them to just before
// the status field.
foreach (MarkupSitemapConfig::getDefaultFields() as $fieldName) {
$field = $form->find("name={$fieldName}")->first();
if ($field) {
$settings = $form->find("name=status")->first();
if ($settings) {
$form->remove($field);
$form->insertBefore($field, $settings);
}
}
}
}
/**
* Render the sitemap
* @param HookEvent $event
*/
public function render(HookEvent $event)
{
// Get the initial root URI.
$rootPage = $this->getRootPageUri();
// If multi-site is present and active, prepend the subdomain prefix.
if ($this->modules->isInstalled(self::MULTI_SITE_MODULE)) {
$multiSite = $this->modules->get(self::MULTI_SITE_MODULE);
if ($multiSite->subdomain) {
$rootPage = "/{$multiSite->subdomain}{$rootPage}";
}
}
// Make sure that the root page exists.
if ($this->pages->get($rootPage) instanceof NullPage) {
return;
}
// Check for cached sitemap or regenerate if it doesn't exist
$rootPageName = $this->sanitizer->pageName($rootPage);
$markupCache = $this->modules->{self::MARKUP_CACHE_MODULE};
if (!$output = $markupCache->get('MarkupSitemap', 3600)) {
$this->urlSet = new Urlset();
$this->addUrls($this->pages->get($rootPage));
$sitemapOutput = new Output();
$output = $sitemapOutput->setIndented(true)->getOutput($this->urlSet);
$markupCache->save($output);
}
header('Content-Type: text/xml', true, 200);
print $output;
exit;
}
/**
* @param $page
*/
protected function addUrls($page)
{
// Add this page
if ($page->viewable() && ($page->sitemap_ignore_page == false || $page->path === '/')) {
$url = new Url($page->httpUrl);
$url->setLastMod(date('c', $page->modified));
// Add multi-language alternates (if available)
if ($this->modules->isInstalled(self::LANGUAGE_SUPPORT_PAGE_NAMES_MODULE)) {
foreach ($this->languages as $language) {
if (!$language->isDefault() && !$page->{"status{$language->id}"}) {
continue;
}
$languageIsoName = $this->pages->get(1)->localName($language);
$alternateLink = new Link($languageIsoName, $page->localHttpUrl($language));
$url->addSubElement($alternateLink);
}
}
$this->urlSet->addUrl($url);
}
// Check for children if allowed
if ($page->sitemap_ignore_children != true) {
$children = $page->children($this->selector);
if (count($children)) {
foreach ($children as $child) {
$this->addUrls($child);
}
}
}
// Always return true
return true;
}
/**
* Given a fieldtype, name, and attributes, create and save a new Field.
* @param string $fieldType
* @param string $name
* @param array $meta
* @return Field|bool
*/
protected function createField($fieldType, $name, $meta, $system = false)
{
if ($this->fields->get($name)) {
return false;
}
// Set the initial properties
$field = new Field();
$fieldType = "Fieldtype{$fieldType}";
$field->type = $this->modules->$fieldType;
$field->name = $name;
if ($system === true) {
$field->set('flags', Field::flagSystem);
}
// Unset extra meta (already used)
unset($meta['type']);
unset($meta['name']);
// Add meta
foreach ($meta as $metaNames => $metaInfo) {
$metaNames = explode('+', $metaNames);
foreach ($metaNames as $metaName) {
$field->$metaName = $metaInfo;
}
}
$field->save();
return $field;
}
/**
* Get the root page URI
* @return string
*/
protected function getRootPageUri()
{
return (string) str_ireplace(trim($this->config->urls->root, '/'), '', $this->sanitizer->path(dirname($this->requestUri)));
}
/**
* Determine if the request is valud
* @return boolean
*/
protected function isValidRequest()
{
$valid = (bool) (
$this->requestUri !== null &&
strlen($this->requestUri) - strlen(self::SITEMAP_URI) === strrpos($this->requestUri, self::SITEMAP_URI)
);
return $valid;
}
}
<?php
class MarkupSitemapConfig extends ModuleConfig
{
/**
* Get the default system fields created by the module
* @return array
*/
public static function getDefaultFields()
{
return [
'sitemap_fieldset',
'sitemap_ignore_page',
'sitemap_ignore_children',
'sitemap_fieldset_END',
];
}
/**
* Get default configuration, automatically passed to input fields.
* @return array
*/
public function getDefaults()
{
return [
];
}
/**
* Render input fields on config Page.
* @return string
*/
public function getInputFields()
{
// Gather a list of templates
$allTemplates = $this->templates;
foreach ($allTemplates as $template) {
// exclude system fields
if ($template->flags & Template::flagSystem) {
continue;
}
$templates[] = $template;
}
if ($this->input->post->submit_save_module) {
$includedTemplates = (array) $this->input->post->includeTemplates;
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');
//add fields to template
foreach ($sitemapFields as $templateField) {
$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;
}
}
}
}
// Start inputfields
$inputfields = parent::getInputfields();
// Add the template-selector fieldset
$includeTemplatesField = $this->buildInputField('InputfieldAsmSelect', [
'name+id' => 'includeTemplates',
'label' => 'Templates with Sitemap options',
'description' => $this->_('Select which Templates (and, therefore, all their Pages) can have individual Sitemap options. Such options are saved on a per-page basis.'),
'notes' => 'If you remove any templates from this list, any data saved for Pages using those templates will be discarded when you save this configuration. Please use with caution.',
'icon' => 'cubes',
]);
foreach ($templates as $template) {
$includeTemplatesField->addOption($template->name);
}
$inputfields->add($includeTemplatesField);
return $inputfields;
}
/**
* Given a fieldtype, create, populate, and return an Inputfield
* @param string $fieldNameId
* @param array $meta
* @return Inputfield
*/
protected function buildInputField($fieldNameId, $meta)
{
$field = $this->modules->$fieldNameId;
foreach ($meta as $metaNames => $metaInfo) {
$metaNames = explode('+', $metaNames);
foreach ($metaNames as $metaName) {
$field->$metaName = $metaInfo;
}
}
return $field;
}
}
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "16a2aed5d58589c937316b07035e0b31",
"packages": [
{
"name": "thepixeldeveloper/sitemap",
"version": "4.5.2",
"source": {
"type": "git",
"url": "https://github.com/ThePixelDeveloper/Sitemap.git",
"reference": "cde221cbd76035328dbcd35caaf000ad9f7d8174"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ThePixelDeveloper/Sitemap/zipball/cde221cbd76035328dbcd35caaf000ad9f7d8174",
"reference": "cde221cbd76035328dbcd35caaf000ad9f7d8174",
"shasum": ""
},
"require": {
"php": ">=5.6.0"
},
"require-dev": {
"phpspec/phpspec": "^2.4"
},
"type": "library",
"autoload": {
"psr-4": {
"Thepixeldeveloper\\Sitemap\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mathew Davies",
"email": "thepixeldeveloper@googlemail.com",
"homepage": "http://mathew-davies.co.uk",
"role": "Developer"
}
],
"description": "XML sitemap generation",
"keywords": [
"Sitemap",
"xml"
],
"time": "2017-07-26T13:35:41+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": []
}
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit8ed7624c0f07184ac3843104617449fd::getLoader();
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
// PSR-0
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
private $missingClasses = array();
private $apcuPrefix;
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $this->prefixesPsr0);
}
return array();
}
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map