2008-11-18 23:10:33 +00:00
< ? php
/**
* Initial implementation of Sitemap support .
* GoogleSitemap should handle requests to 'sitemap.xml'
* the other two classes are used to render the sitemap .
*
* You can notify ( " ping " ) Google about a changed sitemap
* automatically whenever a new page is published or unpublished .
* By default , Google is not notified , and will pick up your new
* sitemap whenever the GoogleBot visits your website .
*
* Enabling notification of Google after every publish ( in your _config . php ) :
* < example
* GoogleSitemap :: enable_google_notificaton ();
* </ example >
*
* @ see http :// www . google . com / support / webmasters / bin / answer . py ? hl = en & answer = 34609
*
* @ package sapphire
* @ subpackage misc
*/
class GoogleSitemap extends Controller {
/**
* @ var boolean
*/
protected static $enabled = true ;
/**
* @ var DataObjectSet
*/
protected $Pages ;
/**
* @ var boolean
*/
protected static $google_notification_enabled = false ;
public function Items () {
$this -> Pages = Versioned :: get_by_stage ( 'SiteTree' , 'Live' );
$newPages = new DataObjectSet ();
foreach ( $this -> Pages as $page ) {
// Only include pages from this host and pages which are not an instance of ErrorPage
2009-04-27 00:58:21 +00:00
// We prefix $_SERVER['HTTP_HOST'] with 'http://' so that parse_url to help parse_url identify the host name component; we could use another protocol (like
// 'ftp://' as the prefix and the code would work the same.
if ( parse_url ( $page -> AbsoluteLink (), PHP_URL_HOST ) == parse_url ( 'http://' . $_SERVER [ 'HTTP_HOST' ], PHP_URL_HOST ) && ! ( $page instanceof ErrorPage )) {
2008-11-18 23:10:33 +00:00
// If the page has been set to 0 priority, we set a flag so it won't be included
2008-12-18 21:07:07 +00:00
if ( $page -> canView () && ( ! isset ( $page -> Priority ) || $page -> Priority > 0 )) {
2008-11-18 23:10:33 +00:00
// The one field that isn't easy to deal with in the template is
// Change frequency, so we set that here.
$properties = $page -> toMap ();
2008-11-28 03:39:40 +00:00
$created = new SSDatetime ();
$created -> value = $properties [ 'Created' ];
$now = new SSDatetime ();
$now -> value = date ( 'Y-m-d H:i:s' );
2008-11-18 23:10:33 +00:00
$versions = $properties [ 'Version' ];
$timediff = $now -> format ( 'U' ) - $created -> format ( 'U' );
// Check how many revisions have been made over the lifetime of the
// Page for a rough estimate of it's changing frequency.
$period = $timediff / ( $versions + 1 );
if ( $period > 60 * 60 * 24 * 365 ) { // > 1 year
$page -> ChangeFreq = 'yearly' ;
2008-11-28 03:39:40 +00:00
} elseif ( $period > 60 * 60 * 24 * 30 ) { // > ~1 month
2008-11-18 23:10:33 +00:00
$page -> ChangeFreq = 'monthly' ;
2008-11-28 03:39:40 +00:00
} elseif ( $period > 60 * 60 * 24 * 7 ) { // > 1 week
2008-11-18 23:10:33 +00:00
$page -> ChangeFreq = 'weekly' ;
2008-11-28 03:39:40 +00:00
} elseif ( $period > 60 * 60 * 24 ) { // > 1 day
2008-11-18 23:10:33 +00:00
$page -> ChangeFreq = 'daily' ;
2008-11-28 03:39:40 +00:00
} elseif ( $period > 60 * 60 ) { // > 1 hour
2008-11-18 23:10:33 +00:00
$page -> ChangeFreq = 'hourly' ;
} else { // < 1 hour
$page -> ChangeFreq = 'always' ;
}
$newPages -> push ( $page );
}
}
}
return $newPages ;
}
/**
* Notifies Google about changes to your sitemap .
* Triggered automatically on every publish / unpublish of a page .
* This behaviour is disabled by default , enable with :
* GoogleSitemap :: enable_google_notificaton ();
*
* If the site is in " dev-mode " , no ping will be sent regardless wether
* the Google notification is enabled .
*
* @ return string Response text
*/
static function ping () {
if ( ! self :: $enabled ) return false ;
//Don't ping if the site has disabled it, or if the site is in dev mode
if ( ! GoogleSitemap :: $google_notification_enabled || Director :: isDev ())
return ;
$location = urlencode ( Director :: absoluteBaseURL () . '/sitemap.xml' );
$response = HTTP :: sendRequest ( " www.google.com " , " /webmasters/sitemaps/ping " ,
" sitemap= " . $location );
return $response ;
}
/**
* Enable pings to google . com whenever sitemap changes .
*/
public static function enable_google_notification () {
self :: $google_notification_enabled = true ;
}
/**
* Disables pings to google when the sitemap changes .
*/
public static function disable_google_notification () {
self :: $google_notification_enabled = false ;
}
function index ( $url ) {
if ( self :: $enabled ) {
2008-12-05 02:47:07 +00:00
SSViewer :: set_source_file_comments ( false );
2008-11-18 23:10:33 +00:00
// We need to override the default content-type
ContentNegotiator :: disable ();
2009-04-26 23:03:56 +00:00
$this -> getResponse () -> addHeader ( 'Content-Type' , 'application/xml; charset="utf-8"' );
2008-11-18 23:10:33 +00:00
// But we want to still render.
return array ();
} else {
return new HTTPResponse ( 'Not allowed' , 405 );
}
}
public static function enable () {
self :: $enabled = true ;
}
public static function disable () {
self :: $enabled = false ;
}
}
/**
* @ package sapphire
* @ subpackage misc
*/
class GoogleSitemapDecorator extends SiteTreeDecorator {
function extraStatics () {
return array (
'db' => array (
" Priority " => " Float " ,
)
);
}
function updateCMSFields ( & $fields ) {
$pagePriorities = array (
'' => _t ( 'SiteTree.PRIORITYAUTOSET' , 'Auto-set based on page depth' ),
'-1' => _t ( 'SiteTree.PRIORITYNOTINDEXED' , " Not indexed " ), // We set this to -ve one because a blank value implies auto-generation of Priority
'1.0' => '1 - ' . _t ( 'SiteTree.PRIORITYMOSTIMPORTANT' , " Most important " ),
'0.9' => '2' ,
'0.8' => '3' ,
'0.7' => '4' ,
'0.6' => '5' ,
'0.5' => '6' ,
'0.4' => '7' ,
'0.3' => '8' ,
'0.2' => '9' ,
'0.1' => '10 - ' . _t ( 'SiteTree.PRIORITYLEASTIMPORTANT' , " Least important " )
);
$tabset = $fields -> findOrMakeTab ( 'Root.Content' );
$tabset -> push (
$addTab = new Tab (
'GoogleSitemap' ,
_t ( 'SiteTree.TABGOOGLESITEMAP' , 'Google Sitemap' ),
new LiteralField (
" GoogleSitemapIntro " ,
" <p> " .
sprintf (
_t (
'SiteTree.METANOTEPRIORITY' ,
" Manually specify a Google Sitemaps priority for this page (%s) "
),
'<a href="https://www.google.com/webmasters/tools/docs/en/protocol.html#prioritydef">?</a>'
) .
" </p> "
),
new DropdownField ( " Priority " , $this -> owner -> fieldLabel ( 'Priority' ), $pagePriorities )
)
);
}
function updateFieldLabels ( & $labels ) {
parent :: updateFieldLabels ( $labels );
$labels [ 'Priority' ] = _t ( 'SiteTree.METAPAGEPRIO' , " Page Priority " );
}
function onAfterPublish () {
GoogleSiteMap :: ping ();
}
function onAfterUnpublish () {
GoogleSiteMap :: ping ();
}
/**
* The default value of the priority field depends on the depth of the page in
* the site tree , so it must be calculated dynamically .
*/
function getPriority () {
if ( ! $this -> owner -> getField ( 'Priority' )) {
$parentStack = $this -> owner -> parentStack ();
$numParents = is_array ( $parentStack ) ? count ( $parentStack ) - 1 : 0 ;
return max ( 0.1 , 1.0 - ( $numParents / 10 ));
2008-11-28 03:39:40 +00:00
} elseif ( $this -> owner -> getField ( 'Priority' ) == - 1 ) {
2008-11-18 23:10:33 +00:00
return 0 ;
} else {
return $this -> owner -> getField ( 'Priority' );
}
}
}
Object :: add_extension ( 'SiteTree' , 'GoogleSitemapDecorator' );
2008-11-28 03:39:40 +00:00
?>