Generates sitemap.xml file by docComment mark @sitemap for Yii controllers actions. Has lots of options, built-in URL-parsers for CActiveRecord and CViewAction, allows dynamic creation of urls.
Requirements ¶
- Yii 1.1.8 (other versions not tested).
- PHP 5.2 or later.
- PHP Reflection extension.
- PHP SimpleXML extension.
Links ¶
- Sitemaps.org
- Google code project page
- Installation wiki page
- Adding URLs wiki page
- Configuration wiki page
- Some notes
Adding URLs to sitemap.xml ¶
Single URL ¶
To add single url by action route just add @sitemap comment:
/**
* @sitemap
*/
public function actionIndex() { ... }
For more functional adding of URLs please see adding URLs wiki page.
Updates ¶
2011/10/25 - v0.81a
- Small bugfixes: php5.2 support for custom models URLs parser by name, and strict mode errors.
2011/10/17 - v0.8a
- Warning: NO backward compatibility for previous versions. Lots of changes in code. If you want to upgrade from previous version, please reinstall extension. See Installation wiki page. Already added @sitemap marks will work fine with new version.
- All configuration moved to config/main.php. Sitemap files are now rendered through own separate controller (no need for code in other controllers except for adding URLs).
- Added caching support. wiki
- Added flexible pre-import support. wiki
- Added support of multiple @sitemap marks in single method doc-comment.
- Added built-in parsers for adding CActiveRecord models and CActionView files. Wiki pages: CActiveRecord-based URLs and CViewAction view files.
- Added support for 'yiic messages' and russian messages file (mostly contains exception messages).
2011/10/09 - v0.7a
- Added to google code. Most of description (which became to large for single extension page) moved to wiki pages. See links section.
- Added CBaseUrlRule class file for handling routes and CAction class file for handling sitemap action. New installation and configuration became even more easily, especially for multiple sitemap files.
- Aliases now can be specified as comma-separated string.
- Added configuration option for route structure. Before that it was by default 'application,modules,controllers'.
- lastmod attribute now can be specified by unix timestamp integer(!) value. Can be useful while using PHPs time(), filemtime() and other functions.
- Small bugfixes.
- Full backward compatibility.
2011/10/04 - v0.6a
Aliases now can be specified to directories of controllers and also to exact controllers files. Example: $aliases=array('application.controllers.SiteController');
Added support for multiple sitemap.xml files. See description for examples. Protocol details: sitemap index file.
Max urls limited to 50000 per single sitemap.xml file. Link: sitemap size Filesize are not checked due to different php settings of data compressing (zlib extension and etc.). If there is serious probability that file size will exceed 10mb, then you will need to create several sitemap files with sitemap index.
Forced conversion datetime's ('lastmod' attribute) to W3C datetime format. Source datetime must be specified in valid datetime format. Timezone must be set in given datetime. If it's not, then will be used default timezone (or you can set it with php function date_default_timezone_set()). Details.
Fixed: Urls with GET params are now escaped. Link: Sitemap url escaping
Added SitemapGenerator::renderAsGz() If by any reason zlib doesn't make buffer output auto-gz-encoding, you can use SitemapGenerator::renderAsGz() method, which is clone of SitemapGenerator::render(), but with forced gzencoding.
To render() methods added headers for browser caching disabling and error exception handling.
2011/10/03 - v0.51a
- fixed PHP 5.2 support.
Clear in usage
can you be clear in your installation instructions. i wish you could say for dynamic pages with models do this and that and for static pages do this and that. Instead of actionIndex, actionIndexTwo.Thanks
New description
Done. I hope this one will be more easy to read.
Sitemap with modules
I have my main config as the way you stated
array( 'components'=>array( 'urlManager'=>array( 'rules'=>array( // index sitemap 'sitemap.xml'=>'/site/sitemap', // large sitemap for BusinessesModule 'sitemapBusinesses.xml'=>'/site/sitemapBusinesses', // another large sitemap for AutosModule 'sitemapAutos.xml'=>'/site/sitemapAutos', ), ), ), );
Next I have this in my sitecontroler
/* Index sitemap */ public function actionSitemap() { Yii::import('ext.sitemapgenerator.SitemapGenerator'); $sitemaps=array( // Add sitemap by route array( 'route'=>'/site/sitemapBusinesses', 'lastmod'=>'2012-12-25', // optional ), array( 'route'=>'/site/sitemapAutos', ), ); SitemapGenerator::renderIndex($sitemaps); } /* Sitemap of URLs for Businesses module controllers */ public function sitemapBusinesses() { Yii::import('ext.sitemapgenerator.SitemapGenerator'); $aliases=array( 'application.modules.BusinessesModule.controllers' ); SitemapGenerator::render($aliases); } /* Sitemap of URLs for Catalog module controllers */ public function sitemapAutos() { Yii::import('ext.sitemapgenerator.SitemapGenerator'); $aliases=array( 'application.modules.AutosModule.controllers' ); SitemapGenerator::render($aliases); }
Before I had added the module sitemap the default below worked fine but after including the modules no sitemap for index and my static pages.
I get this instead when I try to http://localhost/myweb.dev/sitemap.xml.
<sitemapindex xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/siteindex.xsd"><sitemap><loc>http://localhost/myweb.dev/sitemap_businesses.xml</loc><lastmod>2012-12-25T00:00:00+00:00</lastmod></sitemap></sitemapindex>
/
@sitemap
*/
public function actionIndex(){..}
Should I have different actionsitemap() for sitecontroller and for the each module.
Please help your extension seem to be doing what i need. Thanks
RE: Sitemap with modules
Maybe you copy wrong part of simple.xml code, cause as i see, it has only only one sitemap file http://localhost/myweb.dev/sitemap_businesses.xml but you specified at index $sitemaps two of them.
Also looks like this file URL was uncorrectly resolved by route:
In main.cfg:
'sitemapBusinesses.xml'=>'/site/sitemapBusinesses',
but in sitemap.xml file
http://localhost/myweb.dev/sitemap_businesses.xml
Or its again not exact copy/paste.
All sitemaps creates by specified aliases. In your example its only from modules.
If you need also protected/controllers, just add another sitemap to index sitemap.xml.
Like this:
main.cfg
array( 'components'=>array( 'urlManager'=>array( 'rules'=>array( // index sitemap 'sitemap.xml'=>'/site/sitemap', // large sitemap for BusinessesModule 'sitemapBusinesses.xml'=>'/site/sitemapBusinesses', // another large sitemap for AutosModule 'sitemapAutos.xml'=>'/site/sitemapAutos', // protected/controllers sitemap 'sitemapMain.xml'=>'/site/sitemapMain', ), ), ), );
In controller:
/* Index sitemap */ public function actionSitemap() { Yii::import('ext.sitemapgenerator.SitemapGenerator'); $sitemaps=array( array( 'route'=>'/site/sitemapBusinesses' ), array( 'route'=>'/site/sitemapAutos' ), array( 'route'=>'/site/sitemapMain' ), ); SitemapGenerator::renderIndex($sitemaps); } /* Sitemap of URLs for Main controllers */ public function sitemapMain() { Yii::import('ext.sitemapgenerator.SitemapGenerator'); $aliases=array( 'application.controllers' ); SitemapGenerator::render($aliases); } // Other actions as you specified //...
Hope this will help.
Sitemap with modules and static pages
So have configured again and this is what I get.
For the sitemap.xml I get
<sitemapindex xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/siteindex.xsd"><sitemap><loc>http://localhost/myweb.dev/sitemapBusinesses.xml</loc><lastmod>2012-12-25T00:00:00+00:00</lastmod></sitemap><sitemap><loc>http://localhost/myweb.dev/sitemapAutos.xml</loc><lastmod>2011-10-05T20:23:02+00:00</lastmod></sitemap><sitemap><loc>http://localhost/myweb.dev/sitemapMain.xml</loc><lastmod>2011-10-05T20:23:02+00:00</lastmod></sitemap></sitemapindex>
And if I go to each one example sitemapMain.xml I get this.
<urlset xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"><url><loc>http://localhost/myweb.dev/</loc><lastmod>2011-10-04T00:00:00+00:00</lastmod><changefreq>daily</changefreq><priority>0.3</priority></url><url><loc>http://localhost/myweb.dev/about-us</loc><lastmod>2011-10-05T20:25:01+00:00</lastmod><changefreq>yearly</changefreq><priority>0.8</priority></url><url><loc>http://localhost/myweb.dev/rules</loc><lastmod>2011-10-05T20:25:01+00:00</lastmod><changefreq>daily</changefreq><priority>0.9</priority></url><url><loc>http://localhost/myweb.dev/help-support</loc><lastmod>2011-10-05T20:25:01+00:00</lastmod><changefreq>yearly</changefreq><priority>1</priority></url><url><loc>http://localhost/myweb.dev/privacy-statement</loc><lastmod>2011-10-05T20:25:01+00:00</lastmod><changefreq>yearly</changefreq><priority>1</priority></url><url><loc>http://localhost/myweb.dev/terms-use</loc><lastmod>2011-10-05T20:25:01+00:00</lastmod><changefreq>yearly</changefreq><priority>1</priority></url></urlset>
Let me know if this is how the output should be. I think I was not including action part on the methods.
RE: Sitemap with modules and static pages
Corresponding to Sitemap protocol it seems like everything is alright.
If you see all of the pages you needed in sitemapMain.xml, then everything works fine.
Except maybe i recommend you to specify 'lastmod' attribute for them, cause by default it is set to current date but i see there is and 'yearly' modified periods. If its static pages, you can pass result of filemtime() of view files to 'lastmod' attribute. Like this:
/** * @sitemap dataSource=getViewPages */ public function getViewPages() { $pages_path=Yii::getPathOfAlias('webroot.themes.'.Yii::app()->theme->name.'.views.site.pages'); // this is path if you have active theme, change it to yours return array( array( 'params'=>array('view'=>'rules'), 'lastmod'=>date(DATE_W3C,filemtime($pages_path.'/rules.php')), ), ); }
This should work fine.
Thanks
Thanks very much as per sitemap protocol am right. Thanks again I have been doing endless search looking for this kind of extension.
Support for Different Directory Structures
First off - great extension.
One small bug: line 246 has the "new" keyword missing; it should be:
throw new Exception("Alias path not founded. Alias: '$alias'");
But the main reason for this comment is to be able to use SitemapGenerator with project structures other than the standard "out-of-the-box" Yii project sructure, e.g. the Yii project site structure which I use for my projects as it nicely separates the front and back ends.
Currently, SitemapGenerator has the project structure hard coded in line 310:
$route=array_diff($route,array('application','modules','controllers'));
Using SitemapGenerator I was getting URLs like http://domain/frontend/controller/action, whereas they should be http://controller/action - or as modified by the URL rules.
I made the following changes to get it working with my project structure, and they I think they will support the general case:
private $_route=array('application','modules','controllers');
$route=array_diff($route,$this->_route);
public function __construct($aliases=null,$route=null) { // same to here if ($aliases!==null) { if (is_string($aliases)) // allow aliases to be comma delimited string like many other Yii configs $aliases = explode(',',$aliases); if (!is_array($aliases)) throw new Exception('Aliases must be a comma delimited string or an array of aliases.'); $this->_aliases=$aliases; } if ($route!==null) // Set the route if given $this->_route = $route; $this->_xml=new SimpleXMLElement($xml); $this->_xml_index=new SimpleXMLElement($xml_index); }
public static function render($aliases=null,$route=null) { try { $class=__CLASS__; $map=new $class($aliases,$route); // Same after here }
Now I can generate a sitemap for my project with:
public function actionSitemap() { Yii::import('ext.Sitemap'); Sitemap::render('frontend.controllers',array('frontend','modules','controllers')); }
Note use of a string for the alias and the addition of a custom route/structure.
Re: suggestions
2Yeti
Thanks for comment. Really useful. I was preparing some additional code and your comment was right on time. I'll make some fix, but structure will be a little different, cause now there will be support for default values and even more easily installation and configuration. Will be ready soon.
Thanks again for your backreport.
Issue with CController::actions() URL creation
I have a problem when using CController::actions() with anything other than CViewAction(). I have some feedback pages for some holiday properties. Feedback can be viewed "about" a property or "by" a customer; as the two are very similar they use the same action specified in the controller's actions() method.
My URLs should be (for example) http://domain/feeback/about/property_name - I was seeing http://domain/feedback/s/about/property_name (similar results for feedback/by/user_name).
The fix I have found is to change the line in sitemapGenerator::createRoute() that generates the action id to:
$action=($action_method_name==='actions'?'':lcfirst(substr($action_method_name,strlen('action'))));
This sets the action id to an empty string if the action method is "actions"; the params from the data source then complete the URL.
Re: Issue with CController::actions() URL creation
I'm not sure that i correctly understand your example.
Did you try to specify directly route parameter? Cause in case of actions located in controllers actions() it must be specified for correct url creation. May be this is just is your case. Route can be specified as in @sitemap mark, also and in URLs array returned by dataSource method.
Re: Issue with CController::actions() URL creation
This is the function I have for generating the sitemap data for the actions() method; I have only show the settings for properties.
public function sitemapActions() { $data = array(); foreach (array('about','by','index') as $id) { switch ($id) { case 'about': foreach (Property::model()->visible()->findAll() as $property) { $data[] = array( 'params'=>array('about=>$property->slug), 'lastmod'=>$property->latestFeedback->created ); } break; case 'by': // similar to properties, except for users break; case 'index': $data[] = array('params'=>array($id=>'')); break; } } return $data; }
The change I made in previous comment allows me to just specify the action id and parameters and sitemapGenerator generates the URL for me.
Re
Try to do the following:
/** * @sitemap dataSource=sitemapActions route=/feedback */
Where /feedback is your route. This should do the work.
And may be there is a small error (single quote missing after about):
... 'params'=>array('about=>$property->slug), ...
generate file
love the extension, has some trouble wrapping my head around it at first, but now its working great. My only question is, do you have a way to actually generate a file that sits on the server to be downloaded, so that the server doesn't have to run it every time the file is called? My sitemap(s) will have 100k+ urls and i'd prefer to have the file sitting as opposed to having it generated dynamically.
Thanks.
File storing
Why not to use just Yii file caching? This way you can also add dependency for validating sitemap file.
Caching support for component
'controllerMap'=>array( 'sitemap'=>array( 'class'=>'ext.sitemapgenerator.SGController', 'config'=>array( 'sitemap.xml'=>array( ... 'cache'=>array('Some_CFileCache_Component', 99999999, SOME_DEPENDENCY_COMPONENT), ), ), ), ),
This may solve your issue.
Limits
I am using the cache for now, thanks. Is there a way to break up a specific controllers links into multiple files?
help with modules generating
Hi, firstly I would like to thank you for this extension.
My problem is when I add @sitemap to module controllers I'm getting the error "Option '
' cannot be empty."
What might be the problem?
@Sobit
Thanks, glad to help.
About your problem, maybe somewhere in doccomments you paste wrong configuration wich cannot be parsed.
Search for strings with sign equal '=' and empty string near it, like:
@sitemap =
@sitemap route=
or something like this.
@evgeny.l
I deleted all phpdocs and still getting the error. :(
There is about 8-9 controllers in the folder and error appears only when I add at least 1 @sitemap in it. However, it works perfect with controllers that are not in the module.
The module I'm testing it with is yii-user
Do you think it is the module's problem?
@Sobit
Khm. Can't tell you anything more about what is the problem.
Try to debug through file SitemapGenerator.php, line 444 (methos parseParamsString),
insert code var_dump($string); and see yourself wich string parser cannot process.
@evgeny.l
here's the output :(
This page contains the following errors: error on line 1 at column 1: Document is empty Below is a rendering of the page up to the first error.
@Sobit
This error doesn't tells anything about sitemapgenerator. Please debug exactly where is appears. Or what outputs var_dump wich i recommend you to debug in previous comment.
@evgeny.l
It was the output of var_dump placed exactly where you said.
@Sobit
Then looks like you have to move upper by the code execution and debug method parseController
SitemapGenerator.php, line 223
How it happens that this errors pass to parser.
@evgeny.l
Sorry, first var_dump worked but showed nothing because of ".xml". In the source code I found following:
var_dump:
~~~
string(1) " "
~~~
error:
~~~
Option '
' cannot be empty.
~~~
Having trouble getting it to work
I put the files in extensions/sitemapgenerator, and have the following in my main.php config file:
'controllerMap'=>array( 'sitemap'=>array( 'class'=>'ext.sitemapgenerator.SGController', 'config'=>array( 'sitemap.xml'=>array( 'aliases'=>array( 'application.controllers', ), ), ), ), ),
and
'urlManager'=>array( 'urlFormat'=>'path', 'showScriptName'=>false, 'rules'=>array( array( 'class'=>'ext.sitemapgenerator.SGUrlRule', 'route'=>'/sitemap', // Optional. Default: '/sitemap' ), '<controller:\w+>/<id:\d+>'=>'<controller>/view', '<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>', '<controller:\w+>/<action:\w+>'=>'<controller>/<action>', ),
I have 10 controllers in my controllers folder, and nothing shows up under localhost/sitemap.xml
If I add @sitemap to a controller action, I get "Undefined offset: 1". and it refers to SiteMapGenerator line 438L
list($key,$val)=explode('=',$param,2);
Any idea what I am doing wrong here? Thanks.
How to split into multiple sitemaps from one controller?
Im generating urls from a model with +25k records and i would like to split it in 2 sitemaps. How can i do that? Its possible?
@chifliiiii multiple maps for one controller
I had to resort to creating extra controllers around the same model, then configuring them to only send a range of the urls.
~~~
public function getModelsUrls()
{
$criteria = new CDbCriteria(); //$criteria->compare('topic',$topic_id); $criteria->limit = 49999; $criteria->offset = 199997; $criteria->order = "id ASC"; $models=MyModel::model()->findAll($criteria); $data=array(); foreach($models as $model) $data[]=array( 'route'=>'view', 'params'=>array('id'=>$model->id), // Optional parameters 'changefreq'=>'monthly', 'priority'=>'0.5', );
return $data;
}
/**
*/
Sitemap For Static Pages
How can i set sitemap for the static pages
Params
It won't work without any parameters
You have to write anything. Example
/**
*/
moved to github
with the original author's permission I have moved this over to github and will be helping to maintain from here on. please find it at: https://github.com/duncanmapes/yii-sitemapgenerator
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.