<?php
/**
 * This file implements the (Google) Sitemap Plugin.
 *
 * It is inspired by various Google Sitemap plugins or hacks, e.g. the
 * "Google Sitemap Generator for WordPress" ({@link http://www.arnebrachhold.de/2005/06/05/google-sitemaps-generator-v2-final})
 * or {@link http://forums.b2evolution.net/viewtopic.php?t=8516}, which itself has taken code
 * from somewhere. So, thanks everybody.. ;p
 *
 * @see http://manual.b2evolution.net/Sitemap_plugin
 *
 * @copyright (c)2006 by Daniel HAHLER - {@link http://daniel.hahler.de/}
 * Parts of this file are copyright (c)2007 by Francois PLANQUE - {@link http://fplanque.net/}
 *
 * @license http://www.opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
 *
 * @package plugins
 *
 * @author blueyed: Daniel HAHLER
 *
 * @version $Id: _sitemap.plugin.php,v 1.1.2.1 2007/03/17 23:27:59 fplanque Exp $
 */
if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );


/**
 * (Google) Sitemap Plugin
 *
 * @todo Ping Google after new post has been created
 * @todo Provide setting (array?) to include and exclude specific blogs from pinging.
 * @package plugins
 */
class sitemap_plugin extends Plugin
{
	/**
	 * Variables below MUST be overriden by plugin implementations,
	 * either in the subclass declaration or in the subclass constructor.
	 */
	var $name = 'Sitemap Plugin';
	var $priority = 100;
	var $version = '1.10-dev';
	var $author = 'http://daniel.hahler.de/';

	/*
	 * These variables MAY be overriden.
	 */
	var $apply_rendering = 'never';
	#var $number_of_installs = 1;
	#var $group = 'test';


	/**
	 * Init
	 *
	 * This gets called after a plugin has been registered/instantiated.
	 */
	function PluginInit( & $params )
	{
		$this->short_desc = $this->T_('Sitemap plugin');
		$this->long_desc = $this->T_('This plugin generates a Google Sitemap for your blog.');
	}


	/**
	 * We require b2evo 1.9, because of the events we're hooking into.
	 */
	function GetDependencies()
	{
		return array(
				'requires' => array(
					'app_min' => '1.9-dev',
				),
			);
	}


	/**
	 * @return array
	 */
	function GetDefaultSettings( & $params )
	{
		$r = array(
			'include_changefreq' => array(
				'label' => $this->T_('Change frequency'),
				'defaultvalue' => '1',
				'type' => 'checkbox',
				'note' => $this->T_('Include change frequency (see manual).'),
			),
			'auto_prio_cmts' => array(
				'label' => $this->T_('Auto priority'),
				'defaultvalue' => '1',
				'type' => 'checkbox',
				'note' => $this->T_('Use auto priority for items based on comment count.'),
			),
			'prio_items_min' => array(
				'label' => $this->T_('Min post priority'),
				'defaultvalue' => '0.1',
				'type' => 'float',
				'valid_range' => array('min'=>0, 'max'=>1),
				'note' => $this->T_('Minimum priority for posts, even is auto priority is enabled.'),
			),
			'prio_items' => array(
				'label' => $this->T_('Default/Max post priority'),
				'defaultvalue' => '0.8',
				'type' => 'float',
				'valid_range' => array('min'=>0, 'max'=>1),
				'note' => $this->T_('Maximum priority for posts or default if auto priority is disabled.'),
			),
			/*
			'ping_google' => array(
				'label' => $this->T_('Ping Google'),
				'defaultvalue' => '1',
				'type' => 'checkbox',
				'note' => $this->T_('Ping Google after an item gets created or updated?'),
			),
			'pinggoogle_sitemaps' => array(
				'label' => $this->T_('Google Sitemaps'),
				'type' => 'array',
				'defaultvalue' => array(),
				'entries' => array(
					'',
				),
				'note' => $this->T_('A list of Google sitemaps, available for this application. Check to enable them for pinging on creating or updating items.'),
			),
			*/
			array( 'layout' => 'separator' ),
			'output_debug' => array(
					'label' => $this->T_('Debug output'),
					'defaultvalue' => 0,
					'type' => 'checkbox',
					'note' => $this->T_('Debug output in comments of the generated XML.'),
				),
			);

		/*
		if( method_exists('get_Cache') )
		{ // 2.0
			global $BlogCache;
		}
		else $BlogCache = & get_Cache('BlogCache');
		$BlogCache->load_all();
		foreach( $BlogCache->get_ID_array() as $blog_ID )
		{
			$loop_Blog = & $BlogCache->get_by_ID($blog_ID);
		}

		if( $params['for_editing'] )
		{
			pre_dump( $this->Settings->get('google_sitemaps') );
		}
		*/

		return $r;
	}


	/**
	 * We provide the "sitemap" skin, to display the Sitemap XML.
	 *
	 * @return array
	 */
	function GetProvidedSkins()
	{
		return array( 'sitemap' );
	}


	/**
	 * Display the skin - the Google Sitemap.
	 */
	function DisplaySkin( & $params )
	{
		if( $params['skin'] != 'sitemap' )
		{ // should not happen
			debug_die('Received invalid $skin param.');
		}

		global $DB, $app_name, $app_version, $io_charset;
		global $Blog;

		header( 'Content-type: application/xml; charset='.$io_charset );

		// Init:

 		$include_changefreq = $this->Settings->get('include_changefreq');

		if( $this->Settings->get('auto_prio_cmts') )
		{	// We want to compute automatic priorities based on number of comments.

			$comments_total_count = $DB->get_var(
				'SELECT COUNT(*)
					FROM T_comments
				 WHERE comment_status = "published"');
			if( $comments_total_count > 0 )
			{	// There are comments. Get details.

				$comments_info = $DB->get_assoc( '
					SELECT comment_post_ID, COUNT(comment_ID) AS comment_count
						FROM T_comments
 					 WHERE comment_status = "published"
					 GROUP BY comment_post_ID' );
				$prio_items_min = $this->Settings->get('prio_items_min');
			}
		}

		$prio_items = $this->Settings->get('prio_items');

		$timestamp_min = strtotime('-1 week');

		// for "is last week" checks below
		$lastWeek = date('Y-m-d', $timestamp_min);

		$MainList = & new ItemList2( $Blog, NULL, 'now', 50000 /* limit from xml schema */ );
		$MainList->query();

		$blog_url = $Blog->get('url'); // may get used several times

		// OUTPUT:
		echo '<?xml version="1.0" encoding="'.$io_charset.'"?'.">\n";

		echo '<!-- generator="'.$app_name.'/'.$app_version.'" -->'."\n";

		echo '<urlset xmlns="http://www.google.com/schemas/sitemap/0.84" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.google.com/schemas/sitemap/0.84 http://www.google.com/schemas/sitemap/0.84/sitemap.xsd">'."\n";

		// The Blog's URL as first entry:
		?>
		<url>
			<loc><?php $Blog->disp( 'blogurl', 'xml' ) ?></loc>
			<lastmod><?php echo substr($MainList->get_lastpostdate(), 0, 10); ?></lastmod>
			<?php if( $include_changefreq )
			{ ?>
			<changefreq>hourly</changefreq>
			<?php } ?>
			<priority>1.0</priority>
		</url>

		<?php
		while( $Item = $MainList->get_next() )
		{
			// Google only allows URLs on the same host+path as the sitemap, so we need to use the URL from the requested Blog, if it's different from the one of the item.
			// This is the case, if you submit a sitemap for your "Blog All" and/or
			// there are items in a Blog with a main category in another Blog.
			// (This seems to be especially relvant if using another (sub)domain for each blog)
			$item_Blog = & $Item->get_Blog();
			if( $item_Blog != $Blog )
			{
				$blogurl = $blog_url;
			}
			else
			{
				$blogurl = $item_Blog->get('url');
			}
			?>
			<url>
				<loc><?php $Item->permanent_url( 'single', $blogurl ) ?></loc>
				<lastmod><?php $Item->mod_date( 'isoZ', true ) ?></lastmod>
				<?php
				if( $include_changefreq )
				{ ?>
				<changefreq><?php
					// changefreq = "how frequently the content at a particular URL is likely to change"
					// hourly: posts created during the last week
					// monthly: posts modified after having created them
					// yearly: the rest
					if( $Item->issue_date > $lastWeek )
					{
						echo 'hourly';
					}
					elseif( $Item->mod_date > $Item->issue_date )
					{
						echo 'monthly';
					}
					else echo 'yearly';
				?></changefreq>
   			<?php
   			}
   			?>
				<priority><?php
				if( ! empty($comments_total_count) )
				{ // Auto-Prio by number of comments:
					$cur_cmts = isset($comments_info[$Item->ID]) ? $comments_info[$Item->ID] : 0;

					$prio = round( ($cur_cmts*$prio_items*100/$comments_total_count)/100, 1 ); // 0.0 - 1.0

					if( $prio < $prio_items_min )
						echo $prio_items_min;
					else
						echo $prio;

					if( $this->Settings->get('output_debug') )
					{ // Debug output
						?>
						<!-- debug: <?php echo "round( ($cur_cmts*$prio_items*100/$comments_total_count)/100, 1 );" ?> -->
						<?php
					}
				}
				else
				{
					echo $prio_items;
				}
				?></priority>
			</url>

			<?php
		}
		?>
		</urlset>

		<?php
	}


	/**
	 * @todo Ping Google about sitemap update
	 */
	function __AfterItemInsert( & $params )
	{
		global $localtimenow;

		$Item = & $params['Item'];
		if( $Item->status != 'published' || mysql2timestamp($Item->issue_date) < $localtimenow )
		{ // not published (yet):
			return;
		}

		// ...
	}
}

?>
