source: trunk/www.guidonia.net/wp/wp-content/plugins/google-sitemap-generator/sitemap-core.php@ 44

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