Permalink
Browse files

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.
  • Loading branch information...
1 parent c62538a commit 9c0d50e726e4b978c89d2a7049ce3aa940d2e2d3 @rlehmann rlehmann committed with wilr Jun 7, 2011
Showing with 267 additions and 56 deletions.
  1. +3 −17 README.md
  2. +7 −3 _config.php
  3. +163 −35 code/GoogleSitemap.php
  4. +10 −1 code/GoogleSitemapDecorator.php
  5. 0 docs/_manifest_exclude
  6. +84 −0 docs/en/index.md
View
20 README.md
@@ -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
10 _config.php
@@ -5,6 +5,10 @@
'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
198 code/GoogleSitemap.php
@@ -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,28 +220,41 @@ static function ping() {
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;
}
/**
* 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 @@ function index($url) {
}
}
+ /**
+ * 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
11 code/GoogleSitemapDecorator.php
@@ -6,7 +6,16 @@
*
* @package googlesitemaps
*/
-class GoogleSitemapDecorator extends SiteTreeDecorator {
+class GoogleSitemapDecorator extends DataObjectDecorator {
+
+
+}
+
+/**
+ * @package googlesitemaps
+ */
+
+class GoogleSitemapSiteTreeDecorator extends SiteTreeDecorator {
function extraStatics() {
return array(
View
0 docs/_manifest_exclude
No changes.
View
84 docs/en/index.md
@@ -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/

0 comments on commit 9c0d50e

Please sign in to comment.