Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
231 lines (193 sloc) 8.75 KB
<?php
class MarkupSitemapXML extends WireData implements Module, ConfigurableModule
{
public $cacheTime;
/**
* Provide information about this module to ProcessWire
*
*/
public static function getModuleInfo()
{
return array(
'title' => 'Markup Sitemap XML',
'summary' => 'Generates an XML sitemap at yoursite.com/sitemap.xml for use with Google Webmaster Tools etc.',
'href' => 'http://processwire.com/talk/index.php/topic,867.0.html',
'version' => 126,
'permanent' => false,
'autoload' => true,
'singular' => true,
);
}
/**
* Add the hook
*
*/
public function init()
{
$this->cacheTime = 3600;
$urlParams = '';
// load js only on this page
if (wire('input')->get('name') == $this->className) {
// add flag to js config to process with module js file
if (wire('session')->MarkupSitemapXML_generateSitemap == 1) {
wire('config')->js("MarkupSitemapXML_generateSitemap", true);
}
// save generateSitemap request to session no prevent redirect loss on submit
if (wire('input')->post('submit_save_module')) {
wire('session')->MarkupSitemapXML_generateSitemap = 1;
} else {
wire('session')->remove('MarkupSitemapXML_generateSitemap');
}
$this->config->scripts->add($this->config->urls->siteModules . 'MarkupSitemapXML/MarkupSitemapXML.js');
}
if (wire('input')->get('nocache') == 1) {
$this->cacheTime = 0;
$urlParams = '?nocache=1';
}
// Intercept a request for an URL ending in sitemap.xml and output
if (isset($_SERVER['REQUEST_URI']) && strlen($_SERVER['REQUEST_URI']) - strlen('/sitemap.xml' . $urlParams) === strrpos($_SERVER['REQUEST_URI'], '/sitemap.xml' . $urlParams)) {
$this->addHookBefore("ProcessPageView::pageNotFound", $this, "renderSitemap");
}
}
public static function getModuleConfigInputfields(array $data)
{
$inputfields = new InputfieldWrapper();
// add exclude list field (textarea)
$field = wire('modules')->get('InputfieldTextarea');
$field->name = 'sitemap_exclude_list';
$field->label = __("Exclude list");
// $field->value = array_key_exists('sitemap_exclude_list', $data) ? $data['sitemap_exclude_list'] : '';
$field->description = __('Matching pages will be excluded from the sitemap. Add one selector per line.');
$field->notes = __('Examples: "title=My Page Title" or "template=my-template" or "parent.path=/my-page/" (without quotes)');
if (isset($data['sitemap_exclude_list'])) $field->value = $data['sitemap_exclude_list'];
$inputfields->add($field);
return $inputfields;
}
public function renderSitemap(HookEvent $event)
{
//$event->replace = true;
$lang = '';
$this->pageselector = '';
$langname = ''; // for LanguageLocalizedUrl
$subdomain = ''; // for Multisite
// set startpage according to request (sitemap.xml spec says that sitemap
// should only contain pages below it's root page in page tree)
// Fix #11 by FlipZoomMedia | David Karich
$startpage = str_ireplace(trim(wire('config')->urls->root, '/'), '', $this->sanitizer->path(dirname($_SERVER['REQUEST_URI'])));
// Multisite requires minor URL-related tweak
if (wire("modules")->isInstalled("Multisite")) {
$multisite = wire("modules")->get("Multisite");
if ($multisite->subdomain) {
$startpage = "/" . $multisite->subdomain . $startpage;
}
}
// make sure that page used as root for sitemap actually exists
if ($this->pages->get($startpage) instanceof NullPage) return;
// support for LanguageLocalizedURL language module
if (wire("modules")->isInstalled("LanguageLocalizedURL")) {
$llu = wire("modules")->get("LanguageLocalizedURL");
$langname = $this->page->name;
$lang = ($llu->defaultLang == $langname) ? 'default' : $langname;
$langpage = $this->page;
// get the field name for published language from the modules settings
$publishedfield_name = $llu->publishedPageField ? $llu->publishedPageField : 'language_published';
// add a selector to find children pages when generating sitemap list
$this->pageselector = "$publishedfield_name=$langpage->id";
//set user language so the module will spit out language localized urls
$this->user->language = $this->languages->get($lang);
}
// Check for the cached sitemap, else generate and cache a fresh sitemap
$startpagestr = $this->sanitizer->pageName($startpage);
$cache = wire('modules')->get("MarkupCache");
if (!$output = $cache->get("MarkupSitemapXML$startpagestr$langname", $this->cacheTime)) {
$output = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
$output .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
$output .= $this->sitemapListPage(wire('pages')->get($startpage));
$output .= "\n</urlset>";
$cache->save($output);
}
header("Content-Type: text/xml", true, 200);
echo $output;
exit();
}
/**
* Check if Page matches user-entered exclude selector list
*
* @param $page
* @return bool true if match found
*
*/
public function isPageExcluded($page)
{
// get module settings
$configData = wire('modules')->getModuleConfigData($this);
// process exclude list
if ($configData['sitemap_exclude_list'] != '') {
$excludeList = trim($configData['sitemap_exclude_list']);
$excludeList = explode("\n", $excludeList);
$excludeList = array_filter($excludeList, 'trim'); // remove any extra \r characters left behind
// loop through lines of exclude list
foreach ($excludeList as $item) {
// skip items starting with "//" (commented out)
if (substr($item, 0, 2) === '//') {
continue;
}
if ($page->is($item)) {
return true;
}
}
}
return false;
}
public function sitemapListPage($page)
{
$entry = "";
if ($page->viewable() && ($page->sitemap_ignore == 0 || $page->path == '/') && !$this->isPageExcluded($page)) { // $page->path part added so that it ignores hiding the homepage, else you wouldn't have ANY pages returned
$modified = date('Y-m-d', $page->modified);
$entry = "\n <url>\n";
$entry .= " <loc>{$page->httpUrl}</loc>\n";
$entry .= " <lastmod>{$modified}</lastmod>\n";
$entry .= " </url>";
}
// Fix #12 by FlipZoomMedia | David Karich
$children = $page->children($this->pageselector);
if (count($children)) {
foreach ($children as $child) {
$entry .= $this->sitemapListPage($child);
}
}
return $entry;
}
/**
* Install the module
*
*/
public function ___install()
{
if ($this->fields->get('sitemap_ignore')) {
$this->error("You already have a 'sitemap_ignore' field.");
return;
}
wire('modules')->get('MarkupCache');
$field = new Field();
$field->type = $this->modules->get("FieldtypeCheckbox");
$field->name = 'sitemap_ignore';
$field->label = 'Hide page from XML sitemap';
$field->description = 'Hide this page and its children from the XML sitemap';
$field->save();
$this->message("Added field 'sitemap_ignore'. Add this field to any templates where you want to prevent inclusion in the XML sitemap.");
}
/**
* Uninstall the module
*
*/
public function ___uninstall()
{
// only do the following if you want to uninstall the fields that were installed
// this may be one thing that's safe to leave to the user
$field = wire('fields')->get('sitemap_ignore');
if ($field && $field->numFieldgroups() > 0)
throw new WireException("Can't uninstall because field sitemap_ignore is still being used. Please remove it from any templates.");
wire('fields')->delete($field);
}
}
You can’t perform that action at this time.