web/wp-content/plugins/google-sitemap-generator/sitemap-core.php
branchwordpress
changeset 109 03b0d1493584
child 194 32102edaa81b
equal deleted inserted replaced
-1:000000000000 109:03b0d1493584
       
     1 <?php
       
     2 /*
       
     3  
       
     4  $Id: sitemap-core.php 175664 2009-11-20 21:21:09Z arnee $
       
     5 
       
     6 */
       
     7 
       
     8 //Enable for dev! Good code doesn't generate any notices...
       
     9 //error_reporting(E_ALL);
       
    10 //ini_set("display_errors",1);
       
    11 
       
    12 /**
       
    13  * Represents the status (success and failures) of a building process
       
    14  * @author Arne Brachhold
       
    15  * @package sitemap
       
    16  * @since 3.0b5
       
    17  */
       
    18 class GoogleSitemapGeneratorStatus {
       
    19 
       
    20 	function GoogleSitemapGeneratorStatus() {
       
    21 		$this->_startTime = $this->GetMicrotimeFloat();
       
    22 		
       
    23 		$exists = get_option("sm_status");
       
    24 		
       
    25 		if($exists === false) add_option("sm_status","","Status","no");
       
    26 		
       
    27 		$this->Save();
       
    28 	}
       
    29 	
       
    30 	function Save() {
       
    31 		update_option("sm_status",$this);
       
    32 	}
       
    33 	
       
    34 	/**
       
    35 	 * Returns the last saved status object or null
       
    36 	 * 
       
    37 	 * @return GoogleSitemapGeneratorStatus
       
    38 	 */
       
    39 	function Load() {
       
    40 		$status = @get_option("sm_status");
       
    41 		if(is_a($status,"GoogleSitemapGeneratorStatus")) return $status;
       
    42 		else return null;
       
    43 	}
       
    44 	
       
    45 	/**
       
    46 	 * @var float $_startTime The start time of the building process
       
    47 	 * @access private
       
    48 	 */
       
    49 	var $_startTime = 0;
       
    50 	
       
    51 	/**
       
    52 	 * @var float $_endTime The end time of the building process
       
    53 	 * @access private
       
    54 	 */
       
    55 	var $_endTime = 0;
       
    56 	
       
    57 	/**
       
    58 	 * @var bool $$_hasChanged Indicates if the sitemap content has changed
       
    59 	 * @access private
       
    60 	 */
       
    61 	var $_hasChanged = true;
       
    62 	
       
    63 	/**
       
    64 	 * @var int $_memoryUsage The amount of memory used in bytes
       
    65 	 * @access private
       
    66 	 */
       
    67 	var $_memoryUsage = 0;
       
    68 	
       
    69 	/**
       
    70 	 * @var int $_lastPost The number of posts processed. This value is updated every 50 posts.
       
    71 	 * @access private
       
    72 	 */
       
    73 	var $_lastPost = 0;
       
    74 	
       
    75 	/**
       
    76 	 * @var int $_lastTime The time when the last step-update occured. This value is updated every 50 posts.
       
    77 	 * @access private
       
    78 	 */
       
    79 	var $_lastTime = 0;
       
    80 	
       
    81 	function End($hasChanged = true) {
       
    82 		$this->_endTime = $this->GetMicrotimeFloat();
       
    83 		
       
    84 		$this->SetMemoryUsage();
       
    85 		
       
    86 		$this->_hasChanged = $hasChanged;
       
    87 		
       
    88 		$this->Save();
       
    89 	}
       
    90 	
       
    91 	function SetMemoryUsage() {
       
    92 		if(function_exists("memory_get_peak_usage")) {
       
    93 			$this->_memoryUsage = memory_get_peak_usage(true);
       
    94 		} else if(function_exists("memory_get_usage")) {
       
    95 			$this->_memoryUsage =  memory_get_usage(true);
       
    96 		}
       
    97 	}
       
    98 	
       
    99 	function GetMemoryUsage() {
       
   100 		return round($this->_memoryUsage / 1024 / 1024,2);
       
   101 	}
       
   102 	
       
   103 	function SaveStep($postCount) {
       
   104 		$this->SetMemoryUsage();
       
   105 		$this->_lastPost = $postCount;
       
   106 		$this->_lastTime = $this->GetMicrotimeFloat();
       
   107 		
       
   108 		$this->Save();
       
   109 	}
       
   110 	
       
   111 	function GetTime() {
       
   112 		return round($this->_endTime - $this->_startTime,2);
       
   113 	}
       
   114 	
       
   115 	function GetStartTime() {
       
   116 		return round($this->_startTime, 2);
       
   117 	}
       
   118 	
       
   119 	function GetLastTime() {
       
   120 		return round($this->_lastTime - $this->_startTime,2);
       
   121 	}
       
   122 	
       
   123 	function GetLastPost() {
       
   124 		return $this->_lastPost;
       
   125 	}
       
   126 	
       
   127 	var $_usedXml = false;
       
   128 	var $_xmlSuccess = false;
       
   129 	var $_xmlPath = '';
       
   130 	var $_xmlUrl = '';
       
   131 	
       
   132 	function StartXml($path,$url) {
       
   133 		$this->_usedXml = true;
       
   134 		$this->_xmlPath = $path;
       
   135 		$this->_xmlUrl = $url;
       
   136 		
       
   137 		$this->Save();
       
   138 	}
       
   139 	
       
   140 	function EndXml($success) {
       
   141 		$this->_xmlSuccess = $success;
       
   142 		
       
   143 		$this->Save();
       
   144 	}
       
   145 	
       
   146 	
       
   147 	var $_usedZip = false;
       
   148 	var $_zipSuccess = false;
       
   149 	var $_zipPath = '';
       
   150 	var $_zipUrl = '';
       
   151 	
       
   152 	function StartZip($path,$url) {
       
   153 		$this->_usedZip = true;
       
   154 		$this->_zipPath = $path;
       
   155 		$this->_zipUrl = $url;
       
   156 		
       
   157 		$this->Save();
       
   158 	}
       
   159 	
       
   160 	function EndZip($success) {
       
   161 		$this->_zipSuccess = $success;
       
   162 		
       
   163 		$this->Save();
       
   164 	}
       
   165 	
       
   166 	var $_usedGoogle = false;
       
   167 	var $_googleUrl = '';
       
   168 	var $_gooogleSuccess = false;
       
   169 	var $_googleStartTime = 0;
       
   170 	var $_googleEndTime = 0;
       
   171 	
       
   172 	function StartGooglePing($url) {
       
   173 		$this->_googleUrl = $url;
       
   174 		$this->_usedGoogle = true;
       
   175 		$this->_googleStartTime = $this->GetMicrotimeFloat();
       
   176 		
       
   177 		$this->Save();
       
   178 	}
       
   179 	
       
   180 	function EndGooglePing($success) {
       
   181 		$this->_googleEndTime = $this->GetMicrotimeFloat();
       
   182 		$this->_gooogleSuccess = $success;
       
   183 		
       
   184 		$this->Save();
       
   185 	}
       
   186 	
       
   187 	function GetGoogleTime() {
       
   188 		return round($this->_googleEndTime - $this->_googleStartTime,2);
       
   189 	}
       
   190 	
       
   191 	var $_usedYahoo = false;
       
   192 	var $_yahooUrl = '';
       
   193 	var $_yahooSuccess = false;
       
   194 	var $_yahooStartTime = 0;
       
   195 	var $_yahooEndTime = 0;
       
   196 	
       
   197 	function StartYahooPing($url) {
       
   198 		$this->_yahooUrl = $url;
       
   199 		$this->_usedYahoo = true;
       
   200 		$this->_yahooStartTime = $this->GetMicrotimeFloat();
       
   201 		
       
   202 		$this->Save();
       
   203 	}
       
   204 	
       
   205 	function EndYahooPing($success) {
       
   206 		$this->_yahooEndTime = $this->GetMicrotimeFloat();
       
   207 		$this->_yahooSuccess = $success;
       
   208 		
       
   209 		$this->Save();
       
   210 	}
       
   211 	
       
   212 	function GetYahooTime() {
       
   213 		return round($this->_yahooEndTime - $this->_yahooStartTime,2);
       
   214 	}
       
   215 	
       
   216 	var $_usedAsk = false;
       
   217 	var $_askUrl = '';
       
   218 	var $_askSuccess = false;
       
   219 	var $_askStartTime = 0;
       
   220 	var $_askEndTime = 0;
       
   221 	
       
   222 	function StartAskPing($url) {
       
   223 		$this->_usedAsk = true;
       
   224 		$this->_askUrl = $url;
       
   225 		$this->_askStartTime = $this->GetMicrotimeFloat();
       
   226 		
       
   227 		$this->Save();
       
   228 	}
       
   229 	
       
   230 	function EndAskPing($success) {
       
   231 		$this->_askEndTime = $this->GetMicrotimeFloat();
       
   232 		$this->_askSuccess = $success;
       
   233 		
       
   234 		$this->Save();
       
   235 	}
       
   236 	
       
   237 	function GetAskTime() {
       
   238 		return round($this->_askEndTime - $this->_askStartTime,2);
       
   239 	}
       
   240 	
       
   241 	var $_usedMsn = false;
       
   242 	var $_msnUrl = '';
       
   243 	var $_msnSuccess = false;
       
   244 	var $_msnStartTime = 0;
       
   245 	var $_msnEndTime = 0;
       
   246 	
       
   247 	function StartMsnPing($url) {
       
   248 		$this->_usedMsn = true;
       
   249 		$this->_msnUrl = $url;
       
   250 		$this->_msnStartTime = $this->GetMicrotimeFloat();
       
   251 		
       
   252 		$this->Save();
       
   253 	}
       
   254 	
       
   255 	function EndMsnPing($success) {
       
   256 		$this->_msnEndTime = $this->GetMicrotimeFloat();
       
   257 		$this->_msnSuccess = $success;
       
   258 		
       
   259 		$this->Save();
       
   260 	}
       
   261 	
       
   262 	function GetMsnTime() {
       
   263 		return round($this->_msnEndTime - $this->_msnStartTime,2);
       
   264 	}
       
   265 	
       
   266 	function GetMicrotimeFloat() {
       
   267 		list($usec, $sec) = explode(" ", microtime());
       
   268 		return ((float)$usec + (float)$sec);
       
   269 	}
       
   270 		}
       
   271 		
       
   272 /**
       
   273  * Represents an item in the page list
       
   274  * @author Arne Brachhold
       
   275  * @package sitemap
       
   276  * @since 3.0
       
   277  */
       
   278 class GoogleSitemapGeneratorPage {
       
   279 	
       
   280 	/**
       
   281 	 * @var string $_url Sets the URL or the relative path to the blog dir of the page
       
   282 	 * @access private
       
   283 	 */
       
   284 	var $_url;
       
   285 	
       
   286 	/**
       
   287 	 * @var float $_priority Sets the priority of this page
       
   288 	 * @access private
       
   289 	 */
       
   290 	var $_priority;
       
   291 	
       
   292 	/**
       
   293 	 * @var string $_changeFreq Sets the chanfe frequency of the page. I want Enums!
       
   294 	 * @access private
       
   295 	 */
       
   296 	var $_changeFreq;
       
   297 	
       
   298 	/**
       
   299 	 * @var int $_lastMod Sets the lastMod date as a UNIX timestamp.
       
   300 	 * @access private
       
   301 	 */
       
   302 	var $_lastMod;
       
   303 	
       
   304 	/**
       
   305 	 * Initialize a new page object
       
   306 	 *
       
   307 	 * @since 3.0
       
   308 	 * @access public
       
   309 	 * @author Arne Brachhold
       
   310 	 * @param bool $enabled Should this page be included in thesitemap
       
   311 	 * @param string $url The URL or path of the file
       
   312 	 * @param float $priority The Priority of the page 0.0 to 1.0
       
   313 	 * @param string $changeFreq The change frequency like daily, hourly, weekly
       
   314 	 * @param int $lastMod The last mod date as a unix timestamp
       
   315 	 */
       
   316 	function GoogleSitemapGeneratorPage($url="",$priority=0.0,$changeFreq="never",$lastMod=0) {
       
   317 		$this->SetUrl($url);
       
   318 		$this->SetProprity($priority);
       
   319 		$this->SetChangeFreq($changeFreq);
       
   320 		$this->SetLastMod($lastMod);
       
   321 	}
       
   322 	
       
   323 	/**
       
   324 	 * Returns the URL of the page
       
   325 	 *
       
   326 	 * @return string The URL
       
   327 	 */
       
   328 	function GetUrl() {
       
   329 		return $this->_url;
       
   330 	}
       
   331 	
       
   332 	/**
       
   333 	 * Sets the URL of the page
       
   334 	 *
       
   335 	 * @param string $url The new URL
       
   336 	 */
       
   337 	function SetUrl($url) {
       
   338 		$this->_url=(string) $url;
       
   339 	}
       
   340 	
       
   341 	/**
       
   342 	 * Returns the priority of this page
       
   343 	 *
       
   344 	 * @return float the priority, from 0.0 to 1.0
       
   345 	 */
       
   346 	function GetPriority() {
       
   347 		return $this->_priority;
       
   348 	}
       
   349 	
       
   350 	/**
       
   351 	 * Sets the priority of the page
       
   352 	 *
       
   353 	 * @param float $priority The new priority from 0.1 to 1.0
       
   354 	 */
       
   355 	function SetProprity($priority) {
       
   356 		$this->_priority=floatval($priority);
       
   357 	}
       
   358 	
       
   359 	/**
       
   360 	 * Returns the change frequency of the page
       
   361 	 *
       
   362 	 * @return string The change frequncy like hourly, weekly, monthly etc.
       
   363 	 */
       
   364 	function GetChangeFreq() {
       
   365 		return $this->_changeFreq;
       
   366 	}
       
   367 	
       
   368 	/**
       
   369 	 * Sets the change frequency of the page
       
   370 	 *
       
   371 	 * @param string $changeFreq The new change frequency
       
   372 	 */
       
   373 	function SetChangeFreq($changeFreq) {
       
   374 		$this->_changeFreq=(string) $changeFreq;
       
   375 	}
       
   376 	
       
   377 	/**
       
   378 	 * Returns the last mod of the page
       
   379 	 *
       
   380 	 * @return int The lastmod value in seconds
       
   381 	 */
       
   382 	function GetLastMod() {
       
   383 		return $this->_lastMod;
       
   384 	}
       
   385 	
       
   386 	/**
       
   387 	 * Sets the last mod of the page
       
   388 	 *
       
   389 	 * @param int $lastMod The lastmod of the page
       
   390 	 */
       
   391 	function SetLastMod($lastMod) {
       
   392 		$this->_lastMod=intval($lastMod);
       
   393 	}
       
   394 	
       
   395 	function Render() {
       
   396 		
       
   397 		if($this->_url == "/" || empty($this->_url)) return '';
       
   398 		
       
   399 		$r="";
       
   400 		$r.= "\t<url>\n";
       
   401 		$r.= "\t\t<loc>" . $this->EscapeXML($this->_url) . "</loc>\n";
       
   402 		if($this->_lastMod>0) $r.= "\t\t<lastmod>" . date('Y-m-d\TH:i:s+00:00',$this->_lastMod) . "</lastmod>\n";
       
   403 		if(!empty($this->_changeFreq)) $r.= "\t\t<changefreq>" . $this->_changeFreq . "</changefreq>\n";
       
   404 		if($this->_priority!==false && $this->_priority!=="") $r.= "\t\t<priority>" . number_format($this->_priority,1) . "</priority>\n";
       
   405 		$r.= "\t</url>\n";
       
   406 		return $r;
       
   407 	}
       
   408 	
       
   409 	function EscapeXML($string) {
       
   410 		return str_replace ( array ( '&', '"', "'", '<', '>'), array ( '&amp;' , '&quot;', '&apos;' , '&lt;' , '&gt;'), $string);
       
   411 	}
       
   412 }
       
   413 
       
   414 class GoogleSitemapGeneratorXmlEntry {
       
   415 	
       
   416 	var $_xml;
       
   417 	
       
   418 	function GoogleSitemapGeneratorXmlEntry($xml) {
       
   419 		$this->_xml = $xml;
       
   420 	}
       
   421 	
       
   422 	function Render() {
       
   423 		return $this->_xml;
       
   424 	}
       
   425 }
       
   426 
       
   427 class GoogleSitemapGeneratorDebugEntry extends GoogleSitemapGeneratorXmlEntry {
       
   428 	
       
   429 	function Render() {
       
   430 		return "<!-- " . $this->_xml . " -->\n";
       
   431 	}
       
   432 }
       
   433 
       
   434 /**
       
   435  * Base class for all priority providers
       
   436  * @author Arne Brachhold
       
   437  * @package sitemap
       
   438  * @since 3.0
       
   439  */
       
   440 class GoogleSitemapGeneratorPrioProviderBase {
       
   441 	
       
   442 	/**
       
   443 	 * @var int $_totalComments The total number of comments of all posts
       
   444 	 * @access protected
       
   445 	 */
       
   446 	var $_totalComments=0;
       
   447 	
       
   448 	/**
       
   449 	 * @var int $_totalComments The total number of posts
       
   450 	 * @access protected
       
   451 	 */
       
   452 	var $_totalPosts=0;
       
   453 	
       
   454 	/**
       
   455 	 * Returns the (translated) name of this priority provider
       
   456 	 *
       
   457 	 * @since 3.0
       
   458 	 * @access public
       
   459 	 * @author Arne Brachhold
       
   460 	 * @return string The translated name
       
   461 	*/
       
   462 	function GetName() {
       
   463 		return "";
       
   464 	}
       
   465 	
       
   466 	/**
       
   467 	 * Returns the (translated) description of this priority provider
       
   468 	 *
       
   469 	 * @since 3.0
       
   470 	 * @access public
       
   471 	 * @author Arne Brachhold
       
   472 	 * @return string The translated description
       
   473 	*/
       
   474 	function GetDescription() {
       
   475 		return "";
       
   476 	}
       
   477 	
       
   478 	/**
       
   479 	 * Initializes a new priority provider
       
   480 	 *
       
   481 	 * @param $totalComments int The total number of comments of all posts
       
   482 	 * @param $totalPosts int The total number of posts
       
   483 	 * @since 3.0
       
   484 	 * @access public
       
   485 	 * @author Arne Brachhold
       
   486 	*/
       
   487 	function GoogleSitemapGeneratorPrioProviderBase($totalComments,$totalPosts) {
       
   488 		$this->_totalComments=$totalComments;
       
   489 		$this->_totalPosts=$totalPosts;
       
   490 		
       
   491 	}
       
   492 	
       
   493 	/**
       
   494 	 * Returns the priority for a specified post
       
   495 	 *
       
   496 	 * @param $postID int The ID of the post
       
   497 	 * @param $commentCount int The number of comments for this post
       
   498 	 * @since 3.0
       
   499 	 * @access public
       
   500 	 * @author Arne Brachhold
       
   501 	 * @return int The calculated priority
       
   502 	*/
       
   503 	function GetPostPriority($postID,$commentCount) {
       
   504 		return 0;
       
   505 	}
       
   506 }
       
   507 
       
   508 /**
       
   509  * Priority Provider which calculates the priority based on the number of comments
       
   510  * @author Arne Brachhold
       
   511  * @package sitemap
       
   512  * @since 3.0
       
   513  */
       
   514 class GoogleSitemapGeneratorPrioByCountProvider extends GoogleSitemapGeneratorPrioProviderBase {
       
   515 	
       
   516 	/**
       
   517 	 * Returns the (translated) name of this priority provider
       
   518 	 *
       
   519 	 * @since 3.0
       
   520 	 * @access public
       
   521 	 * @author Arne Brachhold
       
   522 	 * @return string The translated name
       
   523 	*/
       
   524 	function GetName() {
       
   525 		return __("Comment Count",'sitemap');
       
   526 	}
       
   527 	
       
   528 	/**
       
   529 	 * Returns the (translated) description of this priority provider
       
   530 	 *
       
   531 	 * @since 3.0
       
   532 	 * @access public
       
   533 	 * @author Arne Brachhold
       
   534 	 * @return string The translated description
       
   535 	*/
       
   536 	function GetDescription() {
       
   537 		return __("Uses the number of comments of the post to calculate the priority",'sitemap');
       
   538 	}
       
   539 	
       
   540 	/**
       
   541 	 * Initializes a new priority provider which calculates the post priority based on the number of comments
       
   542 	 *
       
   543 	 * @param $totalComments int The total number of comments of all posts
       
   544 	 * @param $totalPosts int The total number of posts
       
   545 	 * @since 3.0
       
   546 	 * @access public
       
   547 	 * @author Arne Brachhold
       
   548 	*/
       
   549 	function GoogleSitemapGeneratorPrioByCountProvider($totalComments,$totalPosts) {
       
   550 		parent::GoogleSitemapGeneratorPrioProviderBase($totalComments,$totalPosts);
       
   551 	}
       
   552 	
       
   553 	/**
       
   554 	 * Returns the priority for a specified post
       
   555 	 *
       
   556 	 * @param $postID int The ID of the post
       
   557 	 * @param $commentCount int The number of comments for this post
       
   558 	 * @since 3.0
       
   559 	 * @access public
       
   560 	 * @author Arne Brachhold
       
   561 	 * @return int The calculated priority
       
   562 	*/
       
   563 	function GetPostPriority($postID,$commentCount) {
       
   564 		$prio=0;
       
   565 		if($this->_totalComments>0 && $commentCount>0) {
       
   566 			$prio = round(($commentCount*100/$this->_totalComments)/100,1);
       
   567 		} else {
       
   568 			$prio = 0;
       
   569 		}
       
   570 		return $prio;
       
   571 	}
       
   572 }
       
   573 
       
   574 /**
       
   575  * Priority Provider which calculates the priority based on the average number of comments
       
   576  * @author Arne Brachhold
       
   577  * @package sitemap
       
   578  * @since 3.0
       
   579  */
       
   580 class GoogleSitemapGeneratorPrioByAverageProvider extends GoogleSitemapGeneratorPrioProviderBase {
       
   581 	
       
   582 	/**
       
   583 	 * @var int $_average The average number of comments per post
       
   584 	 * @access protected
       
   585 	 */
       
   586 	var $_average=0.0;
       
   587 	
       
   588 	/**
       
   589 	 * Returns the (translated) name of this priority provider
       
   590 	 *
       
   591 	 * @since 3.0
       
   592 	 * @access public
       
   593 	 * @author Arne Brachhold
       
   594 	 * @return string The translated name
       
   595 	*/
       
   596 	function GetName() {
       
   597 		return __("Comment Average",'sitemap');
       
   598 	}
       
   599 	
       
   600 	/**
       
   601 	 * Returns the (translated) description of this priority provider
       
   602 	 *
       
   603 	 * @since 3.0
       
   604 	 * @access public
       
   605 	 * @author Arne Brachhold
       
   606 	 * @return string The translated description
       
   607 	*/
       
   608 	function GetDescription() {
       
   609 		return __("Uses the average comment count to calculate the priority",'sitemap');
       
   610 	}
       
   611 	
       
   612 	/**
       
   613 	 * Initializes a new priority provider which calculates the post priority based on the average number of comments
       
   614 	 *
       
   615 	 * @param $totalComments int The total number of comments of all posts
       
   616 	 * @param $totalPosts int The total number of posts
       
   617 	 * @since 3.0
       
   618 	 * @access public
       
   619 	 * @author Arne Brachhold
       
   620 	*/
       
   621 	function GoogleSitemapGeneratorPrioByAverageProvider($totalComments,$totalPosts) {
       
   622 		parent::GoogleSitemapGeneratorPrioProviderBase($totalComments,$totalPosts);
       
   623 		
       
   624 		if($this->_totalComments>0 && $this->_totalPosts>0) {
       
   625 			$this->_average= (double) $this->_totalComments / $this->_totalPosts;
       
   626 		}
       
   627 	}
       
   628 	
       
   629 	/**
       
   630 	 * Returns the priority for a specified post
       
   631 	 *
       
   632 	 * @param $postID int The ID of the post
       
   633 	 * @param $commentCount int The number of comments for this post
       
   634 	 * @since 3.0
       
   635 	 * @access public
       
   636 	 * @author Arne Brachhold
       
   637 	 * @return int The calculated priority
       
   638 	*/
       
   639 	function GetPostPriority($postID,$commentCount) {
       
   640 		$prio = 0;
       
   641 		//Do not divide by zero!
       
   642 		if($this->_average==0) {
       
   643 			if($commentCount>0)	$prio = 1;
       
   644 			else $prio = 0;
       
   645 		} else {
       
   646 			$prio = $commentCount/$this->_average;
       
   647 			if($prio>1) $prio = 1;
       
   648 			else if($prio<0) $prio = 0;
       
   649 		}
       
   650 		
       
   651 		return round($prio,1);
       
   652 	}
       
   653 }
       
   654 
       
   655 /**
       
   656  * Priority Provider which calculates the priority based on the popularity by the PopularityContest Plugin
       
   657  * @author Arne Brachhold
       
   658  * @package sitemap
       
   659  * @since 3.0
       
   660  */
       
   661 class GoogleSitemapGeneratorPrioByPopularityContestProvider extends GoogleSitemapGeneratorPrioProviderBase {
       
   662 	
       
   663 	/**
       
   664 	 * Returns the (translated) name of this priority provider
       
   665 	 *
       
   666 	 * @since 3.0
       
   667 	 * @access public
       
   668 	 * @author Arne Brachhold
       
   669 	 * @return string The translated name
       
   670 	*/
       
   671 	function GetName() {
       
   672 		return __("Popularity Contest",'sitemap');
       
   673 	}
       
   674 	
       
   675 	/**
       
   676 	 * Returns the (translated) description of this priority provider
       
   677 	 *
       
   678 	 * @since 3.0
       
   679 	 * @access public
       
   680 	 * @author Arne Brachhold
       
   681 	 * @return string The translated description
       
   682 	*/
       
   683 	function GetDescription() {
       
   684 		return str_replace("%4","index.php?page=popularity-contest.php",str_replace("%3","options-general.php?page=popularity-contest.php",str_replace("%2","http://www.alexking.org/",str_replace("%1","http://www.alexking.org/index.php?content=software/wordpress/content.php",__("Uses the activated <a href=\"%1\">Popularity Contest Plugin</a> from <a href=\"%2\">Alex King</a>. See <a href=\"%3\">Settings</a> and <a href=\"%4\">Most Popular Posts</a>",'sitemap')))));
       
   685 	}
       
   686 	
       
   687 	/**
       
   688 	 * Initializes a new priority provider which calculates the post priority based on the popularity by the PopularityContest Plugin
       
   689 	 *
       
   690 	 * @param $totalComments int The total number of comments of all posts
       
   691 	 * @param $totalPosts int The total number of posts
       
   692 	 * @since 3.0
       
   693 	 * @access public
       
   694 	 * @author Arne Brachhold
       
   695 	*/
       
   696 	function GoogleSitemapGeneratorPrioByPopularityContestProvider($totalComments,$totalPosts) {
       
   697 		parent::GoogleSitemapGeneratorPrioProviderBase($totalComments,$totalPosts);
       
   698 	}
       
   699 	
       
   700 	/**
       
   701 	 * Returns the priority for a specified post
       
   702 	 *
       
   703 	 * @param $postID int The ID of the post
       
   704 	 * @param $commentCount int The number of comments for this post
       
   705 	 * @since 3.0
       
   706 	 * @access public
       
   707 	 * @author Arne Brachhold
       
   708 	 * @return int The calculated priority
       
   709 	*/
       
   710 	function GetPostPriority($postID,$commentCount) {
       
   711 		//$akpc is the global instance of the Popularity Contest Plugin
       
   712 		global $akpc,$posts;
       
   713 		
       
   714 		$res=0;
       
   715 		//Better check if its there
       
   716 		if(!empty($akpc) && is_object($akpc)) {
       
   717 			//Is the method we rely on available?
       
   718 		if(method_exists($akpc,"get_post_rank")) {
       
   719 			if(!is_array($posts) || !$posts) $posts = array();
       
   720 				if(!isset($posts[$postID])) $posts[$postID] = get_post($postID);
       
   721 				//popresult comes as a percent value
       
   722 				$popresult=$akpc->get_post_rank($postID);
       
   723 				if(!empty($popresult) && strpos($popresult,"%")!==false) {
       
   724 					//We need to parse it to get the priority as an int (percent)
       
   725 					$matches=null;
       
   726 					preg_match("/([0-9]{1,3})\%/si",$popresult,$matches);
       
   727 					if(!empty($matches) && is_array($matches) && count($matches)==2) {
       
   728 						//Divide it so 100% = 1, 10% = 0.1
       
   729 						$res=round(intval($matches[1])/100,1);
       
   730 					}
       
   731 				}
       
   732 			}
       
   733 		}
       
   734 		return $res;
       
   735 	}
       
   736 }
       
   737 
       
   738 /**
       
   739  * Class to generate a sitemaps.org Sitemaps compliant sitemap of a WordPress blog.
       
   740  *
       
   741  * @package sitemap
       
   742  * @author Arne Brachhold
       
   743  * @since 3.0
       
   744 */
       
   745 class GoogleSitemapGenerator {
       
   746 	/**
       
   747 	 * @var Version of the generator in SVN
       
   748 	*/
       
   749 	var $_svnVersion = '$Id: sitemap-core.php 175664 2009-11-20 21:21:09Z arnee $';
       
   750 	
       
   751 	/**
       
   752 	 * @var array The unserialized array with the stored options
       
   753 	 */
       
   754 	var $_options = array();
       
   755 	
       
   756 	/**
       
   757 	 * @var array The saved additional pages
       
   758 	 */
       
   759 	var $_pages = array();
       
   760 
       
   761 	/**
       
   762 	 * @var array The values and names of the change frequencies
       
   763 	 */
       
   764 	var $_freqNames = array();
       
   765 	
       
   766 	/**
       
   767 	 * @var array A list of class names which my be called for priority calculation
       
   768 	 */
       
   769 	var $_prioProviders = array();
       
   770 	
       
   771 	/**
       
   772 	 * @var bool True if init complete (options loaded etc)
       
   773 	 */
       
   774 	var $_initiated = false;
       
   775 	
       
   776 	/**
       
   777 	 * @var string Holds the last error if one occurs when writing the files
       
   778 	 */
       
   779 	var $_lastError=null;
       
   780 	
       
   781 	/**
       
   782 	 * @var int The last handled post ID
       
   783 	 */
       
   784 	var $_lastPostID = 0;
       
   785 	
       
   786 	/**
       
   787 	 * @var bool Defines if the sitemap building process is active at the moment
       
   788 	 */
       
   789 	var $_isActive = false;
       
   790 	
       
   791 	/**
       
   792 	 * @var bool Defines if the sitemap building process has been scheduled via Wp cron
       
   793 	 */
       
   794 	var $_isScheduled = false;
       
   795 
       
   796 	/**
       
   797 	 * @var object The file handle which is used to write the sitemap file
       
   798 	 */
       
   799 	var $_fileHandle = null;
       
   800 	
       
   801 	/**
       
   802 	 * @var object The file handle which is used to write the zipped sitemap file
       
   803 	 */
       
   804 	var $_fileZipHandle = null;
       
   805 	
       
   806 	/**
       
   807 	 * Holds the user interface object
       
   808 	 * 
       
   809 	 * @since 3.1.1
       
   810 	 * @var GoogleSitemapGeneratorUI
       
   811 	 */
       
   812 	var $_ui = null;
       
   813 	
       
   814 	/**
       
   815 	 * Returns the path to the blog directory
       
   816 	 *
       
   817 	 * @since 3.0
       
   818 	 * @access private
       
   819 	 * @author Arne Brachhold
       
   820 	 * @return string The full path to the blog directory
       
   821 	*/
       
   822 	function GetHomePath() {
       
   823 		
       
   824 		$res="";
       
   825 		//Check if we are in the admin area -> get_home_path() is avaiable
       
   826 		if(function_exists("get_home_path")) {
       
   827 			$res = get_home_path();
       
   828 		} else {
       
   829 			//get_home_path() is not available, but we can't include the admin
       
   830 			//libraries because many plugins check for the "check_admin_referer"
       
   831 			//function to detect if you are on an admin page. So we have to copy
       
   832 			//the get_home_path function in our own...
       
   833 			$home = get_option( 'home' );
       
   834 			if ( $home != '' && $home != get_option( 'siteurl' ) ) {
       
   835 				$home_path = parse_url( $home );
       
   836 				$home_path = $home_path['path'];
       
   837 				$root = str_replace( $_SERVER["PHP_SELF"], '', $_SERVER["SCRIPT_FILENAME"] );
       
   838 				$home_path = trailingslashit( $root.$home_path );
       
   839 			} else {
       
   840 				$home_path = ABSPATH;
       
   841 			}
       
   842 
       
   843 			$res = $home_path;
       
   844 		}
       
   845 		return $res;
       
   846 	}
       
   847 	
       
   848 	/**
       
   849 	 * Returns the path to the directory where the plugin file is located
       
   850 	 * @since 3.0b5
       
   851 	 * @access private
       
   852 	 * @author Arne Brachhold
       
   853 	 * @return string The path to the plugin directory
       
   854 	 */
       
   855 	function GetPluginPath() {
       
   856 		$path = dirname(__FILE__);
       
   857 		return trailingslashit(str_replace("\\","/",$path));
       
   858 	}
       
   859 	
       
   860 	/**
       
   861 	 * Returns the URL to the directory where the plugin file is located
       
   862 	 * @since 3.0b5
       
   863 	 * @access private
       
   864 	 * @author Arne Brachhold
       
   865 	 * @return string The URL to the plugin directory
       
   866 	 */
       
   867 	function GetPluginUrl() {
       
   868 		
       
   869 		//Try to use WP API if possible, introduced in WP 2.6
       
   870 		if (function_exists('plugins_url')) return trailingslashit(plugins_url(basename(dirname(__FILE__))));
       
   871 		
       
   872 		//Try to find manually... can't work if wp-content was renamed or is redirected
       
   873 		$path = dirname(__FILE__);
       
   874 		$path = str_replace("\\","/",$path);
       
   875 		$path = trailingslashit(get_bloginfo('wpurl')) . trailingslashit(substr($path,strpos($path,"wp-content/")));
       
   876 		return $path;
       
   877 	}
       
   878 	
       
   879 	/**
       
   880 	 * Returns the URL to default XSLT style if it exists
       
   881 	 * @since 3.0b5
       
   882 	 * @access private
       
   883 	 * @author Arne Brachhold
       
   884 	 * @return string The URL to the default stylesheet, empty string if not available.
       
   885 	 */
       
   886 	function GetDefaultStyle() {
       
   887 		$p = $this->GetPluginPath();
       
   888 		if(file_exists($p . "sitemap.xsl")) {
       
   889 			$url = $this->GetPluginUrl();
       
   890 			//If called over the admin area using HTTPS, the stylesheet would also be https url, even if the blog frontend is not.
       
   891 			if(substr(get_bloginfo('url'),0,5) !="https" && substr($url,0,5)=="https") $url="http" . substr($url,5);
       
   892 			return $url . 'sitemap.xsl';
       
   893 		}
       
   894 		return '';
       
   895 	}
       
   896 	
       
   897 	/**
       
   898 	 * Sets up the default configuration
       
   899 	 *
       
   900 	 * @since 3.0
       
   901 	 * @access private
       
   902 	 * @author Arne Brachhold
       
   903 	*/
       
   904 	function InitOptions() {
       
   905 		
       
   906 		$this->_options=array();
       
   907 		$this->_options["sm_b_prio_provider"]="GoogleSitemapGeneratorPrioByCountProvider";			//Provider for automatic priority calculation
       
   908 		$this->_options["sm_b_filename"]="sitemap.xml";		//Name of the Sitemap file
       
   909 		$this->_options["sm_b_debug"]=true;					//Write debug messages in the xml file
       
   910 		$this->_options["sm_b_xml"]=true;					//Create a .xml file
       
   911 		$this->_options["sm_b_gzip"]=true;					//Create a gzipped .xml file(.gz) file
       
   912 		$this->_options["sm_b_ping"]=true;					//Auto ping Google
       
   913 		$this->_options["sm_b_pingyahoo"]=false;			//Auto ping YAHOO
       
   914 		$this->_options["sm_b_yahookey"]='';				//YAHOO Application Key
       
   915 		$this->_options["sm_b_pingask"]=true;				//Auto ping Ask.com
       
   916 		$this->_options["sm_b_pingmsn"]=true;				//Auto ping MSN
       
   917 		$this->_options["sm_b_manual_enabled"]=false;		//Allow manual creation of the sitemap via GET request
       
   918 		$this->_options["sm_b_auto_enabled"]=true;			//Rebuild sitemap when content is changed
       
   919 		$this->_options["sm_b_auto_delay"]=true;			//Use WP Cron to execute the building process in the background
       
   920 		$this->_options["sm_b_manual_key"]=md5(microtime());//The secret key to build the sitemap via GET request
       
   921 		$this->_options["sm_b_memory"] = '';				//Set Memory Limit (e.g. 16M)
       
   922 		$this->_options["sm_b_time"] = -1;					//Set time limit in seconds, 0 for unlimited, -1 for disabled
       
   923 		$this->_options["sm_b_max_posts"] = -1;				//Maximum number of posts, <= 0 for all
       
   924 		$this->_options["sm_b_safemode"] = false;			//Enable MySQL Safe Mode (doesn't use unbuffered results)
       
   925 		$this->_options["sm_b_style_default"] = true;		//Use default style
       
   926 		$this->_options["sm_b_style"] = '';					//Include a stylesheet in the XML
       
   927 		$this->_options["sm_b_robots"] = true;				//Add sitemap location to WordPress' virtual robots.txt file
       
   928 		$this->_options["sm_b_exclude"] = array();			//List of post / page IDs to exclude
       
   929 		$this->_options["sm_b_exclude_cats"] = array();		//List of post / page IDs to exclude
       
   930 		$this->_options["sm_b_location_mode"]="auto";		//Mode of location, auto or manual
       
   931 		$this->_options["sm_b_filename_manual"]="";			//Manuel filename
       
   932 		$this->_options["sm_b_fileurl_manual"]="";			//Manuel fileurl
       
   933 
       
   934 		$this->_options["sm_in_home"]=true;					//Include homepage
       
   935 		$this->_options["sm_in_posts"]=true;				//Include posts
       
   936 		$this->_options["sm_in_posts_sub"]=false;			//Include post pages (<!--nextpage--> tag)
       
   937 		$this->_options["sm_in_pages"]=true;				//Include static pages
       
   938 		$this->_options["sm_in_cats"]=false;				//Include categories
       
   939 		$this->_options["sm_in_arch"]=false;				//Include archives
       
   940 		$this->_options["sm_in_auth"]=false;				//Include author pages
       
   941 		$this->_options["sm_in_tags"]=false;				//Include tag pages
       
   942 		$this->_options["sm_in_tax"]=array();				//Include additional taxonomies
       
   943 		$this->_options["sm_in_lastmod"]=true;				//Include the last modification date
       
   944 
       
   945 		$this->_options["sm_cf_home"]="daily";				//Change frequency of the homepage
       
   946 		$this->_options["sm_cf_posts"]="monthly";			//Change frequency of posts
       
   947 		$this->_options["sm_cf_pages"]="weekly";			//Change frequency of static pages
       
   948 		$this->_options["sm_cf_cats"]="weekly";				//Change frequency of categories
       
   949 		$this->_options["sm_cf_auth"]="weekly";				//Change frequency of author pages
       
   950 		$this->_options["sm_cf_arch_curr"]="daily";			//Change frequency of the current archive (this month)
       
   951 		$this->_options["sm_cf_arch_old"]="yearly";			//Change frequency of older archives
       
   952 		$this->_options["sm_cf_tags"]="weekly";				//Change frequency of tags
       
   953 
       
   954 		$this->_options["sm_pr_home"]=1.0;					//Priority of the homepage
       
   955 		$this->_options["sm_pr_posts"]=0.6;					//Priority of posts (if auto prio is disabled)
       
   956 		$this->_options["sm_pr_posts_min"]=0.2;				//Minimum Priority of posts, even if autocalc is enabled
       
   957 		$this->_options["sm_pr_pages"]=0.6;					//Priority of static pages
       
   958 		$this->_options["sm_pr_cats"]=0.3;					//Priority of categories
       
   959 		$this->_options["sm_pr_arch"]=0.3;					//Priority of archives
       
   960 		$this->_options["sm_pr_auth"]=0.3;					//Priority of author pages
       
   961 		$this->_options["sm_pr_tags"]=0.3;					//Priority of tags
       
   962 		
       
   963 		$this->_options["sm_i_donated"]=false;				//Did you donate? Thank you! :)
       
   964 		$this->_options["sm_i_hide_donated"]=false;			//And hide the thank you..
       
   965 		$this->_options["sm_i_install_date"]=time();		//The installation date
       
   966 		$this->_options["sm_i_hide_note"]=false;			//Hide the note which appears after 30 days
       
   967 		$this->_options["sm_i_hide_works"]=false;			//Hide the "works?" message which appears after 15 days
       
   968 		$this->_options["sm_i_hide_donors"]=false;			//Hide the list of donations
       
   969 	}
       
   970 	
       
   971 	/**
       
   972 	 * Loads the configuration from the database
       
   973 	 *
       
   974 	 * @since 3.0
       
   975 	 * @access private
       
   976 	 * @author Arne Brachhold
       
   977 	*/
       
   978 	function LoadOptions() {
       
   979 		
       
   980 		$this->InitOptions();
       
   981 		
       
   982 		//First init default values, then overwrite it with stored values so we can add default
       
   983 		//values with an update which get stored by the next edit.
       
   984 		$storedoptions=get_option("sm_options");
       
   985 		if($storedoptions && is_array($storedoptions)) {
       
   986 			foreach($storedoptions AS $k=>$v) {
       
   987 				$this->_options[$k]=$v;
       
   988 			}
       
   989 		} else update_option("sm_options",$this->_options); //First time use, store default values
       
   990 	}
       
   991 	
       
   992 	/**
       
   993 	 * Initializes a new Google Sitemap Generator
       
   994 	 *
       
   995 	 * @since 3.0
       
   996 	 * @access private
       
   997 	 * @author Arne Brachhold
       
   998 	*/
       
   999 	function GoogleSitemapGenerator() {
       
  1000 
       
  1001 
       
  1002 		
       
  1003 		
       
  1004 	}
       
  1005 	
       
  1006 	/**
       
  1007 	 * Returns the version of the generator
       
  1008 	 *
       
  1009 	 * @since 3.0
       
  1010 	 * @access public
       
  1011 	 * @author Arne Brachhold
       
  1012 	 * @return int The version
       
  1013 	*/
       
  1014 	function GetVersion() {
       
  1015 		return GoogleSitemapGeneratorLoader::GetVersion();
       
  1016 	}
       
  1017 	
       
  1018 	/**
       
  1019 	 * Returns all parent classes of a class
       
  1020 	 *
       
  1021 	 * @param $className string The name of the class
       
  1022 	 *
       
  1023 	 * @since 3.0
       
  1024 	 * @access private
       
  1025 	 * @author Arne Brachhold
       
  1026 	 * @return array An array which contains the names of the parent classes
       
  1027 	*/
       
  1028 	function GetParentClasses($classname) {
       
  1029 		$parent = get_parent_class($classname);
       
  1030 		$parents = array();
       
  1031 		if (!empty($parent)) {
       
  1032 			$parents = $this->GetParentClasses($parent);
       
  1033 			$parents[] = strtolower($parent);
       
  1034 		}
       
  1035 		return $parents;
       
  1036 	}
       
  1037 	
       
  1038 	/**
       
  1039 	 * Returns if a class is a subclass of another class
       
  1040 	 *
       
  1041 	 * @param $className string The name of the class
       
  1042 	 * @param $$parentName string The name of the parent class
       
  1043 	 *
       
  1044 	 * @since 3.0
       
  1045 	 * @access private
       
  1046 	 * @author Arne Brachhold
       
  1047 	 * @return bool true if the given class is a subclass of the other one
       
  1048 	*/
       
  1049 	function IsSubclassOf($className, $parentName) {
       
  1050 		
       
  1051 		$className = strtolower($className);
       
  1052 		$parentName = strtolower($parentName);
       
  1053 		
       
  1054 		if(empty($className) || empty($parentName) || !class_exists($className) || !class_exists($parentName)) return false;
       
  1055 		
       
  1056 		$parents=$this->GetParentClasses($className);
       
  1057 		
       
  1058 		return in_array($parentName,$parents);
       
  1059 	}
       
  1060 		
       
  1061 	/**
       
  1062 	 * Loads up the configuration and validates the prioity providers
       
  1063 	 *
       
  1064 	 * This method is only called if the sitemaps needs to be build or the admin page is displayed.
       
  1065 	 *
       
  1066 	 * @since 3.0
       
  1067 	 * @access private
       
  1068 	 * @author Arne Brachhold
       
  1069 	*/
       
  1070 	function Initate() {
       
  1071 		if(!$this->_initiated) {
       
  1072 			
       
  1073 			//Loading language file...
       
  1074 			//load_plugin_textdomain('sitemap');
       
  1075 			//Hmm, doesn't work if the plugin file has its own directory.
       
  1076 			//Let's make it our way... load_plugin_textdomain() searches only in the wp-content/plugins dir.
       
  1077 			$currentLocale = get_locale();
       
  1078 			if(!empty($currentLocale)) {
       
  1079 				$moFile = dirname(__FILE__) . "/lang/sitemap-" . $currentLocale . ".mo";
       
  1080 				if(@file_exists($moFile) && is_readable($moFile)) load_textdomain('sitemap', $moFile);
       
  1081 			}
       
  1082 			
       
  1083 			$this->_freqNames = array(
       
  1084 				"always"=>__("Always","sitemap"),
       
  1085 				"hourly"=>__("Hourly","sitemap"),
       
  1086 				"daily"=>__("Daily","sitemap"),
       
  1087 				"weekly"=>__("Weekly","sitemap"),
       
  1088 				"monthly"=>__("Monthly","sitemap"),
       
  1089 				"yearly"=>__("Yearly","sitemap"),
       
  1090 				"never"=>__("Never","sitemap")
       
  1091 			);
       
  1092 			
       
  1093 			
       
  1094 			$this->LoadOptions();
       
  1095 			$this->LoadPages();
       
  1096 			
       
  1097 			//Register our own priority providers
       
  1098 			add_filter("sm_add_prio_provider",array(&$this, 'AddDefaultPrioProviders'));
       
  1099 			
       
  1100 			//Let other plugins register their providers
       
  1101 			$r = apply_filters("sm_add_prio_provider",$this->_prioProviders);
       
  1102 			
       
  1103 			//Check if no plugin return null
       
  1104 			if($r != null) $this->_prioProviders = $r;
       
  1105 				
       
  1106 			$this->ValidatePrioProviders();
       
  1107 			
       
  1108 			$this->_initiated = true;
       
  1109 		}
       
  1110 	}
       
  1111 	
       
  1112 	/**
       
  1113 	 * Returns the instance of the Sitemap Generator
       
  1114 	 *
       
  1115 	 * @since 3.0
       
  1116 	 * @access public
       
  1117 	 * @return GoogleSitemapGenerator The instance or null if not available.
       
  1118 	 * @author Arne Brachhold
       
  1119 	*/
       
  1120 	function &GetInstance() {
       
  1121 		if(isset($GLOBALS["sm_instance"])) {
       
  1122 			return $GLOBALS["sm_instance"];
       
  1123 		} else return null;
       
  1124 	}
       
  1125 	
       
  1126 	/**
       
  1127 	 * Returns if the sitemap building process is currently active
       
  1128 	 *
       
  1129 	 * @since 3.0
       
  1130 	 * @access public
       
  1131 	 * @return bool true if active
       
  1132 	 * @author Arne Brachhold
       
  1133 	*/
       
  1134 	function IsActive() {
       
  1135 		$inst = &GoogleSitemapGenerator::GetInstance();
       
  1136 		return ($inst != null && $inst->_isActive);
       
  1137 	}
       
  1138 	
       
  1139 	/**
       
  1140 	 * Returns if the compressed sitemap was activated
       
  1141 	 *
       
  1142 	 * @since 3.0b8
       
  1143 	 * @access private
       
  1144 	 * @author Arne Brachhold
       
  1145 	 * @return true if compressed
       
  1146 	 */
       
  1147 	function IsGzipEnabled() {
       
  1148 		return ($this->GetOption("b_gzip")===true && function_exists("gzwrite"));
       
  1149 	}
       
  1150 
       
  1151 	/**
       
  1152 	 * Returns if this version of WordPress supports the new taxonomy system
       
  1153 	 *
       
  1154 	 * @since 3.0b8
       
  1155 	 * @access private
       
  1156 	 * @author Arne Brachhold
       
  1157 	 * @return true if supported
       
  1158 	 */
       
  1159 	function IsTaxonomySupported() {
       
  1160 		return (function_exists("get_taxonomy") && function_exists("get_terms"));
       
  1161 	}
       
  1162 	
       
  1163 	/**
       
  1164 	 * Returns the list of custom taxonies. These are basically all taxonomies without categories and post tags
       
  1165 	 * 
       
  1166 	 * @since 3.1.7
       
  1167 	 * @return array Array of names of user-defined taxonomies
       
  1168 	 */
       
  1169 	function GetCustomTaxonomies() {
       
  1170 		$taxonomies = get_object_taxonomies('post');
       
  1171 		return array_diff($taxonomies,array("category","post_tag"));
       
  1172 	}
       
  1173 	
       
  1174 	/**
       
  1175 	 * Enables the Google Sitemap Generator and registers the WordPress hooks
       
  1176 	 *
       
  1177 	 * @since 3.0
       
  1178 	 * @access public
       
  1179 	 * @author Arne Brachhold
       
  1180 	*/
       
  1181 	function Enable() {
       
  1182 		if(!isset($GLOBALS["sm_instance"])) {
       
  1183 			$GLOBALS["sm_instance"]=new GoogleSitemapGenerator();
       
  1184 		}
       
  1185 	}
       
  1186 	
       
  1187 	/**
       
  1188 	 * Checks if sitemap building after content changed is enabled and rebuild the sitemap
       
  1189 	 *
       
  1190 	 * @param int $postID The ID of the post to handle. Used to avoid double rebuilding if more than one hook was fired.
       
  1191 	 * @param bool $external Added in 3.1.9. Skips checking of b_auto_enabled if set to true
       
  1192 	 * @since 3.0
       
  1193 	 * @access public
       
  1194 	 * @author Arne Brachhold
       
  1195 	*/
       
  1196 	function CheckForAutoBuild($postID, $external = false) {
       
  1197 		global $wp_version;
       
  1198 		$this->Initate();
       
  1199 		//Build one time per post and if not importing.
       
  1200 		if((($this->GetOption("b_auto_enabled")===true && $this->_lastPostID != $postID) || $external) && (!defined('WP_IMPORTING') || WP_IMPORTING != true)) {
       
  1201 			
       
  1202 			//Build the sitemap directly or schedule it with WP cron
       
  1203 			if($this->GetOption("b_auto_delay")==true && floatval($wp_version) >= 2.1) {
       
  1204 				if(!$this->_isScheduled) {
       
  1205 					//Schedule in 15 seconds, this should be enough to catch all changes.
       
  1206 					//Clear all other existing hooks, so the sitemap is only built once.
       
  1207 					wp_clear_scheduled_hook('sm_build_cron');
       
  1208 					wp_schedule_single_event(time()+15,'sm_build_cron');
       
  1209 					$this->_isScheduled = true;
       
  1210 				}
       
  1211 			} else {
       
  1212 				//Build sitemap only once and never in bulk mode
       
  1213 				if(!$this->_lastPostID && (!isset($_GET["delete"]) || count((array) $_GET['delete'])<=0)) {
       
  1214 					$this->BuildSitemap();
       
  1215 				}
       
  1216 			}
       
  1217 			$this->_lastPostID = $postID;
       
  1218 		}
       
  1219 	}
       
  1220 	
       
  1221 	/**
       
  1222 	 * Builds the sitemap by external request, for example other plugins.
       
  1223 	 * 
       
  1224 	 * @since 3.1.9
       
  1225 	 * @return null
       
  1226 	 */
       
  1227 	function BuildNowRequest() {
       
  1228 		$this->CheckForAutoBuild(null, true);	
       
  1229 	}
       
  1230 	
       
  1231 	/**
       
  1232 	 * Checks if the rebuild request was send and starts to rebuilt the sitemap
       
  1233 	 *
       
  1234 	 * @since 3.0
       
  1235 	 * @access public
       
  1236 	 * @author Arne Brachhold
       
  1237 	*/
       
  1238 	function CheckForManualBuild() {
       
  1239 		if(!empty($_GET["sm_command"]) && !empty($_GET["sm_key"])) {
       
  1240 			$this->Initate();
       
  1241 			if($this->GetOption("b_manual_enabled")===true && $_GET["sm_command"]=="build" && $_GET["sm_key"]==$this->GetOption("b_manual_key")) {
       
  1242 				$this->BuildSitemap();
       
  1243 				echo "DONE";
       
  1244 				exit;
       
  1245 			}
       
  1246 		}
       
  1247 	}
       
  1248 
       
  1249 	/**
       
  1250 	 * Validates all given Priority Providers by checking them for required methods and existence
       
  1251 	 *
       
  1252 	 * @since 3.0
       
  1253 	 * @access private
       
  1254 	 * @author Arne Brachhold
       
  1255 	*/
       
  1256 	function ValidatePrioProviders() {
       
  1257 		$validProviders=array();
       
  1258 		
       
  1259 		for($i=0; $i<count($this->_prioProviders); $i++) {
       
  1260 			if(class_exists($this->_prioProviders[$i])) {
       
  1261 				if($this->IsSubclassOf($this->_prioProviders[$i],"GoogleSitemapGeneratorPrioProviderBase")) {
       
  1262 					array_push($validProviders,$this->_prioProviders[$i]);
       
  1263 				}
       
  1264 			}
       
  1265 		}
       
  1266 		$this->_prioProviders=$validProviders;
       
  1267 		
       
  1268 		if(!$this->GetOption("b_prio_provider")) {
       
  1269 			if(!in_array($this->GetOption("b_prio_provider"),$this->_prioProviders,true)) {
       
  1270 				$this->SetOption("b_prio_provider","");
       
  1271 			}
       
  1272 		}
       
  1273 	}
       
  1274 
       
  1275 	/**
       
  1276 	 * Adds the default Priority Providers to the provider list
       
  1277 	 *
       
  1278 	 * @since 3.0
       
  1279 	 * @access private
       
  1280 	 * @author Arne Brachhold
       
  1281 	*/
       
  1282 	function AddDefaultPrioProviders($providers) {
       
  1283 		array_push($providers,"GoogleSitemapGeneratorPrioByCountProvider");
       
  1284 		array_push($providers,"GoogleSitemapGeneratorPrioByAverageProvider");
       
  1285 		if(class_exists("ak_popularity_contest")) {
       
  1286 			array_push($providers,"GoogleSitemapGeneratorPrioByPopularityContestProvider");
       
  1287 		}
       
  1288 		return $providers;
       
  1289 	}
       
  1290 	
       
  1291 	/**
       
  1292 	 * Loads the stored pages from the database
       
  1293 	 *
       
  1294 	 * @since 3.0
       
  1295 	 * @access private
       
  1296 	 * @author Arne Brachhold
       
  1297 	*/
       
  1298 	function LoadPages() {
       
  1299 		global $wpdb;
       
  1300 		
       
  1301 		$needsUpdate=false;
       
  1302 		
       
  1303 		$pagesString=$wpdb->get_var("SELECT option_value FROM $wpdb->options WHERE option_name = 'sm_cpages'");
       
  1304 		
       
  1305 		//Class sm_page was renamed with 3.0 -> rename it in serialized value for compatibility
       
  1306 		if(!empty($pagesString) && strpos($pagesString,"sm_page")!==false) {
       
  1307 			$pagesString = str_replace("O:7:\"sm_page\"","O:26:\"GoogleSitemapGeneratorPage\"",$pagesString);
       
  1308 			$needsUpdate=true;
       
  1309 		}
       
  1310 		
       
  1311 		if(!empty($pagesString)) {
       
  1312 			$storedpages=unserialize($pagesString);
       
  1313 			$this->_pages=$storedpages;
       
  1314 		} else {
       
  1315 			$this->_pages=array();
       
  1316 		}
       
  1317 		
       
  1318 		if($needsUpdate) $this->SavePages();
       
  1319 	}
       
  1320 	
       
  1321 	/**
       
  1322 	 * Saved the additional pages back to the database
       
  1323 	 *
       
  1324 	 * @since 3.0
       
  1325 	 * @access private
       
  1326 	 * @author Arne Brachhold
       
  1327 	 * @return true on success
       
  1328 	*/
       
  1329 	function SavePages() {
       
  1330 		$oldvalue = get_option("sm_cpages");
       
  1331 		if($oldvalue == $this->_pages) {
       
  1332 			return true;
       
  1333 		} else {
       
  1334 			delete_option("sm_cpages");
       
  1335 			//Add the option, Note the autoload=false because when the autoload happens, our class GoogleSitemapGeneratorPage doesn't exist
       
  1336 			add_option("sm_cpages",$this->_pages,"Storage for custom pages of the sitemap plugin","no");
       
  1337 			return true;
       
  1338 		}
       
  1339 	}
       
  1340 	
       
  1341 	
       
  1342 	/**
       
  1343 	 * Returns the URL for the sitemap file
       
  1344 	 *
       
  1345 	 * @since 3.0
       
  1346 	 * @access private
       
  1347 	 * @author Arne Brachhold
       
  1348 	 * @param bool $forceAuto Force the return value to the autodetected value.
       
  1349 	 * @return The URL to the Sitemap file
       
  1350 	*/
       
  1351 	function GetXmlUrl($forceAuto=false) {
       
  1352 		
       
  1353 		if(!$forceAuto && $this->GetOption("b_location_mode")=="manual") {
       
  1354 			return $this->GetOption("b_fileurl_manual");
       
  1355 		} else {
       
  1356 			return trailingslashit(get_bloginfo('siteurl')). $this->GetOption("b_filename");
       
  1357 		}
       
  1358 	}
       
  1359 
       
  1360 	/**
       
  1361 	 * Returns the URL for the gzipped sitemap file
       
  1362 	 *
       
  1363 	 * @since 3.0
       
  1364 	 * @access private
       
  1365 	 * @author Arne Brachhold
       
  1366 	 * @param bool $forceAuto Force the return value to the autodetected value.
       
  1367 	 * @return The URL to the gzipped Sitemap file
       
  1368 	*/
       
  1369 	function GetZipUrl($forceAuto=false) {
       
  1370 		return $this->GetXmlUrl($forceAuto) . ".gz";
       
  1371 	}
       
  1372 	
       
  1373 	/**
       
  1374 	 * Returns the file system path to the sitemap file
       
  1375 	 *
       
  1376 	 * @since 3.0
       
  1377 	 * @access private
       
  1378 	 * @author Arne Brachhold
       
  1379 	 * @param bool $forceAuto Force the return value to the autodetected value.
       
  1380 	 * @return The file system path;
       
  1381 	*/
       
  1382 	function GetXmlPath($forceAuto=false) {
       
  1383 		if(!$forceAuto && $this->GetOption("b_location_mode")=="manual") {
       
  1384 			return $this->GetOption("b_filename_manual");
       
  1385 		} else {
       
  1386 			return $this->GetHomePath()  . $this->GetOption("b_filename");
       
  1387 		}
       
  1388 	}
       
  1389 	
       
  1390 	/**
       
  1391 	 * Returns the file system path to the gzipped sitemap file
       
  1392 	 *
       
  1393 	 * @since 3.0
       
  1394 	 * @access private
       
  1395 	 * @author Arne Brachhold
       
  1396 	 * @param bool $forceAuto Force the return value to the autodetected value.
       
  1397 	 * @return The file system path;
       
  1398 	*/
       
  1399 	function GetZipPath($forceAuto=false) {
       
  1400 		return $this->GetXmlPath($forceAuto) . ".gz";
       
  1401 	}
       
  1402 	
       
  1403 	/**
       
  1404 	 * Returns the option value for the given key
       
  1405 	 *
       
  1406 	 * @since 3.0
       
  1407 	 * @access private
       
  1408 	 * @author Arne Brachhold
       
  1409 	 * @param $key string The Configuration Key
       
  1410 	 * @return mixed The value
       
  1411 	 */
       
  1412 	function GetOption($key) {
       
  1413 		$key="sm_" . $key;
       
  1414 		if(array_key_exists($key,$this->_options)) {
       
  1415 			return $this->_options[$key];
       
  1416 		} else return null;
       
  1417 	}
       
  1418 	
       
  1419 	/**
       
  1420 	 * Sets an option to a new value
       
  1421 	 *
       
  1422 	 * @since 3.0
       
  1423 	 * @access private
       
  1424 	 * @author Arne Brachhold
       
  1425 	 * @param $key string The configuration key
       
  1426 	 * @param $value mixed The new object
       
  1427 	 */
       
  1428 	function SetOption($key,$value) {
       
  1429 		if(strstr($key,"sm_")!==0) $key="sm_" . $key;
       
  1430 		
       
  1431 		$this->_options[$key]=$value;
       
  1432 	}
       
  1433 	
       
  1434 	/**
       
  1435 	 * Saves the options back to the database
       
  1436 	 *
       
  1437 	 * @since 3.0
       
  1438 	 * @access private
       
  1439 	 * @author Arne Brachhold
       
  1440 	 * @return bool true on success
       
  1441 	 */
       
  1442 	function SaveOptions() {
       
  1443 		$oldvalue = get_option("sm_options");
       
  1444 		if($oldvalue == $this->_options) {
       
  1445 			return true;
       
  1446 		} else return update_option("sm_options",$this->_options);
       
  1447 	}
       
  1448 	
       
  1449 	/**
       
  1450 	 * Retrieves the number of comments of a post in a asso. array
       
  1451 	 * The key is the postID, the value the number of comments
       
  1452 	 *
       
  1453 	 * @since 3.0
       
  1454 	 * @access private
       
  1455 	 * @author Arne Brachhold
       
  1456 	 * @return array An array with postIDs and their comment count
       
  1457 	 */
       
  1458 	function GetComments() {
       
  1459 		global $wpdb;
       
  1460 		$comments=array();
       
  1461 
       
  1462 		//Query comments and add them into the array
       
  1463 		$commentRes=$wpdb->get_results("SELECT `comment_post_ID` as `post_id`, COUNT(comment_ID) as `comment_count` FROM `" . $wpdb->comments . "` WHERE `comment_approved`='1' GROUP BY `comment_post_ID`");
       
  1464 		if($commentRes) {
       
  1465 			foreach($commentRes as $comment) {
       
  1466 				$comments[$comment->post_id]=$comment->comment_count;
       
  1467 			}
       
  1468 		}
       
  1469 		return $comments;
       
  1470 	}
       
  1471 	
       
  1472 	/**
       
  1473 	 * Calculates the full number of comments from an sm_getComments() generated array
       
  1474 	 *
       
  1475 	 * @since 3.0
       
  1476 	 * @access private
       
  1477 	 * @author Arne Brachhold
       
  1478 	 * @param $comments array The Array with posts and c0mment count
       
  1479 	 * @see sm_getComments
       
  1480 	 * @return The full number of comments
       
  1481 	 */
       
  1482 	function GetCommentCount($comments) {
       
  1483 		$commentCount=0;
       
  1484 		foreach($comments AS $k=>$v) {
       
  1485 			$commentCount+=$v;
       
  1486 		}
       
  1487 		return $commentCount;
       
  1488 	}
       
  1489 	
       
  1490 	/**
       
  1491 	 * Adds a url to the sitemap. You can use this method or call AddElement directly.
       
  1492 	 *
       
  1493 	 * @since 3.0
       
  1494 	 * @access public
       
  1495 	 * @author Arne Brachhold
       
  1496 	 * @param $loc string The location (url) of the page
       
  1497 	 * @param $lastMod int The last Modification time as a UNIX timestamp
       
  1498 	 * @param $changeFreq string The change frequenty of the page, Valid values are "always", "hourly", "daily", "weekly", "monthly", "yearly" and "never".
       
  1499 	 * @param $priorty float The priority of the page, between 0.0 and 1.0
       
  1500 	 * @see AddElement
       
  1501 	 * @return string The URL node
       
  1502 	 */
       
  1503 	function AddUrl($loc, $lastMod = 0, $changeFreq = "monthly", $priority = 0.5) {
       
  1504 		//Strip out the last modification time if activated
       
  1505 		if($this->GetOption('in_lastmod')===false) $lastMod = 0;
       
  1506 		$page = new GoogleSitemapGeneratorPage($loc, $priority, $changeFreq, $lastMod);
       
  1507 		
       
  1508 		$this->AddElement($page);
       
  1509 	}
       
  1510 	
       
  1511 	/**
       
  1512 	 * Adds an element to the sitemap
       
  1513 	 *
       
  1514 	 * @since 3.0
       
  1515 	 * @access private
       
  1516 	 * @author Arne Brachhold
       
  1517 	 * @param $page The element
       
  1518 	 */
       
  1519 	function AddElement(&$page) {
       
  1520 		if(empty($page)) return;
       
  1521 		
       
  1522 		$s = $page->Render();
       
  1523 		
       
  1524 		if($this->_fileZipHandle && $this->IsGzipEnabled()) {
       
  1525 			gzwrite($this->_fileZipHandle,$s);
       
  1526 		}
       
  1527 		
       
  1528 		if($this->_fileHandle && $this->GetOption("b_xml")) {
       
  1529 			fwrite($this->_fileHandle,$s);
       
  1530 		}
       
  1531 	}
       
  1532 	
       
  1533 	/**
       
  1534 	 * Checks if a file is writable and tries to make it if not.
       
  1535 	 *
       
  1536 	 * @since 3.05b
       
  1537 	 * @access private
       
  1538 	 * @author  VJTD3 <http://www.VJTD3.com>
       
  1539 	 * @return bool true if writable
       
  1540 	 */
       
  1541 	function IsFileWritable($filename) {
       
  1542 		//can we write?
       
  1543 		if(!is_writable($filename)) {
       
  1544 			//no we can't.
       
  1545 			if(!@chmod($filename, 0666)) {
       
  1546 				$pathtofilename = dirname($filename);
       
  1547 				//Lets check if parent directory is writable.
       
  1548 				if(!is_writable($pathtofilename)) {
       
  1549 					//it's not writeable too.
       
  1550 					if(!@chmod($pathtoffilename, 0666)) {
       
  1551 						//darn couldn't fix up parrent directory this hosting is foobar.
       
  1552 						//Lets error because of the permissions problems.
       
  1553 						return false;
       
  1554 					}
       
  1555 				}
       
  1556 			}
       
  1557 		}
       
  1558 		//we can write, return 1/true/happy dance.
       
  1559 		return true;
       
  1560 	}
       
  1561 	
       
  1562 	/**
       
  1563 	 * Adds the sitemap to the virtual robots.txt file
       
  1564 	 * This function is executed by WordPress with the do_robots hook
       
  1565 	 * 
       
  1566 	 * @since 3.1.2
       
  1567 	 */
       
  1568 	function DoRobots() {
       
  1569 		$this->Initate();
       
  1570 		if($this->GetOption('b_robots') === true) {
       
  1571 
       
  1572 			$smUrl = $this->GetXmlUrl();
       
  1573 			if($this->IsGzipEnabled()) {
       
  1574 				$smUrl = $this->GetZipUrl();
       
  1575 			}
       
  1576 			
       
  1577 			echo  "\nSitemap: " . $smUrl . "\n";
       
  1578 		}
       
  1579 	}
       
  1580 	
       
  1581 	/**
       
  1582 	 * Builds the sitemap and writes it into a xml file.
       
  1583 	 * 
       
  1584 	 * ATTENTION PLUGIN DEVELOPERS! DONT CALL THIS METHOD DIRECTLY!
       
  1585 	 * The method is probably not available, since it is only loaded when needed.
       
  1586 	 * Use do_action("sm_rebuild"); if you want to rebuild the sitemap.
       
  1587 	 * Please refer to the documentation.txt for more details.
       
  1588 	 *
       
  1589 	 * @since 3.0
       
  1590 	 * @access public
       
  1591 	 * @author Arne Brachhold <himself [at] arnebrachhold [dot] de>
       
  1592 	 * @return array An array with messages such as failed writes etc.
       
  1593 	 */
       
  1594 	function BuildSitemap() {
       
  1595 		global $wpdb, $posts, $wp_version;
       
  1596 		$this->Initate();
       
  1597 		
       
  1598 		if($this->GetOption("b_memory")!='') {
       
  1599 			@ini_set("memory_limit",$this->GetOption("b_memory"));
       
  1600 		}
       
  1601 		
       
  1602 		if($this->GetOption("b_time")!=-1) {
       
  1603 			@set_time_limit($this->GetOption("b_time"));
       
  1604 		}
       
  1605 		
       
  1606 		//This object saves the status information of the script directly to the database
       
  1607 		$status = new GoogleSitemapGeneratorStatus();
       
  1608 		
       
  1609 		//Other plugins can detect if the building process is active
       
  1610 		$this->_isActive = true;
       
  1611 		
       
  1612 		//$this->AddElement(new GoogleSitemapGeneratorXmlEntry());
       
  1613 		
       
  1614 		//Debug mode?
       
  1615 		$debug=$this->GetOption("b_debug");
       
  1616 		
       
  1617 		if($this->GetOption("b_xml")) {
       
  1618 			$fileName = $this->GetXmlPath();
       
  1619 			$status->StartXml($this->GetXmlPath(),$this->GetXmlUrl());
       
  1620 			
       
  1621 			if($this->IsFileWritable($fileName)) {
       
  1622 				
       
  1623 				$this->_fileHandle = fopen($fileName,"w");
       
  1624 				if(!$this->_fileHandle) $status->EndXml(false,"Not openable");
       
  1625 				
       
  1626 			} else $status->EndXml(false,"not writable");
       
  1627 		}
       
  1628 		
       
  1629 		//Write gzipped sitemap file
       
  1630 		if($this->IsGzipEnabled()) {
       
  1631 			$fileName = $this->GetZipPath();
       
  1632 			$status->StartZip($this->GetZipPath(),$this->GetZipUrl());
       
  1633 			
       
  1634 			if($this->IsFileWritable($fileName)) {
       
  1635 				
       
  1636 				$this->_fileZipHandle = gzopen($fileName,"w1");
       
  1637 				if(!$this->_fileZipHandle) $status->EndZip(false,"Not openable");
       
  1638 				
       
  1639 			} else $status->EndZip(false,"not writable");
       
  1640 		}
       
  1641 		
       
  1642 		if(!$this->_fileHandle && !$this->_fileZipHandle) {
       
  1643 			$status->End();
       
  1644 			return;
       
  1645 		}
       
  1646 		
       
  1647 		
       
  1648 		//Content of the XML file
       
  1649 		$this->AddElement(new GoogleSitemapGeneratorXmlEntry('<?xml version="1.0" encoding="UTF-8"' . '?' . '>'));
       
  1650 		
       
  1651 		$styleSheet = ($this->GetDefaultStyle() && $this->GetOption('b_style_default')===true?$this->GetDefaultStyle():$this->GetOption('b_style'));
       
  1652 		
       
  1653 		if(!empty($styleSheet)) {
       
  1654 			$this->AddElement(new GoogleSitemapGeneratorXmlEntry('<' . '?xml-stylesheet type="text/xsl" href="' . $styleSheet . '"?' . '>'));
       
  1655 		}
       
  1656 		
       
  1657 		$this->AddElement(new GoogleSitemapGeneratorDebugEntry("generator=\"wordpress/" . get_bloginfo('version') . "\""));
       
  1658 		$this->AddElement(new GoogleSitemapGeneratorDebugEntry("sitemap-generator-url=\"http://www.arnebrachhold.de\" sitemap-generator-version=\"" . $this->GetVersion() . "\""));
       
  1659 		$this->AddElement(new GoogleSitemapGeneratorDebugEntry("generated-on=\"" . date(get_option("date_format") . " " . get_option("time_format")) . "\""));
       
  1660 		
       
  1661 		//All comments as an asso. Array (postID=>commentCount)
       
  1662 		$comments=($this->GetOption("b_prio_provider")!=""?$this->GetComments():array());
       
  1663 		
       
  1664 		//Full number of comments
       
  1665 		$commentCount=(count($comments)>0?$this->GetCommentCount($comments):0);
       
  1666 		
       
  1667 		if($debug && $this->GetOption("b_prio_provider")!="") {
       
  1668 			$this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Total comment count: " . $commentCount));
       
  1669 		}
       
  1670 		
       
  1671 		//Go XML!
       
  1672 		$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">'));
       
  1673 		
       
  1674 		$home = get_bloginfo('url');
       
  1675 		
       
  1676 		$homePid = 0;
       
  1677 		
       
  1678 		//Add the home page (WITH a slash!)
       
  1679 		if($this->GetOption("in_home")) {
       
  1680 			if('page' == get_option('show_on_front') && get_option('page_on_front')) {
       
  1681 				$pageOnFront = get_option('page_on_front');
       
  1682 				$p = get_page($pageOnFront);
       
  1683 				if($p) {
       
  1684 					$homePid = $p->ID;
       
  1685 					$this->AddUrl(trailingslashit($home),$this->GetTimestampFromMySql(($p->post_modified_gmt && $p->post_modified_gmt!='0000-00-00 00:00:00'?$p->post_modified_gmt:$p->post_date_gmt)),$this->GetOption("cf_home"),$this->GetOption("pr_home"));
       
  1686 				}
       
  1687 			} else {
       
  1688 				$this->AddUrl(trailingslashit($home),$this->GetTimestampFromMySql(get_lastpostmodified('GMT')),$this->GetOption("cf_home"),$this->GetOption("pr_home"));
       
  1689 			}
       
  1690 		}
       
  1691 		
       
  1692 		//Add the posts
       
  1693 		if($this->GetOption("in_posts") || $this->GetOption("in_pages")) {
       
  1694 			
       
  1695 			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Postings"));
       
  1696 		
       
  1697 			//Pre 2.1 compatibility. 2.1 introduced 'future' as post_status so we don't need to check post_date
       
  1698 			$wpCompat = (floatval($wp_version) < 2.1);
       
  1699 			
       
  1700 			$useQTransLate = false; //function_exists('qtrans_convertURL') && function_exists('qtrans_getEnabledLanguages'); Not really working yet
       
  1701 			
       
  1702 			$excludes = $this->GetOption('b_exclude'); //Excluded posts
       
  1703 			
       
  1704 			$exclCats = $this->GetOption("b_exclude_cats"); // Excluded cats
       
  1705 			
       
  1706 			if($exclCats && count($exclCats)>0 && $this->IsTaxonomySupported()) {
       
  1707 				
       
  1708 				$exPosts = get_objects_in_term($exclCats,"category"); // Get all posts in excl. cats
       
  1709 				
       
  1710 				if(is_array($exPosts) && count($exPosts) > 0) { //Merge it with the list of user excluded posts
       
  1711 					$excludes = array_merge($excludes, $exPosts);
       
  1712 				}
       
  1713 			}
       
  1714 			
       
  1715 	
       
  1716 			$contentStmt = '';
       
  1717 			if($useQTransLate) {
       
  1718 				$contentStmt.=', post_content ';
       
  1719 			}
       
  1720 			
       
  1721 			$postPageStmt = '';
       
  1722 			
       
  1723 			$inSubPages = ($this->GetOption('in_posts_sub')===true);
       
  1724 			
       
  1725 			if($inSubPages && $this->GetOption('in_posts')===true) {
       
  1726 				$pageDivider='<!--nextpage-->';
       
  1727 				$postPageStmt = ", (character_length(`post_content`)  - character_length(REPLACE(`post_content`, '$pageDivider', ''))) / " . strlen($pageDivider) . " as postPages";
       
  1728 			}
       
  1729 			
       
  1730 			$sql="SELECT `ID`, `post_author`, `post_date`, `post_date_gmt`, `post_status`, `post_name`, `post_modified`, `post_modified_gmt`, `post_parent`, `post_type` $postPageStmt $contentStmt FROM `" . $wpdb->posts . "` WHERE ";
       
  1731 			
       
  1732 			$where = '(';
       
  1733 			
       
  1734 			if($this->GetOption('in_posts')) {
       
  1735 				//WP < 2.1: posts are post_status = publish
       
  1736 				//WP >= 2.1: post_type must be 'post', no date check required because future posts are post_status='future'
       
  1737 				if($wpCompat) $where.="(post_status = 'publish' AND post_date_gmt <= '" . gmdate('Y-m-d H:i:59') . "')";
       
  1738 				else $where.=" (post_status = 'publish' AND (post_type = 'post' OR post_type = '')) ";
       
  1739 			}
       
  1740 			
       
  1741 			if($this->GetOption('in_pages')) {
       
  1742 				if($this->GetOption('in_posts')) {
       
  1743 					$where.=" OR ";
       
  1744 				}
       
  1745 				if($wpCompat) {
       
  1746 					//WP < 2.1: posts have post_status = published, pages have post_status = static
       
  1747 					$where.=" post_status='static' ";
       
  1748 				} else {
       
  1749 					//WP >= 2.1: posts have post_type = 'post' and pages have post_type = 'page'. Both must be published.
       
  1750 					$where.=" (post_status = 'publish' AND post_type = 'page') ";
       
  1751 				}
       
  1752 			}
       
  1753 			
       
  1754 			$where.=") ";
       
  1755 			
       
  1756 			
       
  1757 			if(is_array($excludes) && count($excludes)>0) {
       
  1758 				$where.=" AND ID NOT IN ('" . implode("','",$excludes) . "')";
       
  1759 			}
       
  1760 			
       
  1761 			$where.=" AND post_password='' ORDER BY post_modified DESC";
       
  1762 			
       
  1763 			$sql .= $where;
       
  1764 			
       
  1765 			if($this->GetOption("b_max_posts")>0) {
       
  1766 				$sql.=" LIMIT 0," . $this->GetOption("b_max_posts");
       
  1767 			}
       
  1768 
       
  1769 			$postCount = intval($wpdb->get_var("SELECT COUNT(*) AS cnt FROM `" . $wpdb->posts . "` WHERE ". $where,0,0));
       
  1770 										
       
  1771 			//Create a new connection because we are using mysql_unbuffered_query and don't want to disturb the WP connection
       
  1772 			//Safe Mode for other plugins which use mysql_query() without a connection handler and will destroy our resultset :(
       
  1773 			$con = $postRes = null;
       
  1774 			
       
  1775 			//In 2.2, a bug which prevented additional DB connections was fixed
       
  1776 			if(floatval($wp_version) < 2.2) {
       
  1777 				$this->SetOption("b_safemode",true);
       
  1778 			}
       
  1779 			
       
  1780 			if($this->GetOption("b_safemode")===true) {
       
  1781 				$postRes = mysql_query($sql,$wpdb->dbh);
       
  1782 				if(!$postRes) {
       
  1783 					trigger_error("MySQL query failed: " . mysql_error(),E_USER_NOTICE); //E_USER_NOTICE will be displayed on our debug mode
       
  1784 					return;
       
  1785 				}
       
  1786 			} else {
       
  1787 				$con = mysql_connect(DB_HOST,DB_USER,DB_PASSWORD,true);
       
  1788 				if(!$con) {
       
  1789 					trigger_error("MySQL Connection failed: " . mysql_error(),E_USER_NOTICE);
       
  1790 					return;
       
  1791 				}
       
  1792 				if(!mysql_select_db(DB_NAME,$con)) {
       
  1793 					trigger_error("MySQL DB Select failed: " . mysql_error(),E_USER_NOTICE);
       
  1794 					return;
       
  1795 				}
       
  1796 				$postRes = mysql_unbuffered_query($sql,$con);
       
  1797 				
       
  1798 				if(!$postRes) {
       
  1799 					trigger_error("MySQL unbuffered query failed: " . mysql_error(),E_USER_NOTICE);
       
  1800 					return;
       
  1801 				}
       
  1802 			}
       
  1803 			
       
  1804 			if($postRes) {
       
  1805 				
       
  1806 				//#type $prioProvider GoogleSitemapGeneratorPrioProviderBase
       
  1807 				$prioProvider=NULL;
       
  1808 				
       
  1809 				if($this->GetOption("b_prio_provider") != '') {
       
  1810 					$providerClass=$this->GetOption('b_prio_provider');
       
  1811 					$prioProvider = new $providerClass($commentCount,$postCount);
       
  1812 				}
       
  1813 				
       
  1814 				//$posts is used by Alex King's Popularity Contest plugin
       
  1815 				//if($posts == null || !is_array($posts)) {
       
  1816 				//	$posts = &$postRes;
       
  1817 				//}
       
  1818 				
       
  1819 				$z = 1;
       
  1820 				$zz = 1;
       
  1821 				
       
  1822 				//Default priorities
       
  1823 				$default_prio_posts = $this->GetOption('pr_posts');
       
  1824 				$default_prio_pages = $this->GetOption('pr_pages');
       
  1825 				
       
  1826 				//Change frequencies
       
  1827 				$cf_pages = $this->GetOption('cf_pages');
       
  1828 				$cf_posts = $this->GetOption('cf_posts');
       
  1829 				
       
  1830 				$minPrio=$this->GetOption('pr_posts_min');
       
  1831 				
       
  1832 			
       
  1833 				//Cycle through all posts and add them
       
  1834 				while($post = mysql_fetch_object($postRes)) {
       
  1835 				
       
  1836 					//Fill the cache with our DB result. Since it's incomplete (no text-content for example), we will clean it later.
       
  1837 					$cache = array(&$post);
       
  1838 					update_post_cache($cache);
       
  1839 					
       
  1840 					//Set the current working post for other plugins which depend on "the loop"
       
  1841 					$GLOBALS['post'] = &$post;
       
  1842 				
       
  1843 					$permalink = get_permalink($post->ID);
       
  1844 					if($permalink != $home && $post->ID != $homePid) {
       
  1845 								
       
  1846 						$isPage = false;
       
  1847 						if($wpCompat) {
       
  1848 							$isPage = ($post->post_status == 'static');
       
  1849 						} else {
       
  1850 							$isPage = ($post->post_type == 'page');
       
  1851 						}
       
  1852 						
       
  1853 					
       
  1854 						//Default Priority if auto calc is disabled
       
  1855 						$prio = 0;
       
  1856 							
       
  1857 						if($isPage) {
       
  1858 							//Priority for static pages
       
  1859 							$prio = $default_prio_pages;
       
  1860 						} else {
       
  1861 							//Priority for normal posts
       
  1862 							$prio = $default_prio_posts;
       
  1863 						}
       
  1864 						
       
  1865 						//If priority calc. is enabled, calculate (but only for posts, not pages)!
       
  1866 						if($prioProvider !== null && !$isPage) {
       
  1867 
       
  1868 							//Comment count for this post
       
  1869 							$cmtcnt = (isset($comments[$post->ID])?$comments[$post->ID]:0);
       
  1870 							$prio = $prioProvider->GetPostPriority($post->ID, $cmtcnt, $post);
       
  1871 
       
  1872 							if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry('Debug: Priority report of postID ' . $post->ID . ': Comments: ' . $cmtcnt . ' of ' . $commentCount . ' = ' . $prio . ' points'));
       
  1873 						}
       
  1874 						
       
  1875 						if(!$isPage && $minPrio>0 && $prio<$minPrio) {
       
  1876 							$prio = $minPrio;
       
  1877 						}
       
  1878 						
       
  1879 						//Add it
       
  1880 						$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);
       
  1881 						
       
  1882 						if($inSubPages) {
       
  1883 							$subPage = '';
       
  1884 							for($p = 1; $p <= $post->postPages; $p++) {
       
  1885 								if(get_option('permalink_structure') == '') {
       
  1886 									$subPage = $permalink . '&amp;page=' . ($p+1);
       
  1887 								} else {
       
  1888 									$subPage = trailingslashit($permalink) . user_trailingslashit($p+1, 'single_paged');
       
  1889 								}
       
  1890 
       
  1891 								$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);
       
  1892 							}
       
  1893 						}
       
  1894 						
       
  1895 						// Multilingual Support with qTranslate, thanks to Qian Qin
       
  1896 						if($useQTransLate) {
       
  1897 							global $q_config;
       
  1898 							foreach(qtrans_getEnabledLanguages($post->post_content) as $language) {
       
  1899 								if($language!=$q_config['default_language']) {
       
  1900 									$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);
       
  1901 								}
       
  1902 							}
       
  1903 						}
       
  1904 					}
       
  1905 					
       
  1906 					//Update the status every 100 posts and at the end.
       
  1907 					//If the script breaks because of memory or time limit,
       
  1908 					//we have a "last reponded" value which can be compared to the server settings
       
  1909 					if($zz==100 || $z == $postCount) {
       
  1910 						$status->SaveStep($z);
       
  1911 						$zz=0;
       
  1912 					} else $zz++;
       
  1913 					
       
  1914 					$z++;
       
  1915 					
       
  1916 					//Clean cache because it's incomplete
       
  1917 					if(version_compare($wp_version,"2.5",">=")) {
       
  1918 						//WP 2.5 makes a mysql query for every clean_post_cache to clear the child cache
       
  1919 						//so I've copied the function here until a patch arrives...
       
  1920 						wp_cache_delete($post->ID, 'posts');
       
  1921 						wp_cache_delete($post->ID, 'post_meta');
       
  1922 						clean_object_term_cache($post->ID, 'post');
       
  1923 					} else {
       
  1924 						clean_post_cache($post->ID);
       
  1925 					}
       
  1926 				}
       
  1927 				unset($postRes);
       
  1928 				unset($prioProvider);
       
  1929 				
       
  1930 				if($this->GetOption("b_safemode")!==true && $con) mysql_close($con);
       
  1931 			}
       
  1932 			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Postings"));
       
  1933 		}
       
  1934 		
       
  1935 		//Add the cats
       
  1936 		if($this->GetOption("in_cats")) {
       
  1937 			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Cats"));
       
  1938 			
       
  1939 			$exclCats = $this->GetOption("b_exclude_cats"); // Excluded cats
       
  1940 			if($exclCats == null) $exclCats=array();
       
  1941 						
       
  1942 			if(!$this->IsTaxonomySupported()) {
       
  1943 			
       
  1944 				$catsRes=$wpdb->get_results("
       
  1945 							SELECT
       
  1946 								c.cat_ID AS ID,
       
  1947 								MAX(p.post_modified_gmt) AS last_mod
       
  1948 							FROM
       
  1949 								`" . $wpdb->categories . "` c,
       
  1950 								`" . $wpdb->post2cat . "` pc,
       
  1951 								`" . $wpdb->posts . "` p
       
  1952 							WHERE
       
  1953 								pc.category_id = c.cat_ID
       
  1954 								AND p.ID = pc.post_id
       
  1955 								AND p.post_status = 'publish'
       
  1956 								AND p.post_type='post'
       
  1957 							GROUP
       
  1958 								BY c.cat_id
       
  1959 							");
       
  1960 				if($catsRes) {
       
  1961 					foreach($catsRes as $cat) {
       
  1962 						if($cat && $cat->ID && $cat->ID>0 && !in_array($cat->ID, $exclCats)) {
       
  1963 							if($debug) if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Cat-ID:" . $cat->ID));
       
  1964 							$this->AddUrl(get_category_link($cat->ID),$this->GetTimestampFromMySql($cat->last_mod),$this->GetOption("cf_cats"),$this->GetOption("pr_cats"));
       
  1965 						}
       
  1966 					}
       
  1967 				}
       
  1968 			} else {
       
  1969 				$cats = get_terms("category",array("hide_empty"=>true,"hierarchical"=>false));
       
  1970 				if($cats && is_array($cats) && count($cats)>0) {
       
  1971 					foreach($cats AS $cat) {
       
  1972 						if(!in_array($cat->term_id, $exclCats)) $this->AddUrl(get_category_link($cat->term_id),0,$this->GetOption("cf_cats"),$this->GetOption("pr_cats"));
       
  1973 					}
       
  1974 				}
       
  1975 			}
       
  1976 			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Cats"));
       
  1977 		}
       
  1978 		
       
  1979 		//Add the archives
       
  1980 		if($this->GetOption("in_arch")) {
       
  1981 			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Archive"));
       
  1982 			$now = current_time('mysql');
       
  1983 
       
  1984 			//WP2.1 introduced post_status='future', for earlier WP versions we need to check the post_date_gmt
       
  1985 			$arcresults = $wpdb->get_results("
       
  1986 						SELECT DISTINCT
       
  1987 							YEAR(post_date_gmt) AS `year`,
       
  1988 							MONTH(post_date_gmt) AS `month`,
       
  1989 							MAX(post_date_gmt) as last_mod,
       
  1990 							count(ID) as posts
       
  1991 						FROM
       
  1992 							$wpdb->posts
       
  1993 						WHERE
       
  1994 							post_date < '$now'
       
  1995 							AND post_status = 'publish'
       
  1996 							AND post_type = 'post'
       
  1997 							" . (floatval($wp_version) < 2.1?"AND {$wpdb->posts}.post_date_gmt <= '" . gmdate('Y-m-d H:i:59') . "'":"") . "
       
  1998 						GROUP BY
       
  1999 							YEAR(post_date_gmt),
       
  2000 							MONTH(post_date_gmt)
       
  2001 						ORDER BY
       
  2002 							post_date_gmt DESC");
       
  2003 			if ($arcresults) {
       
  2004 				foreach ($arcresults as $arcresult) {
       
  2005 					
       
  2006 					$url  = get_month_link($arcresult->year,   $arcresult->month);
       
  2007 					$changeFreq="";
       
  2008 					
       
  2009 					//Archive is the current one
       
  2010 					if($arcresult->month==date("n") && $arcresult->year==date("Y")) {
       
  2011 						$changeFreq=$this->GetOption("cf_arch_curr");
       
  2012 					} else { // Archive is older
       
  2013 						$changeFreq=$this->GetOption("cf_arch_old");
       
  2014 					}
       
  2015 					
       
  2016 					$this->AddUrl($url,$this->GetTimestampFromMySql($arcresult->last_mod),$changeFreq,$this->GetOption("pr_arch"));
       
  2017 				}
       
  2018 			}
       
  2019 			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Archive"));
       
  2020 		}
       
  2021 		
       
  2022 		//Add the author pages
       
  2023 		if($this->GetOption("in_auth")) {
       
  2024 			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Author pages"));
       
  2025 			
       
  2026 			$linkFunc = null;
       
  2027 			
       
  2028 			//get_author_link is deprecated in WP 2.1, try to use get_author_posts_url first.
       
  2029 			if(function_exists('get_author_posts_url')) {
       
  2030 				$linkFunc = 'get_author_posts_url';
       
  2031 			} else if(function_exists('get_author_link')) {
       
  2032 				$linkFunc = 'get_author_link';
       
  2033 			}
       
  2034 			
       
  2035 			//Who knows what happens in later WP versions, so check again if it worked
       
  2036 			if($linkFunc !== null) {
       
  2037 			    //Unfortunately there is no API function to get all authors, so we have to do it the dirty way...
       
  2038 				//We retrieve only users with published and not password protected posts (and not pages)
       
  2039 				//WP2.1 introduced post_status='future', for earlier WP versions we need to check the post_date_gmt
       
  2040 				$sql = "SELECT DISTINCT
       
  2041 							p.ID,
       
  2042 							u.user_nicename,
       
  2043 							MAX(p.post_modified_gmt) AS last_post
       
  2044 						FROM
       
  2045 							{$wpdb->users} u,
       
  2046 							{$wpdb->posts} p
       
  2047 						WHERE
       
  2048 							p.post_author = u.ID
       
  2049 							AND p.post_status = 'publish'
       
  2050 							AND p.post_type = 'post'
       
  2051 							AND p.post_password = ''
       
  2052 							" . (floatval($wp_version) < 2.1?"AND p.post_date_gmt <= '" . gmdate('Y-m-d H:i:59') . "'":"") . "
       
  2053 						GROUP BY
       
  2054 							u.ID,
       
  2055 							u.user_nicename";
       
  2056 							
       
  2057 				$authors = $wpdb->get_results($sql);
       
  2058 				
       
  2059 				if($authors && is_array($authors)) {
       
  2060 					foreach($authors as $author) {
       
  2061 						if($debug) if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Author-ID:" . $author->ID));
       
  2062 						$url = ($linkFunc=='get_author_posts_url'?get_author_posts_url($author->ID,$author->user_nicename):get_author_link(false,$author->ID,$author->user_nicename));
       
  2063 						$this->AddUrl($url,$this->GetTimestampFromMySql($author->last_post),$this->GetOption("cf_auth"),$this->GetOption("pr_auth"));
       
  2064 					}
       
  2065 				}
       
  2066 			} else {
       
  2067 				//Too bad, no author pages for you :(
       
  2068 				if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: No valid author link function found"));
       
  2069 			}
       
  2070 	
       
  2071 			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Author pages"));
       
  2072 		}
       
  2073 		
       
  2074 		//Add tag pages
       
  2075 		if($this->GetOption("in_tags") && $this->IsTaxonomySupported()) {
       
  2076 			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Tags"));
       
  2077 			$tags = get_terms("post_tag",array("hide_empty"=>true,"hierarchical"=>false));
       
  2078 			if($tags && is_array($tags) && count($tags)>0) {
       
  2079 				foreach($tags AS $tag) {
       
  2080 					$this->AddUrl(get_tag_link($tag->term_id),0,$this->GetOption("cf_tags"),$this->GetOption("pr_tags"));
       
  2081 				}
       
  2082 			}
       
  2083 			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Tags"));
       
  2084 		}
       
  2085 		
       
  2086 		//Add custom taxonomy pages
       
  2087 		if($this->GetOption("in_tax") && $this->IsTaxonomySupported()) {
       
  2088 			
       
  2089 			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start custom taxonomies"));
       
  2090 			
       
  2091 			$enabledTaxonomies = $this->GetOption("in_tax");
       
  2092 			
       
  2093 			$taxList = array();
       
  2094 			
       
  2095 			foreach ($enabledTaxonomies as $taxName) {
       
  2096 				$taxonomy = get_taxonomy($taxName);
       
  2097 				if($taxonomy) $taxList[] = $wpdb->escape($taxonomy->name);
       
  2098 			}
       
  2099 			
       
  2100 			if(count($taxList)>0) {
       
  2101 				//We're selecting all term information (t.*) plus some additional fields
       
  2102 				//like the last mod date and the taxonomy name, so WP doesnt need to make
       
  2103 				//additional queries to build the permalink structure.
       
  2104 				//This does NOT work for categories and tags yet, because WP uses get_category_link
       
  2105 				//and get_tag_link internally and that would cause one additional query per term!
       
  2106 				$sql="
       
  2107 					SELECT
       
  2108 						t.*,
       
  2109 						tt.taxonomy AS _taxonomy,
       
  2110 						UNIX_TIMESTAMP(MAX(post_date_gmt)) as _mod_date
       
  2111 					FROM
       
  2112 						{$wpdb->posts} p ,
       
  2113 						{$wpdb->term_relationships} r,
       
  2114 						{$wpdb->terms} t,
       
  2115 						{$wpdb->term_taxonomy} tt
       
  2116 					WHERE
       
  2117 						p.ID = r.object_id
       
  2118 						AND p.post_status = 'publish'
       
  2119 						AND p.post_type = 'post'
       
  2120 						AND p.post_password = ''
       
  2121 						AND r.term_taxonomy_id = t.term_id
       
  2122 						AND t.term_id = tt.term_id
       
  2123 						AND tt.count > 0
       
  2124 						AND tt.taxonomy IN ('" . implode("','",$taxList) . "')
       
  2125 					GROUP BY
       
  2126 						t.term_id";
       
  2127 						
       
  2128 				$termInfo = $wpdb->get_results($sql);
       
  2129 				
       
  2130 				foreach($termInfo AS $term) {
       
  2131 					$this->AddUrl(get_term_link($term,$term->_taxonomy),$term->_mod_date ,$this->GetOption("cf_tags"),$this->GetOption("pr_tags"));
       
  2132 				}
       
  2133 			}
       
  2134 
       
  2135 			if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End custom taxonomies"));
       
  2136 		}
       
  2137 		
       
  2138 		//Add the custom pages
       
  2139 		if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Custom Pages"));
       
  2140 		if($this->_pages && is_array($this->_pages) && count($this->_pages)>0) {
       
  2141 			//#type $page GoogleSitemapGeneratorPage
       
  2142 			foreach($this->_pages AS $page) {
       
  2143 				$this->AddUrl($page->GetUrl(),$page->getLastMod(),$page->getChangeFreq(),$page->getPriority());
       
  2144 			}
       
  2145 		}
       
  2146 		
       
  2147 		if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Custom Pages"));
       
  2148 		
       
  2149 		if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start additional URLs"));
       
  2150 		
       
  2151 		do_action('sm_buildmap');
       
  2152 		
       
  2153 		if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End additional URLs"));
       
  2154 		
       
  2155 		$this->AddElement(new GoogleSitemapGeneratorXmlEntry("</urlset>"));
       
  2156 		
       
  2157 
       
  2158 		$pingUrl='';
       
  2159 		
       
  2160 		if($this->GetOption("b_xml")) {
       
  2161 			if($this->_fileHandle && fclose($this->_fileHandle)) {
       
  2162 				$this->_fileHandle = null;
       
  2163 				$status->EndXml(true);
       
  2164 				$pingUrl=$this->GetXmlUrl();
       
  2165 			} else $status->EndXml(false,"Could not close the sitemap file.");
       
  2166 		}
       
  2167 		
       
  2168 		if($this->IsGzipEnabled()) {
       
  2169 			if($this->_fileZipHandle && fclose($this->_fileZipHandle)) {
       
  2170 				$this->_fileZipHandle = null;
       
  2171 				$status->EndZip(true);
       
  2172 				$pingUrl=$this->GetZipUrl();
       
  2173 			} else $status->EndZip(false,"Could not close the zipped sitemap file");
       
  2174 		}
       
  2175 		
       
  2176 		//Ping Google
       
  2177 		if($this->GetOption("b_ping") && !empty($pingUrl)) {
       
  2178 			$sPingUrl="http://www.google.com/webmasters/sitemaps/ping?sitemap=" . urlencode($pingUrl);
       
  2179 			$status->StartGooglePing($sPingUrl);
       
  2180 			$pingres=$this->RemoteOpen($sPingUrl);
       
  2181 									  
       
  2182 			if($pingres==NULL || $pingres===false) {
       
  2183 				$status->EndGooglePing(false,$this->_lastError);
       
  2184 				trigger_error("Failed to ping Google: " . htmlspecialchars(strip_tags($pingres)),E_USER_NOTICE);
       
  2185 			} else {
       
  2186 				$status->EndGooglePing(true);
       
  2187 			}
       
  2188 		}
       
  2189 				
       
  2190 		//Ping Ask.com
       
  2191 		if($this->GetOption("b_pingask") && !empty($pingUrl)) {
       
  2192 			$sPingUrl="http://submissions.ask.com/ping?sitemap=" . urlencode($pingUrl);
       
  2193 			$status->StartAskPing($sPingUrl);
       
  2194 			$pingres=$this->RemoteOpen($sPingUrl);
       
  2195 									  
       
  2196 			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.
       
  2197 				$status->EndAskPing(false,$this->_lastError);
       
  2198 				trigger_error("Failed to ping Ask.com: " . htmlspecialchars(strip_tags($pingres)),E_USER_NOTICE);
       
  2199 			} else {
       
  2200 				$status->EndAskPing(true);
       
  2201 			}
       
  2202 		}
       
  2203 		
       
  2204 		//Ping YAHOO
       
  2205 		if($this->GetOption("b_pingyahoo")===true && $this->GetOption("b_yahookey")!="" && !empty($pingUrl)) {
       
  2206 			$sPingUrl="http://search.yahooapis.com/SiteExplorerService/V1/updateNotification?appid=" . $this->GetOption("b_yahookey") . "&url=" . urlencode($pingUrl);
       
  2207 			$status->StartYahooPing($sPingUrl);
       
  2208 			$pingres=$this->RemoteOpen($sPingUrl);
       
  2209 
       
  2210 			if($pingres==NULL || $pingres===false || strpos(strtolower($pingres),"success")===false) {
       
  2211 				trigger_error("Failed to ping YAHOO: " . htmlspecialchars(strip_tags($pingres)),E_USER_NOTICE);
       
  2212 				$status->EndYahooPing(false,$this->_lastError);
       
  2213 			} else {
       
  2214 				$status->EndYahooPing(true);
       
  2215 			}
       
  2216 		}
       
  2217 		
       
  2218 		//Ping Bing
       
  2219 		if($this->GetOption("b_pingmsn") && !empty($pingUrl)) {
       
  2220 			$sPingUrl="http://www.bing.com/webmaster/ping.aspx?siteMap=" . urlencode($pingUrl);
       
  2221 			$status->StartMsnPing($sPingUrl);
       
  2222 			$pingres=$this->RemoteOpen($sPingUrl);
       
  2223 									  
       
  2224 			if($pingres==NULL || $pingres===false || strpos($pingres,"Thanks for submitting your sitemap")===false) {
       
  2225 				trigger_error("Failed to ping Bing: " . htmlspecialchars(strip_tags($pingres)),E_USER_NOTICE);
       
  2226 				$status->EndMsnPing(false,$this->_lastError);
       
  2227 			} else {
       
  2228 				$status->EndMsnPing(true);
       
  2229 			}
       
  2230 		}
       
  2231 	
       
  2232 		$status->End();
       
  2233 		
       
  2234 		
       
  2235 		$this->_isActive = false;
       
  2236 	
       
  2237 		//done...
       
  2238 		return $status;
       
  2239 	}
       
  2240 	
       
  2241 	/**
       
  2242 	 * Tries to ping a specific service showing as much as debug output as possible
       
  2243 	 * @since 3.1.9
       
  2244 	 * @return null
       
  2245 	 */
       
  2246 	function ShowPingResult() {
       
  2247 		
       
  2248 		check_admin_referer('sitemap');
       
  2249 		
       
  2250 		if(!current_user_can("administrator")) {
       
  2251 			echo '<p>Please log in as admin</p>';
       
  2252 			return;
       
  2253 		}
       
  2254 		
       
  2255 		$service = !empty($_GET["sm_ping_service"])?$_GET["sm_ping_service"]:null;
       
  2256 		
       
  2257 		$status = GoogleSitemapGeneratorStatus::Load();
       
  2258 		
       
  2259 		if(!$status) die("No build status yet. Build the sitemap first.");
       
  2260 		
       
  2261 		$url = null;
       
  2262 
       
  2263 		switch($service) {
       
  2264 			case "google":
       
  2265 				$url = $status->_googleUrl;
       
  2266 				break;
       
  2267 			case "yahoo":
       
  2268 				$url = $status->_yahooUrl;
       
  2269 				break;
       
  2270 			case "msn":
       
  2271 				$url = $status->_msnUrl;
       
  2272 				break;
       
  2273 			case "ask":
       
  2274 				$url = $status->_askUrl;
       
  2275 				break;			
       
  2276 		}
       
  2277 		
       
  2278 		if(empty($url)) die("Invalid ping url");
       
  2279 		
       
  2280 		echo '<html><head><title>Ping Test</title>';
       
  2281 		if(function_exists('wp_admin_css')) wp_admin_css('css/global',true);
       
  2282 		echo '</head><body><h1>Ping Test</h1>';
       
  2283 				
       
  2284 		echo '<p>Trying to ping: <a href="' . $url . '">' . $url . '</a>. The sections below should give you an idea whats going on.</p>';
       
  2285 		
       
  2286 		//Try to get as much as debug / error output as possible
       
  2287 		$errLevel = error_reporting(E_ALL);
       
  2288 		$errDisplay = ini_set("display_errors",1);
       
  2289 		if(!defined('WP_DEBUG')) define('WP_DEBUG',true);
       
  2290 		
       
  2291 		echo '<h2>Errors, Warnings, Notices:</h2>';
       
  2292 		
       
  2293 		if(WP_DEBUG == false) echo "<i>WP_DEBUG was set to false somewhere before. You might not see all debug information until you remove this declaration!</i><br />";
       
  2294 		if(ini_get("display_errors")!=1) echo "<i>Your display_errors setting currently prevents the plugin from showing errors here. Please check your webserver logfile instead.</i><br />";
       
  2295 		
       
  2296 		$res = $this->RemoteOpen($url);
       
  2297 		
       
  2298 		echo '<h2>Result (text only):</h2>';
       
  2299 
       
  2300 		echo wp_kses($res,array('a' => array('href' => array()),'p' => array(), 'ul' => array(), 'ol' => array(), 'li' => array()));
       
  2301 		
       
  2302 		echo '<h2>Result (HTML):</h2>';
       
  2303 		
       
  2304 		echo htmlspecialchars($res);
       
  2305 
       
  2306 		//Revert back old values
       
  2307 		error_reporting($errLevel);
       
  2308 		ini_set("display_errors",$errDisplay);
       
  2309 		echo '</body></html>';
       
  2310 		exit;
       
  2311 	}
       
  2312 	
       
  2313 	/**
       
  2314 	 * Opens a remote file using the WordPress API or Snoopy
       
  2315 	 * @since 3.0
       
  2316 	 * @param $url The URL to open
       
  2317 	 * @param $method get or post
       
  2318 	 * @param $postData An array with key=>value paris
       
  2319 	 * @param $timeout Timeout for the request, by default 10
       
  2320 	 * @return mixed False on error, the body of the response on success
       
  2321 	 */
       
  2322 	function RemoteOpen($url,$method = 'get', $postData = null, $timeout = 10) {
       
  2323 		global $wp_version;
       
  2324 		
       
  2325 		//Before WP 2.7, wp_remote_fopen was quite crappy so Snoopy was favoured.
       
  2326 		if(floatval($wp_version) < 2.7) {
       
  2327 			if(!file_exists(ABSPATH . 'wp-includes/class-snoopy.php')) {
       
  2328 				trigger_error('Snoopy Web Request failed: Snoopy not found.',E_USER_NOTICE);
       
  2329 				return false; //Hoah?
       
  2330 			}
       
  2331 			
       
  2332 			require_once( ABSPATH . 'wp-includes/class-snoopy.php');
       
  2333 			
       
  2334 			$s = new Snoopy();
       
  2335 			
       
  2336 			$s->read_timeout = $timeout;
       
  2337 			
       
  2338 			if($method == 'get') {
       
  2339 				$s->fetch($url);
       
  2340 			} else {
       
  2341 				$s->submit($url,$postData);
       
  2342 			}
       
  2343 			
       
  2344 			if($s->status != "200") {
       
  2345 				trigger_error('Snoopy Web Request failed: Status: ' . $s->status . "; Content: " . htmlspecialchars($s->results),E_USER_NOTICE);
       
  2346 			}
       
  2347 			
       
  2348 			return $s->results;
       
  2349 	
       
  2350 		} else {
       
  2351 			
       
  2352 			$options = array();
       
  2353 			$options['timeout'] = $timeout;
       
  2354 			
       
  2355 			if($method == 'get') {
       
  2356 				$response = wp_remote_get( $url, $options );
       
  2357 			} else {
       
  2358 				$response = wp_remote_post($url, array_merge($options,array('body'=>$postData)));
       
  2359 			}
       
  2360 			
       
  2361 			if ( is_wp_error( $response ) ) {
       
  2362 				$errs = $response->get_error_messages();
       
  2363 				$errs = htmlspecialchars(implode('; ', $errs));
       
  2364 				trigger_error('WP HTTP API Web Request failed: ' . $errs,E_USER_NOTICE);
       
  2365 				return false;
       
  2366 			}
       
  2367 		
       
  2368 			return $response['body'];
       
  2369 		}
       
  2370 		
       
  2371 		return false;
       
  2372 	}
       
  2373 	
       
  2374 	/**
       
  2375 	 * Echos option fields for an select field containing the valid change frequencies
       
  2376 	 *
       
  2377 	 * @since 3.0
       
  2378 	 * @access private
       
  2379 	 * @author Arne Brachhold
       
  2380 	 * @param $currentVal The value which should be selected
       
  2381 	 * @return all valid change frequencies as html option fields
       
  2382 	 */
       
  2383 	function HtmlGetFreqNames($currentVal) {
       
  2384 				
       
  2385 		foreach($this->_freqNames AS $k=>$v) {
       
  2386 			echo "<option value=\"$k\" " . $this->HtmlGetSelected($k,$currentVal) .">" . $v . "</option>";
       
  2387 		}
       
  2388 	}
       
  2389 	
       
  2390 	/**
       
  2391 	 * Echos option fields for an select field containing the valid priorities (0- 1.0)
       
  2392 	 *
       
  2393 	 * @since 3.0
       
  2394 	 * @access private
       
  2395 	 * @author Arne Brachhold
       
  2396 	 * @param $currentVal string The value which should be selected
       
  2397 	 * @return 0.0 - 1.0 as html option fields
       
  2398 	 */
       
  2399 	function HtmlGetPriorityValues($currentVal) {
       
  2400 		$currentVal=(float) $currentVal;
       
  2401 		for($i=0.0; $i<=1.0; $i+=0.1) {
       
  2402 			$v = number_format($i,1,".","");
       
  2403 			//number_format_i18n is there since WP 2.3
       
  2404 			$t = function_exists('number_format_i18n')?number_format_i18n($i,1):number_format($i,1);
       
  2405 			echo "<option value=\"" . $v . "\" " . $this->HtmlGetSelected("$i","$currentVal") .">";
       
  2406 			echo $t;
       
  2407 			echo "</option>";
       
  2408 		}
       
  2409 	}
       
  2410 	
       
  2411 	/**
       
  2412 	 * Returns the checked attribute if the given values match
       
  2413 	 *
       
  2414 	 * @since 3.0
       
  2415 	 * @access private
       
  2416 	 * @author Arne Brachhold
       
  2417 	 * @param $val string The current value
       
  2418 	 * @param $equals string The value to match
       
  2419 	 * @return The checked attribute if the given values match, an empty string if not
       
  2420 	 */
       
  2421 	function HtmlGetChecked($val,$equals) {
       
  2422 		if($val==$equals) return $this->HtmlGetAttribute("checked");
       
  2423 		else return "";
       
  2424 	}
       
  2425 	
       
  2426 	/**
       
  2427 	 * Returns the selected attribute if the given values match
       
  2428 	 *
       
  2429 	 * @since 3.0
       
  2430 	 * @access private
       
  2431 	 * @author Arne Brachhold
       
  2432 	 * @param $val string The current value
       
  2433 	 * @param $equals string The value to match
       
  2434 	 * @return The selected attribute if the given values match, an empty string if not
       
  2435 	 */
       
  2436 	function HtmlGetSelected($val,$equals) {
       
  2437 		if($val==$equals) return $this->HtmlGetAttribute("selected");
       
  2438 		else return "";
       
  2439 	}
       
  2440 	
       
  2441 	/**
       
  2442 	 * Returns an formatted attribute. If the value is NULL, the name will be used.
       
  2443 	 *
       
  2444 	 * @since 3.0
       
  2445 	 * @access private
       
  2446 	 * @author Arne Brachhold
       
  2447 	 * @param $attr string The attribute name
       
  2448 	 * @param $value string The attribute value
       
  2449 	 * @return The formatted attribute
       
  2450 	 */
       
  2451 	function HtmlGetAttribute($attr,$value=NULL) {
       
  2452 		if($value==NULL) $value=$attr;
       
  2453 		return " " . $attr . "=\"" . $value . "\" ";
       
  2454 	}
       
  2455 	
       
  2456 	/**
       
  2457 	 * Returns an array with GoogleSitemapGeneratorPage objects which is generated from POST values
       
  2458 	 *
       
  2459 	 * @since 3.0
       
  2460 	 * @see GoogleSitemapGeneratorPage
       
  2461 	 * @access private
       
  2462 	 * @author Arne Brachhold
       
  2463 	 * @return array An array with GoogleSitemapGeneratorPage objects
       
  2464 	 */
       
  2465 	function HtmlApplyPages() {
       
  2466 		// Array with all page URLs
       
  2467 		$pages_ur=(!isset($_POST["sm_pages_ur"]) || !is_array($_POST["sm_pages_ur"])?array():$_POST["sm_pages_ur"]);
       
  2468 		
       
  2469 		//Array with all priorities
       
  2470 		$pages_pr=(!isset($_POST["sm_pages_pr"]) || !is_array($_POST["sm_pages_pr"])?array():$_POST["sm_pages_pr"]);
       
  2471 		
       
  2472 		//Array with all change frequencies
       
  2473 		$pages_cf=(!isset($_POST["sm_pages_cf"]) || !is_array($_POST["sm_pages_cf"])?array():$_POST["sm_pages_cf"]);
       
  2474 		
       
  2475 		//Array with all lastmods
       
  2476 		$pages_lm=(!isset($_POST["sm_pages_lm"]) || !is_array($_POST["sm_pages_lm"])?array():$_POST["sm_pages_lm"]);
       
  2477 
       
  2478 		//Array where the new pages are stored
       
  2479 		$pages=array();
       
  2480 		//Loop through all defined pages and set their properties into an object
       
  2481 		if(isset($_POST["sm_pages_mark"]) && is_array($_POST["sm_pages_mark"])) {
       
  2482 			for($i=0; $i<count($_POST["sm_pages_mark"]); $i++) {
       
  2483 				//Create new object
       
  2484 				$p=new GoogleSitemapGeneratorPage();
       
  2485 				if(substr($pages_ur[$i],0,4)=="www.") $pages_ur[$i]="http://" . $pages_ur[$i];
       
  2486 				$p->SetUrl($pages_ur[$i]);
       
  2487 				$p->SetProprity($pages_pr[$i]);
       
  2488 				$p->SetChangeFreq($pages_cf[$i]);
       
  2489 				//Try to parse last modified, if -1 (note ===) automatic will be used (0)
       
  2490 				$lm=(!empty($pages_lm[$i])?strtotime($pages_lm[$i],time()):-1);
       
  2491 				if($lm===-1) $p->setLastMod(0);
       
  2492 				else $p->setLastMod($lm);
       
  2493 				//Add it to the array
       
  2494 				array_push($pages,$p);
       
  2495 			}
       
  2496 		}
       
  2497 
       
  2498 		return $pages;
       
  2499 	}
       
  2500 	
       
  2501 	/**
       
  2502 	 * Converts a mysql datetime value into a unix timestamp
       
  2503 	 * 
       
  2504 	 * @param The value in the mysql datetime format
       
  2505 	 * @return int The time in seconds
       
  2506 	 */
       
  2507 	function GetTimestampFromMySql($mysqlDateTime) {
       
  2508 		list($date, $hours) = split(' ', $mysqlDateTime);
       
  2509 		list($year,$month,$day) = split('-',$date);
       
  2510 		list($hour,$min,$sec) = split(':',$hours);
       
  2511 		return mktime(intval($hour), intval($min), intval($sec), intval($month), intval($day), intval($year));
       
  2512 	}
       
  2513 	
       
  2514 	/**
       
  2515 	 * Returns a link pointing to a spcific page of the authors website
       
  2516 	 * 
       
  2517 	 * @since 3.0
       
  2518 	 * @param The page to link to
       
  2519 	 * @return string The full url
       
  2520 	 */
       
  2521 	function GetRedirectLink($redir) {
       
  2522 		return trailingslashit("http://www.arnebrachhold.de/redir/" . $redir);
       
  2523 	}
       
  2524 	
       
  2525 	/**
       
  2526 	 * Returns a link pointing back to the plugin page in WordPress
       
  2527 	 * 
       
  2528 	 * @since 3.0
       
  2529 	 * @return string The full url
       
  2530 	 */
       
  2531 	function GetBackLink() {
       
  2532 		//admin_url was added in WP 2.6.0
       
  2533 		if(function_exists("admin_url")) return admin_url("options-general.php?page=" .  GoogleSitemapGeneratorLoader::GetBaseName());
       
  2534 		else return $_SERVER['PHP_SELF'] . "?page=" .  GoogleSitemapGeneratorLoader::GetBaseName();
       
  2535 	}
       
  2536 	
       
  2537 	/**
       
  2538 	 * Shows the option page of the plugin. Before 3.1.1, this function was basically the UI, afterwards the UI was outsourced to another class
       
  2539 	 * 
       
  2540 	 * @see GoogleSitemapGeneratorUI
       
  2541 	 * @since 3.0
       
  2542 	 * @return bool
       
  2543 	 */
       
  2544 	function HtmlShowOptionsPage() {
       
  2545 		
       
  2546 		$ui = $this->GetUI();
       
  2547 		if($ui) {
       
  2548 			$ui->HtmlShowOptionsPage();
       
  2549 			return true;
       
  2550 		}
       
  2551 		
       
  2552 		return false;
       
  2553 	}
       
  2554 	
       
  2555 	/**
       
  2556 	 * Includes the user interface class and intializes it
       
  2557 	 * 
       
  2558 	 * @since 3.1.1
       
  2559 	 * @see GoogleSitemapGeneratorUI
       
  2560 	 * @return GoogleSitemapGeneratorUI
       
  2561 	 */
       
  2562 	function GetUI() {
       
  2563 
       
  2564 		global $wp_version;
       
  2565 		
       
  2566 		if($this->_ui === null) {
       
  2567 			
       
  2568 			$className='GoogleSitemapGeneratorUI';
       
  2569 			$fileName='sitemap-ui.php';
       
  2570 
       
  2571 			if(!class_exists($className)) {
       
  2572 				
       
  2573 				$path = trailingslashit(dirname(__FILE__));
       
  2574 				
       
  2575 				if(!file_exists( $path . $fileName)) return false;
       
  2576 				require_once($path. $fileName);
       
  2577 			}
       
  2578 	
       
  2579 			$this->_ui = new $className($this);
       
  2580 			
       
  2581 		}
       
  2582 		
       
  2583 		return $this->_ui;
       
  2584 	}
       
  2585 	
       
  2586 	function HtmlShowHelp() {
       
  2587 		
       
  2588 		
       
  2589 	}
       
  2590 }