FEATURE: added ability to add google sitemap indexes for dataobjects. Added documentation and.

APICHANGE: moved GoogleSiteMapDecorator to GoogleSitemapSiteTreeDecorator to use the original for a hook for extending on googlesitemaps on dataobjects only.
This commit is contained in:
rlehmann 2011-06-07 11:37:38 -07:00 committed by Will Rossiter
parent c62538a860
commit 9c0d50e726
6 changed files with 267 additions and 56 deletions

View File

@ -11,7 +11,7 @@
## Documentation
SilverStripe provides support for the Google Sitemaps XML system, enabling
Google and other search engines to see all pages on your site. This helps
Google and other search engines to see all urls on your site. This helps
your SilverStripe website rank well in search engines, and to encourage the
information on your site to be discovered by Google quickly.
@ -20,21 +20,7 @@ be visited: http://yoursite.com/sitemap.xml
See http://en.wikipedia.org/wiki/Sitemaps for info on this format
In addition, whenever you publish a new or republish an existing page,
SilverStripe automatically informs Google of the change, encouraging a Google
to take notice. If you install the SilverStripe Google Analytics module, you
can see if Google has updated your page as a result.
## Usage Overview
By default, SilverStripe informs Google that the importance of a page depends
on its position of in the sitemap. "Top level" pages are most important, and
the deeper a page is nested, the less important it is. (For each level,
Importance drops from 1.0, to 0.9, to 0.8, and so on, until 0.1 is reached).
In the CMS, in the "Content/GoogleSitemap" tab, you can set the page importance
manually, including requesting to have the page excluded from the google sitemap.
### Setup automatic pinging
GoogleSitemap::enable_google_notificaton();
See docs/en/* for more information about configuring the module.

View File

@ -5,6 +5,10 @@ Director::addRules(10, array(
'sitemap.xml' => 'GoogleSitemap',
));
// add the extension
Object::add_extension('SiteTree', 'GoogleSitemapDecorator');
?>
// add the extension to pages
Object::add_extension('SiteTree', 'GoogleSitemapSiteTreeDecorator');
// if you need to add this to DataObjects include the following in
// your own _config:
// GoogleSiteMap::register_dataobject('MyDataObject');

View File

@ -1,5 +1,4 @@
<?php
/**
* Initial implementation of Sitemap support.
* GoogleSitemap should handle requests to 'sitemap.xml'
@ -11,6 +10,7 @@
* sitemap whenever the GoogleBot visits your website.
*
* Enabling notification of Google after every publish (in your _config.php):
*
* <example>
* GoogleSitemap::enable_google_notificaton();
* </example>
@ -19,7 +19,6 @@
*
* @package googlesitemaps
*/
class GoogleSitemap extends Controller {
/**
@ -41,60 +40,166 @@ class GoogleSitemap extends Controller {
* @var boolean
*/
protected static $use_show_in_search = true;
/**
* List of DataObjects to show in sitemap.xml
*
* @var array
*/
public static $google_sitemap_dataobjects = array();
/**
* List of DataObjects change frequency
*
* @var array
*/
public static $google_sitemap_dataobjects_changefreq = array();
/**
* Decorates the given DataObject with {@link GoogleSitemapDecorator}
* and pushes the class name to the registered DataObjects.
* Note that all registered DataObjects need the method AbsoluteLink().
*
* @param string $className name of DataObject to register
* @param string $changeFreq
*
* @return void
*/
public static function register_dataobject($className, $changeFreq = 'monthly') {
if (!self::is_registered($className)) {
Object::add_extension($className, 'GoogleSitemapDecorator');
self::$google_sitemap_dataobjects[] = $className;
self::$google_sitemap_dataobjects_changefreq[] = $changeFreq;
}
}
/**
* Checks whether the given class name is already registered or not.
*
* @param string $className Name of DataObject to check
*
* @return bool
*/
public static function is_registered($className) {
return in_array($className, self::$google_sitemap_dataobjects);
}
/**
* Adds DataObjects to the existing DataObjectSet with pages from the
* site tree
*
* @param DataObjectSet $newPages
*
* @return DataObjectSet
*/
protected function addRegisteredDataObjects() {
$output = new DataObjectSet();
foreach(self::$google_sitemap_dataobjects as $index => $className) {
$dataObjectSet = DataObject::get($className);
if($dataObjectSet) {
foreach($dataObjectSet as $dataObject) {
if($dataObject->canView() && (!isset($dataObject->Priority) || $dataObject->Priority > 0)) {
$dataObject->ChangeFreq = self::$google_sitemap_dataobjects_changefreq[$index];
if(!isset($dataObject->Priority)) {
$dataObject->Priority = 1.0;
}
$output->push($dataObject);
}
}
}
}
return $output;
}
/**
* Returns all the links to {@link SiteTree} pages and
* {@link DataObject} urls on the page
*
* @return DataObjectSet
*/
public function Items() {
$filter = '';
$bt = defined('DB::USE_ANSI_SQL') ? "\"" : "`";
if(self::$use_show_in_search) {
$filter = "{$bt}ShowInSearch{$bt} = 1";
}
$this->Pages = Versioned::get_by_stage('SiteTree', 'Live', $filter);
$newPages = new DataObjectSet();
if($this->Pages) {
foreach($this->Pages as $page) {
// Only include pages from this host and pages which are not an instance of ErrorPage
// 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)) {
// Only include pages from this host and pages which are not an
// instance of ErrorPage. 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.
$pageHttp = parse_url($page->AbsoluteLink(), PHP_URL_HOST);
$hostHttp = parse_url('http://' . $_SERVER['HTTP_HOST'], PHP_URL_HOST);
if(($pageHttp == $hostHttp) && !($page instanceof ErrorPage)) {
// If the page has been set to 0 priority, we set a flag so it won't be included
// If the page has been set to 0 priority, we set a flag so
// it won't be included
if($page->canView() && (!isset($page->Priority) || $page->Priority > 0)) {
$created = $page->dbObject('Created');
// The one field that isn't easy to deal with in the template is
// Change frequency, so we set that here.
$date = date('Y-m-d H:i:s');
$prop = $page->toMap();
$created = new SS_Datetime();
$created->value = (isset($prop['Created'])) ? $prop['Created'] : $date;
$now = new SS_Datetime();
$now->value = date('Y-m-d H:i:s');
$versions = $page->Version;
$now->value = $date;
$versions = (isset($prop['Version'])) ? $prop['Version'] : 1;
$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';
} elseif($period > 60*60*24*30) { // > ~1 month
$page->ChangeFreq='monthly';
} elseif($period > 60*60*24*7) { // > 1 week
$page->ChangeFreq='weekly';
} elseif($period > 60*60*24) { // > 1 day
$page->ChangeFreq='daily';
} elseif($period > 60*60) { // > 1 hour
$page->ChangeFreq='hourly';
} else { // < 1 hour
$page->ChangeFreq='always';
if($period > 60*60*24*365) {
// > 1 year
$page->ChangeFreq = 'yearly';
}
elseif($period > 60*60*24*30) {
$page->ChangeFreq = 'monthly';
}
elseif($period > 60*60*24*7) {
// > 1 week
$page->ChangeFreq = 'weekly';
}
elseif($period > 60*60*24) {
// > 1 day
$page->ChangeFreq = 'daily';
}
elseif($period > 60*60) {
// > 1 hour
$page->ChangeFreq = 'hourly';
} else {
// < 1 hour
$page->ChangeFreq = 'always';
}
$newPages->push($page);
}
}
}
return $newPages;
}
$newPages->merge($this->addRegisteredDataObjects());
return $newPages;
}
/**
@ -115,16 +220,24 @@ class GoogleSitemap extends Controller {
if(!GoogleSitemap::$google_notification_enabled || Director::isDev())
return;
$location = urlencode(Director::absoluteBaseURL() . '/sitemap.xml');
$location = urlencode(Controller::join_links(
Director::absoluteBaseURL(),
'sitemap.xml'
));
$response = HTTP::sendRequest("www.google.com", "/webmasters/sitemaps/ping",
"sitemap=" . $location);
$response = HTTP::sendRequest(
"www.google.com",
"/webmasters/sitemaps/ping",
sprintf("sitemap=%s", $location)
);
return $response;
}
/**
* Enable pings to google.com whenever sitemap changes.
*
* @return void
*/
public static function enable_google_notification() {
self::$google_notification_enabled = true;
@ -132,11 +245,16 @@ class GoogleSitemap extends Controller {
/**
* Disables pings to google when the sitemap changes.
*
* @return void
*/
public static function disable_google_notification() {
self::$google_notification_enabled = false;
}
/**
* Default controller handler for the sitemap.xml file
*/
function index($url) {
if(self::$enabled) {
SSViewer::set_source_file_comments(false);
@ -149,11 +267,21 @@ class GoogleSitemap extends Controller {
}
}
/**
* Enable the sitemap.xml file
*
* @return void
*/
public static function enable() {
self::$enabled = true;
}
/**
* Disable the sitemap.xml file
*
* @return void
*/
public static function disable() {
self::$enabled = false;
}
}
}

View File

@ -6,7 +6,16 @@
*
* @package googlesitemaps
*/
class GoogleSitemapDecorator extends SiteTreeDecorator {
class GoogleSitemapDecorator extends DataObjectDecorator {
}
/**
* @package googlesitemaps
*/
class GoogleSitemapSiteTreeDecorator extends SiteTreeDecorator {
function extraStatics() {
return array(

0
docs/_manifest_exclude Normal file
View File

84
docs/en/index.md Normal file
View File

@ -0,0 +1,84 @@
# Google Sitemaps Module
SilverStripe provides support for the Google Sitemaps XML system, enabling
Google and other search engines to see all pages on your site. This helps
your SilverStripe website rank well in search engines, and to encourage the
information on your site to be discovered by Google quickly.
Therefore, all Silverstripe websites contain a special controller which can
be visited: http://yoursite.com/sitemap.xml
See http://en.wikipedia.org/wiki/Sitemaps for info on this format
In addition, whenever you publish a new or republish an existing page,
SilverStripe automatically informs Google of the change, encouraging a Google
to take notice. If you install the SilverStripe Google Analytics module, you
can see if Google has updated your page as a result.
By default, SilverStripe informs Google that the importance of a page depends
on its position of in the sitemap. "Top level" pages are most important, and
the deeper a page is nested, the less important it is. (For each level,
Importance drops from 1.0, to 0.9, to 0.8, and so on, until 0.1 is reached).
In the CMS, in the "Content/GoogleSitemap" tab, you can set the page importance
manually, including requesting to have the page excluded from the google sitemap.
## Setup automatic pinging
GoogleSitemap::enable_google_notificaton();
### Include Dataobjects in listing
The module provides support for including DataObject subclasses as pages in
the SiteTree such as comments, forum posts and other pages which are created
by DataObjects.
To include a DataObject in the Sitemap it requires that your subclass defines
two functions.
* AbsoluteLink() function which returns the URL for this DataObject
* canView() function which returns a boolean value.
The SilverStripe convention is to use a Link function to define the AbsoluteLink.
This enables $Link to work for relative links (while in templates) and $AbsoluteLink
to work for RSS Feeds and the Sitemap Links.
The following is a barebones example of a DataObject called 'MyDataObject'. It assumes
that you have a controller called 'MyController' which has a show method to show the
DataObject by it's ID.
<?php
class MyDataObject extends DataObject {
function canView() {
return true;
}
function AbsoluteLink() {
return Director::absoluteURL($this->Link());
}
function Link() {
return 'MyController/show/'. $this->ID;
}
}
After those methods have been defined on your DataObject you now need to tell
googlesitemaps that it should be listed in the sitemap.xml file. Include the
following in your _config.php file.
GoogleSitemap::register_dataobject('MyDataObject');
If you need to change the frequency of the indexing, you can pass the change
frequency (daily, weekly, monthly) as a second parameter to register().
So instead of the previous code you would write:
GoogleSitemap::register('MyDataObject', 'daily');
See the following blog post for more information:
http://www.silvercart.org/blog/dataobjects-and-googlesitemaps/