[TomatoCart] Automatically generate a Google sitemap daily

As you know, it is possible to generate a Google sitemap in the admin panel. But, it is not efficient enough for the store owners. It is better to let your host server to generate the sitemap for your shop everyday. It means the whole procedure to generate sitemap is automatic and accurate, great for SEO involving no time from you once setup.

Note: Requires SSH access.

How to achieve it?

Step 1. Create a fold scripts in your Tomatocart root directory and then create a new generate_sitemap.php in it.

Snip20150418_1Step 2. Copy following code into generate_sitemap.php with your favorite text editor:

<?php 
	$root_path = dirname(__DIR__);
	
	set_include_path($root_path.PATH_SEPARATOR.get_include_path());
	
	include($root_path . '/includes/application_top.php');
	
	include('includes/classes/sefu.php');
	
	class osC_DirectoryListing {
	
		/* Private methods */
	
		var $_directory = '',
		$_include_files = true,
		$_include_directories = true,
		$_exclude_entries = array('.', '..','.svn'),
		$_stats = false,
		$_recursive = false,
		$_check_extension = array(),
		$_add_directory_to_filename = false,
		$_listing;
	
		/* Class constructor */
	
		function osC_DirectoryListing($directory = '', $stats = false) {
			$this->setDirectory(realpath($directory));
			$this->setStats($stats);
		}
	
		/* Public methods */
	
		function setDirectory($directory) {
			$this->_directory = $directory;
		}
	
		function setIncludeFiles($boolean) {
			if ($boolean === true) {
				$this->_include_files = true;
			} else {
				$this->_include_files = false;
			}
		}
	
		function setIncludeDirectories($boolean) {
			if ($boolean === true) {
				$this->_include_directories = true;
			} else {
				$this->_include_directories = false;
			}
		}
	
		function setExcludeEntries($entries) {
			if (is_array($entries)) {
				foreach ($entries as $value) {
					if (!in_array($value, $this->_exclude_entries)) {
						$this->_exclude_entries[] = $value;
					}
				}
			} elseif (is_string($entries)) {
				if (!in_array($entries, $this->_exclude_entries)) {
					$this->_exclude_entries[] = $entries;
				}
			}
		}
	
		function setStats($boolean) {
			if ($boolean === true) {
				$this->_stats = true;
			} else {
				$this->_stats = false;
			}
		}
	
		function setRecursive($boolean) {
			if ($boolean === true) {
				$this->_recursive = true;
			} else {
				$this->_recursive = false;
			}
		}
	
		function setCheckExtension($extension) {
			$this->_check_extension[] = $extension;
		}
	
		function setAddDirectoryToFilename($boolean) {
			if ($boolean === true) {
				$this->_add_directory_to_filename = true;
			} else {
				$this->_add_directory_to_filename = false;
			}
		}
	
		function read($directory = '') {
			if (empty($directory)) {
				$directory = $this->_directory;
			}
	
			if (!is_array($this->_listing)) {
				$this->_listing = array();
			}
	
			if ($dir = @dir($directory)) {
				while (($entry = $dir->read()) !== false) {
					if (!in_array($entry, $this->_exclude_entries)) {
						if (($this->_include_files === true) && is_file($dir->path . '/' . $entry)) {
							if (empty($this->_check_extension) || in_array(substr($entry, strrpos($entry, '.')+1), $this->_check_extension)) {
								if ($this->_add_directory_to_filename === true) {
									if ($dir->path != $this->_directory) {
										$entry = substr($dir->path, strlen($this->_directory)+1) . '/' . $entry;
									}
								}
	
								$this->_listing[] = array('name' => $entry,
										'is_directory' => false);
								if ($this->_stats === true) {
									$stats = array('size' => filesize($dir->path . '/' . $entry),
											'permissions' => fileperms($dir->path . '/' . $entry),
											'user_id' => fileowner($dir->path . '/' . $entry),
											'group_id' => filegroup($dir->path . '/' . $entry),
											'last_modified' => filemtime($dir->path . '/' . $entry));
									$this->_listing[sizeof($this->_listing)-1] = array_merge($this->_listing[sizeof($this->_listing)-1], $stats);
								}
							}
						} elseif (is_dir($dir->path . '/' . $entry)) {
							if ($this->_include_directories === true) {
								$entry_name= $entry;
	
								if ($this->_add_directory_to_filename === true) {
									if ($dir->path != $this->_directory) {
										$entry_name = substr($dir->path, strlen($this->_directory)+1) . '/' . $entry;
									}
								}
	
								$this->_listing[] = array('name' => $entry_name,
										'is_directory' => true);
								if ($this->_stats === true) {
									$stats = array('size' => filesize($dir->path . '/' . $entry),
											'permissions' => fileperms($dir->path . '/' . $entry),
											'user_id' => fileowner($dir->path . '/' . $entry),
											'group_id' => filegroup($dir->path . '/' . $entry),
											'last_modified' => filemtime($dir->path . '/' . $entry));
									$this->_listing[sizeof($this->_listing)-1] = array_merge($this->_listing[sizeof($this->_listing)-1], $stats);
								}
							}
	
							if ($this->_recursive === true) {
								$this->read($dir->path . '/' . $entry);
							}
						}
					}
				}
	
				$dir->close();
				unset($dir);
			}
		}
	
		function getFiles($sort_by_directories = true) {
			if (!is_array($this->_listing)) {
				$this->read();
			}
	
			if (is_array($this->_listing) && (sizeof($this->_listing) > 0)) {
				if ($sort_by_directories === true) {
					usort($this->_listing, array($this, '_sortListing'));
				}
	
				return $this->_listing;
			}
	
			return array();
		}
	
		function getSize() {
			if (!is_array($this->_listing)) {
				$this->read();
			}
	
			return sizeof($this->_listing);
		}
	
		function getDirectory() {
			return $this->_directory;
		}
	
		/* Private methods */
	
		function _sortListing($a, $b) {
			return strcmp((($a['is_directory'] === true) ? 'D' : 'F') . $a['name'], (($b['is_directory'] === true) ? 'D' : 'F') . $b['name']);
		}
	}
		
	
	class toC_Google_Sitemap {
	
		var $_file_name = '',
		$_save_path = '',
		$_base_url = '',
		$_max_entries = 0,
		$_max_file_size = 0,
		$_file_array = array(),
		$_compression = false,
		$_products_change_freq = '',
		$_categories_change_freq = '',
		$_articles_change_freq = '',
		$_products_priority = '',
		$_categories_priority = '',
		$_articles_priority = '',
		$_original_language_code = '',
		$_sefu = null;
	
		function toC_Google_Sitemap($language_code = 'en_US', $products_change_freq = 'weekly', $products_priority = 0.5, $categories_change_freq = 'weekly', $categories_priority = 0.5, $articles_change_freq = 'weekly', $articles_priority = 0.25){
			global $osC_CategoryTree, $osC_Language;
	
			$this->_original_language_code = $osC_Language->getCode();
	
			$osC_Language->set($language_code);
	
			if ($language_code !== 'en_US') {
				$this->_file_name = "sitemaps_{$language_code}_";
			}else {
				$this->_file_name = "sitemaps";
			}
	
			$this->_save_path = DIR_FS_CATALOG;
			$this->_base_url = HTTP_SERVER . DIR_WS_HTTP_CATALOG;
			$this->_max_file_size = 10 * 1024 * 1024;
			$this->_max_entries = 50000;
			$this->_sefu = new toC_Sefu();
	
			$this->_products_change_freq = $products_change_freq;
			$this->_products_priority = $products_priority;
			$this->_categories_change_freq = $categories_change_freq;
			$this->_categories_priority = $categories_priority;
			$this->_articles_change_freq = $articles_change_freq;
			$this->_articles_priority = $articles_priority;
	
			$osC_CategoryTree = new osC_CategoryTree();
		}
	
		function generateSitemap() {
			return $this->_createCategorySitemap() && $this->_createProductSitemap() && $this->_createArticleSitemap() && $this->_createIndexSitemap();
		}
	
		function setCompression($compression) {
			if($compression == 1)
				$this->_compression = true;
		}
	
		function _hrefLink($page, $parameters) {
			$link = osc_href_link($page, $parameters, 'NONSSL', false);
	
			return $this->_sefu->generateURL($link, $page, $parameters);
		}
	
		function _createSitemapFile($file) {
			$file_name = $this->_save_path  . $this->_file_name . $file . '.xml';
	
			if ($this->_compression == true) {
				$file_name .= '.gz';
				$handle = gzopen($file_name,'wb9');
			} else {
				$handle = fopen($file_name, 'w');
			}
	
			$this->_file_array[] =  $file_name;
	
			return $handle;
		}
	
		function _writeFile($handle, $data) {
			if ($this->_compression == true) {
				gzwrite($handle, $data);
			} else {
				fwrite($handle, $data);
			}
		}
	
		function _writeSitemapFile(&$handle, $data, &$num_of_entries, &$num_of_files, $type) {
			$num_of_entries++;
			$this->_writeFile($handle, $data);
	
			if ( ($num_of_entries >= $this->_max_entries) || (filesize(end($this->_file_array)) >= $this->_max_file_size)) {
				$num_of_entries = 0;
				$num_of_files++;
				$handle = $this->_recreateSitemap($handle, $type, $num_of_files);
			}
		}
	
		function _closeSitemapFile($handle) {
			if($this->_compression) {
				fwrite($handle, '</urlset>');
				fclose($handle);
			}else{
				gzwrite($handle, '</urlset>');
				gzclose($handle);
			}
		}
	
		function _createUrlElement($url, $last_mod, $change_freq, $priority) {
			global $osC_Language;
	
			$xml = "\t" . '<url>' . "\n";
	
			//multiple language
			if (count($osC_Language->getAll() > 0)) {
				$xml .= "\t\t" . '<loc>' . $url . '?language=' . $osC_Language->getCode() . '</loc>' . "\n";
			}else {
				$xml .= "\t\t" . '<loc>' . $url . '</loc>' . "\n";
			}
	
			$xml .= "\t\t" . '<lastmod>' . $last_mod . '</lastmod>' . "\n";
			$xml .= "\t\t" . '<changefreq>' . $change_freq . '</changefreq>' . "\n";
			$xml .= "\t\t" . '<priority>' . $priority . '</priority>' . "\n";
			$xml .= "\t" . '</url>' . "\n";
	
			return $xml;
		}
	
		function _createXmlHeader() {
			$xml = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
			$xml .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
	
			return $xml;
		}
	
		function _createIndexSitemap() {
			global $osC_Language;
	
			$handle = fopen($this->_save_path . 'sitemapsIndex.xml', 'w');
			$xml = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
			$xml .= '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
			fwrite($handle, $xml);
	
			$directory_listing = new osC_DirectoryListing($this->_save_path);
			$directory_listing->setIncludeDirectories(false);
			$directory_listing->setIncludeFiles(true);
			$directory_listing->setCheckExtension('xml');
			$xmls = $directory_listing->getFiles();
	
			if (!empty($xmls)) {
				foreach($xmls as $xml) {
					if (($xml['name'] !== $this->_file_name . 'Index.xml') && preg_match('/^sitemaps[A-Za-z_]+\.xml$/', $xml['name'])) {
						$content = "\t". '<sitemap>' . "\n";
						$content .= "\t\t" . '<loc>'.$this->_base_url . basename($xml['name']) . '</loc>' . "\n";
						$content .= "\t\t" . '<lastmod>'.date ("Y-m-d", filemtime($this->_save_path . basename($xml['name']))).'</lastmod>' . "\n";
						$content .= "\t" . '</sitemap>' . "\n";
						fwrite($handle, $content);
					}
				}
			}
	
			fwrite($handle, '</sitemapindex>');
	
			fclose($handle);
	
			$osC_Language->set($this->_original_language_code);
	
			return true;
		}
	
		function _recreateSitemap($handle, $filename, $num_of_file) {
			$this->_closeSitemapFile($handle);
			$file = $filename . $num_of_file;
			$handle = $this->_createSitemapFile($file);
			$this->_writeFile($handle, $this->_createXmlHeader());
	
			return $handle;
		}
	
		function _createProductSitemap() {
			global $osC_Database;
	
			$num_of_entries = 0;
			$num_of_product_file = 0;
	
			$Qproducts = $osC_Database->query('select products_id, if( products_last_modified is null , products_date_added, products_last_modified ) as last_modified, products_ordered from :table_products where products_status=1 order by products_ordered desc');
			$Qproducts->bindTable(':table_products', TABLE_PRODUCTS);
			$Qproducts->execute();
	
			$handle = $this->_createSitemapFile('Products');
			$this->_writeFile($handle, $this->_createXmlHeader());
	
			while ( $Qproducts->next() ) {
				$location = $this->_base_url . $this->_hrefLink(FILENAME_PRODUCTS, $Qproducts->valueInt('products_id'));
				$last_mod = date ("Y-m-d", osC_DateTime::getTimestamp($Qproducts->value('last_modified')));
	
				$this->_writeSitemapFile($handle, $this->_createUrlElement($location, $last_mod, $this->_products_change_freq, $this->_products_priority), $num_of_entries, $num_of_product_file, 'Product');
			}
			$Qproducts->freeResult();
			$this->_closeSitemapFile($handle);
	
			return true;
		}
	
		function _createCategorySitemap() {
			global $osC_Database, $osC_CategoryTree;
	
			$num_of_entries = 0;
			$num_of_category_file = 0;
	
			$Qcategories = $osC_Database->query('select categories_id, if( last_modified is null , date_added, last_modified ) as last_modified from :table_categories order by parent_id asc, sort_order asc, categories_id asc');
			$Qcategories->bindTable(':table_categories', TABLE_CATEGORIES);
			$Qcategories->execute();
	
			$handle = $this->_createSitemapFile('Categories');
			$this->_writeFile($handle, $this->_createXmlHeader());
			while ( $Qcategories->next() ) {
				$location    = $this->_base_url . $this->_hrefLink(FILENAME_DEFAULT, 'cPath=' . $osC_CategoryTree->getFullcPath($Qcategories->valueInt('categories_id')));
				$last_mod    = date ("Y-m-d", osC_DateTime::getTimestamp( $Qcategories->value('last_modified')));
	
				$this->_writeSitemapFile($handle, $this->_createUrlElement($location, $last_mod, $this->_categories_change_freq, $this->_categories_priority), $num_of_entries, $num_of_category_file, 'Category');
			}
			$Qcategories->freeResult();
			$this->_closeSitemapFile($handle);
	
			return true;
		}
	
		function _createArticleSitemap() {
			global $osC_Database;
	
			$num_of_entries = 0;
			$num_of_article_file = 0;
	
			$Qarticles = $osC_Database->query('select articles_id , if( articles_last_modified  is null || articles_last_modified in (\'0000-00-00 00:00:00\'), articles_date_added, articles_last_modified  ) as last_modified from :table_articles order by articles_order asc, articles_id asc');
			$Qarticles->bindTable(':table_articles', TABLE_ARTICLES);
			$Qarticles->execute();
	
			$handle = $this->_createSitemapFile('Articles');
			$this->_writeFile($handle, $this->_createXmlHeader());
			while ( $Qarticles->next() ) {
				$location    = $this->_base_url . $this->_hrefLink(FILENAME_INFO, 'articles&articles_id=' . $Qarticles->valueInt('articles_id'));
				$last_mod    = date ("Y-m-d", osC_DateTime::getTimestamp( $Qarticles->value('last_modified')));
				$change_freq = $article_change_frequency;
	
				$this->_writeSitemapFile($handle, $this->_createUrlElement($location, $last_mod, $this->_articles_change_freq, $this->_articles_priority), $num_of_entries, $num_of_article_file, 'Article');
			}
			$Qarticles->freeResult();
			$this->_closeSitemapFile($handle);
	
			return true;
		}
	
		function getSubmitURL() {
			$sitemap_url = $this->_base_url . 'sitemapsIndex.xml';
			return htmlspecialchars( utf8_encode('http://www.google.com/webmasters/sitemaps/ping?sitemap=' . $sitemap_url));
		}
	}
	
	$google_sitemap = new toC_Google_Sitemap();
	
	$google_sitemap->generateSitemap();
?>

Step3. Login into your host server via ssh:

Snip20150418_2As you can see, your just need to replace the root with your own username. After the @, you have to enter your own shop domain.

Step 4. One you login into your host server, you have to go into your tomatocart root directory. Generally, it should locate in /var/www/yourdomain.com.

Step 5. Type following command to edit the crontab in order to run the above script automatically everyday:

Snip20150418_3

Snip20150418_4As you can see, it means the generate_sitemap script will be run automatically by your server at 23:59 everyday. In this way, all of sitemap xml files within in store root directory will be updated automatically.

Snip20150418_6

Snip20150418_7Done. Note: only the English is supported currently. I will improve the script to make it possible to support multiple languages.

If you are not a developer, it maybe very difficult to complete above steps. I prefer to assist you to apply above changes for your shop. Please contact me via support@tomatocart.com. I will help you as possible as i can.

Looking for quality TomatoCart hosting? Check out Arvixe Web Solutions.

Posted under TomatoCart | RSS 2.0

Author Spotlight

Jack Yin

TomatoCart Developer & Co Founder - Arvixe Web Hosting / TomatoCart Community Liaison

Leave a Reply

Your email address will not be published. Required fields are marked *