Google Sitemap Generator を改造して、モバイルサイトマップも同時に出力させる

プラグインの中を覗いてみた。クラスを使って書かれているので、うまくオーバーライドしてやればよさそう。

google-sitemap-generator/sitemap.php を見るとこんな感じで sitemap ファイルを生成している。

function CallBuildSitemap() {
	if(GoogleSitemapGeneratorLoader::LoadPlugin()) {	
		$gs = GoogleSitemapGenerator::GetInstance();
		$gs->BuildSitemap();
	}
}

記事を投稿したり削除したあとに呼ばれる関数はこんな感じ。

function CallCheckForAutoBuild($args) {
	if(GoogleSitemapGeneratorLoader::LoadPlugin()) {	
		$gs = GoogleSitemapGenerator::GetInstance();
		$gs->CheckForAutoBuild($args);
	}
}

google-sitemap-generator/sitemap-core.php を見ると CheckForAutoBuild() の中でも最終的には BuildSitemap() を呼んでいるだけなので、BuildSitemap() がカギっぽい。

GoogleSitemapGenerator クラスを継承した GoogleSitemapGeneratorMobile というメソッドをつくってやって必要な箇所だけオーバーライドするのが一番省エネかな?

というわけで、その方針でやってみた。

sitemap-core.php の修正

sitemap-core.php の最後に以下のコードを追加する(「ここから」と「ここまで」の間のコードのみをコピペ)。

<?php
(ここから)
/* MOBILE SITEMAP GENERATION */

/**
 * Class to generate a MOBILE Sitemaps of a WordPress blog.
 * 
 * @author minorio
*/
class GoogleSitemapGeneratorMobile extends GoogleSitemapGenerator {

	/**
	 * Returns the instance of the Sitemap Generator MOBILE
	 *
	 * @access public
	 * @return GoogleSitemapGenerator MOBILE The instance or null if not available. 
	 * @author minorio
	*/
	function &GetInstance() {
		if(isset($GLOBALS["sm_instance_mobile"])) {
			return $GLOBALS["sm_instance_mobile"];
		} else return null;
	}
	
	/**
	 * Returns if the MOBILE sitemap building process is currently active
	 *
	 * @access public
	 * @return bool true if active
	 * @author minorio
	*/
	function IsActive() {
		$inst = &GoogleSitemapGeneratorMobile::GetInstance();
		return ($inst != null && $inst->_isActive);
	}
	
	/**
	 * Enables the Google Sitemap Generator MOBILE and registers the WordPress hooks
	 *
	 * @access public
	 * @author minorio
	*/
	function Enable() {
		if(!isset($GLOBALS["sm_instance_mobile"])) {			
			$GLOBALS["sm_instance_mobile"]=new GoogleSitemapGeneratorMobile();
		}
	}

	/**
	 * Returns the URL for the MOBILE sitemap file
	 *
	 * @access private
	 * @author minorio
	 * @param bool $forceAuto Force the return value to the autodetected value.
	 * @return The URL to the MOBILE Sitemap file
	*/
	function GetXmlUrl($forceAuto=false) {
		
		if(!$forceAuto && $this->GetOption("b_location_mode")=="manual") {
			return substr($this->GetOption("b_fileurl_manual"), 0, -4) . "_mobile.xml";
		} else {
			return trailingslashit(get_bloginfo('siteurl')). substr($this->GetOption("b_filename"), 0, -4) . "_mobile.xml";
		}
	}

	/**
	 * Returns the URL for the gzipped MOBILE sitemap file
	 *
	 * @access private
	 * @author minorio
	 * @param bool $forceAuto Force the return value to the autodetected value.
	 * @return The URL to the gzipped MOBILE Sitemap file
	*/
	function GetZipUrl($forceAuto=false) {
		return $this->GetXmlUrl($forceAuto) . ".gz";
	}
	
	/**
	 * Returns the file system path to the MOBILE sitemap file
	 *
	 * @access private
	 * @author minorio
	 * @param bool $forceAuto Force the return value to the autodetected value.
	 * @return The file system path;
	*/
	function GetXmlPath($forceAuto=false) {		
		if(!$forceAuto && $this->GetOption("b_location_mode")=="manual") {
			return substr($this->GetOption("b_filename_manual"), 0, -4) . "_mobile.xml";
		} else {
			return $this->GetHomePath()  . substr($this->GetOption("b_filename"), 0, -4) . "_mobile.xml";
		}
	}
	
	/**
	 * Returns the file system path to the gzipped MOBILE sitemap file
	 *
	 * @access private
	 * @author minorio
	 * @param bool $forceAuto Force the return value to the autodetected value.
	 * @return The file system path;
	*/
	function GetZipPath($forceAuto=false) {
		return $this->GetXmlPath($forceAuto) . ".gz";	
	}
	
	/**
	 * Adds a url to the MOBILE sitemap. You can use this method or call AddElement directly.
	 *
	 * @access public
	 * @author minorio
	 * @param $loc string The location (url) of the page
	 * @param $lastMod int The last Modification time as a UNIX timestamp
	 * @param $changeFreq string The change frequenty of the page, Valid values are "always", "hourly", "daily", "weekly", "monthly", "yearly" and "never".
	 * @param $priorty float The priority of the page, between 0.0 and 1.0
	 * @see AddElement
	 * @return string The URL node
	 */
	function AddUrl($loc,$lastMod=0,$changeFreq="monthly",$priority=0.5) {
		$page = new GoogleSitemapGeneratorPageMobile($loc,$priority,$changeFreq,$lastMod);
		
		$this->AddElement($page);
	}

	/**
	 * Creates or opens the robots.txt in blog root and inserts the MOBILE sitemap location
	 * 
	 * @access private
	 * @author minorio
	 * @return true on success
	 */
	function WriteRobotsFile() {
		$file = $this->GetRobotsFilePath();
		
		$marker = 'XML-SITEMAP-PLUGIN-MOBILE';
		
		$current = extract_from_markers($file,$marker);
		if(is_array($current)) $current = $current[0];
		
		$smUrl = $this->GetXmlUrl();
		if($this->IsGzipEnabled()) {
			$smUrl = $this->GetZipUrl();	
		}
		
		$new = "Sitemap: " . $smUrl;
		
		if($current != $new) {
			if($this->IsFileWritable($file)) return insert_with_markers($file,$marker,array($new));
			else return false;
		}
		return true;						
	}

	/**
	 * Builds the MOBILE sitemap and writes it into a xml file.
	 * 
	 * @access public
	 * @author minorio <minorio [at] nokosu [dot] com>
	 * @return array An array with messages such as failed writes etc.
	 */
	function BuildSitemap() {
		global $wpdb, $posts, $wp_version;	
		$this->Initate();
		
		if($this->GetOption("b_memory")!='') {
			@ini_set("memory_limit",$this->GetOption("b_memory"));	
		}
		
		if($this->GetOption("sm_b_time")!=-1) {
			@set_time_limit($this->GetOption("sm_b_time"));				
		}		
		
		//This object saves the status information of the script directly to the database
		$status = new GoogleSitemapGeneratorStatus();
		
		//Other plugins can detect if the building process is active
		$this->_isActive = true;
		
		//$this->AddElement(new GoogleSitemapGeneratorXmlEntry());
		
		//Debug mode?
		$debug=$this->GetOption("b_debug");
		
		
		if($this->GetOption("b_xml")) {
			$fileName = $this->GetXmlPath();
			$status->StartXml($this->GetXmlPath(),$this->GetXmlUrl());
			
			if($this->IsFileWritable($fileName)) {
				
				$this->_fileHandle = fopen($fileName,"w");
				if(!$this->_fileHandle) $status->EndXml(false,"Not openable");
				
			} else $status->EndXml(false,"not writable");
		}
		
		//Write gzipped sitemap file
		if($this->IsGzipEnabled()) {
			$fileName = $this->GetZipPath();
			$status->StartZip($this->GetZipPath(),$this->GetZipUrl());
			
			if($this->IsFileWritable($fileName)) {
				
				$this->_fileZipHandle = gzopen($fileName,"w1");
				if(!$this->_fileZipHandle) $status->EndZip(false,"Not openable");
				
			} else $status->EndZip(false,"not writable");	
		}	
		
		if(!$this->_fileHandle && !$this->_fileZipHandle) {
			$status->End();
			return;
		}	
		
		
		//Content of the XML file
		$this->AddElement(new GoogleSitemapGeneratorXmlEntry('<?xml version="1.0" encoding="UTF-8"' . '?' . '>'));
		
		if($this->GetOption("b_style")!='') {
			$this->AddElement(new GoogleSitemapGeneratorXmlEntry('<' . '?xml-stylesheet type="text/xsl" href="' . $this->GetOption("b_style") . '"?' . '>'));	
		}
		
		$this->AddElement(new GoogleSitemapGeneratorDebugEntry("generator=\"wordpress/" . get_bloginfo('version') . "\""));
		$this->AddElement(new GoogleSitemapGeneratorDebugEntry("sitemap-generator-url=\"http://www.arnebrachhold.de\" sitemap-generator-version=\"" . $this->GetVersion() . "\""));
		$this->AddElement(new GoogleSitemapGeneratorDebugEntry("generated-on=\"" . date(get_option("date_format") . " " . get_option("time_format")) . "\""));
		
		//All comments as an asso. Array (postID=>commentCount)
		$comments=($this->GetOption("b_prio_provider")!=""?$this->GetComments():array());
		
		//Full number of comments
		$commentCount=(count($comments)>0?$this->GetCommentCount($comments):0);
		
		if($debug && $this->GetOption("b_prio_provider")!="") {
			$this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Total comment count: " . $commentCount));	
		}
		
		//Go XML!
		$this->AddElement(new GoogleSitemapGeneratorXmlEntry('<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:mobile="http://www.google.com/schemas/sitemap-mobile/1.0">'));
		
		$home = get_bloginfo('url');
		
		//Add the home page (WITH a slash!)
		if($this->GetOption("in_home")) {
			$this->AddUrl(trailingslashit($home),$this->GetTimestampFromMySql(get_lastpostmodified('GMT')),$this->GetOption("cf_home"),$this->GetOption("pr_home"));
		}
		
		//Add the posts
		if($this->GetOption("in_posts") || $this->GetOption("in_pages")) {
			
			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Postings"));
		
			//Pre 2.1 compatibility. 2.1 introduced 'future' as post_status so we don't need to check post_date
			$wpCompat = (floatval($wp_version) < 2.1);
			
			$postPageStmt = '';
			
			$inSubPages = ($this->GetOption('sm_in_posts_sub')===true);
			
			if($inSubPages && $this->GetOption('in_posts')===true) {
				$pageDivider='<!--nextpage-->';
				$postPageStmt = ", (character_length(`post_content`)  - character_length(REPLACE(`post_content`, '$pageDivider', ''))) / " . strlen($pageDivider) . " as postPages";	
			}
			
			$sql="SELECT `ID`, `post_author`, `post_date`, `post_date_gmt`, `post_status`, `post_name`, `post_modified`, `post_modified_gmt`, `post_parent`, `post_type` $postPageStmt FROM `" . $wpdb->posts . "` WHERE ";
			
			$where = '(';
			
			if($this->GetOption('in_posts')) {
				//WP < 2.1: posts are post_status = publish 
				//WP >= 2.1: post_type must be 'post', no date check required because future posts are post_status='future'
				if($wpCompat) $where.="(post_status = 'publish' AND post_date_gmt <= '" . gmdate('Y-m-d H:i:59') . "')";
				else $where.=" (post_status = 'publish' AND (post_type = 'post' OR post_type = '')) ";
			}
			
			if($this->GetOption('in_pages')) {
				if($this->GetOption('in_posts')) {
					$where.=" OR ";	
				}
				if($wpCompat) {
					//WP < 2.1: posts have post_status = published, pages have post_status = static
					$where.=" post_status='static' ";
				} else {
					//WP >= 2.1: posts have post_type = 'post' and pages have post_type = 'page'. Both must be published. 
					$where.=" (post_status = 'publish' AND post_type = 'page') ";
				}
			}
			
			$where.=") ";
			
			$excludes = $this->GetOption('b_exclude');
			
			if(is_array($excludes) && count($excludes)>0) {
				$where.=" AND ID NOT IN ('" . implode("','",$excludes) . "')";	
			}
			
			$where.=" AND post_password='' ORDER BY post_modified DESC";
			
			$sql .= $where;
			
			if($this->GetOption("sm_b_max_posts")>0) {
				$sql.=" LIMIT 0," . $this->GetOption("sm_b_max_posts"); 		
			}	

			$postCount = intval($wpdb->get_var("SELECT COUNT(*) AS cnt FROM `" . $wpdb->posts . "` WHERE ". $where,0,0));
										
			//Create a new connection because we are using mysql_unbuffered_query and don't want to disturb the WP connection
			//Safe Mode for other plugins which use mysql_query() without a connection handler and will destroy our resultset :(
			$con = $postRes = null;
			if($this->GetOption("b_safemode")===true) {
				$postRes = mysql_query($sql,$wpdb->dbh);	
				if(!$postRes) {
					trigger_error("MySQL query failed: " . mysql_error(),E_USER_NOTICE); //E_NOTE will be displayed on our debug mode
					return;	
				}
			} else {
				$con = mysql_connect(DB_HOST,DB_USER,DB_PASSWORD,true);
				if(!$con) {
					trigger_error("MySQL Connection failed: " . mysql_error(),E_USER_NOTICE);
					return;
				}
				if(!mysql_select_db(DB_NAME,$con)) {
					trigger_error("MySQL DB Select failed: " . mysql_error(),E_USER_NOTICE);
					return;
				}
				$postRes = mysql_unbuffered_query($sql,$con);
				
				if(!$postRes) {
					trigger_error("MySQL unbuffered query failed: " . mysql_error(),E_USER_NOTICE);
					return;	
				}
			}
			
			if($postRes) {
				
				//#type $prioProvider GoogleSitemapGeneratorPrioProviderBase
				$prioProvider=NULL;
				
				if($this->GetOption("b_prio_provider") != '') {
					$providerClass=$this->GetOption('b_prio_provider');
					$prioProvider = new $providerClass($commentCount,$postCount);
				}
				
				//$posts is used by Alex King's Popularity Contest plugin
				//if($posts == null || !is_array($posts)) {
				//	$posts = &$postRes;	
				//}
				
				$z = 1;
				$zz = 1;
				
				//Default priorities
				$default_prio_posts = $this->GetOption('pr_posts');
				$default_prio_pages = $this->GetOption('pr_pages');
				
				//Change frequencies
				$cf_pages = $this->GetOption('sm_cf_pages');
				$cf_posts = $this->GetOption('sm_cf_posts');
				
				$minPrio=$this->GetOption('pr_posts_min');
				
				$useQTransLate = false; //function_exists('qtrans_convertURL'); Not ready yet
				
				//Cycle through all posts and add them
				while($post = mysql_fetch_object($postRes)) {
				
					//Fill the cache with our DB result. Since it's incomplete (no text-content for example), we will clean it later.
					$cache = array(&$post);
					update_post_cache($cache);
				
					$permalink = get_permalink($post->ID);
					if($permalink != $home) {
								
						$isPage = false;
						if($wpCompat) {
							$isPage = ($post->post_status == 'static');
						} else {
							$isPage = ($post->post_type == 'page');	
						}
						
						//Set the current working post
						$GLOBALS['post'] = &$post;
					
						//Default Priority if auto calc is disabled
						$prio = 0;
							
						if($isPage) {
							//Priority for static pages
							$prio = $default_prio_pages;
						} else {
							//Priority for normal posts
							$prio = $default_prio_posts;
						}
						
						//If priority calc. is enabled, calculate (but only for posts, not pages)!
						if($prioProvider !== null && !$isPage) {

							//Comment count for this post
							$cmtcnt = (isset($comments[$post->ID])?$comments[$post->ID]:0);
							$prio = $prioProvider->GetPostPriority($post->ID,$cmtcnt);

							if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry('Debug: Priority report of postID ' . $post->ID . ': Comments: ' . $cmtcnt . ' of ' . $commentCount . ' = ' . $prio . ' points'));
						}	
						
						if(!$isPage && $minPrio>0 && $prio<$minPrio) {
							$prio = $minPrio;
						}
						
						//Add it
						$this->AddUrl($permalink,$this->GetTimestampFromMySql(($post->post_modified_gmt && $post->post_modified_gmt!='0000-00-00 00:00:00'?$post->post_modified_gmt:$post->post_date_gmt)),($isPage?$cf_pages:$cf_posts),$prio);
						
						if($inSubPages) {
							$subPage = '';
							for($p =1; $p<=$post->postPages; $p++) {
								if(get_option('permalink_structure') == '') {
									$subPage = $permalink . '&amp;page=' . $p;
								} else {
									$subPage = trailingslashit($permalink) . user_trailingslashit($p, 'single_paged');
								}	

								$this->AddUrl($subPage,$this->GetTimestampFromMySql(($post->post_modified_gmt && $post->post_modified_gmt!='0000-00-00 00:00:00'?$post->post_modified_gmt:$post->post_date_gmt)),($isPage?$cf_pages:$cf_posts),$prio);
							}
						}
						
					
                       // Multilingual Support with qTranslate, thanks to Qian Qin
                       if($useQTransLate) {
                           global $q_config;
                           foreach($q_config['enabled_languages'] as $language) {
                               if($language != $q_config['default_language']) {
                                   $this->AddUrl(qtrans_convertURL($permalink,$language),$this->GetTimestampFromMySql(($post->post_modified_gmt && $post->post_modified_gmt!='0000-00-00 00:00:00'?$post->post_modified_gmt:$post->post_date_gmt)),($isPage?$cf_pages:$cf_posts),$prio);
                               }
                           }
                       }						
					}
					
					//Update the status every 100 posts and at the end. 
					//If the script breaks because of memory or time limit, 
					//we have a "last reponded" value which can be compared to the server settings
					if($zz==100 || $z == $postCount) {
						$status->SaveStep($z);
						$zz=0;						
					} else $zz++;
					
					$z++;
					
					//Clean cache because it's incomplete
					if(version_compare($wp_version,"2.5",">=")) {
						//WP 2.5 makes a mysql query for every clean_post_cache to clear the child cache
						//so I've vopied the function here until a patch arrives... 
						wp_cache_delete($post->ID, 'posts');
						wp_cache_delete($post->ID, 'post_meta');
						clean_object_term_cache($post->ID, 'post');
					} else {
						clean_post_cache($post->ID);
					}
				}
				unset($postRes);
				unset($prioProvider);
				
				if($this->GetOption("b_safemode")!==true && $con) mysql_close($con);
			}
			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Postings"));
		}
		
		//Add the cats
		if($this->GetOption("in_cats")) {
			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Cats"));
			
			if(!$this->IsTaxonomySupported()) {
			
				$catsRes=$wpdb->get_results("
							SELECT 
								c.cat_ID AS ID, 
								MAX(p.post_modified_gmt) AS last_mod 
							FROM 
								`" . $wpdb->categories . "` c,
								`" . $wpdb->post2cat . "` pc,
								`" . $wpdb->posts . "` p
							WHERE
								pc.category_id = c.cat_ID
								AND p.ID = pc.post_id
								AND p.post_status = 'publish'
								AND p.post_type='post'
							GROUP
								BY c.cat_id
							");						
				if($catsRes) {
					foreach($catsRes as $cat) {
						if($cat && $cat->ID && $cat->ID>0) {
							if($debug) if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Cat-ID:" . $cat->ID)); 	
							$this->AddUrl(get_category_link($cat->ID),$this->GetTimestampFromMySql($cat->last_mod),$this->GetOption("cf_cats"),$this->GetOption("pr_cats"));
						}
					}	
				}
			} else {
				$cats = get_terms("category",array("hide_empty"=>true,"hierarchical"=>false));
				if($cats && is_array($cats) && count($cats)>0) {
					foreach($cats AS $cat) {
						$this->AddUrl(get_category_link($cat->term_id),0,$this->GetOption("cf_cats"),$this->GetOption("pr_cats"));	
					}	
				}	
			}
			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Cats"));	
		}
		
		//Add the archives
		if($this->GetOption("in_arch")) {
			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Archive"));
			$now = current_time('mysql');

			//WP2.1 introduced post_status='future', for earlier WP versions we need to check the post_date_gmt
			$arcresults = $wpdb->get_results("
						SELECT DISTINCT 
							YEAR(post_date_gmt) AS `year`, 
							MONTH(post_date_gmt) AS `month`, 
							MAX(post_date_gmt) as last_mod, 
							count(ID) as posts 
						FROM 
							$wpdb->posts 
						WHERE 
							post_date < '$now' 
							AND post_status = 'publish' 
							AND post_type = 'post'
							" . (floatval($wp_version) < 2.1?"AND {$wpdb->posts}.post_date_gmt <= '" . gmdate('Y-m-d H:i:59') . "'":"") . "
						GROUP BY 
							YEAR(post_date_gmt), 
							MONTH(post_date_gmt) 
						ORDER BY 
							post_date_gmt DESC");
			if ($arcresults) {
				foreach ($arcresults as $arcresult) {
					
					$url  = get_month_link($arcresult->year,   $arcresult->month);
					$changeFreq="";
					
					//Archive is the current one
					if($arcresult->month==date("n") && $arcresult->year==date("Y")) {
						$changeFreq=$this->GetOption("cf_arch_curr");	
					} else { // Archive is older
						$changeFreq=$this->GetOption("cf_arch_old");	
					}
					
					$this->AddUrl($url,$this->GetTimestampFromMySql($arcresult->last_mod),$changeFreq,$this->GetOption("pr_arch"));				
				}
			}
			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Archive")); 	
		}
		
		//Add the author pages
		if($this->GetOption("in_auth")) {
			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Author pages"));
			
			$linkFunc = null;
			
			//get_author_link is deprecated in WP 2.1, try to use get_author_posts_url first. 
			if(function_exists('get_author_posts_url')) {
				$linkFunc = 'get_author_posts_url'; 		
			} else if(function_exists('get_author_link')) {
				$linkFunc = 'get_author_link'; 	
			} 
			
			//Who knows what happens in later WP versions, so check again if it worked
			if($linkFunc !== null) {
			    //Unfortunately there is no API function to get all authors, so we have to do it the dirty way...
				//We retrieve only users with published and not password protected posts (and not pages)
				//WP2.1 introduced post_status='future', for earlier WP versions we need to check the post_date_gmt
				$sql = "SELECT DISTINCT 
							{$wpdb->users}.ID, 
							{$wpdb->users}.user_nicename, 
							MAX({$wpdb->posts}.post_modified_gmt) AS last_post 
						FROM 
							{$wpdb->users}, 
							{$wpdb->posts} 
						WHERE 
							{$wpdb->posts}.post_author = {$wpdb->users}.ID 
							AND {$wpdb->posts}.post_status = 'publish'
							AND {$wpdb->posts}.post_type = 'post' 
							AND {$wpdb->posts}.post_password = '' 
							" . (floatval($wp_version) < 2.1?"AND {$wpdb->posts}.post_date_gmt <= '" . gmdate('Y-m-d H:i:59') . "'":"") . "
						GROUP BY 
							{$wpdb->users}.ID, 
							{$wpdb->users}.user_nicename";
							
				$authors = $wpdb->get_results($sql);
				
				if($authors && is_array($authors)) {
					foreach($authors as $author) {
						if($debug) if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Author-ID:" . $author->ID)); 	
						$url = ($linkFunc=='get_author_posts_url'?get_author_posts_url($author->ID,$author->user_nicename):get_author_link(false,$author->ID,$author->user_nicename));
						$this->AddUrl($url,$this->GetTimestampFromMySql($author->last_post),$this->GetOption("cf_auth"),$this->GetOption("pr_auth"));
					}
				}
			} else {
				//Too bad, no author pages for you :(
				if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: No valid author link function found"));	
			}
	
			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Author pages"));	
		}
		
		//Add tag pages
		if($this->GetOption("in_tags") && $this->IsTaxonomySupported()) {
			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Tags"));
			$tags = get_terms("post_tag",array("hide_empty"=>true,"hierarchical"=>false));
			if($tags && is_array($tags) && count($tags)>0) {
				foreach($tags AS $tag) {
					$this->AddUrl(get_tag_link($tag->term_id),0,$this->GetOption("cf_tags"),$this->GetOption("pr_tags"));	
				}	
			}	
			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Tags"));	
		}
		
		//Add the custom pages
		if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Custom Pages"));
		if($this->_pages && is_array($this->_pages) && count($this->_pages)>0) {
			//#type $page GoogleSitemapGeneratorPage
			foreach($this->_pages AS $page) {
				$this->AddUrl($page->GetUrl(),$page->getLastMod(),$page->getChangeFreq(),$page->getPriority());
			}	
		}
		
		if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Custom Pages"));
		
		if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start additional URLs"));
		
		do_action("sm_buildmap");
		
		if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End additional URLs"));
		
		$this->AddElement(new GoogleSitemapGeneratorXmlEntry("</urlset>"));
		

		$pingUrl='';
		
		if($this->GetOption("b_xml")) {
			if($this->_fileHandle && fclose($this->_fileHandle)) {
				$this->_fileHandle = null;
				$status->EndXml(true);
				$pingUrl=$this->GetXmlUrl();
			} else $status->EndXml(false,"Could not close the sitemap file.");
		}
		
		if($this->IsGzipEnabled()) {
			if($this->_fileZipHandle && fclose($this->_fileZipHandle)) {
				$this->_fileZipHandle = null;
				$status->EndZip(true);
				$pingUrl=$this->GetZipUrl();
			} else $status->EndZip(false,"Could not close the zipped sitemap file");
		}
		
		//Ping Google
		if($this->GetOption("b_ping") && !empty($pingUrl)) {
			$sPingUrl="http://www.google.com/webmasters/sitemaps/ping?sitemap=" . urlencode($pingUrl);
			$status->StartGooglePing($sPingUrl);
			$pingres=$this->RemoteOpen($sPingUrl);
									  
			if($pingres==NULL || $pingres===false) {
				$status->EndGooglePing(false,$this->_lastError);
			} else {
				$status->EndGooglePing(true);
			}
		} 
				
		//Ping Ask.com
		if($this->GetOption("b_pingask") && !empty($pingUrl)) {
			$sPingUrl="http://submissions.ask.com/ping?sitemap=" . urlencode($pingUrl);
			$status->StartAskPing($sPingUrl);
			$pingres=$this->RemoteOpen($sPingUrl);
									  
			if($pingres==NULL || $pingres===false || strpos($pingres,"successfully received and added")===false) { //Ask.com returns 200 OK even if there was an error, so we need to check the content.
				$status->EndAskPing(false,$this->_lastError);
			} else {
				$status->EndAskPing(true);
			}
		}
		
		//Ping YAHOO
		if($this->GetOption("sm_b_pingyahoo")===true && $this->GetOption("sm_b_yahookey")!="" && !empty($pingUrl)) {
			$sPingUrl="http://search.yahooapis.com/SiteExplorerService/V1/updateNotification?appid=" . $this->GetOption("sm_b_yahookey") . "&url=" . urlencode($pingUrl);
			$status->StartYahooPing($sPingUrl);
			$pingres=$this->RemoteOpen($sPingUrl);

			if($pingres==NULL || $pingres===false || strpos(strtolower($pingres),"success")===false) {
				$status->EndYahooPing(false,$this->_lastError);
			} else {
				$status->EndYahooPing(true);
			}	
		}	
		
		//Ping MSN
		if($this->GetOption("b_pingmsn") && !empty($pingUrl)) {
			$sPingUrl="http://webmaster.live.com/ping.aspx?siteMap=" . urlencode($pingUrl);
			$status->StartMsnPing($sPingUrl);
			$pingres=$this->RemoteOpen($sPingUrl);
									  
			if($pingres==NULL || $pingres===false || strpos($pingres,"Thanks for submitting your sitemap")===false) { 
				$status->EndMsnPing(false,$this->_lastError);
			} else {
				$status->EndMsnPing(true);
			}
		}
	
		$status->End();	

		
		$this->_isActive = false;	
	
		//done...
		return $status;
	}

}


/**
 * Represents an item in the page list
 * @author minorio
 * @package sitemap
 */
class GoogleSitemapGeneratorPageMobile extends GoogleSitemapGeneratorPage {

	function Render() {
		
		if($this->_url == "/" || empty($this->_url)) return '';
		
		$r="";
		$r.= "\t<url>\n";
		$r.= "\t\t<loc>" . $this->EscapeXML($this->_url) . "</loc>\n";
		if($this->_lastMod>0) $r.= "\t\t<lastmod>" . date('Y-m-d\TH:i:s+00:00',$this->_lastMod) . "</lastmod>\n";
		if(!empty($this->_changeFreq)) $r.= "\t\t<changefreq>" . $this->_changeFreq . "</changefreq>\n";	
		if($this->_priority!==false && $this->_priority!=="") $r.= "\t\t<priority>" . number_format($this->_priority,1) . "</priority>\n";
		$r.= "\t\t<mobile:mobile/>\n";
		$r.= "\t</url>\n";	
		return $r;
	}	

}
/* MOBILE SITEMAP GENERATION END */
(ここまで)
?>

クラスがもうちょっと細かく分割されてればコピペする量をもっと減らせるんだけど、とりあえずこれで動くでしょう。

sitemap.php の修正

<?php
(前略)
	function CallCheckForAutoBuild($args) {
		if(GoogleSitemapGeneratorLoader::LoadPlugin()) {	
			$gs = GoogleSitemapGenerator::GetInstance();
			$gs->CheckForAutoBuild($args);
		}
	}
	
	function CallBuildSitemap() {
		if(GoogleSitemapGeneratorLoader::LoadPlugin()) {	
			$gs = GoogleSitemapGenerator::GetInstance();
			$gs->BuildSitemap();
		}
	}
	
	function CallCheckForManualBuild() {
		if(GoogleSitemapGeneratorLoader::LoadPlugin()) {	
			$gs = GoogleSitemapGenerator::GetInstance();
			$gs->CheckForManualBuild();
		}	
	}
	
	function LoadPlugin() {
		
		$mem = abs(intval(@ini_get('memory_limit')));
		if($mem && $mem < 32) {
			@ini_set('memory_limit', '32M');	
		}
		
		$time = abs(intval(@ini_get("max_execution_tim")));
		if($time != 0 && $time < 120) {
			@set_time_limit(120);	
		}
		
		if(!class_exists("GoogleSitemapGenerator")) {
			
			$path = trailingslashit(dirname(__FILE__));
			
			if(!file_exists( $path . 'sitemap-core.php')) return false;
			require_once($path. 'sitemap-core.php');
		} 

		GoogleSitemapGenerator::Enable();	
		return true;	
	}
(後略)
?>

を以下のように変更する。

<?php
(前略)
	function CallCheckForAutoBuild($args) {
		if(GoogleSitemapGeneratorLoader::LoadPlugin()) {	
			$gs = GoogleSitemapGenerator::GetInstance();
			$gs->CheckForAutoBuild($args);
			
			/* MOBILE SITEMAP GENERATION */
			$gsm = GoogleSitemapGeneratorMobile::GetInstance();
			$gsm->CheckForAutoBuild($args);
			/* MOBILE SITEMAP GENERATION END */
		}
	}
	
	function CallBuildSitemap() {
		if(GoogleSitemapGeneratorLoader::LoadPlugin()) {	
			$gs = GoogleSitemapGenerator::GetInstance();
			$gs->BuildSitemap();
			
			/* MOBILE SITEMAP GENERATION */
			$gsm = GoogleSitemapGeneratorMobile::GetInstance();
			$gsm->BuildSitemap();
			/* MOBILE SITEMAP GENERATION END */
		}
	}
	
	function CallCheckForManualBuild() {
		if(GoogleSitemapGeneratorLoader::LoadPlugin()) {	
			$gs = GoogleSitemapGenerator::GetInstance();
			$gs->CheckForManualBuild();
			
			/* MOBILE SITEMAP GENERATION */
			$gsm = GoogleSitemapGeneratorMobile::GetInstance();
			$gsm->CheckForManualBuild();
			/* MOBILE SITEMAP GENERATION END */
		}	
	}
	
	function LoadPlugin() {
		
		$mem = abs(intval(@ini_get('memory_limit')));
		if($mem && $mem < 32) {
			@ini_set('memory_limit', '32M');	
		}
		
		$time = abs(intval(@ini_get("max_execution_tim")));
		if($time != 0 && $time < 120) {
			@set_time_limit(120);	
		}
		
		/* MOBILE SITEMAP GENERATION */
		//if(!class_exists("GoogleSitemapGenerator")) {
		if(!class_exists("GoogleSitemapGenerator") || !class_exists("GoogleSitemapGeneratorMobile")) {
		/* MOBILE SITEMAP GENERATION END */
			
			$path = trailingslashit(dirname(__FILE__));
			
			if(!file_exists( $path . 'sitemap-core.php')) return false;
			require_once($path. 'sitemap-core.php');
		} 

		GoogleSitemapGenerator::Enable();	

		/* MOBILE SITEMAP GENERATION */
		GoogleSitemapGeneratorMobile::Enable();	
		/* MOBILE SITEMAP GENERATION END */
		return true;	
	}
(後略)
?>

管理パネルの XML Sitemap の設定画面から「rebuild sitemap」manually はできません

上記の修正で、投稿時に携帯用のサイトマップが同時に出力されるようになります(ファイル名は sitemap_mobile.xml のように「_mobile」が自動的に追加されます)。

ただし、WordPress 管理パネルの XML Sitemap の設定画面の上の方、「Status」セクション内にある「rebuild sitemap」manually というところのリンクをクリックしても携帯用のサイトマップは生成されません。

これは sitemap-ui.php の方をいじればできるんだけど、個人的に必要ないのでやりません。

サイトマップ生成にかかる時間について

今回はクラスをできる限り再利用することで変更箇所を少なくするという方針でやったので、サイトマップ生成のために同じ SQL を2度発行することになってしまいました。これはかなり無駄です(時間もほぼ2倍かかるし)。

最初から携帯用のサイトマップも生成するつもりなら、1度の SQL で2種類のサイトマップを用意してやればいいので、プラグインの作者さんの方で対応版が出たら、そちらに切り替える方がいいと思います。とりあえず応急処置ということで。

robots.txt への Sitemap: の追加

これも sitemap-ui.php の方でやっている処理なので、そっちをいじる必要があります。
が、面倒だったので FTProbots.txt を開いて書き加えてしまいました。(^_^;

こんな感じで OK です。

# BEGIN XML-SITEMAP-PLUGIN
Sitemap: http://example.com/sitemap.xml.gz
# END XML-SITEMAP-PLUGIN

# BEGIN XML-SITEMAP-PLUGIN-MOBILE
Sitemap: http://example.com/sitemap_mobile.xml.gz
# END XML-SITEMAP-PLUGIN-MOBILE