PageRenderTime 51ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/google-sitemap-generator/sitemap-core.php

https://github.com/sharpmachine/wakeupmedia.com
PHP | 1691 lines | 1018 code | 191 blank | 482 comment | 133 complexity | 8e0cf3a57d8ec91541477e5499456f3b MD5 | raw file
  1. <?php
  2. /*
  3. $Id: sitemap-core.php 583237 2012-08-08 21:06:12Z arnee $
  4. */
  5. //Enable for dev! Good code doesn't generate any notices...
  6. //error_reporting(E_ALL);
  7. //ini_set("display_errors",1);
  8. /**
  9. * Represents the status (success and failures) of a building process
  10. * @author Arne Brachhold
  11. * @package sitemap
  12. * @since 3.0b5
  13. */
  14. class GoogleSitemapGeneratorStatus {
  15. function GoogleSitemapGeneratorStatus() {
  16. $this->_startTime = $this->GetMicrotimeFloat();
  17. $exists = get_option("sm_status");
  18. if($exists === false) add_option("sm_status","",null,"no");
  19. $this->Save();
  20. }
  21. function Save() {
  22. update_option("sm_status",$this);
  23. }
  24. /**
  25. * Returns the last saved status object or null
  26. *
  27. * @return GoogleSitemapGeneratorStatus
  28. */
  29. function &Load() {
  30. $status = @get_option("sm_status");
  31. if(is_a($status,"GoogleSitemapGeneratorStatus")) return $status;
  32. else return null;
  33. }
  34. /**
  35. * @var float $_startTime The start time of the building process
  36. * @access private
  37. */
  38. var $_startTime = 0;
  39. /**
  40. * @var float $_endTime The end time of the building process
  41. * @access private
  42. */
  43. var $_endTime = 0;
  44. /**
  45. * @var bool $$_hasChanged Indicates if the sitemap content has changed
  46. * @access private
  47. */
  48. var $_hasChanged = true;
  49. /**
  50. * @var int $_memoryUsage The amount of memory used in bytes
  51. * @access private
  52. */
  53. var $_memoryUsage = 0;
  54. /**
  55. * @var int $_lastPost The number of posts processed. This value is updated every 50 posts.
  56. * @access private
  57. */
  58. var $_lastPost = 0;
  59. /**
  60. * @var int $_lastTime The time when the last step-update occured. This value is updated every 50 posts.
  61. * @access private
  62. */
  63. var $_lastTime = 0;
  64. function End($hasChanged = true) {
  65. $this->_endTime = $this->GetMicrotimeFloat();
  66. $this->SetMemoryUsage();
  67. $this->_hasChanged = $hasChanged;
  68. $this->Save();
  69. }
  70. function SetMemoryUsage() {
  71. if(function_exists("memory_get_peak_usage")) {
  72. $this->_memoryUsage = memory_get_peak_usage(true);
  73. } else if(function_exists("memory_get_usage")) {
  74. $this->_memoryUsage = memory_get_usage(true);
  75. }
  76. }
  77. function GetMemoryUsage() {
  78. return round($this->_memoryUsage / 1024 / 1024,2);
  79. }
  80. function SaveStep($postCount) {
  81. $this->SetMemoryUsage();
  82. $this->_lastPost = $postCount;
  83. $this->_lastTime = $this->GetMicrotimeFloat();
  84. $this->Save();
  85. }
  86. function GetTime() {
  87. return round($this->_endTime - $this->_startTime,2);
  88. }
  89. function GetStartTime() {
  90. return round($this->_startTime, 2);
  91. }
  92. function GetLastTime() {
  93. return round($this->_lastTime - $this->_startTime,2);
  94. }
  95. function GetLastPost() {
  96. return $this->_lastPost;
  97. }
  98. var $_usedXml = false;
  99. var $_xmlSuccess = false;
  100. var $_xmlPath = '';
  101. var $_xmlUrl = '';
  102. function StartXml($path,$url) {
  103. $this->_usedXml = true;
  104. $this->_xmlPath = $path;
  105. $this->_xmlUrl = $url;
  106. $this->Save();
  107. }
  108. function EndXml($success) {
  109. $this->_xmlSuccess = $success;
  110. $this->Save();
  111. }
  112. var $_usedZip = false;
  113. var $_zipSuccess = false;
  114. var $_zipPath = '';
  115. var $_zipUrl = '';
  116. function StartZip($path,$url) {
  117. $this->_usedZip = true;
  118. $this->_zipPath = $path;
  119. $this->_zipUrl = $url;
  120. $this->Save();
  121. }
  122. function EndZip($success) {
  123. $this->_zipSuccess = $success;
  124. $this->Save();
  125. }
  126. var $_usedGoogle = false;
  127. var $_googleUrl = '';
  128. var $_gooogleSuccess = false;
  129. var $_googleStartTime = 0;
  130. var $_googleEndTime = 0;
  131. function StartGooglePing($url) {
  132. $this->_googleUrl = $url;
  133. $this->_usedGoogle = true;
  134. $this->_googleStartTime = $this->GetMicrotimeFloat();
  135. $this->Save();
  136. }
  137. function EndGooglePing($success) {
  138. $this->_googleEndTime = $this->GetMicrotimeFloat();
  139. $this->_gooogleSuccess = $success;
  140. $this->Save();
  141. }
  142. function GetGoogleTime() {
  143. return round($this->_googleEndTime - $this->_googleStartTime,2);
  144. }
  145. var $_usedMsn = false;
  146. var $_msnUrl = '';
  147. var $_msnSuccess = false;
  148. var $_msnStartTime = 0;
  149. var $_msnEndTime = 0;
  150. function StartMsnPing($url) {
  151. $this->_usedMsn = true;
  152. $this->_msnUrl = $url;
  153. $this->_msnStartTime = $this->GetMicrotimeFloat();
  154. $this->Save();
  155. }
  156. function EndMsnPing($success) {
  157. $this->_msnEndTime = $this->GetMicrotimeFloat();
  158. $this->_msnSuccess = $success;
  159. $this->Save();
  160. }
  161. function GetMsnTime() {
  162. return round($this->_msnEndTime - $this->_msnStartTime,2);
  163. }
  164. function GetMicrotimeFloat() {
  165. list($usec, $sec) = explode(" ", microtime());
  166. return ((float)$usec + (float)$sec);
  167. }
  168. }
  169. /**
  170. * Represents an item in the page list
  171. * @author Arne Brachhold
  172. * @package sitemap
  173. * @since 3.0
  174. */
  175. class GoogleSitemapGeneratorPage {
  176. /**
  177. * @var string $_url Sets the URL or the relative path to the blog dir of the page
  178. * @access private
  179. */
  180. var $_url;
  181. /**
  182. * @var float $_priority Sets the priority of this page
  183. * @access private
  184. */
  185. var $_priority;
  186. /**
  187. * @var string $_changeFreq Sets the chanfe frequency of the page. I want Enums!
  188. * @access private
  189. */
  190. var $_changeFreq;
  191. /**
  192. * @var int $_lastMod Sets the lastMod date as a UNIX timestamp.
  193. * @access private
  194. */
  195. var $_lastMod;
  196. /**
  197. * Initialize a new page object
  198. *
  199. * @since 3.0
  200. * @access public
  201. * @author Arne Brachhold
  202. * @param bool $enabled Should this page be included in thesitemap
  203. * @param string $url The URL or path of the file
  204. * @param float $priority The Priority of the page 0.0 to 1.0
  205. * @param string $changeFreq The change frequency like daily, hourly, weekly
  206. * @param int $lastMod The last mod date as a unix timestamp
  207. */
  208. function GoogleSitemapGeneratorPage($url="",$priority=0.0,$changeFreq="never",$lastMod=0) {
  209. $this->SetUrl($url);
  210. $this->SetProprity($priority);
  211. $this->SetChangeFreq($changeFreq);
  212. $this->SetLastMod($lastMod);
  213. }
  214. /**
  215. * Returns the URL of the page
  216. *
  217. * @return string The URL
  218. */
  219. function GetUrl() {
  220. return $this->_url;
  221. }
  222. /**
  223. * Sets the URL of the page
  224. *
  225. * @param string $url The new URL
  226. */
  227. function SetUrl($url) {
  228. $this->_url=(string) $url;
  229. }
  230. /**
  231. * Returns the priority of this page
  232. *
  233. * @return float the priority, from 0.0 to 1.0
  234. */
  235. function GetPriority() {
  236. return $this->_priority;
  237. }
  238. /**
  239. * Sets the priority of the page
  240. *
  241. * @param float $priority The new priority from 0.1 to 1.0
  242. */
  243. function SetProprity($priority) {
  244. $this->_priority=floatval($priority);
  245. }
  246. /**
  247. * Returns the change frequency of the page
  248. *
  249. * @return string The change frequncy like hourly, weekly, monthly etc.
  250. */
  251. function GetChangeFreq() {
  252. return $this->_changeFreq;
  253. }
  254. /**
  255. * Sets the change frequency of the page
  256. *
  257. * @param string $changeFreq The new change frequency
  258. */
  259. function SetChangeFreq($changeFreq) {
  260. $this->_changeFreq=(string) $changeFreq;
  261. }
  262. /**
  263. * Returns the last mod of the page
  264. *
  265. * @return int The lastmod value in seconds
  266. */
  267. function GetLastMod() {
  268. return $this->_lastMod;
  269. }
  270. /**
  271. * Sets the last mod of the page
  272. *
  273. * @param int $lastMod The lastmod of the page
  274. */
  275. function SetLastMod($lastMod) {
  276. $this->_lastMod=intval($lastMod);
  277. }
  278. function Render() {
  279. if($this->_url == "/" || empty($this->_url)) return '';
  280. $r="";
  281. $r.= "\t<url>\n";
  282. $r.= "\t\t<loc>" . $this->EscapeXML($this->_url) . "</loc>\n";
  283. if($this->_lastMod>0) $r.= "\t\t<lastmod>" . date('Y-m-d\TH:i:s+00:00',$this->_lastMod) . "</lastmod>\n";
  284. if(!empty($this->_changeFreq)) $r.= "\t\t<changefreq>" . $this->_changeFreq . "</changefreq>\n";
  285. if($this->_priority!==false && $this->_priority!=="") $r.= "\t\t<priority>" . number_format($this->_priority,1) . "</priority>\n";
  286. $r.= "\t</url>\n";
  287. return $r;
  288. }
  289. function EscapeXML($string) {
  290. return str_replace ( array ( '&', '"', "'", '<', '>'), array ( '&amp;' , '&quot;', '&apos;' , '&lt;' , '&gt;'), $string);
  291. }
  292. }
  293. class GoogleSitemapGeneratorXmlEntry {
  294. var $_xml;
  295. function GoogleSitemapGeneratorXmlEntry($xml) {
  296. $this->_xml = $xml;
  297. }
  298. function Render() {
  299. return $this->_xml;
  300. }
  301. }
  302. class GoogleSitemapGeneratorDebugEntry extends GoogleSitemapGeneratorXmlEntry {
  303. function Render() {
  304. return "<!-- " . $this->_xml . " -->\n";
  305. }
  306. }
  307. /**
  308. * Base class for all priority providers
  309. * @author Arne Brachhold
  310. * @package sitemap
  311. * @since 3.0
  312. */
  313. class GoogleSitemapGeneratorPrioProviderBase {
  314. /**
  315. * @var int $_totalComments The total number of comments of all posts
  316. * @access protected
  317. */
  318. var $_totalComments=0;
  319. /**
  320. * @var int $_totalComments The total number of posts
  321. * @access protected
  322. */
  323. var $_totalPosts=0;
  324. /**
  325. * Returns the (translated) name of this priority provider
  326. *
  327. * @since 3.0
  328. * @access public
  329. * @author Arne Brachhold
  330. * @return string The translated name
  331. */
  332. function GetName() {
  333. return "";
  334. }
  335. /**
  336. * Returns the (translated) description of this priority provider
  337. *
  338. * @since 3.0
  339. * @access public
  340. * @author Arne Brachhold
  341. * @return string The translated description
  342. */
  343. function GetDescription() {
  344. return "";
  345. }
  346. /**
  347. * Initializes a new priority provider
  348. *
  349. * @param $totalComments int The total number of comments of all posts
  350. * @param $totalPosts int The total number of posts
  351. * @since 3.0
  352. * @access public
  353. * @author Arne Brachhold
  354. */
  355. function GoogleSitemapGeneratorPrioProviderBase($totalComments,$totalPosts) {
  356. $this->_totalComments=$totalComments;
  357. $this->_totalPosts=$totalPosts;
  358. }
  359. /**
  360. * Returns the priority for a specified post
  361. *
  362. * @param $postID int The ID of the post
  363. * @param $commentCount int The number of comments for this post
  364. * @since 3.0
  365. * @access public
  366. * @author Arne Brachhold
  367. * @return int The calculated priority
  368. */
  369. function GetPostPriority($postID,$commentCount) {
  370. return 0;
  371. }
  372. }
  373. /**
  374. * Priority Provider which calculates the priority based on the number of comments
  375. * @author Arne Brachhold
  376. * @package sitemap
  377. * @since 3.0
  378. */
  379. class GoogleSitemapGeneratorPrioByCountProvider extends GoogleSitemapGeneratorPrioProviderBase {
  380. /**
  381. * Returns the (translated) name of this priority provider
  382. *
  383. * @since 3.0
  384. * @access public
  385. * @author Arne Brachhold
  386. * @return string The translated name
  387. */
  388. function GetName() {
  389. return __("Comment Count",'sitemap');
  390. }
  391. /**
  392. * Returns the (translated) description of this priority provider
  393. *
  394. * @since 3.0
  395. * @access public
  396. * @author Arne Brachhold
  397. * @return string The translated description
  398. */
  399. function GetDescription() {
  400. return __("Uses the number of comments of the post to calculate the priority",'sitemap');
  401. }
  402. /**
  403. * Initializes a new priority provider which calculates the post priority based on the number of comments
  404. *
  405. * @param $totalComments int The total number of comments of all posts
  406. * @param $totalPosts int The total number of posts
  407. * @since 3.0
  408. * @access public
  409. * @author Arne Brachhold
  410. */
  411. function GoogleSitemapGeneratorPrioByCountProvider($totalComments,$totalPosts) {
  412. parent::GoogleSitemapGeneratorPrioProviderBase($totalComments,$totalPosts);
  413. }
  414. /**
  415. * Returns the priority for a specified post
  416. *
  417. * @param $postID int The ID of the post
  418. * @param $commentCount int The number of comments for this post
  419. * @since 3.0
  420. * @access public
  421. * @author Arne Brachhold
  422. * @return int The calculated priority
  423. */
  424. function GetPostPriority($postID,$commentCount) {
  425. $prio=0;
  426. if($this->_totalComments>0 && $commentCount>0) {
  427. $prio = round(($commentCount*100/$this->_totalComments)/100,1);
  428. } else {
  429. $prio = 0;
  430. }
  431. return $prio;
  432. }
  433. }
  434. /**
  435. * Priority Provider which calculates the priority based on the average number of comments
  436. * @author Arne Brachhold
  437. * @package sitemap
  438. * @since 3.0
  439. */
  440. class GoogleSitemapGeneratorPrioByAverageProvider extends GoogleSitemapGeneratorPrioProviderBase {
  441. /**
  442. * @var int $_average The average number of comments per post
  443. * @access protected
  444. */
  445. var $_average=0.0;
  446. /**
  447. * Returns the (translated) name of this priority provider
  448. *
  449. * @since 3.0
  450. * @access public
  451. * @author Arne Brachhold
  452. * @return string The translated name
  453. */
  454. function GetName() {
  455. return __("Comment Average",'sitemap');
  456. }
  457. /**
  458. * Returns the (translated) description of this priority provider
  459. *
  460. * @since 3.0
  461. * @access public
  462. * @author Arne Brachhold
  463. * @return string The translated description
  464. */
  465. function GetDescription() {
  466. return __("Uses the average comment count to calculate the priority",'sitemap');
  467. }
  468. /**
  469. * Initializes a new priority provider which calculates the post priority based on the average number of comments
  470. *
  471. * @param $totalComments int The total number of comments of all posts
  472. * @param $totalPosts int The total number of posts
  473. * @since 3.0
  474. * @access public
  475. * @author Arne Brachhold
  476. */
  477. function GoogleSitemapGeneratorPrioByAverageProvider($totalComments,$totalPosts) {
  478. parent::GoogleSitemapGeneratorPrioProviderBase($totalComments,$totalPosts);
  479. if($this->_totalComments>0 && $this->_totalPosts>0) {
  480. $this->_average= (double) $this->_totalComments / $this->_totalPosts;
  481. }
  482. }
  483. /**
  484. * Returns the priority for a specified post
  485. *
  486. * @param $postID int The ID of the post
  487. * @param $commentCount int The number of comments for this post
  488. * @since 3.0
  489. * @access public
  490. * @author Arne Brachhold
  491. * @return int The calculated priority
  492. */
  493. function GetPostPriority($postID,$commentCount) {
  494. $prio = 0;
  495. //Do not divide by zero!
  496. if($this->_average==0) {
  497. if($commentCount>0) $prio = 1;
  498. else $prio = 0;
  499. } else {
  500. $prio = $commentCount/$this->_average;
  501. if($prio>1) $prio = 1;
  502. else if($prio<0) $prio = 0;
  503. }
  504. return round($prio,1);
  505. }
  506. }
  507. /**
  508. * Priority Provider which calculates the priority based on the popularity by the PopularityContest Plugin
  509. * @author Arne Brachhold
  510. * @package sitemap
  511. * @since 3.0
  512. */
  513. class GoogleSitemapGeneratorPrioByPopularityContestProvider extends GoogleSitemapGeneratorPrioProviderBase {
  514. /**
  515. * Returns the (translated) name of this priority provider
  516. *
  517. * @since 3.0
  518. * @access public
  519. * @author Arne Brachhold
  520. * @return string The translated name
  521. */
  522. function GetName() {
  523. return __("Popularity Contest",'sitemap');
  524. }
  525. /**
  526. * Returns the (translated) description of this priority provider
  527. *
  528. * @since 3.0
  529. * @access public
  530. * @author Arne Brachhold
  531. * @return string The translated description
  532. */
  533. function GetDescription() {
  534. 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')))));
  535. }
  536. /**
  537. * Initializes a new priority provider which calculates the post priority based on the popularity by the PopularityContest Plugin
  538. *
  539. * @param $totalComments int The total number of comments of all posts
  540. * @param $totalPosts int The total number of posts
  541. * @since 3.0
  542. * @access public
  543. * @author Arne Brachhold
  544. */
  545. function GoogleSitemapGeneratorPrioByPopularityContestProvider($totalComments,$totalPosts) {
  546. parent::GoogleSitemapGeneratorPrioProviderBase($totalComments,$totalPosts);
  547. }
  548. /**
  549. * Returns the priority for a specified post
  550. *
  551. * @param $postID int The ID of the post
  552. * @param $commentCount int The number of comments for this post
  553. * @since 3.0
  554. * @access public
  555. * @author Arne Brachhold
  556. * @return int The calculated priority
  557. */
  558. function GetPostPriority($postID,$commentCount) {
  559. //$akpc is the global instance of the Popularity Contest Plugin
  560. global $akpc,$posts;
  561. $res=0;
  562. //Better check if its there
  563. if(!empty($akpc) && is_object($akpc)) {
  564. //Is the method we rely on available?
  565. if(method_exists($akpc,"get_post_rank")) {
  566. if(!is_array($posts) || !$posts) $posts = array();
  567. if(!isset($posts[$postID])) $posts[$postID] = get_post($postID);
  568. //popresult comes as a percent value
  569. $popresult=$akpc->get_post_rank($postID);
  570. if(!empty($popresult) && strpos($popresult,"%")!==false) {
  571. //We need to parse it to get the priority as an int (percent)
  572. $matches=null;
  573. preg_match("/([0-9]{1,3})\%/si",$popresult,$matches);
  574. if(!empty($matches) && is_array($matches) && count($matches)==2) {
  575. //Divide it so 100% = 1, 10% = 0.1
  576. $res=round(intval($matches[1])/100,1);
  577. }
  578. }
  579. }
  580. }
  581. return $res;
  582. }
  583. }
  584. /**
  585. * Class to generate a sitemaps.org Sitemaps compliant sitemap of a WordPress blog.
  586. *
  587. * @package sitemap
  588. * @author Arne Brachhold
  589. * @since 3.0
  590. */
  591. class GoogleSitemapGenerator {
  592. /**
  593. * @var Version of the generator in SVN
  594. */
  595. var $_svnVersion = '$Id: sitemap-core.php 583237 2012-08-08 21:06:12Z arnee $';
  596. /**
  597. * @var array The unserialized array with the stored options
  598. */
  599. var $_options = array();
  600. /**
  601. * @var array The saved additional pages
  602. */
  603. var $_pages = array();
  604. /**
  605. * @var array The values and names of the change frequencies
  606. */
  607. var $_freqNames = array();
  608. /**
  609. * @var array A list of class names which my be called for priority calculation
  610. */
  611. var $_prioProviders = array();
  612. /**
  613. * @var bool True if init complete (options loaded etc)
  614. */
  615. var $_initiated = false;
  616. /**
  617. * @var string Holds the last error if one occurs when writing the files
  618. */
  619. var $_lastError=null;
  620. /**
  621. * @var int The last handled post ID
  622. */
  623. var $_lastPostID = 0;
  624. /**
  625. * @var bool Defines if the sitemap building process is active at the moment
  626. */
  627. var $_isActive = false;
  628. /**
  629. * @var bool Defines if the sitemap building process has been scheduled via Wp cron
  630. */
  631. var $_isScheduled = false;
  632. /**
  633. * @var object The file handle which is used to write the sitemap file
  634. */
  635. var $_fileHandle = null;
  636. /**
  637. * @var object The file handle which is used to write the zipped sitemap file
  638. */
  639. var $_fileZipHandle = null;
  640. /**
  641. * Holds the user interface object
  642. *
  643. * @since 3.1.1
  644. * @var GoogleSitemapGeneratorUI
  645. */
  646. var $_ui = null;
  647. /**
  648. * Returns the path to the blog directory
  649. *
  650. * @since 3.0
  651. * @access private
  652. * @author Arne Brachhold
  653. * @return string The full path to the blog directory
  654. */
  655. function GetHomePath() {
  656. $res="";
  657. //Check if we are in the admin area -> get_home_path() is avaiable
  658. if(function_exists("get_home_path")) {
  659. $res = get_home_path();
  660. } else {
  661. //get_home_path() is not available, but we can't include the admin
  662. //libraries because many plugins check for the "check_admin_referer"
  663. //function to detect if you are on an admin page. So we have to copy
  664. //the get_home_path function in our own...
  665. $home = get_option( 'home' );
  666. if ( $home != '' && $home != get_option( 'url' ) ) {
  667. $home_path = parse_url( $home );
  668. $home_path = $home_path['path'];
  669. $root = str_replace( $_SERVER["PHP_SELF"], '', $_SERVER["SCRIPT_FILENAME"] );
  670. $home_path = trailingslashit( $root.$home_path );
  671. } else {
  672. $home_path = ABSPATH;
  673. }
  674. $res = $home_path;
  675. }
  676. return $res;
  677. }
  678. /**
  679. * Returns the path to the directory where the plugin file is located
  680. * @since 3.0b5
  681. * @access private
  682. * @author Arne Brachhold
  683. * @return string The path to the plugin directory
  684. */
  685. function GetPluginPath() {
  686. $path = dirname(__FILE__);
  687. return trailingslashit(str_replace("\\","/",$path));
  688. }
  689. /**
  690. * Returns the URL to the directory where the plugin file is located
  691. * @since 3.0b5
  692. * @access private
  693. * @author Arne Brachhold
  694. * @return string The URL to the plugin directory
  695. */
  696. function GetPluginUrl() {
  697. //Try to use WP API if possible, introduced in WP 2.6
  698. if (function_exists('plugins_url')) return trailingslashit(plugins_url(basename(dirname(__FILE__))));
  699. //Try to find manually... can't work if wp-content was renamed or is redirected
  700. $path = dirname(__FILE__);
  701. $path = str_replace("\\","/",$path);
  702. $path = trailingslashit(get_bloginfo('wpurl')) . trailingslashit(substr($path,strpos($path,"wp-content/")));
  703. return $path;
  704. }
  705. /**
  706. * Returns the URL to default XSLT style if it exists
  707. * @since 3.0b5
  708. * @access private
  709. * @author Arne Brachhold
  710. * @return string The URL to the default stylesheet, empty string if not available.
  711. */
  712. function GetDefaultStyle() {
  713. $p = $this->GetPluginPath();
  714. if(file_exists($p . "sitemap.xsl")) {
  715. $url = $this->GetPluginUrl();
  716. //If called over the admin area using HTTPS, the stylesheet would also be https url, even if the blog frontend is not.
  717. if(substr(get_bloginfo('url'),0,5) !="https" && substr($url,0,5)=="https") $url="http" . substr($url,5);
  718. return $url . 'sitemap.xsl';
  719. }
  720. return '';
  721. }
  722. /**
  723. * Sets up the default configuration
  724. *
  725. * @since 3.0
  726. * @access private
  727. * @author Arne Brachhold
  728. */
  729. function InitOptions() {
  730. $this->_options=array();
  731. $this->_options["sm_b_prio_provider"]="GoogleSitemapGeneratorPrioByCountProvider"; //Provider for automatic priority calculation
  732. $this->_options["sm_b_filename"]="sitemap.xml"; //Name of the Sitemap file
  733. $this->_options["sm_b_debug"]=true; //Write debug messages in the xml file
  734. $this->_options["sm_b_xml"]=true; //Create a .xml file
  735. $this->_options["sm_b_gzip"]=true; //Create a gzipped .xml file(.gz) file
  736. $this->_options["sm_b_ping"]=true; //Auto ping Google
  737. $this->_options["sm_b_pingmsn"]=true; //Auto ping MSN
  738. $this->_options["sm_b_manual_enabled"]=false; //Allow manual creation of the sitemap via GET request
  739. $this->_options["sm_b_auto_enabled"]=true; //Rebuild sitemap when content is changed
  740. $this->_options["sm_b_auto_delay"]=true; //Use WP Cron to execute the building process in the background
  741. $this->_options["sm_b_manual_key"]=md5(microtime());//The secret key to build the sitemap via GET request
  742. $this->_options["sm_b_memory"] = ''; //Set Memory Limit (e.g. 16M)
  743. $this->_options["sm_b_time"] = -1; //Set time limit in seconds, 0 for unlimited, -1 for disabled
  744. $this->_options["sm_b_max_posts"] = -1; //Maximum number of posts, <= 0 for all
  745. $this->_options["sm_b_safemode"] = false; //Enable MySQL Safe Mode (doesn't use unbuffered results)
  746. $this->_options["sm_b_style_default"] = true; //Use default style
  747. $this->_options["sm_b_style"] = ''; //Include a stylesheet in the XML
  748. $this->_options["sm_b_robots"] = true; //Add sitemap location to WordPress' virtual robots.txt file
  749. $this->_options["sm_b_exclude"] = array(); //List of post / page IDs to exclude
  750. $this->_options["sm_b_exclude_cats"] = array(); //List of post / page IDs to exclude
  751. $this->_options["sm_b_location_mode"]="auto"; //Mode of location, auto or manual
  752. $this->_options["sm_b_filename_manual"]=""; //Manuel filename
  753. $this->_options["sm_b_fileurl_manual"]=""; //Manuel fileurl
  754. $this->_options["sm_in_home"]=true; //Include homepage
  755. $this->_options["sm_in_posts"]=true; //Include posts
  756. $this->_options["sm_in_posts_sub"]=false; //Include post pages (<!--nextpage--> tag)
  757. $this->_options["sm_in_pages"]=true; //Include static pages
  758. $this->_options["sm_in_cats"]=false; //Include categories
  759. $this->_options["sm_in_arch"]=false; //Include archives
  760. $this->_options["sm_in_auth"]=false; //Include author pages
  761. $this->_options["sm_in_tags"]=false; //Include tag pages
  762. $this->_options["sm_in_tax"]=array(); //Include additional taxonomies
  763. $this->_options["sm_in_customtypes"]=array(); //Include custom post types
  764. $this->_options["sm_in_lastmod"]=true; //Include the last modification date
  765. $this->_options["sm_cf_home"]="daily"; //Change frequency of the homepage
  766. $this->_options["sm_cf_posts"]="monthly"; //Change frequency of posts
  767. $this->_options["sm_cf_pages"]="weekly"; //Change frequency of static pages
  768. $this->_options["sm_cf_cats"]="weekly"; //Change frequency of categories
  769. $this->_options["sm_cf_auth"]="weekly"; //Change frequency of author pages
  770. $this->_options["sm_cf_arch_curr"]="daily"; //Change frequency of the current archive (this month)
  771. $this->_options["sm_cf_arch_old"]="yearly"; //Change frequency of older archives
  772. $this->_options["sm_cf_tags"]="weekly"; //Change frequency of tags
  773. $this->_options["sm_pr_home"]=1.0; //Priority of the homepage
  774. $this->_options["sm_pr_posts"]=0.6; //Priority of posts (if auto prio is disabled)
  775. $this->_options["sm_pr_posts_min"]=0.2; //Minimum Priority of posts, even if autocalc is enabled
  776. $this->_options["sm_pr_pages"]=0.6; //Priority of static pages
  777. $this->_options["sm_pr_cats"]=0.3; //Priority of categories
  778. $this->_options["sm_pr_arch"]=0.3; //Priority of archives
  779. $this->_options["sm_pr_auth"]=0.3; //Priority of author pages
  780. $this->_options["sm_pr_tags"]=0.3; //Priority of tags
  781. $this->_options["sm_i_donated"]=false; //Did you donate? Thank you! :)
  782. $this->_options["sm_i_hide_donated"]=false; //And hide the thank you..
  783. $this->_options["sm_i_install_date"]=time(); //The installation date
  784. $this->_options["sm_i_hide_note"]=false; //Hide the note which appears after 30 days
  785. $this->_options["sm_i_hide_works"]=false; //Hide the "works?" message which appears after 15 days
  786. $this->_options["sm_i_hide_donors"]=false; //Hide the list of donations
  787. }
  788. /**
  789. * Loads the configuration from the database
  790. *
  791. * @since 3.0
  792. * @access private
  793. * @author Arne Brachhold
  794. */
  795. function LoadOptions() {
  796. $this->InitOptions();
  797. //First init default values, then overwrite it with stored values so we can add default
  798. //values with an update which get stored by the next edit.
  799. $storedoptions=get_option("sm_options");
  800. if($storedoptions && is_array($storedoptions)) {
  801. foreach($storedoptions AS $k=>$v) {
  802. $this->_options[$k]=$v;
  803. }
  804. } else update_option("sm_options",$this->_options); //First time use, store default values
  805. }
  806. /**
  807. * Initializes a new Google Sitemap Generator
  808. *
  809. * @since 3.0
  810. * @access private
  811. * @author Arne Brachhold
  812. */
  813. function GoogleSitemapGenerator() {
  814. }
  815. /**
  816. * Returns the version of the generator
  817. *
  818. * @since 3.0
  819. * @access public
  820. * @author Arne Brachhold
  821. * @return int The version
  822. */
  823. function GetVersion() {
  824. return GoogleSitemapGeneratorLoader::GetVersion();
  825. }
  826. /**
  827. * Returns all parent classes of a class
  828. *
  829. * @param $className string The name of the class
  830. *
  831. * @since 3.0
  832. * @access private
  833. * @author Arne Brachhold
  834. * @return array An array which contains the names of the parent classes
  835. */
  836. function GetParentClasses($classname) {
  837. $parent = get_parent_class($classname);
  838. $parents = array();
  839. if (!empty($parent)) {
  840. $parents = $this->GetParentClasses($parent);
  841. $parents[] = strtolower($parent);
  842. }
  843. return $parents;
  844. }
  845. /**
  846. * Returns if a class is a subclass of another class
  847. *
  848. * @param $className string The name of the class
  849. * @param $$parentName string The name of the parent class
  850. *
  851. * @since 3.0
  852. * @access private
  853. * @author Arne Brachhold
  854. * @return bool true if the given class is a subclass of the other one
  855. */
  856. function IsSubclassOf($className, $parentName) {
  857. $className = strtolower($className);
  858. $parentName = strtolower($parentName);
  859. if(empty($className) || empty($parentName) || !class_exists($className) || !class_exists($parentName)) return false;
  860. $parents=$this->GetParentClasses($className);
  861. return in_array($parentName,$parents);
  862. }
  863. /**
  864. * Loads up the configuration and validates the prioity providers
  865. *
  866. * This method is only called if the sitemaps needs to be build or the admin page is displayed.
  867. *
  868. * @since 3.0
  869. * @access private
  870. * @author Arne Brachhold
  871. */
  872. function Initate() {
  873. if(!$this->_initiated) {
  874. //Loading language file...
  875. //load_plugin_textdomain('sitemap');
  876. //Hmm, doesn't work if the plugin file has its own directory.
  877. //Let's make it our way... load_plugin_textdomain() searches only in the wp-content/plugins dir.
  878. $currentLocale = get_locale();
  879. if(!empty($currentLocale)) {
  880. $moFile = dirname(__FILE__) . "/lang/sitemap-" . $currentLocale . ".mo";
  881. if(@file_exists($moFile) && is_readable($moFile)) load_textdomain('sitemap', $moFile);
  882. }
  883. $this->_freqNames = array(
  884. "always"=>__("Always","sitemap"),
  885. "hourly"=>__("Hourly","sitemap"),
  886. "daily"=>__("Daily","sitemap"),
  887. "weekly"=>__("Weekly","sitemap"),
  888. "monthly"=>__("Monthly","sitemap"),
  889. "yearly"=>__("Yearly","sitemap"),
  890. "never"=>__("Never","sitemap")
  891. );
  892. $this->LoadOptions();
  893. $this->LoadPages();
  894. //Register our own priority providers
  895. add_filter("sm_add_prio_provider",array(&$this, 'AddDefaultPrioProviders'));
  896. //Let other plugins register their providers
  897. $r = apply_filters("sm_add_prio_provider",$this->_prioProviders);
  898. //Check if no plugin return null
  899. if($r != null) $this->_prioProviders = $r;
  900. $this->ValidatePrioProviders();
  901. $this->_initiated = true;
  902. }
  903. }
  904. /**
  905. * Returns the instance of the Sitemap Generator
  906. *
  907. * @since 3.0
  908. * @access public
  909. * @return GoogleSitemapGenerator The instance or null if not available.
  910. * @author Arne Brachhold
  911. */
  912. function &GetInstance() {
  913. if(isset($GLOBALS["sm_instance"])) {
  914. return $GLOBALS["sm_instance"];
  915. } else return null;
  916. }
  917. /**
  918. * Returns if the sitemap building process is currently active
  919. *
  920. * @since 3.0
  921. * @access public
  922. * @return bool true if active
  923. * @author Arne Brachhold
  924. */
  925. function IsActive() {
  926. $inst = &GoogleSitemapGenerator::GetInstance();
  927. return ($inst != null && $inst->_isActive);
  928. }
  929. /**
  930. * Returns if the compressed sitemap was activated
  931. *
  932. * @since 3.0b8
  933. * @access private
  934. * @author Arne Brachhold
  935. * @return true if compressed
  936. */
  937. function IsGzipEnabled() {
  938. return ($this->GetOption("b_gzip")===true && function_exists("gzwrite"));
  939. }
  940. /**
  941. * Returns if this version of WordPress supports the new taxonomy system
  942. *
  943. * @since 3.0b8
  944. * @access private
  945. * @author Arne Brachhold
  946. * @return true if supported
  947. */
  948. function IsTaxonomySupported() {
  949. return (function_exists("get_taxonomy") && function_exists("get_terms"));
  950. }
  951. /**
  952. * Returns if this version of WordPress supports custom post types
  953. *
  954. * @since 3.2.5
  955. * @access private
  956. * @author Lee Willis
  957. * @return true if supported
  958. */
  959. function IsCustomPostTypesSupported() {
  960. return (function_exists("get_post_types") && function_exists("register_post_type"));
  961. }
  962. /**
  963. * Returns the list of custom taxonies. These are basically all taxonomies without categories and post tags
  964. *
  965. * @since 3.1.7
  966. * @return array Array of names of user-defined taxonomies
  967. */
  968. function GetCustomTaxonomies() {
  969. $taxonomies = get_object_taxonomies('post');
  970. return array_diff($taxonomies,array("category","post_tag","post_format"));
  971. }
  972. /**
  973. * Returns the list of custom post types. These are all custome post types except post, page and attachment
  974. *
  975. * @since 3.2.5
  976. * @author Lee Willis
  977. * @return array Array of custom post types as per get_post_types
  978. */
  979. function GetCustomPostTypes() {
  980. $post_types = get_post_types(array("public"=>1));
  981. $post_types = array_diff($post_types,array("post","page","attachment"));
  982. return $post_types;
  983. }
  984. /**
  985. * Enables the Google Sitemap Generator and registers the WordPress hooks
  986. *
  987. * @since 3.0
  988. * @access public
  989. * @author Arne Brachhold
  990. */
  991. function Enable() {
  992. if(!isset($GLOBALS["sm_instance"])) {
  993. $GLOBALS["sm_instance"]=new GoogleSitemapGenerator();
  994. }
  995. }
  996. /**
  997. * Checks if sitemap building after content changed is enabled and rebuild the sitemap
  998. *
  999. * @param int $postID The ID of the post to handle. Used to avoid double rebuilding if more than one hook was fired.
  1000. * @param bool $external Added in 3.1.9. Skips checking of b_auto_enabled if set to true
  1001. * @since 3.0
  1002. * @access public
  1003. * @author Arne Brachhold
  1004. */
  1005. function CheckForAutoBuild($postID, $external = false) {
  1006. global $wp_version;
  1007. $this->Initate();
  1008. //Build one time per post and if not importing.
  1009. if((($this->GetOption("b_auto_enabled")===true && $this->_lastPostID != $postID) || $external) && (!defined('WP_IMPORTING') || WP_IMPORTING != true)) {
  1010. //Build the sitemap directly or schedule it with WP cron
  1011. if($this->GetOption("b_auto_delay")==true && floatval($wp_version) >= 2.1) {
  1012. if(!$this->_isScheduled) {
  1013. //Schedule in 15 seconds, this should be enough to catch all changes.
  1014. //Clear all other existing hooks, so the sitemap is only built once.
  1015. wp_clear_scheduled_hook('sm_build_cron');
  1016. wp_schedule_single_event(time()+15,'sm_build_cron');
  1017. $this->_isScheduled = true;
  1018. }
  1019. } else {
  1020. //Build sitemap only once and never in bulk mode
  1021. if(!$this->_lastPostID && (!isset($_GET["delete"]) || count((array) $_GET['delete'])<=0)) {
  1022. $this->BuildSitemap();
  1023. }
  1024. }
  1025. $this->_lastPostID = $postID;
  1026. }
  1027. }
  1028. /**
  1029. * Builds the sitemap by external request, for example other plugins.
  1030. *
  1031. * @since 3.1.9
  1032. * @return null
  1033. */
  1034. function BuildNowRequest() {
  1035. $this->CheckForAutoBuild(null, true);
  1036. }
  1037. /**
  1038. * Checks if the rebuild request was send and starts to rebuilt the sitemap
  1039. *
  1040. * @since 3.0
  1041. * @access public
  1042. * @author Arne Brachhold
  1043. */
  1044. function CheckForManualBuild() {
  1045. if(!empty($_GET["sm_command"]) && !empty($_GET["sm_key"])) {
  1046. $this->Initate();
  1047. if($this->GetOption("b_manual_enabled")===true && $_GET["sm_command"]=="build" && $_GET["sm_key"]==$this->GetOption("b_manual_key")) {
  1048. $this->BuildSitemap();
  1049. echo "DONE";
  1050. exit;
  1051. }
  1052. }
  1053. }
  1054. /**
  1055. * Validates all given Priority Providers by checking them for required methods and existence
  1056. *
  1057. * @since 3.0
  1058. * @access private
  1059. * @author Arne Brachhold
  1060. */
  1061. function ValidatePrioProviders() {
  1062. $validProviders=array();
  1063. for($i=0; $i<count($this->_prioProviders); $i++) {
  1064. if(class_exists($this->_prioProviders[$i])) {
  1065. if($this->IsSubclassOf($this->_prioProviders[$i],"GoogleSitemapGeneratorPrioProviderBase")) {
  1066. array_push($validProviders,$this->_prioProviders[$i]);
  1067. }
  1068. }
  1069. }
  1070. $this->_prioProviders=$validProviders;
  1071. if(!$this->GetOption("b_prio_provider")) {
  1072. if(!in_array($this->GetOption("b_prio_provider"),$this->_prioProviders,true)) {
  1073. $this->SetOption("b_prio_provider","");
  1074. }
  1075. }
  1076. }
  1077. /**
  1078. * Adds the default Priority Providers to the provider list
  1079. *
  1080. * @since 3.0
  1081. * @access private
  1082. * @author Arne Brachhold
  1083. */
  1084. function AddDefaultPrioProviders($providers) {
  1085. array_push($providers,"GoogleSitemapGeneratorPrioByCountProvider");
  1086. array_push($providers,"GoogleSitemapGeneratorPrioByAverageProvider");
  1087. if(class_exists("ak_popularity_contest")) {
  1088. array_push($providers,"GoogleSitemapGeneratorPrioByPopularityContestProvider");
  1089. }
  1090. return $providers;
  1091. }
  1092. /**
  1093. * Loads the stored pages from the database
  1094. *
  1095. * @since 3.0
  1096. * @access private
  1097. * @author Arne Brachhold
  1098. */
  1099. function LoadPages() {
  1100. global $wpdb;
  1101. $needsUpdate=false;
  1102. $pagesString=$wpdb->get_var("SELECT option_value FROM $wpdb->options WHERE option_name = 'sm_cpages'");
  1103. //Class sm_page was renamed with 3.0 -> rename it in serialized value for compatibility
  1104. if(!empty($pagesString) && strpos($pagesString,"sm_page")!==false) {
  1105. $pagesString = str_replace("O:7:\"sm_page\"","O:26:\"GoogleSitemapGeneratorPage\"",$pagesString);
  1106. $needsUpdate=true;
  1107. }
  1108. if(!empty($pagesString)) {
  1109. $storedpages=unserialize($pagesString);
  1110. $this->_pages=$storedpages;
  1111. } else {
  1112. $this->_pages=array();
  1113. }
  1114. if($needsUpdate) $this->SavePages();
  1115. }
  1116. /**
  1117. * Saved the additional pages back to the database
  1118. *
  1119. * @since 3.0
  1120. * @access private
  1121. * @author Arne Brachhold
  1122. * @return true on success
  1123. */
  1124. function SavePages() {
  1125. $oldvalue = get_option("sm_cpages");
  1126. if($oldvalue == $this->_pages) {
  1127. return true;
  1128. } else {
  1129. delete_option("sm_cpages");
  1130. //Add the option, Note the autoload=false because when the autoload happens, our class GoogleSitemapGeneratorPage doesn't exist
  1131. add_option("sm_cpages",$this->_pages,null,"no");
  1132. return true;
  1133. }
  1134. }
  1135. /**
  1136. * Returns the URL for the sitemap file
  1137. *
  1138. * @since 3.0
  1139. * @access private
  1140. * @author Arne Brachhold
  1141. * @param bool $forceAuto Force the return value to the autodetected value.
  1142. * @return The URL to the Sitemap file
  1143. */
  1144. function GetXmlUrl($forceAuto=false) {
  1145. if(!$forceAuto && $this->GetOption("b_location_mode")=="manual") {
  1146. return $this->GetOption("b_fileurl_manual");
  1147. } else {
  1148. return trailingslashit(get_bloginfo('url')). $this->GetOption("b_filename");
  1149. }
  1150. }
  1151. /**
  1152. * Returns the URL for the gzipped sitemap file
  1153. *
  1154. * @since 3.0
  1155. * @access private
  1156. * @author Arne Brachhold
  1157. * @param bool $forceAuto Force the return value to the autodetected value.
  1158. * @return The URL to the gzipped Sitemap file
  1159. */
  1160. function GetZipUrl($forceAuto=false) {
  1161. return $this->GetXmlUrl($forceAuto) . ".gz";
  1162. }
  1163. /**
  1164. * Returns the file system path to the sitemap file
  1165. *
  1166. * @since 3.0
  1167. * @access private
  1168. * @author Arne Brachhold
  1169. * @param bool $forceAuto Force the return value to the autodetected value.
  1170. * @return The file system path;
  1171. */
  1172. function GetXmlPath($forceAuto=false) {
  1173. if(!$forceAuto && $this->GetOption("b_location_mode")=="manual") {
  1174. return $this->GetOption("b_filename_manual");
  1175. } else {
  1176. return $this->GetHomePath() . $this->GetOption("b_filename");
  1177. }
  1178. }
  1179. /**
  1180. * Returns the file system path to the gzipped sitemap file
  1181. *
  1182. * @since 3.0
  1183. * @access private
  1184. * @author Arne Brachhold
  1185. * @param bool $forceAuto Force the return value to the autodetected value.
  1186. * @return The file system path;
  1187. */
  1188. function GetZipPath($forceAuto=false) {
  1189. return $this->GetXmlPath($forceAuto) . ".gz";
  1190. }
  1191. /**
  1192. * Returns the option value for the given key
  1193. *
  1194. * @since 3.0
  1195. * @access private
  1196. * @author Arne Brachhold
  1197. * @param $key string The Configuration Key
  1198. * @return mixed The value
  1199. */
  1200. function GetOption($key) {
  1201. $key="sm_" . $key;
  1202. if(array_key_exists($key,$this->_options)) {
  1203. return $this->_options[$key];
  1204. } else return null;
  1205. }
  1206. /**
  1207. * Sets an option to a new value
  1208. *
  1209. * @since 3.0
  1210. * @access private
  1211. * @author Arne Brachhold
  1212. * @param $key string The configuration key
  1213. * @param $value mixed The new object
  1214. */
  1215. function SetOption($key,$value) {
  1216. if(strstr($key,"sm_")!==0) $key="sm_" . $key;
  1217. $this->_options[$key]=$value;
  1218. }
  1219. /**
  1220. * Saves the options back to the database
  1221. *
  1222. * @since 3.0
  1223. * @access private
  1224. * @author Arne Brachhold
  1225. * @return bool true on success
  1226. */
  1227. function SaveOptions() {
  1228. $oldvalue = get_option("sm_options");
  1229. if($oldvalue == $this->_options) {
  1230. return true;
  1231. } else return update_option("sm_options",$this->_options);
  1232. }
  1233. /**
  1234. * Retrieves the number of comments of a post in a asso. array
  1235. * The key is the postID, the value the number of comments
  1236. *
  1237. * @since 3.0
  1238. * @access private
  1239. * @author Arne Brachhold
  1240. * @return array An array with postIDs and their comment count
  1241. */
  1242. function GetComments() {
  1243. global $wpdb;
  1244. $comments=array();
  1245. //Query comments and add them into the array
  1246. $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`");
  1247. if($commentRes) {
  1248. foreach($commentRes as $comment) {
  1249. $comments[$comment->post_id]=$comment->comment_count;
  1250. }
  1251. }
  1252. return $comments;
  1253. }
  1254. /**
  1255. * Calculates the full number of comments from an sm_getComments() generated array
  1256. *
  1257. * @since 3.0
  1258. * @access private
  1259. * @author Arne Brachhold
  1260. * @param $comments array The Array with posts and c0mment count
  1261. * @see sm_getComments
  1262. * @return The full number of comments
  1263. */
  1264. function GetCommentCount($comments) {
  1265. $commentCount=0;
  1266. foreach($comments AS $k=>$v) {
  1267. $commentCount+=$v;
  1268. }
  1269. return $commentCount;
  1270. }
  1271. /**
  1272. * Adds a url to the sitemap. You can use this method or call AddElement directly.
  1273. *
  1274. * @since 3.0
  1275. * @access public
  1276. * @author Arne Brachhold
  1277. * @param $loc string The location (url) of the page
  1278. * @param $lastMod int The last Modification time as a UNIX timestamp
  1279. * @param $changeFreq string The change frequenty of the page, Valid values are "always", "hourly", "daily", "weekly", "monthly", "yearly" and "never".
  1280. * @param $priorty float The priority of the page, between 0.0 and 1.0
  1281. * @see AddElement
  1282. * @return string The URL node
  1283. */
  1284. function AddUrl($loc, $lastMod = 0, $changeFreq = "monthly", $priority = 0.5) {
  1285. //Strip out the last modification time if activated
  1286. if($this->GetOption('in_lastmod')===false) $lastMod = 0;
  1287. $page = new GoogleSitemapGeneratorPage($loc, $priority, $changeFreq, $lastMod);
  1288. $this->AddElement($page);
  1289. }
  1290. /**
  1291. * Adds an element to the sitemap
  1292. *
  1293. * @since 3.0
  1294. * @access private
  1295. * @author Arne Brachhold
  1296. * @param $page The element
  1297. */
  1298. function AddElement(&$page) {
  1299. if(empty($page)) return;
  1300. $s = $page->Render();
  1301. if($this->_fileZipHandle && $this->IsGzipEnabled()) {
  1302. gzwrite($this->_fileZipHandle,$s);
  1303. }
  1304. if($this->_fileHandle && $this->GetOption("b_xml")) {
  1305. fwrite($this->_fileHandle,$s);
  1306. }
  1307. }
  1308. /**
  1309. * Checks if a file is writable and tries to make it if not.
  1310. *
  1311. * @since 3.05b
  1312. * @access private
  1313. * @author VJTD3 <http://www.VJTD3.com>
  1314. * @return bool true if writable
  1315. */
  1316. function IsFileWritable($filename) {
  1317. //can we write?
  1318. if(!is_writable($filename)) {
  1319. //no we can't.
  1320. if(!@chmod($filename, 0666)) {
  1321. $pathtofilename = dirname($filename);
  1322. //Lets check if parent directory is writable.
  1323. if(!is_writable($pathtofilename)) {
  1324. //it's not writeable too.
  1325. if(!@chmod($pathtoffilename, 0666)) {
  1326. //darn couldn't fix up parrent directory this hosting is foobar.
  1327. //Lets error because of the permissions problems.
  1328. return false;
  1329. }
  1330. }
  1331. }
  1332. }
  1333. //we can write, return 1/true/happy dance.
  1334. return true;
  1335. }
  1336. /**
  1337. * Adds the sitemap to the virtual robots.txt file
  1338. * This function is executed by WordPress with the do_robots hook
  1339. *
  1340. * @since 3.1.2
  1341. */
  1342. function DoRobots() {
  1343. $this->Initate();
  1344. if($this->GetOption('b_robots') === true) {
  1345. $smUrl = $this->GetXmlUrl();
  1346. if($this->IsGzipEnabled()) {
  1347. $smUrl = $this->GetZipUrl();
  1348. }
  1349. echo "\nSitemap: " . $smUrl . "\n";
  1350. }
  1351. }
  1352. /**
  1353. * Builds the sitemap and writes it into a xml file.
  1354. *
  1355. * ATTENTION PLUGIN DEVELOPERS! DONT CALL THIS METHOD DIRECTLY!
  1356. * The method is probably not available, since it is only loaded when needed.
  1357. * Use do_action("sm_rebuild"); if you want to rebuild the sitemap.
  1358. * Please refer to the documentation.txt for more details.
  1359. *
  1360. * @since 3.0
  1361. * @access public
  1362. * @author Arne Brachhold <himself [at] arnebrachhold [dot] de>
  1363. * @return array An array with messages such as failed writes etc.
  1364. */
  1365. function BuildSitemap() {
  1366. global $wpdb, $posts, $wp_version;
  1367. $this->Initate();
  1368. if($this->GetOption("b_memory")!='') {
  1369. @ini_set("memory_limit",$this->GetOption("b_memory"));
  1370. }
  1371. if($this->GetOption("b_time")!=-1) {
  1372. @set_time_limit($this->GetOption("b_time"));
  1373. }
  1374. //This object saves the status information of the script directly to the database
  1375. $status = new GoogleSitemapGeneratorStatus();
  1376. //Other plugins can detect if the building process is active
  1377. $this->_isActive = true;
  1378. //$this->AddElement(new GoogleSitemapGeneratorXmlEntry());
  1379. //Debug mode?
  1380. $debug=$this->GetOption("b_debug");
  1381. if($this->GetOption("b_xml")) {
  1382. $fileName = $this->GetXmlPath();
  1383. $status->StartXml($this->GetXmlPath(),$this->GetXmlUrl());
  1384. if($this->IsFileWritable($fileName)) {
  1385. $this->_fileHandle = fopen($fileName,"w");
  1386. if(!$this->_fileHandle) $status->EndXml(false,"Not openable");
  1387. } else $status->EndXml(false,"not writable");
  1388. }
  1389. //Write gzipped sitemap file
  1390. if($this->IsGzipEnabled()) {
  1391. $fileName = $this->GetZipPath();
  1392. $status->StartZip($this->GetZipPath(),$this->GetZipUrl());
  1393. if($this->IsFileWritable($fileName)) {
  1394. $this->_fileZipHandle = gzopen($fileName,"w1");
  1395. if(!$this->_fileZipHandle) $status->EndZip(false,"Not openable");
  1396. } else $status->EndZip(false,"not writable");
  1397. }
  1398. if(!$this->_fileHandle && !$this->_fileZipHandle) {
  1399. $status->End();
  1400. return;
  1401. }
  1402. //Content of the XML file
  1403. $this->AddElement(new GoogleSitemapGeneratorXmlEntry('<?xml version="1.0" encoding="UTF-8"' . '?' . '>'));
  1404. $styleSheet = ($this->GetDefaultStyle() && $this->GetOption('b_style_default')===true?$this->GetDefaultStyle():$this->GetOption('b_style'));
  1405. if(!empty($styleSheet)) {
  1406. $this->AddElement(new GoogleSitemapGeneratorXmlEntry('<' . '?xml-stylesheet type="text/xsl" href="' . $styleSheet . '"?' . '>'));
  1407. }
  1408. $this->AddElement(new GoogleSitemapGeneratorDebugEntry("generator=\"wordpress/" . get_bloginfo('version') . "\""));
  1409. $this->AddElement(new GoogleSitemapGeneratorDebugEntry("sitemap-generator-url=\"http://www.arnebrachhold.de\" sitemap-generator-version=\"" . $this->GetVersion() . "\""));
  1410. $this->AddElement(new GoogleSitemapGeneratorDebugEntry("generated-on=\"" . date(get_option("date_format") . " " . get_option("time_format")) . "\""));
  1411. //All comments as an asso. Array (postID=>commentCount)
  1412. $comments=($this->GetOption("b_prio_provider")!=""?$this->GetComments():array());
  1413. //Full number of comments
  1414. $commentCount=(count($comments)>0?$this->GetCommentCount($comments):0);
  1415. if($debug && $this->GetOption("b_prio_provider")!="") {
  1416. $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Total comment count: " . $commentCount));
  1417. }
  1418. //Go XML!
  1419. $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">'));
  1420. $home = get_bloginfo('url');
  1421. $homePid = 0;
  1422. //Add the home page (WITH a slash!)
  1423. if($this->GetOption("in_home")) {
  1424. if('page' == get_option('show_on_front') && get_option('page_on_front')) {
  1425. $pageOnFront = get_option('page_on_front');
  1426. $p = get_page($pageOnFront);
  1427. if($p) {
  1428. $homePid = $p->ID;
  1429. $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"));
  1430. }
  1431. } else {
  1432. $this->AddUrl(trailingslashit($home),$this->GetTimestampFromMySql(get_lastpostmodified('GMT')),$this->GetOption("cf_home"),$this->GetOption("pr_home"));
  1433. }
  1434. }
  1435. //Add the posts
  1436. if($this->GetOption("in_posts") || $this->GetOption("in_pages")) {
  1437. if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Postings"));
  1438. //Pre 2.1 compatibility. 2.1 introduced 'future' as post_status so we don't need to check post_date
  1439. $wpCompat = (floatval($wp_version) < 2.1);
  1440. $useQTransLate = false; //function_exists('qtrans_convertURL') && function_exists('qtrans_getEnabledLanguages'); Not really working yet
  1441. $excludes = $this->GetOption('b_exclude'); //Excluded posts and pages (user enetered ID)
  1442. $exclCats = $this->GetOption("b_exclude_cats"); // Excluded cats
  1443. if($exclCats && count($exclCats)>0 && $this->IsTaxonomySupported()) {
  1444. $excludedCatPosts = get_objects_in_term($exclCats,"category"); // Get all posts in excl. cats. Unforttunately this also gives us pages, revisions and so on...
  1445. //Remove the pages, revisions etc from the exclude by category list, because they are always in the uncategorized one.
  1446. if(count($excludedCatPosts)>0) {
  1447. $exclPages = $wpdb->get_col("SELECT ID FROM `" . $wpdb->posts . "` WHERE post_type!='post' AND ID IN ('" . implode("','",$excludedCatPosts) . "')");
  1448. $exclPages = array_map('intval', $exclPages);
  1449. //Remove the pages from the exlusion list before
  1450. if(count($exclPages)>0) $excludedCatPosts = array_diff($excludedCatPosts, $exclPa