2011-12-13 12:29:05 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
if (IN_serendipity !== true) {
|
|
|
|
die ("Don't hack!");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** This plugin builds a sitemap.xml according to sitemap.org's defintion of the
|
|
|
|
* "Sitemap XML format" Version 0.9 after every save and publish.
|
|
|
|
* See http://www.sitemaps.org/protocol.html for details
|
2013-08-12 09:49:28 +02:00
|
|
|
*
|
2011-12-13 12:29:05 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
// Probe for a language include with constants. Still include defines later on, if some constants were missing
|
|
|
|
$probelang = dirname(__FILE__) . '/' . $serendipity['charset'] . 'lang_' . $serendipity['lang'] . '.inc.php';
|
|
|
|
if (file_exists($probelang)) {
|
|
|
|
include $probelang;
|
|
|
|
}
|
|
|
|
|
|
|
|
include dirname(__FILE__) . '/lang_en.inc.php';
|
|
|
|
|
|
|
|
/* This plugin is named "_google_sitemap" for historical reasons:
|
|
|
|
* The sitemap-protocol was originally created by Google, but was supported
|
|
|
|
* by other crawlers (Ask, MSN and Yahoo) as of version 0.9.
|
|
|
|
*/
|
|
|
|
class serendipity_event_google_sitemap extends serendipity_event {
|
|
|
|
var $title = PLUGIN_EVENT_SITEMAP_TITLE;
|
|
|
|
|
|
|
|
function introspect(&$propbag) {
|
|
|
|
$propbag->add('name', PLUGIN_EVENT_SITEMAP_TITLE);
|
|
|
|
$propbag->add('description', PLUGIN_EVENT_SITEMAP_DESC);
|
|
|
|
$propbag->add('author', 'Boris');
|
|
|
|
$propbag->add('version', '0.58');
|
|
|
|
$propbag->add('event_hooks', array(
|
|
|
|
'backend_publish' => true,
|
|
|
|
'backend_save' => true,
|
|
|
|
'backend_staticpages_update' => true,
|
|
|
|
'backend_staticpages_insert' => true
|
|
|
|
));
|
|
|
|
$propbag->add('stackable', false);
|
|
|
|
$propbag->add('groups', array('FRONTEND_EXTERNAL_SERVICES'));
|
|
|
|
$propbag->add('configuration', array('report', 'url', 'gzip_sitemap', 'types_to_add', 'gnews', 'gnews_single', 'custom', 'custom2', 'gnews_name', 'gnews_subscription', 'gnews_genre'));
|
|
|
|
$propbag->add('requirements', array('serendipity' => '0.8'));
|
|
|
|
}
|
|
|
|
|
|
|
|
function introspect_config_item($name, &$propbag) {
|
|
|
|
global $serendipity;
|
|
|
|
switch($name) {
|
|
|
|
case 'report':
|
|
|
|
$propbag->add('type', 'boolean');
|
|
|
|
$propbag->add('name', PLUGIN_EVENT_SITEMAP_REPORT);
|
|
|
|
$propbag->add('description', PLUGIN_EVENT_SITEMAP_REPORT_DESC);
|
|
|
|
$propbag->add('default', false);
|
|
|
|
break;
|
|
|
|
case 'url':
|
|
|
|
$propbag->add('type', 'string');
|
|
|
|
$propbag->add('name', PLUGIN_EVENT_SITEMAP_URL);
|
|
|
|
$propbag->add('description', PLUGIN_EVENT_SITEMAP_URL_DESC);
|
|
|
|
$propbag->add('default', 'http://www.google.com/webmasters/tools/ping?sitemap=%s;http://submissions.ask.com/ping?sitemap=%s');
|
|
|
|
break;
|
|
|
|
case 'gzip_sitemap':
|
|
|
|
$propbag->add('type', 'boolean');
|
|
|
|
$propbag->add('name', PLUGIN_EVENT_SITEMAP_GZIP_SITEMAP);
|
|
|
|
$propbag->add('description', PLUGIN_EVENT_SITEMAP_GZIP_SITEMAP_DESC);
|
|
|
|
$propbag->add('default', true);
|
|
|
|
break;
|
|
|
|
case 'types_to_add':
|
|
|
|
$types = array(
|
|
|
|
'sm_feeds' => PLUGIN_EVENT_SITEMAP_TYPES_TO_ADD_FEEDS,
|
|
|
|
'sm_categories' => PLUGIN_EVENT_SITEMAP_TYPES_TO_ADD_CATEGORIES,
|
|
|
|
'sm_authors' => PLUGIN_EVENT_SITEMAP_TYPES_TO_ADD_AUTHORS,
|
|
|
|
'sm_permalinks' => PLUGIN_EVENT_SITEMAP_TYPES_TO_ADD_PERMALINKS,
|
|
|
|
'sm_archives' => PLUGIN_EVENT_SITEMAP_TYPES_TO_ADD_ARCHIVES,
|
|
|
|
'sm_static' => PLUGIN_EVENT_SITEMAP_TYPES_TO_ADD_STATIC,
|
|
|
|
'sm_tags'=> PLUGIN_EVENT_SITEMAP_TYPES_TO_ADD_TAGS
|
|
|
|
);
|
|
|
|
$propbag->add('type', 'multiselect');
|
|
|
|
$propbag->add('name', PLUGIN_EVENT_SITEMAP_TYPES_TO_ADD);
|
|
|
|
$propbag->add('description', PLUGIN_EVENT_SITEMAP_TYPES_TO_ADD_DESC);
|
|
|
|
$propbag->add('select_values', $types);
|
|
|
|
$propbag->add('select_size', 6);
|
|
|
|
$propbag->add('default', implode(array_keys($types), '^'));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'gnews_subscription':
|
|
|
|
$types = array(
|
|
|
|
'none' => PLUGIN_EVENT_SITEMAP_PUBLIC,
|
|
|
|
'subscription' => PLUGIN_EVENT_SITEMAP_SUBSCRIPTION,
|
|
|
|
'registration' => PLUGIN_EVENT_SITEMAP_REGISTRATION
|
|
|
|
);
|
|
|
|
$propbag->add('type', 'select');
|
|
|
|
$propbag->add('name', PLUGIN_EVENT_SITEMAP_GNEWS_SUBSCRIPTION);
|
|
|
|
$propbag->add('description', PLUGIN_EVENT_SITEMAP_GNEWS_SUBSCRIPTION_DESC);
|
|
|
|
$propbag->add('select_values', $types);
|
|
|
|
$propbag->add('select_size', 6);
|
|
|
|
$propbag->add('default', 'none');
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'gnews_genre':
|
|
|
|
$types = array(
|
|
|
|
'none' => PLUGIN_EVENT_SITEMAP_NONE,
|
|
|
|
'PressRelease' => PLUGIN_EVENT_SITEMAP_PRESS,
|
|
|
|
'Satire' => PLUGIN_EVENT_SITEMAP_SATIRE,
|
|
|
|
'Blog' => PLUGIN_EVENT_SITEMAP_BLOG,
|
|
|
|
'OpEd' => PLUGIN_EVENT_SITEMAP_OPED,
|
|
|
|
'Opinion' => PLUGIN_EVENT_SITEMAP_OPINION,
|
|
|
|
'UserGenerated' => PLUGIN_EVENT_SITEMAP_USERGENERATED
|
|
|
|
);
|
|
|
|
$propbag->add('type', 'multiselect');
|
|
|
|
$propbag->add('name', PLUGIN_EVENT_SITEMAP_GENRES);
|
|
|
|
$propbag->add('description', PLUGIN_EVENT_SITEMAP_GENRES_DESC);
|
|
|
|
$propbag->add('select_values', $types);
|
|
|
|
$propbag->add('select_size', 6);
|
|
|
|
$propbag->add('default', 'none');
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'gnews':
|
|
|
|
$propbag->add('type', 'boolean');
|
|
|
|
$propbag->add('name', PLUGIN_EVENT_SITEMAP_NEWS);
|
|
|
|
$propbag->add('description', '');
|
|
|
|
$propbag->add('default', false);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'gnews_single':
|
|
|
|
$propbag->add('type', 'boolean');
|
|
|
|
$propbag->add('name', PLUGIN_EVENT_SITEMAP_NEWS_SINGLE);
|
|
|
|
$propbag->add('description', PLUGIN_EVENT_SITEMAP_NEWS_SINGLE_DESC);
|
|
|
|
$propbag->add('default', true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'custom':
|
|
|
|
$propbag->add('type', 'text');
|
|
|
|
$propbag->add('name', PLUGIN_EVENT_SITEMAP_CUSTOM);
|
|
|
|
$propbag->add('description', PLUGIN_EVENT_SITEMAP_CUSTOM_DESC);
|
|
|
|
$propbag->add('default', '');
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'custom2':
|
|
|
|
$propbag->add('type', 'text');
|
|
|
|
$propbag->add('name', PLUGIN_EVENT_SITEMAP_CUSTOM2);
|
|
|
|
$propbag->add('description', PLUGIN_EVENT_SITEMAP_CUSTOM2_DESC);
|
|
|
|
$propbag->add('default', '');
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'gnews_name':
|
|
|
|
$propbag->add('type', 'string');
|
|
|
|
$propbag->add('name', PLUGIN_EVENT_SITEMAP_GNEWS_NAME);
|
|
|
|
$propbag->add('description', PLUGIN_EVENT_SITEMAP_GNEWS_NAME_DESC);
|
|
|
|
$propbag->add('default', $serendipity['blogTitle']);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! function to add an entry to the xml-string $str */
|
|
|
|
function addtoxml(&$str, $url, $lastmod = null, $priority = null, $changefreq = null, $props = null) {
|
|
|
|
/* Sitemap requires this.
|
|
|
|
* I think that s9y does not include these specialchars, so this is just a precaution */
|
|
|
|
$url = htmlspecialchars($url, ENT_QUOTES);
|
|
|
|
|
|
|
|
$str .= "\t<url>\n";
|
|
|
|
$str .= "\t\t<loc>$url</loc>\n";
|
|
|
|
if ($lastmod!=null) {
|
|
|
|
$str_lastmod = gmstrftime('%Y-%m-%dT%H:%M:%SZ', $lastmod); // 'Z' does mean UTC in W3C Date/Time
|
|
|
|
$str .= "\t\t<lastmod>$str_lastmod</lastmod>\n";
|
|
|
|
if ($this->gnewsmode) {
|
|
|
|
$str .= "\t\t<news:news>\n";
|
|
|
|
|
|
|
|
$str .= "\t\t\t<news:publication>\n";
|
|
|
|
$str .= "\t\t\t\t<news:name>" . htmlspecialchars($this->get_config('gnews_name')) . '</news:name>' . "\n";
|
|
|
|
$str .= "\t\t\t\t<news:language>" . htmlspecialchars($GLOBALS['serendipity']['lang']) . '</news:language>' . "\n";
|
|
|
|
$str .= "\t\t\t</news:publication>\n";
|
|
|
|
|
|
|
|
$sub = $this->get_config('gnews_subscription');
|
|
|
|
$genre = $props['properties']['ep_gnews_genre'];
|
|
|
|
if (empty($genre)) {
|
|
|
|
$genre = $props['properties']['gnews_genre'];
|
|
|
|
}
|
|
|
|
if (empty($genre)) {
|
|
|
|
$genre = $props['gnews_genre'];
|
|
|
|
}
|
|
|
|
if (empty($genre)) {
|
|
|
|
$genre = str_replace('^', ',', $this->get_config('gnews_genre'));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!empty($sub) && $sub != 'none') {
|
|
|
|
$str .= "\t\t\t<news:access>" . $sub . "</news:access>\n";
|
|
|
|
}
|
|
|
|
#http://www.google.com/support/news_pub/bin/answer.py?answer=93992
|
|
|
|
|
|
|
|
if (!empty($genre) && $genre != 'none') {
|
|
|
|
$str .= "\t\t\t<news:genres>" . $genre . "</news:genres>\n";
|
|
|
|
}
|
|
|
|
$str .= "\t\t\t<news:title>" . htmlspecialchars($props['title']) . "</news:title>\n";
|
|
|
|
|
|
|
|
$str .= "\t\t\t<news:publication_date>$str_lastmod</news:publication_date>\n";
|
|
|
|
if (is_array($props) && isset($props['meta_keywords'])) {
|
|
|
|
$str .= "\t\t\t<news:keywords>" . htmlspecialchars($props['meta_keywords']) . "</news:keywords>\n";
|
|
|
|
}
|
|
|
|
$str .= "\t\t</news:news>\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($priority!==null) {
|
|
|
|
$str .= "\t\t<priority>".sprintf("%1.1f",$priority)."</priority>\n";
|
|
|
|
}
|
|
|
|
if ($changefreq!=null) {
|
|
|
|
$str .= "\t\t<changefreq>$changefreq</changefreq>\n";
|
|
|
|
}
|
|
|
|
$str .= "\t</url>\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! This functions returns whether a URL-type should be added or not */
|
|
|
|
function should_add($type) {
|
|
|
|
if(!isset($this->types)) {
|
|
|
|
$this->types = explode('^', $this->get_config('types_to_add'));
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!is_array($this->types) || count($this->types)===0) {
|
|
|
|
// default: add all
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return in_array($type, $this->types);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*! This functions returns the NULL-function for the current DB-specific SQL-dialect */
|
|
|
|
function get_sqlnullfunction() {
|
|
|
|
global $serendipity;
|
|
|
|
// decide which NULL-function to use
|
|
|
|
switch($serendipity['dbType']) {
|
|
|
|
case 'postgres':
|
|
|
|
$sqlnullfunction = 'COALESCE';
|
|
|
|
break;
|
|
|
|
case 'sqlite':
|
|
|
|
case 'mysql':
|
|
|
|
case 'mysqli':
|
|
|
|
$sqlnullfunction = 'IFNULL';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
$sqlnullfunction='';
|
|
|
|
}
|
|
|
|
return $sqlnullfunction;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! Get the real baseURL from the DB to get the primary URLs and
|
|
|
|
* prevent wrong URLs (e.g. with https or different hostnames)
|
|
|
|
*/
|
|
|
|
function get_BaseURL() {
|
|
|
|
global $serendipity;
|
|
|
|
|
|
|
|
$url = serendipity_db_query(
|
|
|
|
'SELECT value
|
|
|
|
FROM '.$serendipity['dbPrefix'].'config AS config
|
|
|
|
WHERE name = \'baseURL\'',
|
|
|
|
false, 'assoc');
|
|
|
|
|
|
|
|
return (is_array($url))? $url[0]['value'] : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
function add_entries(&$sitemap_xml, $limit = 0) {
|
|
|
|
global $serendipity;
|
|
|
|
$sqlnullfunction = $this->get_sqlnullfunction();
|
|
|
|
|
|
|
|
// fetch all entries from the db (tested with: mysql, sqlite, postgres)
|
|
|
|
$entries = serendipity_db_query(
|
|
|
|
'SELECT
|
|
|
|
entries.id AS id,
|
|
|
|
entries.title AS title,
|
|
|
|
'.$sqlnullfunction.'(entries.last_modified,0) AS timestamp_1,
|
|
|
|
'.$sqlnullfunction.'(MAX(comments.timestamp),0) AS timestamp_2
|
|
|
|
FROM '.$serendipity['dbPrefix'].'entries entries
|
|
|
|
LEFT JOIN '.$serendipity['dbPrefix'].'comments comments
|
|
|
|
ON entries.id = comments.entry_id
|
|
|
|
WHERE entries.isdraft = \'false\'
|
|
|
|
AND entries.timestamp < ' . time() . '
|
|
|
|
GROUP BY entries.id, entries.title, entries.last_modified
|
|
|
|
ORDER BY entries.id DESC
|
|
|
|
' . ($limit > 0 ? ' LIMIT ' . $limit : '')
|
|
|
|
,
|
|
|
|
false, 'assoc');
|
|
|
|
|
|
|
|
if(is_array($entries)) {
|
|
|
|
|
|
|
|
if ($this->should_add('sm_archives')) {
|
|
|
|
// get the P*.html sites if there are more than fetchLimit entries
|
|
|
|
for($i=2; $i<=ceil(sizeof($entries) / $serendipity['fetchLimit']); ++$i) {
|
|
|
|
$url = $url=serendipity_rewriteURL(PATH_ARCHIVES. "/P$i.html");
|
|
|
|
$this->addtoxml($sitemap_xml, $url, null, 0.5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add entries
|
|
|
|
foreach($entries as $entry) {
|
|
|
|
$max = max($entry['timestamp_1']+0, $entry['timestamp_2']+0);
|
|
|
|
$url = serendipity_archiveURL($entry['id'], $entry['title']);
|
|
|
|
$props = serendipity_fetchEntryProperties($entry['id']);
|
|
|
|
$props['title'] = $entry['title'];
|
|
|
|
$this->addtoxml($sitemap_xml, $url, $max, 0.7, null, $props);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function add_permalinks(&$sitemap_xml) {
|
|
|
|
global $serendipity;
|
|
|
|
|
|
|
|
$permlink = serendipity_db_query(
|
|
|
|
'SELECT entryid, timestamp, value
|
|
|
|
FROM '.$serendipity['dbPrefix'].'entryproperties AS entryproperties,
|
|
|
|
'.$serendipity['dbPrefix'].'entries AS entries
|
|
|
|
WHERE entryproperties.property = \'permalink\'
|
|
|
|
AND timestamp < ' . time() . '
|
|
|
|
AND value NOT LIKE \'%/' . UNKNOWN . '%\'
|
|
|
|
AND entries.id=entryproperties.entryid',
|
|
|
|
false, 'assoc');
|
|
|
|
|
|
|
|
if (is_array($permlink)) {
|
|
|
|
foreach($permlink as $cur) {
|
|
|
|
$path_quoted = preg_quote($serendipity['serendipityHTTPPath'], '#');
|
|
|
|
$url = $serendipity['baseURL'] . preg_replace("#$path_quoted#", '', $cur['value'],1);
|
|
|
|
$cur_time = ($cur['timestamp']==0)? null : (int)$cur['timestamp'];
|
|
|
|
$this->addtoxml($sitemap_xml, $url, $cur_time, 0.8);
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for the right order of plugins
|
|
|
|
$order = serendipity_db_query(
|
|
|
|
'SELECT name, sort_order
|
|
|
|
FROM '.$serendipity['dbPrefix'].'plugins AS plugins
|
|
|
|
WHERE plugins.name LIKE \'%serendipity_event_google_sitemap%\'
|
|
|
|
OR plugins.name LIKE \'%serendipity_event_custom_permalinks%\'
|
|
|
|
ORDER BY plugins.sort_order',
|
|
|
|
false, 'assoc');
|
|
|
|
if (is_array($order) && isset($order[0]) && isset($order[1])) {
|
|
|
|
if( strpos($order[0]['name'], 'serendipity_event_custom_permalinks')===FALSE) {
|
|
|
|
echo '<br/>'.PLUGIN_EVENT_SITEMAP_PERMALINK_WARNING.'<br/>';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function add_categories(&$sitemap_xml) {
|
|
|
|
global $serendipity;
|
|
|
|
|
|
|
|
// fetch categories and their last entry date (tested with: mysql, sqlite, postgres)
|
|
|
|
$categories = serendipity_db_query(
|
|
|
|
'SELECT
|
|
|
|
category.categoryid AS id,
|
|
|
|
category_name,
|
|
|
|
category_description,
|
|
|
|
MAX(entries.last_modified) AS last_mod
|
|
|
|
FROM
|
|
|
|
'.$serendipity['dbPrefix'].'category category,
|
|
|
|
'.$serendipity['dbPrefix'].'entrycat entrycat,
|
|
|
|
'.$serendipity['dbPrefix'].'entries entries
|
|
|
|
WHERE
|
|
|
|
category.categoryid = entrycat.categoryid
|
|
|
|
AND
|
|
|
|
entrycat.entryid = entries.id
|
|
|
|
GROUP BY
|
|
|
|
category.categoryid,
|
|
|
|
category.category_name,
|
|
|
|
category.category_description
|
|
|
|
ORDER BY category.categoryid',
|
|
|
|
false, 'assoc');
|
|
|
|
|
|
|
|
if(is_array($categories)) {
|
|
|
|
foreach($categories as $category) {
|
|
|
|
$max = 0+$category['last_mod'];
|
|
|
|
/* v0.9 */
|
|
|
|
if(version_compare((float)$serendipity['version'], '0.9', '>=')) {
|
|
|
|
$data = array(
|
|
|
|
'categoryid' => $category['id'],
|
|
|
|
'category_name' => $category['category_name'],
|
|
|
|
'category_description' => $category['category_description']);
|
|
|
|
$url = serendipity_categoryURL($data);
|
|
|
|
} else {
|
|
|
|
$url = serendipity_rewriteURL(PATH_CATEGORIES . '/' . serendipity_makePermalink(PERM_CATEGORIES, array('id' => $category['id'], 'title' => $category['category_name'])));
|
|
|
|
}
|
|
|
|
$this->addtoxml($sitemap_xml, $url, $max, 0.4);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$categories = array();
|
|
|
|
}
|
|
|
|
|
|
|
|
// remember for category-feeds and archives
|
|
|
|
$this->categories = $categories;
|
|
|
|
}
|
|
|
|
|
|
|
|
function add_authors(&$sitemap_xml) {
|
|
|
|
global $serendipity;
|
|
|
|
|
|
|
|
// fetch authors and their last entry date (tested with: mysql, sqlite, postgres)
|
|
|
|
$authors = serendipity_db_query(
|
|
|
|
'SELECT
|
|
|
|
authors.authorid as id,
|
|
|
|
realname,
|
|
|
|
username,
|
|
|
|
email,
|
|
|
|
MAX(entries.last_modified) as time
|
|
|
|
FROM
|
|
|
|
'.$serendipity['dbPrefix'].'authors authors,
|
|
|
|
'.$serendipity['dbPrefix'].'entries entries
|
|
|
|
WHERE authors.authorid = entries.authorid
|
|
|
|
GROUP BY
|
|
|
|
authors.authorid,
|
|
|
|
authors.realname,
|
|
|
|
authors.username,
|
|
|
|
authors.email
|
|
|
|
ORDER BY authors.authorid',
|
|
|
|
false, 'assoc');
|
|
|
|
|
|
|
|
if(is_array($authors)) {
|
|
|
|
// add authors
|
|
|
|
foreach($authors as $author) {
|
|
|
|
$max = 0+$author['time'];
|
|
|
|
/* v0.9 */
|
|
|
|
if(version_compare((float)$serendipity['version'], '0.9', '>=')) {
|
|
|
|
$data = array(
|
|
|
|
'authorid' => $author['id'],
|
|
|
|
'realname' => $author['realname'],
|
|
|
|
'username' => $author['username'],
|
|
|
|
'email' => $author['email']);
|
|
|
|
$url = serendipity_authorURL($data);
|
|
|
|
} else {
|
|
|
|
$url=serendipity_rewriteURL(PATH_AUTHORS .'/'. serendipity_makePermalink(PERM_AUTHORS, array('id' => $author['id'], 'title' => $author['realname'])));
|
|
|
|
}
|
|
|
|
$this->addtoxml($sitemap_xml, $url, $max, 0.2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function add_archives(&$sitemap_xml) {
|
|
|
|
global $serendipity;
|
|
|
|
|
|
|
|
// fetch date of the oldest entry (tested with: mysql, sqlite, postgres)
|
|
|
|
$min = serendipity_db_query(
|
|
|
|
'SELECT
|
|
|
|
MIN(timestamp) AS min_time
|
|
|
|
FROM '.$serendipity['dbPrefix'].'entries',
|
|
|
|
true, 'num');
|
|
|
|
$first_year = 0+gmstrftime('%Y', $min[0]);
|
|
|
|
$first_month = 0+gmstrftime('%m', $min[0]);
|
|
|
|
$last_year = 0+gmstrftime('%Y', time());
|
|
|
|
$last_month = 0+gmstrftime('%m', time());
|
|
|
|
|
|
|
|
// add all the month-links
|
|
|
|
if(is_array($min) && $first_year<=$last_year) {
|
|
|
|
for($year=$first_year; $year<=$last_year; ++$year) {
|
|
|
|
$from_month = ($year==$first_year)? $first_month : 1;
|
|
|
|
$till_month = ($year==$last_year)? $last_month : 12;
|
|
|
|
|
|
|
|
for($month=$from_month; $month<=$till_month; ++$month) {
|
|
|
|
$str_month = (($month<10)? '0' : '').$month;
|
|
|
|
$url=serendipity_rewriteURL(PATH_ARCHIVES. "/$year/$str_month.html");
|
|
|
|
$this->addtoxml($sitemap_xml, $url, $max, 0.3);
|
|
|
|
$url=serendipity_rewriteURL(PATH_ARCHIVES. "/$year/$str_month/summary.html");
|
|
|
|
$this->addtoxml($sitemap_xml, $url, $max, 0.1);
|
|
|
|
|
|
|
|
if($this->should_add('sm_categories')) {
|
|
|
|
foreach($this->categories as $category) {
|
|
|
|
$url=serendipity_rewriteURL(PATH_ARCHIVES. "/$year/$str_month/C{$category['id']}.html");
|
|
|
|
$this->addtoxml($sitemap_xml, $url, $max, 0.1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function add_feeds(&$sitemap_xml) {
|
|
|
|
global $serendipity;
|
|
|
|
|
|
|
|
// add the category-newsfeed URLs
|
|
|
|
if($this->should_add('sm_categories')) {
|
|
|
|
foreach($this->categories as $category) {
|
|
|
|
$max = 0+$category['last_mod'];
|
|
|
|
// v0.9
|
|
|
|
if(version_compare((float)$serendipity['version'], '0.9', '>=')) {
|
|
|
|
$data = array(
|
|
|
|
'categoryid' => $category['id'],
|
|
|
|
'category_name' => $category['category_name'],
|
|
|
|
'category_description' => $category['category_description']);
|
|
|
|
$url = serendipity_feedCategoryURL($data);
|
|
|
|
} else {
|
|
|
|
$url = serendipity_rewriteURL(PATH_FEEDS .'/'. PATH_CATEGORIES .'/'. serendipity_makePermalink(PERM_FEEDS_CATEGORIES, array('id' => $category['id'], 'title' => $category['category_name'])));
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->addtoxml($sitemap_xml, $url, $max, 0.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add the global newsfeed URLs
|
|
|
|
if($this->should_add('sm_feeds')) {
|
|
|
|
$filelist = array('/index.rss', '/index.rss1', '/index.rss2', '/atom.xml');
|
|
|
|
foreach($filelist as $curfile) {
|
|
|
|
$url = serendipity_rewriteURL(PATH_FEEDS . $curfile);
|
|
|
|
$this->addtoxml($sitemap_xml, $url, $max, 0.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function add_static(&$sitemap_xml) {
|
|
|
|
global $serendipity;
|
|
|
|
$sqlnullfunction = $this->get_sqlnullfunction();
|
|
|
|
|
|
|
|
// add possible static pages
|
|
|
|
$static_pages = serendipity_db_query(
|
|
|
|
'SELECT permalink, '.$sqlnullfunction.'(timestamp, 0)
|
|
|
|
FROM '.$serendipity['dbPrefix'].'staticpages
|
|
|
|
WHERE pass = \'\'
|
|
|
|
AND publishstatus = 1',
|
|
|
|
false, 'assoc');
|
|
|
|
|
|
|
|
if (is_array($static_pages)) {
|
|
|
|
foreach($static_pages as $cur) {
|
|
|
|
$path_quoted = preg_quote($serendipity['serendipityHTTPPath'], '#');
|
|
|
|
$url = $serendipity['baseURL'] . preg_replace("#$path_quoted#", '', $cur['permalink'],1);
|
|
|
|
$cur_time = ($cur['timestamp']==0)? null : (int)$cur['timestamp'];
|
|
|
|
$this->addtoxml($sitemap_xml, $url, $cur_time, 0.7);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function add_tags(&$sitemap_xml) {
|
|
|
|
global $serendipity;
|
|
|
|
$sqlnullfunction = $this->get_sqlnullfunction();
|
|
|
|
|
|
|
|
// add possible tags pages
|
|
|
|
$tag_pages = serendipity_db_query(
|
|
|
|
'SELECT tag
|
|
|
|
FROM '.$serendipity['dbPrefix'].'entrytags
|
|
|
|
GROUP BY tag',
|
|
|
|
false, 'assoc');
|
|
|
|
if (is_array($tag_pages)) {
|
|
|
|
foreach($tag_pages as $cur) {
|
|
|
|
$path_quoted = preg_quote($serendipity['serendipityHTTPPath'], '#');
|
|
|
|
$url = $serendipity['baseURL'] . ($serendipity['rewrite'] == 'none' ? $serendipity['indexFile'] . '?/' : '') . 'plugin/tag/'. preg_replace("#$path_quoted#", '', urlencode($cur['tag']),1);
|
|
|
|
$cur_time = ($cur['timestamp']==0)? null : (int)$cur['timestamp'];
|
|
|
|
$this->addtoxml($sitemap_xml, $url, $cur_time, 0.4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function event_hook($event, &$bag, &$eventData, $addData = null) {
|
|
|
|
global $serendipity;
|
|
|
|
|
|
|
|
$hooks = &$bag->get('event_hooks');
|
|
|
|
|
|
|
|
if (isset($hooks[$event])) {
|
|
|
|
switch ($event) {
|
|
|
|
case 'backend_publish':
|
|
|
|
case 'backend_save':
|
|
|
|
case 'backend_staticpages_insert':
|
|
|
|
case 'backend_staticpages_update':
|
|
|
|
/* Backup the baseURL.
|
|
|
|
* This is a nasty workaround the issues with $serendipity['baseURL'] not
|
|
|
|
* pointing to the primary url on hostname-autosensing. See this forum-thread
|
|
|
|
* for details and discussion: http://board.s9y.org/viewtopic.php?p=60164#60164
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!empty($serendipity['defaultBaseURL'])) {
|
|
|
|
$serendipity['baseURL'] = $old_url = $serendipity['defaultBaseURL'];
|
|
|
|
} else {
|
|
|
|
$old_url = $serendipity['baseURL'];
|
|
|
|
$serendipity['baseURL'] = $this->get_BaseURL();
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->write_sitemap('sitemap.xml', $eventData);
|
|
|
|
|
|
|
|
if (serendipity_db_bool($this->get_config('gnews'))) {
|
|
|
|
$this->write_sitemap('news_sitemap.xml', $eventData, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// restore baseURL (see above)
|
|
|
|
$serendipity['baseURL'] = $old_url;
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function write_sitemap($basefilename = 'sitemap.xml', &$eventData, $gnewsmode = false) {
|
|
|
|
global $serendipity;
|
|
|
|
|
|
|
|
// start the xml
|
|
|
|
$sitemap_xml = '<?xml version="1.0" encoding="UTF-8"?>'."\n";
|
|
|
|
$sitemap_xml .= "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"\n";
|
|
|
|
$sitemap_xml .= "\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
|
|
|
|
if ($gnewsmode) {
|
|
|
|
$sitemap_xml .= "\txmlns:news=\"http://www.google.com/schemas/sitemap-news/0.9\"\n";
|
|
|
|
}
|
|
|
|
$sitemap_xml .= "\txsi:schemaLocation=\"http://www.sitemaps.org/schemas/sitemap/0.9\n";
|
|
|
|
$sitemap_xml .= "\t\t\thttp://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd\" ";
|
|
|
|
$sitemap_xml .= $this->get_config('custom2');
|
|
|
|
$sitemap_xml .= ">\n";
|
|
|
|
|
|
|
|
$this->gnewsmode = false;
|
|
|
|
|
|
|
|
// If this variable is enabled, each XML article will get its gnews:... counterpart.
|
|
|
|
// This is NOT desired in the usual sitemap!
|
|
|
|
if ($gnewsmode) {
|
|
|
|
$this->gnewsmode = true;
|
|
|
|
} elseif (serendipity_db_bool($this->get_config('gnews_single')) && serendipity_db_bool($this->get_config('gnews'))) {
|
|
|
|
$this->gnewsmode = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// add link to the main page
|
|
|
|
$this->addtoxml($sitemap_xml, $serendipity['baseURL'], time(), 0.6);
|
|
|
|
|
|
|
|
|
|
|
|
if (!$gnewsmode) {
|
|
|
|
$this->add_entries($sitemap_xml);
|
|
|
|
|
|
|
|
if ($this->should_add('sm_permalinks')) {
|
|
|
|
$this->add_permalinks($sitemap_xml);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->should_add('sm_categories')) {
|
|
|
|
$this->add_categories($sitemap_xml);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->should_add('sm_authors')) {
|
|
|
|
$this->add_authors($sitemap_xml);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->should_add('sm_archives')) {
|
|
|
|
$this->add_archives($sitemap_xml);
|
|
|
|
// add link to archive-mainpage
|
|
|
|
$this->addtoxml($sitemap_xml, serendipity_rewriteURL(PATH_ARCHIVE), time(), 0.5);
|
|
|
|
}
|
|
|
|
|
|
|
|
if($this->should_add('sm_feeds')) {
|
|
|
|
$this->add_feeds($sitemap_xml);
|
|
|
|
}
|
|
|
|
|
|
|
|
if($this->should_add('sm_static')) {
|
|
|
|
$this->add_static($sitemap_xml);
|
|
|
|
}
|
|
|
|
|
|
|
|
if($this->should_add('sm_tags')) {
|
|
|
|
$this->add_tags($sitemap_xml);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$this->add_entries($sitemap_xml, 900);
|
|
|
|
}
|
|
|
|
|
|
|
|
$sitemap_xml .= $this->get_config('custom');
|
|
|
|
|
|
|
|
// finish the xml
|
|
|
|
$sitemap_xml .= "</urlset>\n";
|
|
|
|
|
|
|
|
$do_gzip = serendipity_db_bool($this->get_config('gzip_sitemap', true));
|
|
|
|
|
|
|
|
// decide whether to use gzip-output or not
|
|
|
|
if ($do_gzip && function_exists('gzencode')) {
|
|
|
|
$filename = '/' . $basefilename . '.gz';
|
|
|
|
$temp = gzencode($sitemap_xml);
|
|
|
|
|
|
|
|
// only use the compressed data and filename if no error occured
|
|
|
|
if ( !($temp === FALSE) ) {
|
|
|
|
$sitemap_xml = $temp;
|
|
|
|
} else {
|
|
|
|
$filename = '/' . $basefilename;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$filename = '/' . $basefilename;
|
|
|
|
}
|
|
|
|
|
|
|
|
// write result to file
|
|
|
|
$outfile = fopen($serendipity['serendipityPath'] . $filename, 'w');
|
|
|
|
if($outfile === false) {
|
|
|
|
echo '<strong>'.PLUGIN_EVENT_SITEMAP_FAILEDOPEN.' (' . $serendipity['serendipityPath'] . $filename . ')</strong>';
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
flock($outfile, LOCK_EX);
|
|
|
|
fputs($outfile, $sitemap_xml);
|
|
|
|
flock($outfile, LOCK_UN);
|
|
|
|
fclose($outfile);
|
|
|
|
|
|
|
|
|
|
|
|
$do_pingback = serendipity_db_bool($this->get_config('report', false));
|
|
|
|
$pingback_url = $this->get_config('url', false);
|
|
|
|
// Walk through the list of pingback-URLs
|
|
|
|
echo $basefilename . ':<br />';
|
|
|
|
foreach(explode(';', $pingback_url) as $cur_pingback_url) {
|
|
|
|
$pingback_name = PLUGIN_EVENT_SITEMAP_UNKNOWN_HOST;
|
|
|
|
$cur_url = sprintf($cur_pingback_url, rawurlencode($serendipity['baseURL'].$filename));
|
|
|
|
|
|
|
|
// extract domain-portion from URL
|
|
|
|
if(preg_match('@^https?://([^/]+)@', $cur_pingback_url, $matches)>0) {
|
|
|
|
$pingback_name = $matches[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!serendipity_db_bool($eventData['isdraft']) && $do_pingback && $cur_url) {
|
|
|
|
$answer = $this->send_ping($cur_url);
|
|
|
|
if($answer) {
|
|
|
|
printf(PLUGIN_EVENT_SITEMAP_REPORT_OK, $pingback_name);
|
|
|
|
} else {
|
|
|
|
printf(PLUGIN_EVENT_SITEMAP_REPORT_ERROR, $pingback_name, $cur_url);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
printf(PLUGIN_EVENT_SITEMAP_REPORT_MANUAL, $pingback_name, $cur_url);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
echo PLUGIN_EVENT_SITEMAP_ROBOTS_TXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
function send_ping($loc) {
|
|
|
|
global $serendipity;
|
|
|
|
require_once (defined('S9Y_PEAR_PATH') ? S9Y_PEAR_PATH : S9Y_INCLUDE_PATH . 'bundled-libs/') . 'HTTP/Request.php';
|
|
|
|
$req = new HTTP_Request($loc);
|
|
|
|
|
|
|
|
if (PEAR::isError($req->sendRequest()) || $req->getResponseCode() != '200') {
|
|
|
|
print_r($req);
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// vim: set sts=4 ts=4 expandtab :
|
|
|
|
// kate: encoding us-ascii; indent-width 4; indent-mode normal; space-indent on; tab-width 4; mixedindent off;
|