1<?php
2/**
3 * Generates individually sitemap.org compatible XML files for use with Google and other search engines.
4 * It supports albums and images as well as optionally Zenpage pages, news articles and news categories.
5 * Sitemaps need to be generated via the button on the admin overview page and are cached as static
6 * files in the <var>/%STATIC_CACHE_FOLDER%/sitemap/</var> folder.
7 * Individual sitemaps are generated for all of the above item types as well as a sitemapindex file.
8 * Album sitemaps are split into individual sitemaps per album (incl. all albums pages) and image sitemaps
9 * into individual sitemaps per album.
10 *
11 * Based on the plugin by Jeppe Toustrup (Tenzer) http://github.com/Tenzer/zenphoto-sitemap
12 *
13 * The sitemapindex file can be referenced via <var>www.yourdomain.com/zenphoto/index.php?sitemap</var> or
14 * with modrewrite <var>www.yourdomain.com/zenphoto/?sitemap</var>.
15 *
16 * <b>IMPORTANT:</b> A multilingual sitemap requires the <var>dynamic-locale</var> plugin and either the <var>seo_locale</var> plugin or <i>language subdomains</i>.
17 *
18 * @author Malte Müller (acrylian), Jeppe Toustrup (Tenzer), timo, Blue Dragonfly and Francois Marechal (frankm)
19 * @package plugins
20 * @subpackage sitemap-extended
21 */
22$plugin_is_filter = 0 | CLASS_PLUGIN;
23$plugin_description = gettext('Generates sitemap.org compatible XML files for use with Google and other search engines.');
24$plugin_notice = gettext('<strong>Note:</strong> The index links may not match if using the Zenpage option "news on index" that some themes provide! Also it does not "know" about "custom pages" outside Zenpage or any special custom theme setup!!');
25$plugin_author = 'Malte Müller (acrylian), Jeppe Toustrup (Tenzer), timo, Blue Dragonfly and Francois Marechal (frankm)';
26$plugin_category = gettext('SEO');
27$option_interface = 'sitemapOptions';
28
29zp_register_filter('admin_utilities_buttons', 'sitemap::button');
30
31$sitemapfolder = SERVERPATH . '/' . STATIC_CACHE_FOLDER . '/sitemap';
32if (!file_exists($sitemapfolder)) {
33	if (!mkdir_recursive($sitemapfolder, FOLDER_MOD)) {
34		die(gettext("sitemap cache folder could not be created. Please try to create it manually via FTP with chmod 0777."));
35	}
36}
37if (getOption('sitemap_galleryindex')) {
38	purgeOption('sitemap_galleryindex');
39}
40define('SITEMAP_CHUNK', getOption('sitemap_processing_chunk'));
41define('GOOGLE_SITEMAP', getOption('sitemap_google'));
42if (getOption('multi_lingual') && defined('LOCALE_TYPE')) {
43	define('SITEMAP_LOCALE_TYPE', LOCALE_TYPE);
44} else {
45	define('SITEMAP_LOCALE_TYPE', 0);
46}
47
48/**
49 * Plugin option handling class
50 *
51 */
52class sitemapOptions {
53
54	var $startmtime;
55	var $disable = false; // manual disable caching a page
56
57	function __construct() {
58		setOptionDefault('sitemap_changefreq_index', 'daily');
59		setOptionDefault('sitemap_changefreq_albums', 'daily');
60		setOptionDefault('sitemap_changefreq_images', 'daily');
61		setOptionDefault('sitemap_changefreq_pages', 'weekly');
62		setOptionDefault('sitemap_changefreq_newsindex', 'daily');
63		setOptionDefault('sitemap_changefreq_news', 'daily');
64		setOptionDefault('sitemap_changefreq_newscats', 'weekly');
65		setOptionDefault('sitemap_lastmod_albums', 'mtime');
66		setOptionDefault('sitemap_lastmod_images', 'mtime');
67		setOptionDefault('sitemap_processing_chunk', 25);
68		setOptionDefault('sitemap_google', 0);
69		setOptionDefault('sitemap_google_fullimage', 0);
70	}
71
72	function getOptionsSupported() {
73		global $_common_locale_type;
74		$localdesc = '<p>' . gettext('If checked links to the alternative languages will be in the form <code><em>language</em>.domain</code> where <code><em>language</em></code> is the language code, e.g. <code><em>fr</em></code> for French.') . '</p>';
75		if (!$_common_locale_type) {
76			$localdesc .= '<p>' . gettext('This requires that you have created the appropriate subdomains pointing to your Zenphoto installation. That is <code>fr.mydomain.com/zenphoto/</code> must point to the same location as <code>mydomain.com/zenphoto/</code>. (Some providers will automatically redirect undefined subdomains to the main domain. If your provider does this, no subdomain creation is needed.)') . '</p>';
77		}
78		$options = array(
79				gettext('Album date') => array(
80						'key' => 'sitemap_lastmod_albums',
81						'type' => OPTION_TYPE_SELECTOR,
82						'order' => 0,
83						'selections' => array(
84								gettext("date") => "date",
85								gettext("mtime") => "mtime",
86								gettext("last change date") => 'lastchange'),
87						'desc' => gettext('Field to use for the last modification date of albums.')),
88				gettext('Image date') => array(
89						'key' => 'sitemap_lastmod_images',
90						'type' => OPTION_TYPE_SELECTOR,
91						'order' => 1,
92						'selections' => array(
93								gettext("date") => "date",
94								gettext("mtime") => "mtime",
95								gettext("last change date") => 'lastchange'),
96						'desc' => gettext('Field to use for the last modification date of images.')),
97				gettext('Change frequency - Zenphoto index') => array(
98						'key' => 'sitemap_changefreq_index',
99						'type' => OPTION_TYPE_SELECTOR,
100						'order' => 2,
101						'selections' => array(gettext("always") => "always",
102								gettext("hourly") => "hourly",
103								gettext("daily") => "daily",
104								gettext("weekly") => "weekly",
105								gettext("monthly") => "monthly",
106								gettext("yearly") => "yearly",
107								gettext("never") => "never"),
108						'desc' => ''),
109				gettext('Change frequency - albums') => array(
110						'key' => 'sitemap_changefreq_albums',
111						'type' => OPTION_TYPE_SELECTOR,
112						'order' => 3,
113						'selections' => array(gettext("always") => "always",
114								gettext("hourly") => "hourly",
115								gettext("daily") => "daily",
116								gettext("weekly") => "weekly",
117								gettext("monthly") => "monthly",
118								gettext("yearly") => "yearly",
119								gettext("never") => "never"),
120						'desc' => ''),
121				gettext('Change frequency - images') => array(
122						'key' => 'sitemap_changefreq_images',
123						'type' => OPTION_TYPE_SELECTOR,
124						'order' => 4,
125						'selections' => array(gettext("always") => "always",
126								gettext("hourly") => "hourly",
127								gettext("daily") => "daily",
128								gettext("weekly") => "weekly",
129								gettext("monthly") => "monthly",
130								gettext("yearly") => "yearly",
131								gettext("never") => "never"),
132						'desc' => ''),
133				gettext('Change frequency - Zenpage pages') => array(
134						'key' => 'sitemap_changefreq_pages',
135						'type' => OPTION_TYPE_SELECTOR,
136						'order' => 5,
137						'selections' => array(gettext("always") => "always",
138								gettext("hourly") => "hourly",
139								gettext("daily") => "daily",
140								gettext("weekly") => "weekly",
141								gettext("monthly") => "monthly",
142								gettext("yearly") => "yearly",
143								gettext("never") => "never"),
144						'desc' => ''),
145				gettext('Change frequency - Zenpage news index') => array(
146						'key' => 'sitemap_changefreq_newsindex',
147						'type' => OPTION_TYPE_SELECTOR,
148						'order' => 6,
149						'selections' => array(gettext("always") => "always",
150								gettext("hourly") => "hourly",
151								gettext("daily") => "daily",
152								gettext("weekly") => "weekly",
153								gettext("monthly") => "monthly",
154								gettext("yearly") => "yearly",
155								gettext("never") => "never"),
156						'desc' => ''),
157				gettext('Change frequency: Zenpage news articles') => array(
158						'key' => 'sitemap_changefreq_news',
159						'type' => OPTION_TYPE_SELECTOR,
160						'order' => 7,
161						'selections' => array(gettext("always") => "always",
162								gettext("hourly") => "hourly",
163								gettext("daily") => "daily",
164								gettext("weekly") => "weekly",
165								gettext("monthly") => "monthly",
166								gettext("yearly") => "yearly",
167								gettext("never") => "never"),
168						'desc' => ''),
169				gettext('Change frequency - Zenpage news categories') => array(
170						'key' => 'sitemap_changefreq_newscats',
171						'type' => OPTION_TYPE_SELECTOR,
172						'order' => 8,
173						'selections' => array(gettext("always") => "always",
174								gettext("hourly") => "hourly",
175								gettext("daily") => "daily",
176								gettext("weekly") => "weekly",
177								gettext("monthly") => "monthly",
178								gettext("yearly") => "yearly",
179								gettext("never") => "never"),
180						'desc' => ''),
181				gettext('Enable Google image and video extension') => array(
182						'key' => 'sitemap_google',
183						'type' => OPTION_TYPE_CHECKBOX,
184						'order' => 9,
185						'desc' => gettext('If checked, the XML output file will be formatted using the Google XML image and video extensions where applicable.') . '<p class="notebox">' . gettext('<strong>Note:</strong> Other search engines (Yahoo, Bing) might not be able to read your sitemap. Also the Google extensions cover only image and video formats. If you use custom file types that are not covered by Zenphoto standard plugins or types like .mp3, .txt and .html you should probably not use this or modify the plugin. Also, if your site is really huge think about if you really need this setting as the creation may cause extra workload of your server and result in timeouts') . '</p>'),
186				gettext('Google image and video extension: Link full image ') => array(
187						'key' => 'sitemap_google_fullimage',
188						'type' => OPTION_TYPE_CHECKBOX,
189						'order' => 10,
190						'desc' => gettext('If checked, the original full image is referenced instead of the sized images in the cache. For image formats only.')),
191				gettext('Google - URL to image license') => array(
192						'key' => 'sitemap_license',
193						'type' => OPTION_TYPE_TEXTBOX,
194						'order' => 12,
195						'multilingual' => false,
196						'desc' => gettext('Optional. Used only if the Google extension is checked. Must be an absolute URL address of the form: http://mydomain.com/license.html')),
197				gettext('Sitemap processing chunk') => array(
198						'key' => 'sitemap_processing_chunk',
199						'type' => OPTION_TYPE_TEXTBOX,
200						'order' => 13,
201						'desc' => gettext('The number of albums that will be processed for each sitemap file. Lower this value if you get script timeouts when creating the files.')),
202				gettext('Use subdomains') . '*' => array(
203						'key' => 'dynamic_locale_subdomain',
204						'type' => OPTION_TYPE_CHECKBOX,
205						'order' => 14,
206						'disabled' => $_common_locale_type,
207						'desc' => $localdesc)
208		);
209		if ($_common_locale_type) {
210			$options['note'] = array(
211					'key' => 'sitemap_locale_type',
212					'type' => OPTION_TYPE_NOTE,
213					'order' => 15,
214					'desc' => '<p class="notebox">' . $_common_locale_type . '</p>');
215		} else {
216			$_common_locale_type = gettext('* This option may be set via the <a href="javascript:gotoName(\'sitemap-extended\');"><em>sitemap-extended</em></a> plugin options.');
217			$options['note'] = array(
218					'key' => 'sitemap_locale_type',
219					'type' => OPTION_TYPE_NOTE,
220					'order' => 16,
221					'desc' => gettext('<p class="notebox">*<strong>Note:</strong> The setting of this option is shared with other plugins.</p>'));
222		}
223		return $options;
224	}
225
226	function handleOption($option, $currentValue) {
227
228	}
229
230}
231
232if (isset($_GET['sitemap'])) {
233	$sitemappath = SERVERPATH . '/' . STATIC_CACHE_FOLDER . '/sitemap/sitemapindex.xml';
234	if (file_exists($sitemappath)) {
235		$sitemapfile = file_get_contents($sitemappath);
236		echo $sitemapfile;
237	}
238	exitZP();
239}
240
241/**
242 * Sitemap class
243 */
244class sitemap {
245
246	/**
247	 * creates the Utilities button to purge the static sitemap cache
248	 * @param array $buttons
249	 * @return array
250	 */
251	static function button($buttons) {
252		$buttons[] = array(
253				'category' => gettext('Seo'),
254				'enable' => true,
255				'button_text' => gettext('Sitemap tools'),
256				'formname' => 'sitemap_button',
257				'action' => FULLWEBPATH . '/' . ZENFOLDER . '/' . PLUGIN_FOLDER . '/sitemap-extended/sitemap-extended-admin.php',
258				'icon' => FULLWEBPATH . '/' . ZENFOLDER . '/images/cache.png',
259				'title' => gettext('Generate or purge sitemap cache files.'),
260				'alt' => '',
261				'hidden' => '',
262				'rights' => ADMIN_RIGHTS
263		);
264		return $buttons;
265	}
266
267	/**
268	 * Simple helper function which simply outputs a string and ends it of with a new-line.
269	 * @param  string $string text string
270	 * @return string
271	 */
272	static function echonl($string) {
273		return $string . "\n";
274	}
275
276	/**
277	 * Generates a sitemap file.
278	 *
279	 * @param string $filename How the file should be named. ".xml" is appended automatically
280	 * @param string $data The actual sitemap data as generated by the appropiate functions
281	 */
282	static function generateCacheFile($filename, $data) {
283		if (!empty($data)) {
284			$filepath = SERVERPATH . '/' . STATIC_CACHE_FOLDER . '/sitemap/' . $filename . '.xml';
285			$handler = fopen($filepath, 'w');
286			fwrite($handler, $data);
287			fclose($handler);
288			echo '<li>' . $filename . '</li>';
289		}
290	}
291
292	/**
293	 * Generates the sitemap index file that points to the individual sitemaps from the content of the sitemap cache.
294	 * It is always named "sitemapindex.xml"
295	 */
296	static function generateIndexCacheFile() {
297		$data = '';
298		$cachefolder = SERVERPATH . '/' . STATIC_CACHE_FOLDER . '/sitemap/';
299		$dirs = array_diff(scandir($cachefolder), array('.', '..', '.DS_Store', 'Thumbs.db', '.htaccess', '.svn'));
300		if ($dirs) {
301			$data .= sitemap::echonl('<?xml version="1.0" encoding="UTF-8"?>');
302			$data .= sitemap::echonl('<sitemapindex xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/siteindex.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">');
303			foreach ($dirs as $dir) {
304				$data .= sitemap::echonl("\t<sitemap>");
305				$data .= sitemap::echonl("\t\t<loc>" . FULLWEBPATH . '/' . STATIC_CACHE_FOLDER . '/sitemap/' . $dir . '</loc>');
306				$data .= sitemap::echonl("\t\t<lastmod>" . sitemap::getISO8601Date() . '</lastmod>');
307				$data .= sitemap::echonl("\t</sitemap>");
308			}
309			$data .= sitemap::echonl('</sitemapindex>');
310			$filepath = SERVERPATH . '/' . STATIC_CACHE_FOLDER . '/sitemap/sitemapindex.xml';
311			$handler = fopen($filepath, 'w');
312			fwrite($handler, $data);
313			fclose($handler);
314			echo '<p>sitemapindex.xml created.</p>';
315		}
316	}
317
318	/**
319	 * Checks the changefreq value if entered manually and makes sure it is only one of the supported regarding sitemap.org
320	 * @param  string $changefreq One of the supported changefrequence values regarding sitemap.org. Default is empty or wrong is "daily".
321	 * @return string
322	 */
323	static function getChangefreq($changefreq = '') {
324		$changefreq = sanitize($changefreq);
325		switch ($changefreq) {
326			case 'always':
327			case 'hourly':
328			case 'daily':
329			case 'weekly':
330			case 'monthly':
331			case 'yearly':
332			case 'never':
333				$changefreq = $changefreq;
334				break;
335			default:
336				$changefreq = 'daily';
337				break;
338		}
339		return $changefreq;
340	}
341
342	/**
343	 * Gets the dateformat for images and albums only.
344	 * @param object $obj image or album object
345	 * @param  string $option "date" or "mtime". If "mtime" is discovered to be not set, the date values is taken instead so we don't get 1970-01-10 dates
346	 * @return string
347	 */
348	static function getDateformat($obj, $option) {
349		$date = '';
350		switch ($option) {
351			case 'date':
352			default:
353				$date = $obj->getDatetime();
354				break;
355			case 'mtime':
356				$timestamp = $obj->get('mtime');
357				if ($timestamp == 0) {
358					$date = $obj->getDatetime();
359				} else {
360					return gmstrftime('%Y-%m-%dT%H:%M:%SZ', $timestamp);
361					// For more streamlined but PHP5-only equivalent, remove the above line and uncomment the following:
362					// return gmstrftime(DATE_ISO8601, $timestamp);
363				}
364				break;
365			case 'lastchange':
366				$date = sitemap::getLastChangeDate($obj, true);
367				break;
368		}
369		return sitemap::getISO8601Date($date);
370		// For more streamlined but PHP5-only equivalent, remove the above line and uncomment the following:
371		// return gmstrftime(DATE_ISO8601, strtotime($date));
372	}
373
374	/**
375	 * Gets the limit and offset for the db queries for sitemap splitting.
376	 * @param  int $items_per_sitemap Number of items per sitemap
377	 * @return string
378	 */
379	static function getDBLimit($items_per_sitemap = 2) {
380		global $_sitemap_number;
381		if ($_sitemap_number < 1) {
382			$_sitemap_number = 1;
383		}
384		$offset = ($_sitemap_number - 1) * $items_per_sitemap;
385		$limit = " LIMIT " . $offset . "," . $items_per_sitemap;
386		return $limit;
387	}
388
389	/*	 * TODO index links are not splitted into several sitemaps yet
390	 *
391	 * Gets the links to the index of a Zenphoto gallery incl. index pagination
392	 *
393	 * @return string
394	 */
395
396	static function getIndexLinks() {
397		global $_zp_gallery, $_sitemap_number;
398		$data = '';
399		if ($_sitemap_number < 2) {
400			set_context(ZP_INDEX);
401			$albums_per_page = getOption('albums_per_page');
402			if (getOption('custom_index_page')) {
403				$galleryindex = getCustomGalleryIndexURL(1, '');
404			} else {
405				$galleryindex = getStandardGalleryIndexURL(1, '');
406			}
407			$toplevelpages = getTotalPages();
408			$data .= sitemap::echonl('<?xml version="1.0" encoding="UTF-8"?>');
409			$data .= sitemap::echonl('<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">');
410			$sitemap_locales = generateLanguageList();
411			$changefreq = sitemap::getChangefreq(getOption('sitemap_changefreq_index'));
412			// normal index/homepage we need in any case always
413			$date = sitemap::getISO8601Date();
414			switch (SITEMAP_LOCALE_TYPE) {
415				case 1:
416					foreach ($sitemap_locales as $locale) {
417						$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . seo_locale::localePath(true, $locale) . "/</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
418					}
419					break;
420				case 2:
421					foreach ($sitemap_locales as $locale) {
422						$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . dynamic_locale::fullHostPath($locale) . "/</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
423					}
424					break;
425				default:
426					$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . FULLWEBPATH . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
427					break;
428			}
429			// the extra ones if we have a custom gallery index
430			if (getOption('custom_index_page')) {
431				switch (SITEMAP_LOCALE_TYPE) {
432					case 1:
433						foreach ($sitemap_locales as $locale) {
434							$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . seo_locale::localePath(true, $locale) . '/' . $galleryindex . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
435						}
436						break;
437					case 2:
438						foreach ($sitemap_locales as $locale) {
439							$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . dynamic_locale::fullHostPath($locale) . '/' . $galleryindex . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
440						}
441						break;
442					default:
443						$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . FULLWEBPATH . $galleryindex . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
444						break;
445				}
446			}
447			// print further index pages if available
448			if ($toplevelpages) {
449				for ($x = 2; $x <= $toplevelpages; $x++) {
450					if (getOption('custom_index_page')) {
451						$galleryindex = getCustomGalleryIndexURL($x, '');
452					} else {
453						$galleryindex = getStandardGalleryIndexURL($x, '');
454					}
455					switch (SITEMAP_LOCALE_TYPE) {
456						case 1:
457							foreach ($sitemap_locales as $locale) {
458								$url = seo_locale::localePath(true, $locale) . $galleryindex;
459								$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
460							}
461							break;
462						case 2:
463							foreach ($sitemap_locales as $locale) {
464								$url = dynamic_locale::fullHostPath($locale) . $galleryindex;
465								$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
466							}
467							break;
468						default:
469							$url = FULLWEBPATH . $galleryindex;
470							$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
471							break;
472					}
473				}
474			}
475			$data .= sitemap::echonl('</urlset>'); // End off the <urlset> tag
476			restore_context();
477			return $data;
478		} // sitemap number end
479	}
480
481	/**
482	 *
483	 * Enter description here ...
484	 * @param object $obj the starting point
485	 * @param array $albumlist the container for the results
486	 */
487	static function getAlbumList($obj, &$albumlist) {
488		global $_zp_gallery;
489		$locallist = $obj->getAlbums();
490		foreach ($locallist as $folder) {
491			$album = newAlbum($folder);
492			if ($album->isPublic() && !$album->isProtected()) {
493				$albumlist[] = array('folder' => $album->name, 'date' => $album->getDateTime(), 'title' => $album->getTitle());
494				if (!$album->isDynamic()) {
495					sitemap::getAlbumList($album, $albumlist);
496				}
497			}
498		}
499	}
500
501	/**
502	 * gateway check for albums (no refinement of the criteria)
503	 *
504	 * @deprecated Unused
505	 * @param object $album
506	 */
507	static function passAlbums($album) {
508		return true;
509	}
510
511	/**
512	 * gateway function for images (screens out dynamic albums and password protected albums)
513	 *
514	 * @deprecated Unused
515	 * @param object $album
516	 */
517	static function passImages($album) {
518		return !$album->isDynamic() && !$album->getPassword();
519	}
520
521	/**
522	 * Places album and all of its album pages on one sitemap
523	 *
524	 * Gets links to all albums incl. pagination and if the Google image video extension is enabled for images using this as well.
525	 * This is independent from the images fetched by getSitemapImages().
526	 *
527	 * NOTE: Using the Google extension is currently NOT recommended if you have a huge gallery.
528	 *
529	 * @return string
530	 */
531	static function getAlbums() {
532		global $_zp_gallery, $_sitemap_number;
533		$data_start = $data = '';
534		$sitemap_locales = generateLanguageList();
535		$albumchangefreq = getOption('sitemap_changefreq_albums');
536		$imagechangefreq = getOption('sitemap_changefreq_images');
537		$albumlastmod = getOption('sitemap_lastmod_albums');
538		$albumlastmod = sanitize($albumlastmod);
539		$imagelastmod = getOption('sitemap_lastmod_images');
540		$albums = array();
541		sitemap::getAlbumList($_zp_gallery, $albums);
542		$offset = ($_sitemap_number - 1);
543		$albums = array_slice($albums, $offset, SITEMAP_CHUNK);
544		if (!empty($albums)) {
545			$data_start .= sitemap::echonl('<?xml version="1.0" encoding="UTF-8"?>');
546			$data_start .= sitemap::echonl('<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">');
547			foreach ($albums as $album) {
548				$albumobj = newAlbum($album['folder']);
549				set_context(ZP_ALBUM);
550				makeAlbumCurrent($albumobj);
551				$pageCount = getTotalPages();
552				//$imageCount = getNumImages();
553				//$images = $albumobj->getImages();
554				$date = sitemap::getDateformat($albumobj, $albumlastmod);
555				switch (SITEMAP_LOCALE_TYPE) {
556					case 1:
557						foreach ($sitemap_locales as $locale) {
558							$url = seo_locale::localePath(true, $locale) . '/' . pathurlencode($albumobj->linkname) . '/';
559							$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $albumchangefreq . "</changefreq>\n\t\t<priority>0.8</priority>\n");
560							$data .= sitemap::echonl("\t</url>");
561						}
562						break;
563					case 2:
564						foreach ($sitemap_locales as $locale) {
565							$url = rewrite_path(pathurlencode($albumobj->linkname) . '/', '?album=' . pathurlencode($albumobj->name), dynamic_locale::fullHostPath($locale));
566							$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $albumchangefreq . "</changefreq>\n\t\t<priority>0.8</priority>\n");
567							$data .= sitemap::echonl("\t</url>");
568						}
569						break;
570					default:
571						$url = rewrite_path(pathurlencode($albumobj->linkname) . '/', '?album=' . pathurlencode($albumobj->name), FULLWEBPATH);
572						$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $albumchangefreq . "</changefreq>\n\t\t<priority>0.8</priority>\n");
573						$data .= sitemap::echonl("\t</url>");
574						break;
575				}
576				// print album pages if avaiable
577				if ($pageCount > 1) {
578					for ($x = 2; $x <= $pageCount; $x++) {
579						switch (SITEMAP_LOCALE_TYPE) {
580							case 1:
581								foreach ($sitemap_locales as $locale) {
582									$url = seo_locale::localePath(true, $locale) . '/' . pathurlencode($albumobj->linkname) . '/' . _PAGE_ . '/' . $x . '/';
583									$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $albumchangefreq . "</changefreq>\n\t\t<priority>0.8</priority>\n");
584									$data .= sitemap::echonl("\t</url>");
585								}
586								break;
587							case 2:
588								foreach ($sitemap_locales as $locale) {
589									$url = rewrite_path(pathurlencode($albumobj->linkname) . '/' . _PAGE_ . '/' . $x . '/', '?album=' . pathurlencode($albumobj->name) . '&amp;page=' . $x, dynamic_locale::fullHostPath($locale));
590									$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $albumchangefreq . "</changefreq>\n\t\t<priority>0.8</priority>\n");
591									$data .= sitemap::echonl("\t</url>");
592								}
593								break;
594							default:
595								$url = rewrite_path(pathurlencode($albumobj->linkname) . '/' . _PAGE_ . '/' . $x . '/', '?album=' . pathurlencode($albumobj->name) . '&amp;page=' . $x, FULLWEBPATH);
596								$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $albumchangefreq . "</changefreq>\n\t\t<priority>0.8</priority>\n");
597								$data .= sitemap::echonl("\t</url>");
598								break;
599						}
600					}
601				}
602			}
603			if (!empty($data)) {
604				$data = $data_start . $data . sitemap::echonl('</urlset>'); // End off the <urlset> tag
605			}
606		}
607		restore_context();
608		return $data;
609	}
610
611	/**
612	 * currently this splitts only sitemaps for albums and its images. Spliting the images itself requires a major rework...
613	 *
614	 * Gets links to all images for all albums (album by album)
615	 *
616	 * @return string
617	 */
618	static function getImages() {
619		global $_zp_gallery, $_sitemap_number;
620		$data_start = $data = '';
621		$sitemap_locales = generateLanguageList();
622		$imagechangefreq = getOption('sitemap_changefreq_images');
623		$imagelastmod = getOption('sitemap_lastmod_images');
624		$limit = sitemap::getDBLimit(1);
625		$albums = array();
626		sitemap::getAlbumList($_zp_gallery, $albums);
627		$offset = ($_sitemap_number - 1);
628		$albums = array_slice($albums, $offset, SITEMAP_CHUNK);
629		if ($albums) {
630			$data_start .= sitemap::echonl('<?xml version="1.0" encoding="UTF-8"?>');
631			if (GOOGLE_SITEMAP) {
632				$data_start .= sitemap::echonl('<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">');
633			} else {
634				$data_start .= sitemap::echonl('<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">');
635			}
636			foreach ($albums as $album) {
637				@set_time_limit(120); //	Extend script timeout to allow for gathering the images.
638				$albumobj = newAlbum($album['folder']);
639				$images = $albumobj->getImages();
640				// print plain images links if available
641				if ($images) {
642					foreach ($images as $image) {
643						$imageobj = newImage($albumobj, $image);
644						if($imageobj->isPublic() && !$albumobj->isDynamic()) {
645						$ext = getSuffix($imageobj->filename);
646						$date = sitemap::getDateformat($imageobj, $imagelastmod);
647						switch (SITEMAP_LOCALE_TYPE) {
648							case 1:
649								foreach ($sitemap_locales as $locale) {
650									$path = seo_locale::localePath(true, $locale) . '/' . pathurlencode($albumobj->linkname) . '/' . urlencode($imageobj->filename) . IM_SUFFIX;
651									$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $path . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $imagechangefreq . "</changefreq>\n\t\t<priority>0.6</priority>\n");
652									if (GOOGLE_SITEMAP) {
653										$data .= sitemap::getGoogleImageVideoExtras($albumobj, $imageobj, $locale);
654									}
655									$data .= sitemap::echonl("</url>");
656								}
657								break;
658							case 2:
659								foreach ($sitemap_locales as $locale) {
660									$path = rewrite_path(pathurlencode($albumobj->linkname) . '/' . urlencode($imageobj->filename) . IM_SUFFIX, '?album=' . pathurlencode($albumobj->name) . '&amp;image=' . urlencode($imageobj->filename), dynamic_locale::fullHostPath($locale));
661									$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $path . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $imagechangefreq . "</changefreq>\n\t\t<priority>0.6</priority>\n");
662									if (GOOGLE_SITEMAP) {
663										$data .= sitemap::getGoogleImageVideoExtras($albumobj, $imageobj, $locale);
664									}
665									$data .= sitemap::echonl("</url>");
666								}
667								break;
668							default:
669								$path = rewrite_path(pathurlencode($albumobj->linkname) . '/' . urlencode($imageobj->filename) . IM_SUFFIX, '?album=' . pathurlencode($albumobj->name) . '&amp;image=' . urlencode($imageobj->filename), FULLWEBPATH);
670								$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $path . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $imagechangefreq . "</changefreq>\n\t\t<priority>0.6</priority>\n");
671								if (GOOGLE_SITEMAP) {
672									$data .= sitemap::getGoogleImageVideoExtras($albumobj, $imageobj, NULL);
673								}
674								$data .= sitemap::echonl("</url>");
675								break;
676						}
677					}
678				}
679			}
680			}
681			if (!empty($data)) {
682				$data = $data_start . $data . sitemap::echonl('</urlset>'); // End off the <urlset> tag
683			}
684		}
685		return $data;
686	}
687
688	/**
689	 * Helper function to get the loop index if the Google video extension is enabled
690	 */
691	static function getGoogleLoopIndex($imageCount, $pageCount) {
692		if (GOOGLE_SITEMAP) {
693			$loop_index = array();
694			for ($x = 1; $x <= $pageCount; $x++) {
695				if ($imageCount < ($x * getOption('images_per_page'))) {
696					$val = $imageCount - (($x - 1) * getOption('images_per_page'));
697				} else {
698					$val = getOption('images_per_page');
699				}
700				array_push($loop_index, $val);
701			}
702			return $loop_index;
703		}
704		return NULL;
705	}
706
707	/**
708	 * Helper function to get the image/video extra entries for albums if the Google video extension is enabled
709	 * @return string
710	 */
711	static function getGoogleImageVideoExtras($albumobj, $imageobj, $locale) {
712		$data = '';
713		$host = PROTOCOL . '://' . html_encode($_SERVER["HTTP_HOST"]);
714		$ext = strtolower(strrchr($imageobj->filename, "."));
715		$location = '';
716		if ($imageobj->getLocation()) {
717			$location .= $imageobj->getLocation($locale) . ', ';
718		}
719		if ($imageobj->getCity()) {
720			$location .= $imageobj->getCity($locale) . ', ';
721		}
722		if ($imageobj->getState()) {
723			$location .= $imageobj->getState($locale) . ', ';
724		}
725		if ($imageobj->getCountry()) {
726			$location .= $imageobj->getCountry($locale);
727		}
728		$license = getOption('sitemap_license');
729		if (empty($license)) {
730			$license = $imageobj->getCopyrightURL();
731		}
732		if (isImageVideo($imageobj) && in_array($ext, array('.mpg', '.mpeg', '.mp4', '.m4v', '.mov', '.wmv', '.asf', '.avi', '.ra', '.ram', '.flv', '.swf'))) { // google says it can index these so we list them even if unsupported by Zenphoto
733			$data .= sitemap::echonl("\t\t<video:video>\n\t\t\t<video:thumbnail_loc>" . $host . html_encode($imageobj->getThumb()) . "</video:thumbnail_loc>\n");
734			$data .= sitemap::echonl("\t\t\t<video:title>" . html_encode($imageobj->getTitle($locale)) . "</video:title>");
735			if ($imageobj->getDesc()) {
736				$data .= sitemap::echonl("\t\t\t<video:description>" . html_encode(getBare($imageobj->getDesc($locale))) . "</video:description>");
737			}
738			$data .= sitemap::echonl("\t\t\t<video:content_loc>" . $host . pathurlencode($imageobj->getFullImageURL()) . "</video:content_loc>");
739			$data .= sitemap::echonl("\t\t</video:video>");
740		} else if (in_array($ext, array('.jpg', '.jpeg', '.gif', '.png'))) { // this might need to be extended!
741			if (getOption('sitemap_google_fullimage')) {
742				$imagelocation = $host . pathurlencode($imageobj->getFullImageURL());
743			} else {
744				$imagelocation = $host . html_encode($imageobj->getSizedImage(getOption('image_size')));
745			}
746			$data .= sitemap::echonl("\t\t<image:image>\n\t\t\t<image:loc>" . html_encode($imagelocation) . "</image:loc>\n");
747			// disabled for the multilingual reasons above
748			$data .= sitemap::echonl("\t\t\t<image:title>" . html_encode($imageobj->getTitle($locale)) . "</image:title>");
749			if ($imageobj->getDesc()) {
750				$data .= sitemap::echonl("\t\t\t<image:caption>" . html_encode(getBare($imageobj->getDesc($locale))) . "</image:caption>");
751			}
752			if (!empty($license)) {
753				$data .= sitemap::echonl("\t\t\t<image:license>" . html_encode($license) . "</image:license>");
754			}
755			// location is kept although the same multilingual issue applies
756			if (!empty($location)) {
757				$data .= sitemap::echonl("\t\t\t<image:geo_location>" . html_encode($location) . "</image:geo_location>");
758			}
759			$data .= sitemap::echonl("\t\t</image:image>");
760		}
761		return $data;
762	}
763
764	/**
765	 * Gets links to all Zenpage pages
766	 *
767	 * @return string
768	 */
769	static function getZenpagePages() {
770		global $_zp_zenpage, $_sitemap_number;
771		//not splitted into several sitemaps yet
772		if ($_sitemap_number == 1) {
773			$data_start = $data = '';
774			$limit = sitemap::getDBLimit(2);
775			$sitemap_locales = generateLanguageList();
776			$changefreq = getOption('sitemap_changefreq_pages');
777			$pages = $_zp_zenpage->getPages(true);
778			if ($pages) {
779				$data_start .= sitemap::echonl('<?xml version="1.0" encoding="UTF-8"?>');
780				$data_start .= sitemap::echonl('<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">');
781				foreach ($pages as $page) {
782					$pageobj = new ZenpagePage($page['titlelink']);
783					if ($pageobj->isPublic() && !$pageobj->isProtected()) {
784						$date = sitemap::getLastChangeDate($pageobj, false);
785							switch (SITEMAP_LOCALE_TYPE) {
786								case 1:
787									foreach ($sitemap_locales as $locale) {
788										$url = seo_locale::localePath(true, $locale) . '/' . _PAGES_ . '/' . urlencode($page['titlelink']) . '/';
789										$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
790									}
791									break;
792								case 2:
793									foreach ($sitemap_locales as $locale) {
794										$url = rewrite_path(_PAGES_ . '/' . urlencode($page['titlelink']) . '/', '?p=pages&amp;title=' . urlencode($page['titlelink']), dynamic_locale::fullHostPath($locale));
795										$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
796									}
797									break;
798								default:
799									$url = rewrite_path(_PAGES_ . '/' . urlencode($page['titlelink']) . '/', '?p=pages&amp;title=' . urlencode($page['titlelink']), FULLWEBPATH);
800									$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
801									break;
802							}
803						}
804
805				}
806				if (!empty($data)) {
807					$data = $data_start . $data . sitemap::echonl('</urlset>'); // End off the <urlset> tag
808				}
809			}
810			return $data;
811		}
812	}
813
814	/**
815	 * Gets links to the main Zenpage news index incl. pagination
816	 *
817	 * @return string
818	 */
819	static function getZenpageNewsIndex() {
820		global $_zp_zenpage, $_sitemap_number;
821		//not splitted into several sitemaps yet
822		if ($_sitemap_number == 1) {
823			$data = '';
824			$data .= sitemap::echonl('<?xml version="1.0" encoding="UTF-8"?>');
825			$data .= sitemap::echonl('<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">');
826			$sitemap_locales = generateLanguageList();
827			$changefreq = getOption('sitemap_changefreq_newsindex');
828			$date = sitemap::getISO8601Date();
829			switch (SITEMAP_LOCALE_TYPE) {
830				case 1:
831					foreach ($sitemap_locales as $locale) {
832						$url = seo_locale::localePath(true, $locale) . '/' . _NEWS_ . '/1/';
833						$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
834					}
835					Break;
836				case 2:
837					foreach ($sitemap_locales as $locale) {
838						$url = rewrite_path(_NEWS_ . '/1/', '?p=news&amp;page=1', dynamic_locale::fullHostPath($locale));
839						$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
840					}
841					Break;
842				default:
843					$url = rewrite_path(_NEWS_ . '/1/', '?p=news&amp;page=1', FULLWEBPATH);
844					$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
845					Break;
846			}
847			// getting pages for the main news loop
848			/* Not used anyway
849			  if(!empty($articlesperpage)) {
850			  $zenpage_articles_per_page = sanitize_numeric($articlesperpage);
851			  } else {
852			  $zenpage_articles_per_page = ZP_ARTICLES_PER_PAGE;
853			  } */
854			$zenpage_articles_per_page = ZP_ARTICLES_PER_PAGE;
855			$newspages = ceil($_zp_zenpage->getTotalArticles() / $zenpage_articles_per_page);
856			if ($newspages > 1) {
857				for ($x = 2; $x <= $newspages; $x++) {
858					switch (SITEMAP_LOCALE_TYPE) {
859						case 1:
860							foreach ($sitemap_locales as $locale) {
861								$url = seo_locale::localePath(true, $locale) . '/' . _NEWS_ . '/' . $x . '/';
862								$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
863							}
864							break;
865						case 2:
866							foreach ($sitemap_locales as $locale) {
867								$url = rewrite_path(_NEWS_ . '/' . $x . '/', '?p=news&amp;page=' . $x, dynamic_locale::fullHostPath($locale));
868								$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
869							}
870							break;
871						default:
872							$url = rewrite_path(_NEWS_ . '/' . $x . '/', '?p=news&amp;page=' . $x, FULLWEBPATH);
873							$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
874							break;
875					}
876				}
877			}
878			$data .= sitemap::echonl('</urlset>'); // End off the <urlset> tag
879			return $data;
880		}
881	}
882
883	/**
884	 * Gets to the Zenpage news articles
885	 *
886	 * @param  string $changefreq One of the supported changefrequence values regarding sitemap.org. Default is empty or wrong is "daily".
887	 * @return string
888	 */
889	static function getZenpageNewsArticles() {
890		global $_zp_zenpage, $_sitemap_number;
891		//not splitted into several sitemaps yet
892		if ($_sitemap_number == 1) {
893			$data_start = $data = '';
894			$sitemap_locales = generateLanguageList();
895			$changefreq = getOption('sitemap_changefreq_news');
896			$articles = $_zp_zenpage->getArticles('', 'published', true, "date", "desc");
897			if ($articles) {
898				$data_start .= sitemap::echonl('<?xml version="1.0" encoding="UTF-8"?>');
899				$data_start .= sitemap::echonl('<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">');
900				foreach ($articles as $article) {
901					$articleobj = new ZenpageNews($article['titlelink']);
902					if ($articleobj->isPublic() && !$articleobj->isProtected()) {
903						$date = sitemap::getLastChangeDate($articleobj, false);
904							switch (SITEMAP_LOCALE_TYPE) {
905								case 1:
906									foreach ($sitemap_locales as $locale) {
907										$url = seo_locale::localePath(true, $locale) . '/' . _NEWS_ . '/' . urlencode($articleobj->getTitlelink()) . '/';
908										$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
909									}
910									break;
911								case 2:
912									foreach ($sitemap_locales as $locale) {
913										$url = rewrite_path(_NEWS_ . '/' . urlencode($articleobj->getTitlelink()) . '/', '?p=news&amp;title=' . urlencode($articleobj->getTitlelink()), dynamic_locale::fullHostPath($locale));
914										$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
915									}
916									break;
917								default:
918									$url = rewrite_path(_NEWS_ . '/' . urlencode($articleobj->getTitlelink()) . '/', '?p=news&amp;title=' . urlencode($articleobj->getTitlelink()), FULLWEBPATH);
919									$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<lastmod>" . $date . "</lastmod>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
920									break;
921							}
922						}
923					}
924				if (!empty($data)) {
925					$data = $data_start . $data . sitemap::echonl('</urlset>'); // End off the <urlset> tag
926				}
927			}
928			return $data;
929		}
930	}
931
932	/**
933	 * Gets links to Zenpage news categories incl. pagination
934	 *
935	 * @return string
936	 */
937	static function getZenpageNewsCategories() {
938		global $_zp_zenpage, $_sitemap_number;
939		//TODO not splitted into several sitemaps yet
940		if ($_sitemap_number == 1) {
941			$data_start = $data = '';
942			$sitemap_locales = generateLanguageList();
943			$changefreq = getOption('sitemap_changefreq_newscats');
944			$newscats = $_zp_zenpage->getAllCategories();
945			if ($newscats) {
946				$data_start .= sitemap::echonl('<?xml version="1.0" encoding="UTF-8"?>');
947				$data_start .= sitemap::echonl('<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">');
948				foreach ($newscats as $newscat) {
949					$catobj = new ZenpageCategory($newscat['titlelink']);
950					if ($catobj->isPublic() && !$catobj->isProtected()) {
951							switch (SITEMAP_LOCALE_TYPE) {
952								case 1:
953									foreach ($sitemap_locales as $locale) {
954										$url = seo_locale::localePath(true, $locale) . '/' . _CATEGORY_ . '/' . urlencode($catobj->getTitlelink()) . '/1/';
955										$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
956									}
957									break;
958								case 2:
959									foreach ($sitemap_locales as $locale) {
960										$url = rewrite_path(_CATEGORY_ . '/' . urlencode($catobj->getTitlelink()) . '/1/', '?p=news&amp;category=' . urlencode($catobj->getTitlelink()) . '&amp;page=1', dynamic_locale::fullHostPath($locale));
961										$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
962									}
963									break;
964								default:
965									$url = rewrite_path(_CATEGORY_ . '/' . urlencode($catobj->getTitlelink()) . '/1/', '?p=news&amp;category=' . urlencode($catobj->getTitlelink()) . '&amp;page=1', FULLWEBPATH);
966									$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
967									break;
968							}
969							// getting pages for the categories
970							/*
971							  if(!empty($articlesperpage)) {
972							  $zenpage_articles_per_page = sanitize_numeric($articlesperpage);
973							  } else {
974							  $zenpage_articles_per_page = ZP_ARTICLES_PER_PAGE;
975							  } */
976							$zenpage_articles_per_page = ZP_ARTICLES_PER_PAGE;
977							$articlecount = count($catobj->getArticles());
978							$catpages = ceil($articlecount / $zenpage_articles_per_page);
979							if ($catpages > 1) {
980								for ($x = 2; $x <= $catpages; $x++) {
981									switch (SITEMAP_LOCALE_TYPE) {
982										case 1:
983											foreach ($sitemap_locales as $locale) {
984												$url = seo_locale::localePath(true, $locale) . '/' . _CATEGORY_ . '/' . urlencode($catobj->getTitlelink()) . '/' . $x . '/';
985												$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
986											}
987											break;
988										case 2:
989											foreach ($sitemap_locales as $locale) {
990												$url = rewrite_path(_CATEGORY_ . '/' . urlencode($catobj->getTitlelink()) . '/' . $x . '/', '?p=news&amp;category=' . urlencode($catobj->getTitlelink()) . '&amp;page=' . $x, dynamic_locale::fullHostPath($locale));
991												$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
992											}
993											break;
994										default:
995											$url = rewrite_path(_CATEGORY_ . '/' . urlencode($catobj->getTitlelink()) . '/' . $x . '/', '?p=news&amp;category=' . urlencode($catobj->getTitlelink()) . '&amp;page=' . $x, FULLWEBPATH);
996											$data .= sitemap::echonl("\t<url>\n\t\t<loc>" . $url . "</loc>\n\t\t<changefreq>" . $changefreq . "</changefreq>\n\t\t<priority>0.9</priority>\n\t</url>");
997											break;
998									}
999								}
1000							}
1001						}
1002					}
1003
1004				if (!empty($data)) {
1005					$data = $data_start . $data . sitemap::echonl('</urlset>'); // End off the <urlset> tag
1006				}
1007			}
1008			return $data;
1009		}
1010	}
1011
1012	/**
1013	 * Cleans out the cache folder.
1014	 *
1015	 */
1016	static function clearCache() {
1017		$cachefolder = SERVERPATH . '/' . STATIC_CACHE_FOLDER . '/sitemap/';
1018		if (is_dir($cachefolder)) {
1019			$handle = opendir($cachefolder);
1020			while (false !== ($filename = readdir($handle))) {
1021				$fullname = $cachefolder . '/' . $filename;
1022				if (is_dir($fullname) && !(substr($filename, 0, 1) == '.')) {
1023					if (($filename != '.') && ($filename != '..')) {
1024						RSS::clearRSSCache($fullname);
1025						rmdir($fullname);
1026					}
1027				} else {
1028					if (file_exists($fullname) && !(substr($filename, 0, 1) == '.')) {
1029						@chmod($fullname, 0777);
1030						unlink($fullname);
1031					}
1032				}
1033			}
1034			closedir($handle);
1035		}
1036	}
1037
1038	/**
1039	 * Returns an ISO-8601 compliant date/time string for the given date/time.
1040	 * While PHP5 can use the date format constant DATE_ISO8601, this function is designed to allow PHP4 use as well.
1041	 * Eventually it can be deprecated, by:
1042	 *   1. Replacing parameterless references to this function with date(DATE_ISO8601)
1043	 *   2. Replacing references to this function in sitemap_getDateformat as documented there
1044	 *
1045	 */
1046	static function getISO8601Date($date = '') {
1047		if (empty($date)) {
1048			return gmstrftime('%Y-%m-%dT%H:%M:%SZ');
1049		} else {
1050			return gmstrftime('%Y-%m-%dT%H:%M:%SZ', strtotime($date));
1051		}
1052	}
1053
1054	static function printAvailableSitemaps() {
1055		$cachefolder = SERVERPATH . '/' . STATIC_CACHE_FOLDER . '/sitemap/';
1056		$dirs = array_diff(scandir($cachefolder), array('.', '..', '.DS_Store', 'Thumbs.db', '.htaccess', '.svn'));
1057		echo '<h2>' . gettext('Available sitemap files:') . '</h2>';
1058		if (!$dirs) {
1059			echo '<p>' . gettext('No sitemap files available.') . '</p>';
1060		} else {
1061			echo '<ol>';
1062			foreach ($dirs as $dir) {
1063				$filemtime = filemtime($cachefolder . $dir);
1064				$lastchange = date('Y-m-d H:m:s', $filemtime);
1065				?>
1066				<li><a target="_blank" href="<?php echo FULLWEBPATH . '/' . STATIC_CACHE_FOLDER; ?>/sitemap/<?php echo $dir; ?>"><?php echo $dir; ?></a> (<small><?php echo $lastchange; ?>)</small>
1067				</li>
1068				<?php
1069			}
1070			echo '</ol>';
1071		}
1072	}
1073
1074	/**
1075	 * Gets the date as Y-m-d or if available last change date of $obj
1076	 *
1077	 * @param obj $obj
1078	 * @param bool $fulldate True to return the full date incl. time, otherwise the date only
1079	 * @return string
1080	 */
1081	static function getLastChangeDate($obj, $fulldate = false) {
1082		$date = $obj->getDatetime();
1083		if (!$fulldate) {
1084			$date = substr($date, 0, 10);
1085		}
1086		$lastchange = '';
1087		if (!is_null($obj->getLastchange())) {
1088			$lastchange = $obj->getLastchange();
1089			if (!$fulldate) {
1090				$lastchange = substr($lastchange, 0, 10);
1091			}
1092		}
1093		if ($date > $lastchange && !empty($lastchange)) {
1094			return $lastchange;
1095		}
1096		return $date;
1097	}
1098
1099}
1100