Version: current

      1 <?php
      2 /**
      3  * Initial implementation of Sitemap support.
      4  * GoogleSitemap should handle requests to 'sitemap.xml'
      5  * the other two classes are used to render the sitemap.
      6  *
      7  * You can notify ("ping") Google about a changed sitemap
      8  * automatically whenever a new page is published or unpublished.
      9  * By default, Google is not notified, and will pick up your new
     10  * sitemap whenever the GoogleBot visits your website.
     11  *
     12  * Enabling notification of Google after every publish (in your _config.php):
     13  * <example
     14  * GoogleSitemap::enable_google_notificaton();
     15  * </example>
     16  *
     17  * @see http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=34609
     18  *
     19  * @package googlesitemaps
     20  */
     21 class GoogleSitemap extends Controller {
     22
     23     static $cache_expire = 86400;
     24
     25     static function local_sitemap_path() {
     26         return ASSETS_PATH . '/sitemap.xml';
     27     }
     28
     29     static function clear_cache() {
     30         $file = self::local_sitemap_path();
     31         if (@file_exists($file))
     32             unlink($file);
     33     }
     34
     35     /**
     36      * @var boolean
     37      */
     38     protected static $enabled = true;
     39
     40     /**
     41      * @var boolean
     42      */
     43     protected static $google_notification_enabled = false;
     44
     45     /**
     46      * Использовать флаг ShowInSiteMap(он есть не во всех версиях Webylon) @var boolean
     47      */
     48     protected static $use_show_in_sitemap = true;
     49
     50     //Установка использования флага ShowInSiteMap
     51     static function set_use_show_in_sitemap($val = false) {
     52         self::$use_show_in_sitemap = $val;
     53     }
     54
     55     public function Items($start=0) {
     56         $count = 1000;
     57         Versioned::reading_stage('Live');
     58         $filter = '';
     59         if(self::$use_show_in_sitemap) {
     60             $filter .= '"ShowInSiteMap" = 1';
     61         }
     62
     63         $pages = DataObject::get('SiteTree', $filter, '', '', "{$start},{$count}");
     64         if (!$pages) return false;
     65         $newPages = new DataObjectSet();
     66         while($page = $pages->shift()) {
     67             // Only include pages from this host and pages which are not an instance of ErrorPage
     68             // 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
     69             // 'ftp://' as the prefix and the code would work the same.
     70             if (parse_url($page->AbsoluteLink(), PHP_URL_HOST) != parse_url('http://' . $_SERVER['HTTP_HOST'], PHP_URL_HOST)) continue;
     71             if ($page instanceof ErrorPage) continue;
     72             if ($page->Priority < 0) continue;
     73             if (!$page->canView()) continue;
     74
     75             // The one field that isn't easy to deal with in the template is
     76             // Change frequency, so we set that here.
     77             $created = new SS_Datetime();
     78             $created->value = $page->Created;
     79
     80             $now = new SS_Datetime();
     81             $now->value = date('Y-m-d H:i:s');
     82
     83             $versions = $page->Version;
     84             $timediff = $now->format('U') - $created->format('U');
     85
     86             // Check how many revisions have been made over the lifetime of the
     87             // Page for a rough estimate of it's changing frequency.
     88
     89             $period = $timediff / ($versions + 1);
     90
     91             if($period > 60*60*24*365) { // > 1 year
     92                 $page->ChangeFreq='yearly';
     93             } elseif($period > 60*60*24*30) { // > ~1 month
     94                 $page->ChangeFreq='monthly';
     95             } elseif($period > 60*60*24*7) { // > 1 week
     96                 $page->ChangeFreq='weekly';
     97             } elseif($period > 60*60*24) { // > 1 day
     98                 $page->ChangeFreq='daily';
     99             } elseif($period > 60*60) { // > 1 hour
    100                 $page->ChangeFreq='hourly';
    101             } else { // < 1 hour
    102                 $page->ChangeFreq='always';
    103             }
    104
    105             $newPages->push($page);
    106         }
    107         return $newPages;
    108     }
    109
    110     /**
    111      * Notifies Google about changes to your sitemap.
    112      * Triggered automatically on every publish/unpublish of a page.
    113      * This behaviour is disabled by default, enable with:
    114      * GoogleSitemap::enable_google_notificaton();
    115      *
    116      * If the site is in "dev-mode", no ping will be sent regardless wether
    117      * the Google notification is enabled.
    118      *
    119      * @return string Response text
    120      */
    121     static function ping() {
    122         if(!self::$enabled) return false;
    123
    124         //Don't ping if the site has disabled it, or if the site is in dev mode
    125         if(!GoogleSitemap::$google_notification_enabled || Director::isDev())
    126             return;
    127
    128         $location = urlencode(Director::absoluteBaseURL() . '/sitemap.xml');
    129
    130         $response = HTTP::sendRequest("www.google.com", "/webmasters/sitemaps/ping",
    131             "sitemap=" . $location);
    132
    133         return $response;
    134     }
    135
    136     /**
    137      * Enable pings to google.com whenever sitemap changes.
    138      */
    139     public static function enable_google_notification() {
    140         self::$google_notification_enabled = true;
    141     }
    142
    143     /**
    144      * Disables pings to google when the sitemap changes.
    145      */
    146     public static function disable_google_notification() {
    147         self::$google_notification_enabled = false;
    148     }
    149
    150     function index($request) {
    151         if(self::$enabled) {
    152             $cache_path = self::local_sitemap_path();
    153             if ($request->requestVar('force')) {
    154                 self::clear_cache();
    155             }
    156
    157             if (!Director::is_cli()) {
    158                 if (@file_exists($cache_path) && (@filemtime($cache_path) + self::$cache_expire > time())) {
    159                     Controller::curr()->getResponse()->addHeader("Content-Type", "text/xml");
    160                     readfile($cache_path);
    161                     return;
    162                 }
    163             }
    164
    165             increase_time_limit_to(1000);
    166             increase_memory_limit_to('1000M');
    167             $markStart = time();
    168             $html = '<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
    169             file_put_contents($cache_path, $html);
    170
    171             $start = 0;
    172             $totCount = 0;
    173             $f = true;
    174             while ($f) {
    175                 $pages = $this->Items($start);
    176                 if (!$pages) {
    177                     $f = false;
    178                 } else {
    179                     $html = '';
    180                     $pCount = $pages->Count();
    181                     foreach($pages as $page) {
    182                         $html .= $page->renderWith('SitemapURL');
    183                         $page->destroy();
    184                         $totCount++;
    185                     }
    186                     file_put_contents($cache_path, $html, FILE_APPEND);
    187                     $start += $pCount;
    188                     unset($pages);
    189                 }
    190             }
    191             file_put_contents($cache_path, '</urlset>', FILE_APPEND);
    192
    193             if (Director::is_cli()) {
    194                 $markEnd = time();
    195                 echo
    196                     'start: ' . date('Y-m-d H:i:s', $markStart) . "\n"
    197                     . '  end: ' . date('Y-m-d H:i:s', $markEnd) . "\n"
    198                     . 'duration: ' . ($markEnd - $markStart) . "\n"
    199                     . Director::absoluteURL(Director::makeRelative($cache_path)) ."\n"
    200                 ;
    201             }
    202             else {
    203                 Controller::curr()->getResponse()->addHeader("Content-Type", "text/xml");
    204                 readfile($cache_path);
    205             }
    206
    207             // But we want to still render.
    208             //return array();
    209         } else {
    210             return new SS_HTTPResponse('Not allowed', 405);
    211         }
    212     }
    213
    214     public static function enable() {
    215         self::$enabled = true;
    216     }
    217
    218     public static function disable() {
    219         self::$enabled = false;
    220     }
    221 }
    222
    223

[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -