Configuration Page
Version: 3.0.3
Author: Arne Brachhold
Author URI: http://www.arnebrachhold.de/
Contributors:
==============================================================================
Basic Idea Michael Nguyen http://www.socialpatterns.com/
SQL Improvements Rodney Shupe http://www.shupe.ca/
Japanse Lang. File Hirosama http://hiromasa.zone.ne.jp/
Spanish lang. File César Gómez Martín http://www.cesargomez.org/
Italian lang. File Stefano Aglietti http://wordpress-it.it/
Trad.Chinese File Kirin Lin http://kirin-lin.idv.tw/
Simpl.Chinese File june6 http://www.june6.cn/
Swedish Lang. File Tobias Bergius http://tobiasbergius.se/
Czech Lang. File Peter Kahoun http://kahi.cz
Ping Code Template 1 James http://www.adlards.com/
Ping Code Template 2 John http://www.jonasblog.com/
Bug Report Brad http://h3h.net/
Bug Report Christian Aust http://publicvoidblog.de/
Bug Report Joseph Abboud
Bug Report Mike http://baptiste.us/
Bug Report Peter http://fastagent.de/
Bug Report Glenn http://publicityship.com.au/
Bug Report froosh
File Handling VJTD3 http://www.vjtd3.com/
Code, Documentation, Hosting and all other Stuff:
Arne Brachhold http://www.arnebrachhold.de/
Thanks to all contributors and bug reporters! :)
Release History:
==============================================================================
2005-06-05 1.0 First release
2005-06-05 1.1 Added archive support
2005-06-05 1.2 Added category support
2005-06-05 2.0a Beta: Real Plugin! Static file generation, Admin UI
2005-06-05 2.0 Various fixes, more help, more comments, configurable filename
2005-06-07 2.01 Fixed 2 Bugs: 147 is now _e(strval($i)); instead of _e($i); 344 uses a full < ?php instead of < ?
Thanks to Christian Aust for reporting this :)
2005-06-07 2.1 Correct usage of last modification date for cats and archives (thx to Rodney Shupe (http://www.shupe.ca/))
Added support for .gz generation
Fixed bug which ignored different post/page priorities
Should support now different wordpress/admin directories
2005-06-07 2.11 Fixed bug with hardcoded table table names instead of the $wpd vars
2005-06-07 2.12 Changed SQL Statement of the categories to get it work on MySQL 3
2005-06-08 2.2 Added language file support:
- Japanese Language Files and code modifications by hiromasa (http://hiromasa.zone.ne.jp/)
- German Language File by Arne Brachhold (http://www.arnebrachhold.de)
2005-06-14 2.5 Added support for external pages
Added support for Google Ping
Added the minimum Post Priority option
Added Spanish Language File by César Gómez Martín (http://www.cesargomez.org/)
Added Italian Language File by Stefano Aglietti (http://wordpress-it.it/)
Added Traditional Chine Language File by Kirin Lin (http://kirin-lin.idv.tw/)
2005-07-03 2.6 Added support to store the files at a custom location
Changed the home URL to have a slash at the end
Required admin-functions.php so the script will work with external calls, wp-mail for example
Added support for other plugins to add content to the sitemap via add_filter()
2005-07-20 2.7 Fixed wrong date format in additional pages
Added Simplified Chinese Language Files by june6 (http://www.june6.cn/)
Added Swedish Language File by Tobias Bergius (http://tobiasbergius.se/)
2006-01-07 3.0b Added different priority calculation modes and introduced an API to create custom ones
Added support to use the Popularity Contest plugin by Alex King to calculate post priority
Added Button to restore default configuration
Added several links to homepage and support
Added option to exclude password protected posts
Added function to start sitemap creation via GET and a secret key
Posts and pages marked for publish with a date in the future won't be included
Improved compatiblity with other plugins
Improved speed and optimized settings handling
Improved user-interface
Recoded plugin architecture which is now fully OOP
2006-01-07 3.0b1 Changed the way for hook support to be PHP5 and PHP4 compatible
Readded support for tools like w.Bloggar
Fixed "doubled-content" bug with WP2
Added xmlns to enable validation
2006-03-01 3.0b3 More performance
More caching
Better support for Popularity Contest and WP 2.x
2006-11-16 3.0b4 Fixed bug with option SELECTS
Decreased memory usage which should solve timeout and memory problems
Updated namespace to support YAHOO and MSN
2007-01-19 3.0b5 Javascripted page editor
WP 2 Design
YAHOO notification
New status report, removed ugly logfiles
Better Popularity Contest Support
Fixed double backslashes on windows systems
Added option to specify time limit and memory limit
Added option to define a XSLT stylesheet and added a default one
Fixed bug with sub-pages. Thanks to:
- Mike Baptiste (http://baptiste.us),
- Peter Claus Lamprecht (http://fastagent.de)
- Glenn Nicholas (http://publicityship.com.au)
Improved file handling, thanks to VJTD3 (http://www.VJTD3.com)
WP 2.1 improvements
2007-01-23 3.0b6 Use memory_get_peak_usage instead of memory_get_usage if available
Removed the usage of REQUEST_URI since it not correct in all environments
Fixed that sitemap.xml.gz was not compressed
Added compat function "stripos" for PHP4 (Thanks to Joseph Abboud!)
Streamlined some code
2007-05-17 3.0b7 Added option to include the author pages like /author/john
Small enhancements, removed stripos dependency and the added compat function
Added check to not build the sitemap if importing posts
Fixed missing domain parameter for translator name
Fixed WP 2.1 / Pre 2.1 post / pages database changes
Fixed wrong XSLT location (Thanks froosh)
Added Ask.com notification
Removed unused javascript
2007-07-22 3.0b8 Changed category SQL to prevent unused cats from beeing included
Plugin will be loaded on "init" instead of direclty after the file has been loaded.
Added support for robots.txt modification
Switched YAHOO ping API from YAHOO Web Services to the "normal" ping service which doesn't require an app id
Search engines will only be pinged if the sitemap file has changed
2007-09-02 3.0b9 Added tag support for WordPress 2.3
Now using post_date_gmt instead of post_date everywhere
Fixed archive bug with static pages (Thanks to Peter Claus Lamprecht)
Fixed some missing translation domains, thanks to Kirin Lin!
Added Czech translation files for 2.7.1, thanks to Peter Kahoun (http://kahi.cz)
2007-09-04 3.0b10 Added category support for WordPress 2.3
Fixed bug with empty URLs in sitemap
Repaired GET building
Added more info on debug mode
2007-09-23 3.0b11 Changed mysql queries to unbuffered queries
Uses MUCH less memory
Fixed really stupid bug with search engine pings
Option to set how many posts will be included
2007-09-24 3.0 Yeah, 3.0 Final after one and a half year ;)
Removed useless functions
2007-11-03 3.0.1 Using the Snoopy HTTP client for ping requests instead of wp_remote_fopen
Fixed undefined translation strings
Added "safemode" for SQL which doesn't use unbuffered results (old style)
Added option to run the building process in background using wp-cron
Removed unnecessary function_exists, Thanks to user00265
Added links to test the ping if it failed.
2007-11-25 3.0.2 Fixed bug which caused that some settings were not saved correctly
Added option to exclude pages or post by ID
Restored YAHOO ping service with API key since the other one is to unreliable. (see 3.0b8)
2007-11-28 3.0.2.1 Fixed wrong XML Schema Location (Thanks to Emanuele Tessore)
Added Russian Language files by Sergey http://ryvkin.ru
2007-12-30 3.0.3 Added Live Search Ping
Removed some hooks which rebuilt the sitemap with every comment
Maybe Todo:
==============================================================================
- Your wishes :)
License:
==============================================================================
Copyright 2005, 2006, 2007 ARNE BRACHHOLD (email : himself - arnebrachhold - de)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Developer Documentation
==============================================================================
Adding other pages to the sitemap via other plugins
This plugin uses the action system of WordPress to allow other plugins
to add urls to the sitemap. Simply add your function with add_action to
the list and the plugin will execute yours every time the sitemap is build.
Use the static method "GetInstance" to get the generator and AddUrl method
to add your content.
Sample:
function your_pages() {
$generatorObject = &GoogleSitemapGenerator::GetInstance(); //Please note the "&" sign!
if($generatorObject!=null) $generatorObject->AddUrl("http://blog.uri/tags/hello/",time(),"daily",0.5);
}
add_action("sm_buildmap","your_pages");
Parameters:
- The URL to the page
- The last modified data, as a UNIX timestamp (optional)
- The Change Frequency (daily, hourly, weekly and so on) (optional)
- The priority 0.0 to 1.0 (optional)
===============================================
Adding additional PriorityProviders
This plugin uses several classes to calculate the post priority.
You can register your own provider and choose it at the options screen.
Your class has to extend the GoogleSitemapGeneratorPrioProviderBase class
which has a default constructor and a method called GetPostPriority
which you can override.
Look at the GoogleSitemapGeneratorPrioByPopularityContestProvider class
for an example.
To register your provider to the sitemap generator, use the following filter:
add_filter("sm_add_prio_provider","AddMyProvider");
Your function could look like this:
function AddMyProvider($providers) {
array_push($providers,"MyProviderClass");
return $providers;
}
Note that you have to return the modified list!
*/
//Enable for dev! Good code doesn't generate any notices...
//error_reporting(E_ALL);
//ini_set("display_errors",1);
#region PHP5 compat functions
if (!function_exists('file_get_contents')) {
/**
* Replace file_get_contents()
*
* @category PHP
* @package PHP_Compat
* @link http://php.net/function.file_get_contents
* @author Aidan Lister
* @version $Revision: 1.21 $
* @internal resource_context is not supported
* @since PHP 5
*/
function file_get_contents($filename, $incpath = false, $resource_context = null) {
if (false === $fh = fopen($filename, 'rb', $incpath)) {
user_error('file_get_contents() failed to open stream: No such file or directory', E_USER_WARNING);
return false;
}
clearstatcache();
if ($fsize = @filesize($filename)) {
$data = fread($fh, $fsize);
} else {
$data = '';
while (!feof($fh)) {
$data .= fread($fh, 8192);
}
}
fclose($fh);
return $data;
}
}
if(!function_exists('file_put_contents')) {
if (!defined('FILE_USE_INCLUDE_PATH')) {
define('FILE_USE_INCLUDE_PATH', 1);
}
if (!defined('LOCK_EX')) {
define('LOCK_EX', 2);
}
if (!defined('FILE_APPEND')) {
define('FILE_APPEND', 8);
}
/**
* Replace file_put_contents()
*
* @category PHP
* @package PHP_Compat
* @link http://php.net/function.file_put_contents
* @author Aidan Lister
* @version $Revision: 1.25 $
* @internal resource_context is not supported
* @since PHP 5
* @require PHP 4.0.0 (user_error)
*/
function file_put_contents($filename, $content, $flags = null, $resource_context = null) {
// If $content is an array, convert it to a string
if (is_array($content)) {
$content = implode('', $content);
}
// If we don't have a string, throw an error
if (!is_scalar($content)) {
user_error('file_put_contents() The 2nd parameter should be either a string or an array',E_USER_WARNING);
return false;
}
// Get the length of data to write
$length = strlen($content);
// Check what mode we are using
$mode = ($flags & FILE_APPEND)?'a':'wb';
// Check if we're using the include path
$use_inc_path = ($flags & FILE_USE_INCLUDE_PATH)?true:false;
// Open the file for writing
if (($fh = @fopen($filename, $mode, $use_inc_path)) === false) {
user_error('file_put_contents() failed to open stream: Permission denied',E_USER_WARNING);
return false;
}
// Attempt to get an exclusive lock
$use_lock = ($flags & LOCK_EX) ? true : false ;
if ($use_lock === true) {
if (!flock($fh, LOCK_EX)) {
return false;
}
}
// Write to the file
$bytes = 0;
if (($bytes = @fwrite($fh, $content)) === false) {
$errormsg = sprintf('file_put_contents() Failed to write %d bytes to %s',$length,$filename);
user_error($errormsg, E_USER_WARNING);
return false;
}
// Close the handle
@fclose($fh);
// Check all the data was written
if ($bytes != $length) {
$errormsg = sprintf('file_put_contents() Only %d of %d bytes written, possibly out of free disk space.',$bytes,$length);
user_error($errormsg, E_USER_WARNING);
return false;
}
// Return length
return $bytes;
}
}
#endregion
/**
* Represents the status (success and failures) of a building process
* @author Arne Brachhold
* @package sitemap
* @since 3.0b5
*/
class GoogleSitemapGeneratorStatus {
function GoogleSitemapGeneratorStatus() {
$this->_startTime = $this->GetMicrotimeFloat();
$exists = get_option("sm_status");
if($exists === false) add_option("sm_status","","Status","no");
$this->Save();
}
function Save() {
update_option("sm_status",$this);
}
function Load() {
$status = @get_option("sm_status");
if(is_a($status,"GoogleSitemapGeneratorStatus")) return $status;
else return null;
}
/**
* @var float $_startTime The start time of the building process
* @access private
*/
var $_startTime = 0;
/**
* @var float $_endTime The end time of the building process
* @access private
*/
var $_endTime = 0;
/**
* @var bool $$_hasChanged Indicates if the sitemap content has changed
* @access private
*/
var $_hasChanged = true;
/**
* @var int $_memoryUsage The amount of memory used in bytes
* @access private
*/
var $_memoryUsage = 0;
/**
* @var int $_lastPost The number of posts processed. This value is updated every 50 posts.
* @access private
*/
var $_lastPost = 0;
/**
* @var int $_lastTime The time when the last step-update occured. This value is updated every 50 posts.
* @access private
*/
var $_lastTime = 0;
function End($hasChanged = true) {
$this->_endTime = $this->GetMicrotimeFloat();
$this->SetMemoryUsage();
$this->_hasChanged = $hasChanged;
$this->Save();
}
function SetMemoryUsage() {
if(function_exists("memory_get_peak_usage")) {
$this->_memoryUsage = memory_get_peak_usage(true);
} else if(function_exists("memory_get_usage")) {
$this->_memoryUsage = memory_get_usage(true);
}
}
function GetMemoryUsage() {
return round($this->_memoryUsage / 1024 / 1024,2);
}
function SaveStep($postCount) {
$this->SetMemoryUsage();
$this->_lastPost = $postCount;
$this->_lastTime = $this->GetMicrotimeFloat();
$this->Save();
}
function GetTime() {
return round($this->_endTime - $this->_startTime,2);
}
function GetLastTime() {
return round($this->_lastTime - $this->_startTime,2);
}
function GetLastPost() {
return $this->_lastPost;
}
var $_usedXml = false;
var $_xmlSuccess = false;
var $_xmlPath = '';
var $_xmlUrl = '';
function StartXml($path,$url) {
$this->_usedXml = true;
$this->_xmlPath = $path;
$this->_xmlUrl = $url;
$this->Save();
}
function EndXml($success) {
$this->_xmlSuccess = $success;
$this->Save();
}
var $_usedZip = false;
var $_zipSuccess = false;
var $_zipPath = '';
var $_zipUrl = '';
function StartZip($path,$url) {
$this->_usedZip = true;
$this->_zipPath = $path;
$this->_zipUrl = $url;
$this->Save();
}
function EndZip($success) {
$this->_zipSuccess = $success;
$this->Save();
}
var $_usedGoogle = false;
var $_googleUrl = '';
var $_gooogleSuccess = false;
var $_googleStartTime = 0;
var $_googleEndTime = 0;
function StartGooglePing($url) {
$this->_googleUrl = true;
$this->_usedGoogle = true;
$this->_googleStartTime = $this->GetMicrotimeFloat();
$this->Save();
}
function EndGooglePing($success) {
$this->_googleEndTime = $this->GetMicrotimeFloat();
$this->_gooogleSuccess = $success;
$this->Save();
}
function GetGoogleTime() {
return round($this->_googleEndTime - $this->_googleStartTime,2);
}
var $_usedYahoo = false;
var $_yahooUrl = '';
var $_yahooSuccess = false;
var $_yahooStartTime = 0;
var $_yahooEndTime = 0;
function StartYahooPing($url) {
$this->_yahooUrl = $url;
$this->_usedYahoo = true;
$this->_yahooStartTime = $this->GetMicrotimeFloat();
$this->Save();
}
function EndYahooPing($success) {
$this->_yahooEndTime = $this->GetMicrotimeFloat();
$this->_yahooSuccess = $success;
$this->Save();
}
function GetYahooTime() {
return round($this->_yahooEndTime - $this->_yahooStartTime,2);
}
var $_usedAsk = false;
var $_askUrl = '';
var $_askSuccess = false;
var $_askStartTime = 0;
var $_askEndTime = 0;
function StartAskPing($url) {
$this->_usedAsk = true;
$this->_askUrl = $url;
$this->_askStartTime = $this->GetMicrotimeFloat();
$this->Save();
}
function EndAskPing($success) {
$this->_askEndTime = $this->GetMicrotimeFloat();
$this->_askSuccess = $success;
$this->Save();
}
function GetAskTime() {
return round($this->_askEndTime - $this->_askStartTime,2);
}
var $_usedMsn = false;
var $_msnUrl = '';
var $_msnSuccess = false;
var $_msnStartTime = 0;
var $_msnEndTime = 0;
function StartMsnPing($url) {
$this->_usedMsn = true;
$this->_msnUrl = $url;
$this->_msnStartTime = $this->GetMicrotimeFloat();
$this->Save();
}
function EndMsnPing($success) {
$this->_msnEndTime = $this->GetMicrotimeFloat();
$this->_msnSuccess = $success;
$this->Save();
}
function GetMsnTime() {
return round($this->_msnEndTime - $this->_msnStartTime,2);
}
function GetMicrotimeFloat() {
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
}
/**
* Represents an item in the page list
* @author Arne Brachhold
* @package sitemap
* @since 3.0
*/
class GoogleSitemapGeneratorPage {
/**
* @var string $_url Sets the URL or the relative path to the blog dir of the page
* @access private
*/
var $_url;
/**
* @var float $_priority Sets the priority of this page
* @access private
*/
var $_priority;
/**
* @var string $_changeFreq Sets the chanfe frequency of the page. I want Enums!
* @access private
*/
var $_changeFreq;
/**
* @var int $_lastMod Sets the lastMod date as a UNIX timestamp.
* @access private
*/
var $_lastMod;
/**
* Initialize a new page object
*
* @since 3.0
* @access public
* @author Arne Brachhold
* @param bool $enabled Should this page be included in thesitemap
* @param string $url The URL or path of the file
* @param float $priority The Priority of the page 0.0 to 1.0
* @param string $changeFreq The change frequency like daily, hourly, weekly
* @param int $lastMod The last mod date as a unix timestamp
*/
function GoogleSitemapGeneratorPage($url="",$priority=0.0,$changeFreq="never",$lastMod=0) {
$this->SetUrl($url);
$this->SetProprity($priority);
$this->SetChangeFreq($changeFreq);
$this->SetLastMod($lastMod);
}
/**
* Returns the URL of the page
*
* @return string The URL
*/
function GetUrl() {
return $this->_url;
}
/**
* Sets the URL of the page
*
* @param string $url The new URL
*/
function SetUrl($url) {
$this->_url=(string) $url;
}
/**
* Returns the priority of this page
*
* @return float the priority, from 0.0 to 1.0
*/
function GetPriority() {
return $this->_priority;
}
/**
* Sets the priority of the page
*
* @param float $priority The new priority from 0.1 to 1.0
*/
function SetProprity($priority) {
$this->_priority=floatval($priority);
}
/**
* Returns the change frequency of the page
*
* @return string The change frequncy like hourly, weekly, monthly etc.
*/
function GetChangeFreq() {
return $this->_changeFreq;
}
/**
* Sets the change frequency of the page
*
* @param string $changeFreq The new change frequency
*/
function SetChangeFreq($changeFreq) {
$this->_changeFreq=(string) $changeFreq;
}
/**
* Returns the last mod of the page
*
* @return int The lastmod value in seconds
*/
function GetLastMod() {
return $this->_lastMod;
}
/**
* Sets the last mod of the page
*
* @param int $lastMod The lastmod of the page
*/
function SetLastMod($lastMod) {
$this->_lastMod=intval($lastMod);
}
function Render() {
if($this->_url == "/" || empty($this->_url)) return '';
$r="";
$r.= "\t\n";
$r.= "\t\t" . $this->EscapeXML($this->_url) . "\n";
if($this->_lastMod>0) $r.= "\t\t" . date('Y-m-d\TH:i:s+00:00',$this->_lastMod) . "\n";
if(!empty($this->_changeFreq)) $r.= "\t\t" . $this->_changeFreq . "\n";
if($this->_priority!==false && $this->_priority!=="") $r.= "\t\t" . number_format($this->_priority,1) . "\n";
$r.= "\t\n";
return $r;
}
function EscapeXML($string) {
return str_replace ( array ( '&', '"', "'", '<', '>'), array ( '&' , '"', ''' , '<' , '>'), $string);
}
}
class GoogleSitemapGeneratorXmlEntry {
var $_xml;
function GoogleSitemapGeneratorXmlEntry($xml) {
$this->_xml = $xml;
}
function Render() {
return $this->_xml;
}
}
class GoogleSitemapGeneratorDebugEntry extends GoogleSitemapGeneratorXmlEntry {
function Render() {
return "";
}
}
/**
* Base class for all priority providers
* @author Arne Brachhold
* @package sitemap
* @since 3.0
*/
class GoogleSitemapGeneratorPrioProviderBase {
/**
* @var int $_totalComments The total number of comments of all posts
* @access protected
*/
var $_totalComments=0;
/**
* @var int $_totalComments The total number of posts
* @access protected
*/
var $_totalPosts=0;
/**
* Returns the (translated) name of this priority provider
*
* @since 3.0
* @access public
* @author Arne Brachhold
* @return string The translated name
*/
function GetName() {
return "";
}
/**
* Returns the (translated) description of this priority provider
*
* @since 3.0
* @access public
* @author Arne Brachhold
* @return string The translated description
*/
function GetDescription() {
return "";
}
/**
* Initializes a new priority provider
*
* @param $totalComments int The total number of comments of all posts
* @param $totalPosts int The total number of posts
* @since 3.0
* @access public
* @author Arne Brachhold
*/
function GoogleSitemapGeneratorPrioProviderBase($totalComments,$totalPosts) {
$this->_totalComments=$totalComments;
$this->_totalPosts=$totalPosts;
}
/**
* Returns the priority for a specified post
*
* @param $postID int The ID of the post
* @param $commentCount int The number of comments for this post
* @since 3.0
* @access public
* @author Arne Brachhold
* @return int The calculated priority
*/
function GetPostPriority($postID,$commentCount) {
return 0;
}
}
/**
* Priority Provider which calculates the priority based on the number of comments
* @author Arne Brachhold
* @package sitemap
* @since 3.0
*/
class GoogleSitemapGeneratorPrioByCountProvider extends GoogleSitemapGeneratorPrioProviderBase {
/**
* Returns the (translated) name of this priority provider
*
* @since 3.0
* @access public
* @author Arne Brachhold
* @return string The translated name
*/
function GetName() {
return __("Comment Count",'sitemap');
}
/**
* Returns the (translated) description of this priority provider
*
* @since 3.0
* @access public
* @author Arne Brachhold
* @return string The translated description
*/
function GetDescription() {
return __("Uses the number of comments of the post to calculate the priority",'sitemap');
}
/**
* Initializes a new priority provider which calculates the post priority based on the number of comments
*
* @param $totalComments int The total number of comments of all posts
* @param $totalPosts int The total number of posts
* @since 3.0
* @access public
* @author Arne Brachhold
*/
function GoogleSitemapGeneratorPrioByCountProvider($totalComments,$totalPosts) {
parent::GoogleSitemapGeneratorPrioProviderBase($totalComments,$totalPosts);
}
/**
* Returns the priority for a specified post
*
* @param $postID int The ID of the post
* @param $commentCount int The number of comments for this post
* @since 3.0
* @access public
* @author Arne Brachhold
* @return int The calculated priority
*/
function GetPostPriority($postID,$commentCount) {
$prio=0;
if($this->_totalComments>0 && $commentCount>0) {
$prio = round(($commentCount*100/$this->_totalComments)/100,1);
} else {
$prio = 0;
}
return $prio;
}
}
/**
* Priority Provider which calculates the priority based on the average number of comments
* @author Arne Brachhold
* @package sitemap
* @since 3.0
*/
class GoogleSitemapGeneratorPrioByAverageProvider extends GoogleSitemapGeneratorPrioProviderBase {
/**
* @var int $_average The average number of comments per post
* @access protected
*/
var $_average=0.0;
/**
* Returns the (translated) name of this priority provider
*
* @since 3.0
* @access public
* @author Arne Brachhold
* @return string The translated name
*/
function GetName() {
return __("Comment Average",'sitemap');
}
/**
* Returns the (translated) description of this priority provider
*
* @since 3.0
* @access public
* @author Arne Brachhold
* @return string The translated description
*/
function GetDescription() {
return __("Uses the average comment count to calculate the priority",'sitemap');
}
/**
* Initializes a new priority provider which calculates the post priority based on the average number of comments
*
* @param $totalComments int The total number of comments of all posts
* @param $totalPosts int The total number of posts
* @since 3.0
* @access public
* @author Arne Brachhold
*/
function GoogleSitemapGeneratorPrioByAverageProvider($totalComments,$totalPosts) {
parent::GoogleSitemapGeneratorPrioProviderBase($totalComments,$totalPosts);
if($this->_totalComments>0 && $this->_totalPosts>0) {
$this->_average= (double) $this->_totalComments / $this->_totalPosts;
}
}
/**
* Returns the priority for a specified post
*
* @param $postID int The ID of the post
* @param $commentCount int The number of comments for this post
* @since 3.0
* @access public
* @author Arne Brachhold
* @return int The calculated priority
*/
function GetPostPriority($postID,$commentCount) {
$prio = 0;
//Do not divide by zero!
if($this->_average==0) {
if($commentCount>0) $prio = 1;
else $prio = 0;
} else {
$prio = $commentCount/$this->_average;
if($prio>1) $prio = 1;
else if($prio<0) $prio = 0;
}
return round($prio,1);
}
}
/**
* Priority Provider which calculates the priority based on the popularity by the PopularityContest Plugin
* @author Arne Brachhold
* @package sitemap
* @since 3.0
*/
class GoogleSitemapGeneratorPrioByPopularityContestProvider extends GoogleSitemapGeneratorPrioProviderBase {
/**
* Returns the (translated) name of this priority provider
*
* @since 3.0
* @access public
* @author Arne Brachhold
* @return string The translated name
*/
function GetName() {
return __("Popularity Contest",'sitemap');
}
/**
* Returns the (translated) description of this priority provider
*
* @since 3.0
* @access public
* @author Arne Brachhold
* @return string The translated description
*/
function GetDescription() {
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 Popularity Contest Plugin from Alex King. See Settings and Most Popular Posts",'sitemap')))));
}
/**
* Initializes a new priority provider which calculates the post priority based on the popularity by the PopularityContest Plugin
*
* @param $totalComments int The total number of comments of all posts
* @param $totalPosts int The total number of posts
* @since 3.0
* @access public
* @author Arne Brachhold
*/
function GoogleSitemapGeneratorPrioByPopularityContestProvider($totalComments,$totalPosts) {
parent::GoogleSitemapGeneratorPrioProviderBase($totalComments,$totalPosts);
}
/**
* Returns the priority for a specified post
*
* @param $postID int The ID of the post
* @param $commentCount int The number of comments for this post
* @since 3.0
* @access public
* @author Arne Brachhold
* @return int The calculated priority
*/
function GetPostPriority($postID,$commentCount) {
//$akpc is the global instance of the Popularity Contest Plugin
global $akpc,$posts;
$res=0;
//Better check if its there
if(!empty($akpc) && is_object($akpc)) {
//Is the method we rely on available?
if(method_exists($akpc,"get_post_rank")) {
if(!is_array($posts) || !$posts) $posts = array();
if(!isset($posts[$postID])) $posts[$postID] = get_post($postID);
//popresult comes as a percent value
$popresult=$akpc->get_post_rank($postID);
if(!empty($popresult) && strpos($popresult,"%")!==false) {
//We need to parse it to get the priority as an int (percent)
$matches=null;
preg_match("/([0-9]{1,3})\%/si",$popresult,$matches);
if(!empty($matches) && is_array($matches) && count($matches)==2) {
//Divide it so 100% = 1, 10% = 0.1
$res=round(intval($matches[1])/100,1);
}
}
}
}
return $res;
}
}
/**
* Class to generate a sitemaps.org Sitemaps compliant sitemap of a WordPress blog.
*
* @package sitemap
* @author Arne Brachhold
* @since 3.0
*/
class GoogleSitemapGenerator {
/**
* @var Version of the generator
*/
var $_version = "3.0.3";
/**
* @var Version of the generator in SVN
*/
var $_svnVersion = '$Id: sitemap.php 28069 2007-12-30 17:35:00Z arnee $';
/**
* @var string The full path to the blog directory
*/
var $_homePath = "";
/**
* @var array The unserialized array with the stored options
*/
var $_options = array();
/**
* @var array The saved additional pages
*/
var $_pages = array();
/**
* @var array A list of available freuency names
*/
var $_freqNames = array();
/**
* @var array A list of class names which my be called for priority calculation
*/
var $_prioProviders = array();
/**
* @var bool True if init complete (options loaded etc)
*/
var $_initiated = false;
/**
* @var string Holds the last error if one occurs when writing the files
*/
var $_lastError=null;
/**
* @var array Contains the elements of the sitemap
*/
var $_content = array();
/**
* @var int The last handled post ID
*/
var $_lastPostID = 0;
/**
* @var bool Defines if the sitemap building process is active at the moment
*/
var $_isActive = false;
/**
* @var bool Defines if the sitemap building process has been scheduled via Wp cron
*/
var $_isScheduled = false;
/**
* @var object The file handle which is used to write the sitemap file
*/
var $_fileHandle = null;
/**
* @var object The file handle which is used to write the zipped sitemap file
*/
var $_fileZipHandle = null;
/**
* Returns the path to the blog directory
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @return string The full path to the blog directory
*/
function GetHomePath() {
$res="";
//Check if we are in the admin area -> get_home_path() is avaiable
if(function_exists("get_home_path")) {
$res = get_home_path();
} else {
//get_home_path() is not available, but we can't include the admin
//libraries because many plugins check for the "check_admin_referer"
//function to detect if you are on an admin page. So we have to copy
//the get_home_path function in our own...
$home = get_option( 'home' );
if ( $home != '' && $home != get_option( 'siteurl' ) ) {
$home_path = parse_url( $home );
$home_path = $home_path['path'];
$root = str_replace( $_SERVER["PHP_SELF"], '', $_SERVER["SCRIPT_FILENAME"] );
$home_path = trailingslashit( $root.$home_path );
} else {
$home_path = ABSPATH;
}
$res = $home_path;
}
return $res;
}
/**
* Returns the path to the directory where the plugin file is located
* @since 3.0b5
* @access private
* @author Arne Brachhold
* @return string The path to the plugin directory
*/
function GetPluginPath() {
$path = dirname(__FILE__);
return trailingslashit(str_replace("\\","/",$path));
}
/**
* Returns the URL to the directory where the plugin file is located
* @since 3.0b5
* @access private
* @author Arne Brachhold
* @return string The URL to the plugin directory
*/
function GetPluginUrl() {
$path = dirname(__FILE__);
$path = str_replace("\\","/",$path);
$path = trailingslashit(get_bloginfo('wpurl')) . trailingslashit(substr($path,strpos($path,"wp-content/")));
return $path;
}
/**
* Returns the URL to default XSLT style if it exists
* @since 3.0b5
* @access private
* @author Arne Brachhold
* @return string The URL to the default stylesheet, empry string if not available.
*/
function GetDefaultStyle() {
$p = $this->GetPluginPath();
if(file_exists($p . "sitemap.xsl")) {
return $this->GetPluginUrl() . 'sitemap.xsl';
}
return '';
}
/**
* Returns the path to the robots.txt file in the blog root
*
* @since 3.0b8
* @access private
* @author Arne Brachhold
* @return The full path to the robots.txt file
*/
function GetRobotsFilePath() {
return trailingslashit($this->GetHomePath()) . 'robots.txt';
}
/**
* Returns the URL to the robots.txt file in the blog root
*
* @since 3.0b8
* @access private
* @author Arne Brachhold
* @return The full URL to the robots.txt file
*/
function GetRobotsFileUrl() {
return trailingslashit(get_bloginfo('siteurl')) . 'robots.txt';
}
/**
* Sets up the default configuration
*
* @since 3.0
* @access private
* @author Arne Brachhold
*/
function InitOptions() {
$this->_options=array();
$this->_options["sm_b_prio_provider"]="GoogleSitemapGeneratorPrioByCountProvider"; //Provider for automatic priority calculation
$this->_options["sm_b_filename"]="sitemap.xml"; //Name of the Sitemap file
$this->_options["sm_b_debug"]=true; //Write debug messages in the xml file
$this->_options["sm_b_xml"]=true; //Create a .xml file
$this->_options["sm_b_gzip"]=true; //Create a gzipped .xml file(.gz) file
$this->_options["sm_b_ping"]=true; //Auto ping Google
$this->_options["sm_b_pingyahoo"]=false; //Auto ping YAHOO
$this->_options["sm_b_yahookey"]=''; //YAHOO Application Key
$this->_options["sm_b_pingask"]=true; //Auto ping Ask.com
$this->_options["sm_b_pingmsn"]=true; //Auto ping MSN
$this->_options["sm_b_manual_enabled"]=false; //Allow manual creation of the sitemap via GET request
$this->_options["sm_b_auto_enabled"]=true; //Rebuild sitemap when content is changed
$this->_options["sm_b_auto_delay"]=false; //Use WP Cron to execute the building process in the background
$this->_options["sm_b_manual_key"]=md5(microtime());//The secret key to build the sitemap via GET request
$this->_options["sm_b_memory"] = ''; //Set Memory Limit (e.g. 16M)
$this->_options["sm_b_time"] = -1; //Set time limit in seconds, 0 for unlimited, -1 for disabled
$this->_options["sm_b_max_posts"] = -1; //Maximum number of posts, <= 0 for all
$this->_options["sm_b_safemode"] = false; //Enable MySQL Safe Mode (doesn't use unbuffered results)
$this->_options["sm_b_style"] = $this->GetDefaultStyle(); //Include a stylesheet in the XML
$this->_options["sm_b_robots"] = false; //Modify or create robots.txt file in blog root which contains the sitemap location
$this->_options["sm_b_exclude"] = array(); //List of post / page IDs to exclude
$this->_options["sm_b_location_mode"]="auto"; //Mode of location, auto or manual
$this->_options["sm_b_filename_manual"]=""; //Manuel filename
$this->_options["sm_b_fileurl_manual"]=""; //Manuel fileurl
$this->_options["sm_in_home"]=true; //Include homepage
$this->_options["sm_in_posts"]=true; //Include posts
$this->_options["sm_in_pages"]=true; //Include static pages
$this->_options["sm_in_cats"]=false; //Include categories
$this->_options["sm_in_arch"]=false; //Include archives
$this->_options["sm_in_auth"]=false; //Include author pages
$this->_options["sm_in_tags"]=false; //Include tag pages
$this->_options["sm_cf_home"]="daily"; //Change frequency of the homepage
$this->_options["sm_cf_posts"]="monthly"; //Change frequency of posts
$this->_options["sm_cf_pages"]="weekly"; //Change frequency of static pages
$this->_options["sm_cf_cats"]="weekly"; //Change frequency of categories
$this->_options["sm_cf_auth"]="weekly"; //Change frequency of author pages
$this->_options["sm_cf_arch_curr"]="daily"; //Change frequency of the current archive (this month)
$this->_options["sm_cf_arch_old"]="yearly"; //Change frequency of older archives
$this->_options["sm_cf_tags"]="weekly"; //Change frequency of tags
$this->_options["sm_pr_home"]=1.0; //Priority of the homepage
$this->_options["sm_pr_posts"]=0.6; //Priority of posts (if auto prio is disabled)
$this->_options["sm_pr_posts_min"]=0.2; //Minimum Priority of posts, even if autocalc is enabled
$this->_options["sm_pr_pages"]=0.6; //Priority of static pages
$this->_options["sm_pr_cats"]=0.3; //Priority of categories
$this->_options["sm_pr_arch"]=0.3; //Priority of archives
$this->_options["sm_pr_auth"]=0.3; //Priority of author pages
$this->_options["sm_pr_tags"]=0.3; //Priority of tags
$this->_options["sm_i_donated"]=false; //Did you donate? Thank you! :)
$this->_options["sm_i_hide_donated"]=false; //And hide the thank you..
$this->_options["sm_i_install_date"]=time(); //The installation date
$this->_options["sm_i_hide_note"]=false; //Hide the note which appears after 30 days
$this->_options["sm_i_hide_donors"]=false; //Hide the list of donations
}
/**
* Loads the configuration from the database
*
* @since 3.0
* @access private
* @author Arne Brachhold
*/
function LoadOptions() {
$this->InitOptions();
//First init default values, then overwrite it with stored values so we can add default
//values with an update which get stored by the next edit.
$storedoptions=get_option("sm_options");
if($storedoptions && is_array($storedoptions)) {
foreach($storedoptions AS $k=>$v) {
$this->_options[$k]=$v;
}
} else update_option("sm_options",$this->_options); //First time use, store default values
}
/**
* Initializes a new Google Sitemap Generator
*
* @since 3.0
* @access private
* @author Arne Brachhold
*/
function GoogleSitemapGenerator() {
$this->_freqNames = array("always", "hourly", "daily", "weekly", "monthly", "yearly","never");
$this->_prioProviders = array();
$this->_homePath = $this->GetHomePath();
}
/**
* Returns the version of the generator
*
* @since 3.0
* @access public
* @author Arne Brachhold
* @return int The version
*/
function GetVersion() {
return $this->_version;
}
/**
* Returns all parent classes of a class
*
* @param $className string The name of the class
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @return array An array which contains the names of the parent classes
*/
function GetParentClasses($classname) {
$parent = get_parent_class($classname);
$parents = array();
if (!empty($parent)) {
$parents = $this->GetParentClasses($parent);
$parents[] = strtolower($parent);
}
return $parents;
}
/**
* Returns if a class is a subclass of another class
*
* @param $className string The name of the class
* @param $$parentName string The name of the parent class
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @return bool true if the given class is a subclass of the other one
*/
function IsSubclassOf($className, $parentName) {
$className = strtolower($className);
$parentName = strtolower($parentName);
if(empty($className) || empty($parentName) || !class_exists($className) || !class_exists($parentName)) return false;
$parents=$this->GetParentClasses($className);
return in_array($parentName,$parents);
}
/**
* Loads up the configuration and validates the prioity providers
*
* This method is only called if the sitemaps needs to be build or the admin page is displayed.
*
* @since 3.0
* @access private
* @author Arne Brachhold
*/
function Initate() {
if(!$this->_initiated) {
//Loading language file...
//load_plugin_textdomain('sitemap');
//Hmm, doesn't work if the plugin file has its own directory.
//Let's make it our way... load_plugin_textdomain() searches only in the wp-content/plugins dir.
$currentLocale = get_locale();
if(!empty($currentLocale)) {
$moFile = dirname(__FILE__) . "/sitemap-" . $currentLocale . ".mo";
if(@file_exists($moFile) && is_readable($moFile)) load_textdomain('sitemap', $moFile);
}
$this->LoadOptions();
$this->LoadPages();
add_filter("sm_add_prio_provider",array(&$this, 'AddDefaultPrioProviders'));
$r = apply_filters("sm_add_prio_provider",$this->_prioProviders);
if($r != null) $this->_prioProviders = $r;
$this->ValidatePrioProviders();
$this->_initiated = true;
}
}
/**
* Returns the instance of the Sitemap Generator
*
* @since 3.0
* @access public
* @return GoogleSitemapGenerator The instance or null if not available.
* @author Arne Brachhold
*/
function &GetInstance() {
if(isset($GLOBALS["sm_instance"])) {
return $GLOBALS["sm_instance"];
} else return null;
}
/**
* Returns if the sitemap building process is currently active
*
* @since 3.0
* @access public
* @return bool true if active
* @author Arne Brachhold
*/
function IsActive() {
$inst = &GoogleSitemapGenerator::GetInstance();
return ($inst != null && $inst->_isActive);
}
/**
* Returns if the compressed sitemap was activated
*
* @since 3.0b8
* @access private
* @author Arne Brachhold
* @return true if compressed
*/
function IsGzipEnabled() {
return ($this->GetOption("b_gzip")===true && function_exists("gzwrite"));
}
/**
* Returns if this version of WordPress supports the new taxonomy system
*
* @since 3.0b8
* @access private
* @author Arne Brachhold
* @return true if supported
*/
function IsTaxonomySupported() {
return (function_exists("get_taxonomy") && function_exists("get_terms"));
}
/**
* Enables the Google Sitemap Generator and registers the WordPress hooks
*
* @since 3.0
* @access public
* @author Arne Brachhold
*/
function Enable() {
if(!isset($GLOBALS["sm_instance"])) {
$GLOBALS["sm_instance"]=new GoogleSitemapGenerator();
//Register the sitemap creator to wordpress...
add_action('admin_menu', array(&$GLOBALS["sm_instance"], 'RegisterAdminPage'));
//Register to various events... @WordPress Dev Team: I wish me a 'public_content_changed' action :)
//Publish + Delete should work in most cases.
//If a new post is saved //Disabled for now...
//add_action('save_post', array(&$GLOBALS["sm_instance"], 'CheckForAutoBuild'),9999,1);
//Existing post gets edited //Disabled for now...
//add_action('edit_post', array(&$GLOBALS["sm_instance"], 'CheckForAutoBuild'),9999,1);
//Existing posts gets deleted
add_action('delete_post', array(&$GLOBALS["sm_instance"], 'CheckForAutoBuild'),9999,1);
//Existing post gets published
add_action('publish_post', array(&$GLOBALS["sm_instance"], 'CheckForAutoBuild'),9999,1);
//WP Cron hook
add_action('sm_build_cron', array(&$GLOBALS["sm_instance"], 'BuildSitemap'),1,0);
//Manual Hook via GET
$GLOBALS["sm_instance"]->CheckForManualBuild();
}
}
/**
* Checks if sitemap building after content changed is enabled and rebuild the sitemap
*
* @param int $postID The ID of the post to handle. Used to avoid double rebuilding if more than one hook was fired.
* @since 3.0
* @access public
* @author Arne Brachhold
*/
function CheckForAutoBuild($postID) {
$this->Initate();
//Build one time per post and if not importing.
if($this->GetOption("b_auto_enabled")===true && $this->_lastPostID != $postID && (!defined('WP_IMPORTING') || WP_IMPORTING != true)) {
$this->_lastPostID = $postID;
//Build the sitemap directly or schedule it with WP cron
if($this->GetOption("b_auto_delay")==true) {
if(!$this->_isScheduled) {
//Schedule in 10 seconds, this should be enough to catch all changes
wp_schedule_single_event(time()+10,'sm_build_cron');
$this->_isScheduled = true;
}
} else {
$this->BuildSitemap();
}
}
}
/**
* Checks if the rebuild request was send and starts to rebuilt the sitemap
*
* @since 3.0
* @access public
* @author Arne Brachhold
*/
function CheckForManualBuild() {
if(!empty($_GET["sm_command"]) && !empty($_GET["sm_key"])) {
$this->Initate();
if($this->GetOption("b_manual_enabled")===true && $_GET["sm_command"]=="build" && $_GET["sm_key"]==$this->GetOption("b_manual_key")) {
$this->BuildSitemap();
exit;
}
}
}
/**
* Validates all given Priority Providers by checking them for required methods and existence
*
* @since 3.0
* @access private
* @author Arne Brachhold
*/
function ValidatePrioProviders() {
$validProviders=array();
for($i=0; $i_prioProviders); $i++) {
if(class_exists($this->_prioProviders[$i])) {
if($this->IsSubclassOf($this->_prioProviders[$i],"GoogleSitemapGeneratorPrioProviderBase")) {
array_push($validProviders,$this->_prioProviders[$i]);
}
}
}
$this->_prioProviders=$validProviders;
if(!$this->GetOption("b_prio_provider")) {
if(!in_array($this->GetOption("b_prio_provider"),$this->_prioProviders,true)) {
$this->SetOption("b_prio_provider","");
}
}
}
/**
* Adds the default Priority Providers to the provider list
*
* @since 3.0
* @access private
* @author Arne Brachhold
*/
function AddDefaultPrioProviders($providers) {
array_push($providers,"GoogleSitemapGeneratorPrioByCountProvider");
array_push($providers,"GoogleSitemapGeneratorPrioByAverageProvider");
if(class_exists("ak_popularity_contest")) {
array_push($providers,"GoogleSitemapGeneratorPrioByPopularityContestProvider");
}
return $providers;
}
/**
* Loads the stored pages from the database
*
* @since 3.0
* @access private
* @author Arne Brachhold
*/
function LoadPages() {
global $wpdb;
$needsUpdate=false;
$pagesString=$wpdb->get_var("SELECT option_value FROM $wpdb->options WHERE option_name = 'sm_cpages'");
//Class sm_page was renamed with 3.0 -> rename it in serialized value for compatibility
if(!empty($pagesString) && strpos($pagesString,"sm_page")!==false) {
$pagesString = str_replace("O:7:\"sm_page\"","O:26:\"GoogleSitemapGeneratorPage\"",$pagesString);
$needsUpdate=true;
}
if(!empty($pagesString)) {
$storedpages=unserialize($pagesString);
$this->_pages=$storedpages;
} else {
$this->_pages=array();
}
if($needsUpdate) $this->SavePages();
}
/**
* Saved the additional pages back to the database
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @return true on success
*/
function SavePages() {
$oldvalue = get_option("sm_cpages");
if($oldvalue == $this->_pages) {
return true;
} else {
delete_option("sm_cpages");
//Add the option, Note the autoload=false because when the autoload happens, our class GoogleSitemapGeneratorPage doesn't exist
add_option("sm_cpages",$this->_pages,"Storage for custom pages of the sitemap plugin","no");
return true;
}
}
/**
* Returns the URL for the sitemap file
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @param bool $forceAuto Force the return value to the autodetected value.
* @return The URL to the Sitemap file
*/
function GetXmlUrl($forceAuto=false) {
if(!$forceAuto && $this->GetOption("b_location_mode")=="manual") {
return $this->GetOption("b_fileurl_manual");
} else {
return trailingslashit(get_bloginfo('siteurl')). $this->GetOption("b_filename");
}
}
/**
* Returns the URL for the gzipped sitemap file
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @param bool $forceAuto Force the return value to the autodetected value.
* @return The URL to the gzipped Sitemap file
*/
function GetZipUrl($forceAuto=false) {
return $this->GetXmlUrl($forceAuto) . ".gz";
}
/**
* Returns the file system path to the sitemap file
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @param bool $forceAuto Force the return value to the autodetected value.
* @return The file system path;
*/
function GetXmlPath($forceAuto=false) {
if(!$forceAuto && $this->GetOption("b_location_mode")=="manual") {
return $this->GetOption("b_filename_manual");
} else {
return $this->GetHomePath() . $this->GetOption("b_filename");
}
}
/**
* Returns the file system path to the gzipped sitemap file
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @param bool $forceAuto Force the return value to the autodetected value.
* @return The file system path;
*/
function GetZipPath($forceAuto=false) {
return $this->GetXmlPath($forceAuto) . ".gz";
}
/**
* Returns the option value for the given key
* Alias for getOption
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @param $key string The Configuration Key
* @return mixed The value
*/
function Go($key) {
return $this->getOption($key);
}
/**
* Returns the option value for the given key
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @param $key string The Configuration Key
* @return mixed The value
*/
function GetOption($key) {
if(strpos($key,"sm_")!==0) $key="sm_" . $key;
if(array_key_exists($key,$this->_options)) {
return $this->_options[$key];
} else return null;
}
/**
* Sets an option to a new value
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @param $key string The configuration key
* @param $value mixed The new object
*/
function SetOption($key,$value) {
if(strstr($key,"sm_")!==0) $key="sm_" . $key;
$this->_options[$key]=$value;
}
/**
* Saves the options back to the database
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @return bool true on success
*/
function SaveOptions() {
$oldvalue = get_option("sm_options");
if($oldvalue == $this->_options) {
return true;
} else return update_option("sm_options",$this->_options);
}
/**
* Retrieves the number of comments of a post in a asso. array
* The key is the postID, the value the number of comments
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @return array An array with postIDs and their comment count
*/
function GetComments() {
global $wpdb;
$comments=array();
//Query comments and add them into the array
$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`");
if($commentRes) {
foreach($commentRes as $comment) {
$comments[$comment->post_id]=$comment->comment_count;
}
}
return $comments;
}
/**
* Calculates the full number of comments from an sm_getComments() generated array
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @param $comments array The Array with posts and c0mment count
* @see sm_getComments
* @return The full number of comments
*/
function GetCommentCount($comments) {
$commentCount=0;
foreach($comments AS $k=>$v) {
$commentCount+=$v;
}
return $commentCount;
}
/**
* Adds a url to the sitemap. You can use this method or call AddElement directly.
*
* @since 3.0
* @access public
* @author Arne Brachhold
* @param $loc string The location (url) of the page
* @param $lastMod int The last Modification time as a UNIX timestamp
* @param $changeFreq string The change frequenty of the page, Valid values are "always", "hourly", "daily", "weekly", "monthly", "yearly" and "never".
* @param $priorty float The priority of the page, between 0.0 and 1.0
* @see AddElement
* @return string The URL node
*/
function AddUrl($loc,$lastMod=0,$changeFreq="monthly",$priority=0.5) {
$page = new GoogleSitemapGeneratorPage($loc,$priority,$changeFreq,$lastMod);
$this->AddElement($page);
}
/**
* Adds an element to the sitemap
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @param $page The element
*/
function AddElement(&$page) {
if(empty($page)) return;
$s = $page->Render();
if($this->_fileZipHandle && $this->IsGzipEnabled()) {
gzwrite($this->_fileZipHandle,$s);
}
if($this->_fileHandle && $this->GetOption("b_xml")) {
fwrite($this->_fileHandle,$s);
}
}
/**
* Checks if a file is writable and tries to make it if not.
*
* @since 3.05b
* @access private
* @author VJTD3
* @return bool true if writable
*/
function IsFileWritable($filename) {
//can we write?
if(!is_writable($filename)) {
//no we can't.
if(!@chmod($filename, 0666)) {
$pathtofilename = dirname($filename);
//Lets check if parent directory is writable.
if(!is_writable($pathtofilename)) {
//it's not writeable too.
if(!@chmod($pathtoffilename, 0666)) {
//darn couldn't fix up parrent directory this hosting is foobar.
//Lets error because of the permissions problems.
return false;
}
}
}
}
//we can write, return 1/true/happy dance.
return true;
}
/**
* Creates or opens the robots.txt in blog root and inserts the sitemap location
*
* @since 3.0b8
* @access private
* @author Arne Brachhold
* @return true on success
*/
function WriteRobotsFile() {
$file = $this->GetRobotsFilePath();
$marker = 'XML-SITEMAP-PLUGIN';
$current = extract_from_markers($file,$marker);
if(is_array($current)) $current = $current[0];
$smUrl = $this->GetXmlUrl();
if($this->IsGzipEnabled()) {
$smUrl = $this->GetZipUrl();
}
$new = "Sitemap: " . $smUrl;
if($current != $new) {
if($this->IsFileWritable($file)) return insert_with_markers($file,$marker,array($new));
else return false;
}
return true;
}
/**
* Builds the sitemap and writes it into a xml file.
*
* @since 3.0
* @access public
* @author Arne Brachhold
* @return array An array with messages such as failed writes etc.
*/
function BuildSitemap() {
global $wpdb, $posts, $wp_version;
$this->Initate();
if($this->GetOption("b_memory")!='') {
@ini_set("memory_limit",$this->GetOption("b_memory"));
}
if($this->GetOption("sm_b_time")!=-1) {
@set_time_limit($this->GetOption("sm_b_time"));
}
//This object saves the status information of the script directly to the database
$status = new GoogleSitemapGeneratorStatus();
//Other plugins can detect if the building process is active
$this->_isActive = true;
//$this->AddElement(new GoogleSitemapGeneratorXmlEntry());
//Debug mode?
$debug=$this->GetOption("b_debug");
if($this->GetOption("b_xml")) {
$fileName = $this->GetXmlPath();
$status->StartXml($this->GetXmlPath(),$this->GetXmlUrl());
if($this->IsFileWritable($fileName)) {
$this->_fileHandle = fopen($fileName,"w");
if(!$this->_fileHandle) $status->EndXml(false,"Not openable");
} else $status->EndXml(false,"not writable");
}
//Write gzipped sitemap file
if($this->IsGzipEnabled()) {
$fileName = $this->GetZipPath();
$status->StartZip($this->GetZipPath(),$this->GetZipUrl());
if($this->IsFileWritable($fileName)) {
$this->_fileZipHandle = gzopen($fileName,"w1");
if(!$this->_fileZipHandle) $status->EndZip(false,"Not openable");
} else $status->EndZip(false,"not writable");
}
if(!$this->_fileHandle && !$this->_fileZipHandle) {
$status->End();
return;
}
//Content of the XML file
$this->AddElement(new GoogleSitemapGeneratorXmlEntry(''));
if($this->GetOption("b_style")!='') {
$this->AddElement(new GoogleSitemapGeneratorXmlEntry('<' . '?xml-stylesheet type="text/xsl" href="' . $this->GetOption("b_style") . '"?' . '>'));
}
$this->AddElement(new GoogleSitemapGeneratorDebugEntry("generator=\"wordpress/" . get_bloginfo('version') . "\""));
$this->AddElement(new GoogleSitemapGeneratorDebugEntry("sitemap-generator-url=\"http://www.arnebrachhold.de\" sitemap-generator-version=\"" . $this->GetVersion() . "\""));
$this->AddElement(new GoogleSitemapGeneratorDebugEntry("generated-on=\"" . date(get_option("date_format") . " " . get_option("time_format")) . "\""));
//All comments as an asso. Array (postID=>commentCount)
$comments=($this->GetOption("b_prio_provider")!=""?$this->GetComments():array());
//Full number of comments
$commentCount=(count($comments)>0?$this->GetCommentCount($comments):0);
if($debug && $this->GetOption("b_prio_provider")!="") {
$this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Total comment count: " . $commentCount));
}
//Go XML!
$this->AddElement(new GoogleSitemapGeneratorXmlEntry(''));
$home = get_bloginfo('url');
//Add the home page (WITH a slash!)
if($this->GetOption("in_home")) {
$this->AddUrl(trailingslashit($home),$this->GetTimestampFromMySql(get_lastpostmodified('GMT')),$this->GetOption("cf_home"),$this->GetOption("pr_home"));
}
//Add the posts
if($this->GetOption("in_posts") || $this->GetOption("in_pages")) {
if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Postings"));
//Pre 2.1 compatibility. 2.1 introduced 'future' as post_status so we don't need to check post_date
$wpCompat = (floatval($wp_version) < 2.1);
$sql="SELECT `ID`, `post_author`, `post_date`, `post_date_gmt`, `post_status`, `post_name`, `post_modified`, `post_modified_gmt`, `post_parent`, `post_type` FROM `" . $wpdb->posts . "` WHERE ";
$where = '(';
if($this->GetOption('in_posts')) {
//WP < 2.1: posts are post_status = publish
//WP >= 2.1: post_type must be 'post', no date check required because future posts are post_status='future'
if($wpCompat) $where.="(post_status = 'publish' AND post_date_gmt <= '" . gmdate('Y-m-d H:i:59') . "')";
else $where.=" (post_status = 'publish' AND (post_type = 'post' OR post_type = '')) ";
}
if($this->GetOption('in_pages')) {
if($this->GetOption('in_posts')) {
$where.=" OR ";
}
if($wpCompat) {
//WP < 2.1: posts have post_status = published, pages have post_status = static
$where.=" post_status='static' ";
} else {
//WP >= 2.1: posts have post_type = 'post' and pages have post_type = 'page'. Both must be published.
$where.=" (post_status = 'publish' AND post_type = 'page') ";
}
}
$where.=") ";
$excludes = $this->GetOption('b_exclude');
if(is_array($excludes) && count($excludes)>0) {
$where.=" AND ID NOT IN ('" . implode("','",$excludes) . "')";
}
$where.=" AND post_password='' ORDER BY post_modified DESC";
$sql .= $where;
if($this->GetOption("sm_b_max_posts")>0) {
$sql.=" LIMIT 0," . $this->GetOption("sm_b_max_posts");
}
$postCount = intval($wpdb->get_var("SELECT COUNT(*) AS cnt FROM `" . $wpdb->posts . "` WHERE ". $where,0,0));
//Create a new connection because we are using mysql_unbuffered_query and don't want to disturb the WP connection
//Safe Mode for other plugins which use mysql_query() without a connection handler and will destroy our resultset :(
$con = $postRes = null;
if($this->GetOption("b_safemode")===true) {
$postRes = mysql_query($sql,$wpdb->dbh);
if(!$postRes) {
trigger_error("MySQL query failed: " . mysql_error(),E_USER_NOTICE); //E_NOTE will be displayed on our debug mode
return;
}
} else {
$con = mysql_connect(DB_HOST,DB_USER,DB_PASSWORD,true);
if(!$con) {
trigger_error("MySQL Connection failed: " . mysql_error(),E_USER_NOTICE);
return;
}
if(!mysql_select_db(DB_NAME,$con)) {
trigger_error("MySQL DB Select failed: " . mysql_error(),E_USER_NOTICE);
return;
}
$postRes = mysql_unbuffered_query($sql,$con);
if(!$postRes) {
trigger_error("MySQL unbuffered query failed: " . mysql_error(),E_USER_NOTICE);
return;
}
}
if($postRes) {
//#type $prioProvider GoogleSitemapGeneratorPrioProviderBase
$prioProvider=NULL;
if($this->GetOption("b_prio_provider") != '') {
$providerClass=$this->GetOption('b_prio_provider');
$prioProvider = new $providerClass($commentCount,$postCount);
}
//$posts is used by Alex King's Popularity Contest plugin
//if($posts == null || !is_array($posts)) {
// $posts = &$postRes;
//}
$z = 1;
$zz = 1;
//Default priorities
$default_prio_posts = $this->GetOption('pr_posts');
$default_prio_pages = $this->GetOption('pr_pages');
//Change frequencies
$cf_pages = $this->GetOption('sm_cf_pages');
$cf_posts = $this->GetOption('sm_cf_posts');
$minPrio=$this->GetOption('pr_posts_min');
//Cycle through all posts and add them
while($post = mysql_fetch_object($postRes)) {
//Fill the cache with our DB result. Since it's incomplete (no text-content for example), we will clean it later.
$cache = array(&$post);
update_post_cache($cache);
$permalink = get_permalink($post->ID);
if($permalink != $home) {
$isPage = false;
if($wpCompat) {
$isPage = ($post->post_status == 'static');
} else {
$isPage = ($post->post_type == 'page');
}
//Set the current working post
$GLOBALS['post'] = &$post;
//Default Priority if auto calc is disabled
$prio = 0;
if($isPage) {
//Priority for static pages
$prio = $default_prio_pages;
} else {
//Priority for normal posts
$prio = $default_prio_posts;
}
//If priority calc. is enabled, calculate (but only for posts, not pages)!
if($prioProvider !== null && !$isPage) {
//Comment count for this post
$cmtcnt = (isset($comments[$post->ID])?$comments[$post->ID]:0);
$prio = $prioProvider->GetPostPriority($post->ID,$cmtcnt);
if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry('Debug: Priority report of postID ' . $post->ID . ': Comments: ' . $cmtcnt . ' of ' . $commentCount . ' = ' . $prio . ' points'));
}
if(!$isPage && $minPrio>0 && $prio<$minPrio) {
$prio = $minPrio;
}
//Add it
$this->AddUrl($permalink,$this->GetTimestampFromMySql(($post->post_modified_gmt && $post->post_modified_gmt!='0000-00-00 00:00:00'?$post->post_modified_gmt:$post->post_date_gmt)),($isPage?$cf_pages:$cf_posts),$prio);
}
//Update the status every 100 posts and at the end.
//If the script breaks because of memory or time limit,
//we have a "last reponded" value which can be compared to the server settings
if($zz==100 || $z == $postCount) {
$status->SaveStep($z);
$zz=0;
} else $zz++;
$z++;
//Clean cache because it's incomplete
clean_post_cache($post->ID);
}
unset($postRes);
unset($prioProvider);
if($this->GetOption("b_safemode")!==true && $con) mysql_close($con);
}
if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Postings"));
}
//Add the cats
if($this->GetOption("in_cats")) {
if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Cats"));
if(!$this->IsTaxonomySupported()) {
$catsRes=$wpdb->get_results("
SELECT
c.cat_ID AS ID,
MAX(p.post_modified_gmt) AS last_mod
FROM
`" . $wpdb->categories . "` c,
`" . $wpdb->post2cat . "` pc,
`" . $wpdb->posts . "` p
WHERE
pc.category_id = c.cat_ID
AND p.ID = pc.post_id
AND p.post_status = 'publish'
AND p.post_type='post'
GROUP
BY c.cat_id
");
if($catsRes) {
foreach($catsRes as $cat) {
if($cat && $cat->ID && $cat->ID>0) {
if($debug) if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Cat-ID:" . $cat->ID));
$this->AddUrl(get_category_link($cat->ID),$this->GetTimestampFromMySql($cat->last_mod),$this->GetOption("cf_cats"),$this->GetOption("pr_cats"));
}
}
}
} else {
$cats = get_terms("category",array("hide_empty"=>true,"hierarchical"=>false));
if($cats && is_array($cats) && count($cats)>0) {
foreach($cats AS $cat) {
$this->AddUrl(get_category_link($cat->term_id),0,$this->GetOption("cf_cats"),$this->GetOption("pr_cats"));
}
}
}
if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Cats"));
}
//Add the archives
if($this->GetOption("in_arch")) {
if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Archive"));
$now = current_time('mysql');
//WP2.1 introduced post_status='future', for earlier WP versions we need to check the post_date_gmt
$arcresults = $wpdb->get_results("
SELECT DISTINCT
YEAR(post_date_gmt) AS `year`,
MONTH(post_date_gmt) AS `month`,
MAX(post_date_gmt) as last_mod,
count(ID) as posts
FROM
$wpdb->posts
WHERE
post_date < '$now'
AND post_status = 'publish'
AND post_type = 'post'
" . (floatval($wp_version) < 2.1?"AND {$wpdb->posts}.post_date_gmt <= '" . gmdate('Y-m-d H:i:59') . "'":"") . "
GROUP BY
YEAR(post_date_gmt),
MONTH(post_date_gmt)
ORDER BY
post_date_gmt DESC");
if ($arcresults) {
foreach ($arcresults as $arcresult) {
$url = get_month_link($arcresult->year, $arcresult->month);
$changeFreq="";
//Archive is the current one
if($arcresult->month==date("n") && $arcresult->year==date("Y")) {
$changeFreq=$this->GetOption("cf_arch_curr");
} else { // Archive is older
$changeFreq=$this->GetOption("cf_arch_old");
}
$this->AddUrl($url,$this->GetTimestampFromMySql($arcresult->last_mod),$changeFreq,$this->GetOption("pr_arch"));
}
}
if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Archive"));
}
//Add the author pages
if($this->GetOption("in_auth")) {
if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Author pages"));
$linkFunc = null;
//get_author_link is deprecated in WP 2.1, try to use get_author_posts_url first.
if(function_exists('get_author_posts_url')) {
$linkFunc = 'get_author_posts_url';
} else if(function_exists('get_author_link')) {
$linkFunc = 'get_author_link';
}
//Who knows what happens in later WP versions, so check again if it worked
if($linkFunc !== null) {
//Unfortunately there is no API function to get all authors, so we have to do it the dirty way...
//We retrieve only users with published and not password protected posts (and not pages)
//WP2.1 introduced post_status='future', for earlier WP versions we need to check the post_date_gmt
$sql = "SELECT DISTINCT
{$wpdb->users}.ID,
{$wpdb->users}.user_nicename,
MAX({$wpdb->posts}.post_modified_gmt) AS last_post
FROM
{$wpdb->users},
{$wpdb->posts}
WHERE
{$wpdb->posts}.post_author = {$wpdb->posts}.ID
AND {$wpdb->posts}.post_status = 'publish'
AND {$wpdb->posts}.post_type = 'post'
AND {$wpdb->posts}.post_password = ''
" . (floatval($wp_version) < 2.1?"AND {$wpdb->posts}.post_date_gmt <= '" . gmdate('Y-m-d H:i:59') . "'":"") . "
GROUP BY
{$wpdb->posts}.ID,
{$wpdb->users}.user_nicename";
$authors = $wpdb->get_results($sql);
if($authors && is_array($authors)) {
foreach($authors as $author) {
if($debug) if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Author-ID:" . $author->ID));
$url = ($linkFunc=='get_author_posts_url'?get_author_posts_url($author->ID,$author->user_nicename):get_author_link(false,$author->ID,$author->user_nicename));
$this->AddUrl($url,$this->GetTimestampFromMySql($author->last_post),$this->GetOption("cf_auth"),$this->GetOption("pr_auth"));
}
}
} else {
//Too bad, no author pages for you :(
if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: No valid author link function found"));
}
if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Author pages"));
}
//Add tag pages
if($this->GetOption("in_tags") && $this->IsTaxonomySupported()) {
if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Tags"));
$tags = get_terms("post_tag",array("hide_empty"=>true,"hierarchical"=>false));
if($tags && is_array($tags) && count($tags)>0) {
foreach($tags AS $tag) {
$this->AddUrl(get_tag_link($tag->term_id),0,$this->GetOption("cf_tags"),$this->GetOption("pr_tags"));
}
}
if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Tags"));
}
//Add the custom pages
if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start Custom Pages"));
if($this->_pages && is_array($this->_pages) && count($this->_pages)>0) {
//#type $page GoogleSitemapGeneratorPage
foreach($this->_pages AS $page) {
$this->AddUrl($page->GetUrl(),$page->getLastMod(),$page->getChangeFreq(),$page->getPriority());
}
}
if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End Custom Pages"));
if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: Start additional URLs"));
do_action("sm_buildmap");
if($debug) $this->AddElement(new GoogleSitemapGeneratorDebugEntry("Debug: End additional URLs"));
$this->AddElement(new GoogleSitemapGeneratorXmlEntry(""));
$pingUrl='';
if($this->GetOption("b_xml")) {
if($this->_fileHandle && fclose($this->_fileHandle)) {
$this->_fileHandle = null;
$status->EndXml(true);
$pingUrl=$this->GetXmlUrl();
} else $status->EndXml(false,"Could not close the sitemap file.");
}
if($this->IsGzipEnabled()) {
if($this->_fileZipHandle && fclose($this->_fileZipHandle)) {
$this->_fileZipHandle = null;
$status->EndZip(true);
$pingUrl=$this->GetZipUrl();
} else $status->EndZip(false,"Could not close the zipped sitemap file");
}
//Ping Google
if($this->GetOption("b_ping") && !empty($pingUrl)) {
$sPingUrl="http://www.google.com/webmasters/sitemaps/ping?sitemap=" . urlencode($pingUrl);
$status->StartGooglePing($sPingUrl);
$pingres=$this->RemoteOpen($sPingUrl);
if($pingres==NULL || $pingres===false) {
$status->EndGooglePing(false,$this->_lastError);
} else {
$status->EndGooglePing(true);
}
}
//Ping Ask.com
if($this->GetOption("b_pingask") && !empty($pingUrl)) {
$sPingUrl="http://submissions.ask.com/ping?sitemap=" . urlencode($pingUrl);
$status->StartAskPing($sPingUrl);
$pingres=$this->RemoteOpen($sPingUrl);
if($pingres==NULL || $pingres===false || strpos($pingres,"successfully received and added")===false) { //Ask.com returns 200 OK even if there was an error, so we need to check the content.
$status->EndAskPing(false,$this->_lastError);
} else {
$status->EndAskPing(true);
}
}
//Ping YAHOO
if($this->GetOption("sm_b_pingyahoo")===true && $this->GetOption("sm_b_yahookey")!="" && !empty($pingUrl)) {
$sPingUrl="http://search.yahooapis.com/SiteExplorerService/V1/updateNotification?appid=" . $this->GetOption("sm_b_yahookey") . "&url=" . urlencode($pingUrl);
$status->StartYahooPing($sPingUrl);
$pingres=$this->RemoteOpen($sPingUrl);
if($pingres==NULL || $pingres===false || strpos(strtolower($pingres),"success")===false) {
$status->EndYahooPing(false,$this->_lastError);
} else {
$status->EndYahooPing(true);
}
}
//Ping MSN
if($this->GetOption("b_pingmsn") && !empty($pingUrl)) {
$sPingUrl="http://webmaster.live.com/ping.aspx?siteMap=" . urlencode($pingUrl);
$status->StartMsnPing($sPingUrl);
$pingres=$this->RemoteOpen($sPingUrl);
if($pingres==NULL || $pingres===false || strpos($pingres,"Thanks for submitting your sitemap")===false) {
$status->EndMsnPing(false,$this->_lastError);
} else {
$status->EndMsnPing(true);
}
}
$status->End();
$this->_isActive = false;
//done...
return $status;
}
function RemoteOpen($url) {
$res = null;
if(file_exists(ABSPATH . 'wp-includes/class-snoopy.php')) {
require_once( ABSPATH . 'wp-includes/class-snoopy.php');
$s = new Snoopy();
$s->fetch($url);
if($s->status == 200) {
$res = $s->results;
}
} else {
$res = wp_remote_fopen($url);
}
return $res;
}
/**
* Tracks the last error (gets called by PHP)
*
* @since 3.0
* @access private
* @author Arne Brachhold
*/
function TrackError($log_level, $log_text, $error_file, $error_line) {
$this->_lastError = $log_text;
}
/**
* Adds the options page in the admin menu
*
* @since 3.0
* @access public
* @author Arne Brachhold
*/
function RegisterAdminPage() {
if (function_exists('add_options_page')) {
add_options_page(__('XML-Sitemap Generator','sitemap'), __('XML-Sitemap','sitemap'), 'administrator', basename(__FILE__), array(&$this,'HtmlShowOptionsPage'));
}
}
/**
* Echos option fields for an select field containing the valid change frequencies
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @param $currentVal The value which should be selected
* @return all valid change frequencies as html option fields
*/
function HtmlGetFreqNames($currentVal) {
foreach($this->_freqNames AS $v) {
echo "";
}
}
/**
* Echos option fields for an select field containing the valid priorities (0- 1.0)
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @param $currentVal string The value which should be selected
* @return 0.0 - 1.0 as html option fields
*/
function HtmlGetPriorityValues($currentVal) {
$currentVal=(float) $currentVal;
for($i=0.0; $i<=1.0; $i+=0.1) {
echo "";
}
}
/**
* Returns the checked attribute if the given values match
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @param $val string The current value
* @param $equals string The value to match
* @return The checked attribute if the given values match, an empty string if not
*/
function HtmlGetChecked($val,$equals) {
if($val==$equals) return $this->HtmlGetAttribute("checked");
else return "";
}
/**
* Returns the selected attribute if the given values match
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @param $val string The current value
* @param $equals string The value to match
* @return The selected attribute if the given values match, an empty string if not
*/
function HtmlGetSelected($val,$equals) {
if($val==$equals) return $this->HtmlGetAttribute("selected");
else return "";
}
/**
* Returns an formatted attribute. If the value is NULL, the name will be used.
*
* @since 3.0
* @access private
* @author Arne Brachhold
* @param $attr string The attribute name
* @param $value string The attribute value
* @return The formatted attribute
*/
function HtmlGetAttribute($attr,$value=NULL) {
if($value==NULL) $value=$attr;
return " " . $attr . "=\"" . $value . "\" ";
}
/**
* Returns an array with GoogleSitemapGeneratorPage objects which is generated from POST values
*
* @since 3.0
* @see GoogleSitemapGeneratorPage
* @access private
* @author Arne Brachhold
* @return array An array with GoogleSitemapGeneratorPage objects
*/
function HtmlApplyPages() {
// Array with all page URLs
$pages_ur=(!isset($_POST["sm_pages_ur"]) || !is_array($_POST["sm_pages_ur"])?array():$_POST["sm_pages_ur"]);
//Array with all priorities
$pages_pr=(!isset($_POST["sm_pages_pr"]) || !is_array($_POST["sm_pages_pr"])?array():$_POST["sm_pages_pr"]);
//Array with all change frequencies
$pages_cf=(!isset($_POST["sm_pages_cf"]) || !is_array($_POST["sm_pages_cf"])?array():$_POST["sm_pages_cf"]);
//Array with all lastmods
$pages_lm=(!isset($_POST["sm_pages_lm"]) || !is_array($_POST["sm_pages_lm"])?array():$_POST["sm_pages_lm"]);
//Array where the new pages are stored
$pages=array();
//Loop through all defined pages and set their properties into an object
if(isset($_POST["sm_pages_mark"]) && is_array($_POST["sm_pages_mark"])) {
for($i=0; $iSetUrl($pages_ur[$i]);
$p->SetProprity($pages_pr[$i]);
$p->SetChangeFreq($pages_cf[$i]);
//Try to parse last modified, if -1 (note ===) automatic will be used (0)
$lm=(!empty($pages_lm[$i])?strtotime($pages_lm[$i],time()):-1);
if($lm===-1) $p->setLastMod(0);
else $p->setLastMod($lm);
//Add it to the array
array_push($pages,$p);
}
}
return $pages;
}
function GetTimestampFromMySql($mysqlDateTime) {
list($date, $hours) = split(' ', $mysqlDateTime);
list($year,$month,$day) = split('-',$date);
list($hour,$min,$sec) = split(':',$hours);
return mktime($hour, $min, $sec, $month, $day, $year);
}
function GetResourceLink($resourceID) {
return trailingslashit(get_bloginfo('siteurl')) . '?res=' . $resourceID;
}
function GetRedirectLink($redir) {
return trailingslashit("http://www.arnebrachhold.de/redir/" . $redir);
}
function GetBackLink() {
$page = basename(__FILE__);
if(isset($_GET['page']) && !empty($_GET['page'])) {
$page = preg_replace('[^a-zA-Z0-9\.\_\-]','',$_GET['page']);
}
return $_SERVER['PHP_SELF'] . "?page=" . $page;
}
/**
* Displays the option page
*
* @since 3.0
* @access public
* @author Arne Brachhold
*/
function HtmlShowOptionsPage() {
$this->Initate();
//All output should go in this var which get printed at the end
$message="";
if(isset($_GET['sm_donated'])) {
$this->SetOption('i_donated',true);
$this->SaveOptions();
}
if(isset($_GET['sm_hide_note'])) {
$this->SetOption('i_hide_note',true);
$this->SaveOptions();
}
if(isset($_GET['sm_hidedonors'])) {
$this->SetOption('i_hide_donors',true);
$this->SaveOptions();
}
if(isset($_GET['sm_donated']) || ($this->GetOption('i_donated')===true && $this->GetOption('i_hide_donated')!==true)) {
?>
GetRedirectLink("sitemap-donate-note"),__('Thanks for using this plugin! You\'ve installed this plugin over a month ago. If it works and your are satisfied with the results, isn\'t it worth at least one dollar? Donations help me to continue support and development of this free software! Sure, no problem!','sitemap')); ?> " style="float:right; display:block; border:none;">
This is the debug mode of the XML Sitemap Generator. It will show all PHP notices and warnings as well as the internal logs, messages and configuration.
';
echo '
DO NOT POST THIS INFORMATION ON PUBLIC PAGES LIKE SUPPORT FORUMS AS IT MAY CONTAIN PASSWORDS OR SECRET SERVER INFORMATION!
';
echo "
WordPress and PHP Information
";
echo '
WordPress ' . $GLOBALS['wp_version'] . ' with ' . ' DB ' . $GLOBALS['wp_db_version'] . ' on PHP ' . phpversion() . '