18c2e8227SGreg Roach<?php 28c2e8227SGreg Roach/** 38c2e8227SGreg Roach * webtrees: online genealogy 4*369c0ce6SGreg Roach * Copyright (C) 2016 webtrees development team 58c2e8227SGreg Roach * This program is free software: you can redistribute it and/or modify 68c2e8227SGreg Roach * it under the terms of the GNU General Public License as published by 78c2e8227SGreg Roach * the Free Software Foundation, either version 3 of the License, or 88c2e8227SGreg Roach * (at your option) any later version. 98c2e8227SGreg Roach * This program is distributed in the hope that it will be useful, 108c2e8227SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 118c2e8227SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 128c2e8227SGreg Roach * GNU General Public License for more details. 138c2e8227SGreg Roach * You should have received a copy of the GNU General Public License 148c2e8227SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 158c2e8227SGreg Roach */ 1676692c8bSGreg Roachnamespace Fisharebest\Webtrees\Module; 1776692c8bSGreg Roach 180e62c4b8SGreg Roachuse Fisharebest\Webtrees\Auth; 190e62c4b8SGreg Roachuse Fisharebest\Webtrees\Controller\PageController; 200e62c4b8SGreg Roachuse Fisharebest\Webtrees\Database; 210e62c4b8SGreg Roachuse Fisharebest\Webtrees\Filter; 220e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N; 230e62c4b8SGreg Roachuse Fisharebest\Webtrees\Individual; 240e62c4b8SGreg Roachuse Fisharebest\Webtrees\Media; 250e62c4b8SGreg Roachuse Fisharebest\Webtrees\Note; 260e62c4b8SGreg Roachuse Fisharebest\Webtrees\Repository; 270e62c4b8SGreg Roachuse Fisharebest\Webtrees\Source; 280e62c4b8SGreg Roachuse Fisharebest\Webtrees\Tree; 298c2e8227SGreg Roach 308c2e8227SGreg Roach/** 318c2e8227SGreg Roach * Class SiteMapModule 328c2e8227SGreg Roach */ 33e2a378d3SGreg Roachclass SiteMapModule extends AbstractModule implements ModuleConfigInterface { 348c2e8227SGreg Roach const RECORDS_PER_VOLUME = 500; // Keep sitemap files small, for memory, CPU and max_allowed_packet limits. 358c2e8227SGreg Roach const CACHE_LIFE = 1209600; // Two weeks 368c2e8227SGreg Roach 378c2e8227SGreg Roach /** {@inheritdoc} */ 388c2e8227SGreg Roach public function getTitle() { 398c2e8227SGreg Roach return /* I18N: Name of a module - see http://en.wikipedia.org/wiki/Sitemaps */ I18N::translate('Sitemaps'); 408c2e8227SGreg Roach } 418c2e8227SGreg Roach 428c2e8227SGreg Roach /** {@inheritdoc} */ 438c2e8227SGreg Roach public function getDescription() { 448c2e8227SGreg Roach return /* I18N: Description of the “Sitemaps” module */ I18N::translate('Generate sitemap files for search engines.'); 458c2e8227SGreg Roach } 468c2e8227SGreg Roach 4776692c8bSGreg Roach /** 4876692c8bSGreg Roach * This is a general purpose hook, allowing modules to respond to routes 4976692c8bSGreg Roach * of the form module.php?mod=FOO&mod_action=BAR 5076692c8bSGreg Roach * 5176692c8bSGreg Roach * @param string $mod_action 5276692c8bSGreg Roach */ 538c2e8227SGreg Roach public function modAction($mod_action) { 548c2e8227SGreg Roach switch ($mod_action) { 558c2e8227SGreg Roach case 'admin': 568c2e8227SGreg Roach $this->admin(); 578c2e8227SGreg Roach break; 588c2e8227SGreg Roach case 'generate': 598c2e8227SGreg Roach $this->generate(Filter::get('file')); 608c2e8227SGreg Roach break; 618c2e8227SGreg Roach default: 628c2e8227SGreg Roach http_response_code(404); 638c2e8227SGreg Roach } 648c2e8227SGreg Roach } 658c2e8227SGreg Roach 668c2e8227SGreg Roach /** 6776692c8bSGreg Roach * Generate an XML file. 6876692c8bSGreg Roach * 698c2e8227SGreg Roach * @param string $file 708c2e8227SGreg Roach */ 718c2e8227SGreg Roach private function generate($file) { 728c2e8227SGreg Roach if ($file == 'sitemap.xml') { 738c2e8227SGreg Roach $this->generateIndex(); 748c2e8227SGreg Roach } elseif (preg_match('/^sitemap-(\d+)-([isrmn])-(\d+).xml$/', $file, $match)) { 758c2e8227SGreg Roach $this->generateFile($match[1], $match[2], $match[3]); 768c2e8227SGreg Roach } else { 778c2e8227SGreg Roach http_response_code(404); 788c2e8227SGreg Roach } 798c2e8227SGreg Roach } 808c2e8227SGreg Roach 818c2e8227SGreg Roach /** 828c2e8227SGreg Roach * The index file contains references to all the other files. 838c2e8227SGreg Roach * These files are the same for visitors/users/admins. 848c2e8227SGreg Roach */ 858c2e8227SGreg Roach private function generateIndex() { 868c2e8227SGreg Roach // Check the cache 878c2e8227SGreg Roach $timestamp = $this->getSetting('sitemap.timestamp'); 888c2e8227SGreg Roach if ($timestamp > WT_TIMESTAMP - self::CACHE_LIFE) { 898c2e8227SGreg Roach $data = $this->getSetting('sitemap.xml'); 908c2e8227SGreg Roach } else { 918c2e8227SGreg Roach $data = ''; 928c2e8227SGreg Roach $lastmod = '<lastmod>' . date('Y-m-d') . '</lastmod>'; 938c2e8227SGreg Roach foreach (Tree::getAll() as $tree) { 948c2e8227SGreg Roach if ($tree->getPreference('include_in_sitemap')) { 958c2e8227SGreg Roach $n = Database::prepare( 968c2e8227SGreg Roach "SELECT COUNT(*) FROM `##individuals` WHERE i_file = :tree_id" 978c2e8227SGreg Roach )->execute(array('tree_id' => $tree->getTreeId()))->fetchOne(); 988c2e8227SGreg Roach for ($i = 0; $i <= $n / self::RECORDS_PER_VOLUME; ++$i) { 998c2e8227SGreg Roach $data .= '<sitemap><loc>' . WT_BASE_URL . 'module.php?mod=' . $this->getName() . '&mod_action=generate&file=sitemap-' . $tree->getTreeId() . '-i-' . $i . '.xml</loc>' . $lastmod . '</sitemap>' . PHP_EOL; 1008c2e8227SGreg Roach } 1018c2e8227SGreg Roach $n = Database::prepare( 1028c2e8227SGreg Roach "SELECT COUNT(*) FROM `##sources` WHERE s_file = :tree_id" 1038c2e8227SGreg Roach )->execute(array('tree_id' => $tree->getTreeId()))->fetchOne(); 1048c2e8227SGreg Roach if ($n) { 1058c2e8227SGreg Roach for ($i = 0; $i <= $n / self::RECORDS_PER_VOLUME; ++$i) { 1068c2e8227SGreg Roach $data .= '<sitemap><loc>' . WT_BASE_URL . 'module.php?mod=' . $this->getName() . '&mod_action=generate&file=sitemap-' . $tree->getTreeId() . '-s-' . $i . '.xml</loc>' . $lastmod . '</sitemap>' . PHP_EOL; 1078c2e8227SGreg Roach } 1088c2e8227SGreg Roach } 1098c2e8227SGreg Roach $n = Database::prepare( 1108c2e8227SGreg Roach "SELECT COUNT(*) FROM `##other` WHERE o_file = :tree_id AND o_type = 'REPO'" 1118c2e8227SGreg Roach )->execute(array('tree_id' => $tree->getTreeId()))->fetchOne(); 1128c2e8227SGreg Roach if ($n) { 1138c2e8227SGreg Roach for ($i = 0; $i <= $n / self::RECORDS_PER_VOLUME; ++$i) { 1148c2e8227SGreg Roach $data .= '<sitemap><loc>' . WT_BASE_URL . 'module.php?mod=' . $this->getName() . '&mod_action=generate&file=sitemap-' . $tree->getTreeId() . '-r-' . $i . '.xml</loc>' . $lastmod . '</sitemap>' . PHP_EOL; 1158c2e8227SGreg Roach } 1168c2e8227SGreg Roach } 1178c2e8227SGreg Roach $n = Database::prepare( 1188c2e8227SGreg Roach "SELECT COUNT(*) FROM `##other` WHERE o_file = :tree_id AND o_type = 'NOTE'" 1198c2e8227SGreg Roach )->execute(array('tree_id' => $tree->getTreeId()))->fetchOne(); 1208c2e8227SGreg Roach if ($n) { 1218c2e8227SGreg Roach for ($i = 0; $i <= $n / self::RECORDS_PER_VOLUME; ++$i) { 1228c2e8227SGreg Roach $data .= '<sitemap><loc>' . WT_BASE_URL . 'module.php?mod=' . $this->getName() . '&mod_action=generate&file=sitemap-' . $tree->getTreeId() . '-n-' . $i . '.xml</loc>' . $lastmod . '</sitemap>' . PHP_EOL; 1238c2e8227SGreg Roach } 1248c2e8227SGreg Roach } 1258c2e8227SGreg Roach $n = Database::prepare( 1268c2e8227SGreg Roach "SELECT COUNT(*) FROM `##media` WHERE m_file = :tree_id" 1278c2e8227SGreg Roach )->execute(array('tree_id' => $tree->getTreeId()))->fetchOne(); 1288c2e8227SGreg Roach if ($n) { 1298c2e8227SGreg Roach for ($i = 0; $i <= $n / self::RECORDS_PER_VOLUME; ++$i) { 1308c2e8227SGreg Roach $data .= '<sitemap><loc>' . WT_BASE_URL . 'module.php?mod=' . $this->getName() . '&mod_action=generate&file=sitemap-' . $tree->getTreeId() . '-m-' . $i . '.xml</loc>' . $lastmod . '</sitemap>' . PHP_EOL; 1318c2e8227SGreg Roach } 1328c2e8227SGreg Roach } 1338c2e8227SGreg Roach } 1348c2e8227SGreg Roach } 1358c2e8227SGreg Roach $data = '<' . '?xml version="1.0" encoding="UTF-8" ?' . '>' . PHP_EOL . '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . PHP_EOL . $data . '</sitemapindex>' . PHP_EOL; 1368c2e8227SGreg Roach // Cache this data. 1378c2e8227SGreg Roach $this->setSetting('sitemap.xml', $data); 1388c2e8227SGreg Roach $this->setSetting('sitemap.timestamp', WT_TIMESTAMP); 1398c2e8227SGreg Roach } 1408c2e8227SGreg Roach header('Content-Type: application/xml'); 1418c2e8227SGreg Roach header('Content-Length: ' . strlen($data)); 1428c2e8227SGreg Roach echo $data; 1438c2e8227SGreg Roach } 1448c2e8227SGreg Roach 1458c2e8227SGreg Roach /** 1468c2e8227SGreg Roach * A separate file for each family tree and each record type. 1478c2e8227SGreg Roach * These files depend on access levels, so only cache for visitors. 1488c2e8227SGreg Roach * 149cbc1590aSGreg Roach * @param int $ged_id 1508c2e8227SGreg Roach * @param string $rec_type 1518c2e8227SGreg Roach * @param string $volume 1528c2e8227SGreg Roach */ 1538c2e8227SGreg Roach private function generateFile($ged_id, $rec_type, $volume) { 15424ec66ceSGreg Roach $tree = Tree::findById($ged_id); 1558c2e8227SGreg Roach // Check the cache 1568c2e8227SGreg Roach $timestamp = $this->getSetting('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.timestamp'); 1578c2e8227SGreg Roach if ($timestamp > WT_TIMESTAMP - self::CACHE_LIFE && !Auth::check()) { 1588c2e8227SGreg Roach $data = $this->getSetting('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.xml'); 1598c2e8227SGreg Roach } else { 1608c2e8227SGreg Roach $data = '<url><loc>' . WT_BASE_URL . 'index.php?ctype=gedcom&ged=' . $tree->getNameUrl() . '</loc></url>' . PHP_EOL; 1618c2e8227SGreg Roach $records = array(); 1628c2e8227SGreg Roach switch ($rec_type) { 1638c2e8227SGreg Roach case 'i': 1648c2e8227SGreg Roach $rows = Database::prepare( 16524ec66ceSGreg Roach "SELECT i_id AS xref, i_gedcom AS gedcom" . 1668c2e8227SGreg Roach " FROM `##individuals`" . 1678c2e8227SGreg Roach " WHERE i_file = :tree_id" . 1688c2e8227SGreg Roach " ORDER BY i_id" . 1698c2e8227SGreg Roach " LIMIT :limit OFFSET :offset" 1708c2e8227SGreg Roach )->execute(array( 1718c2e8227SGreg Roach 'tree_id' => $ged_id, 1728c2e8227SGreg Roach 'limit' => self::RECORDS_PER_VOLUME, 1738c2e8227SGreg Roach 'offset' => self::RECORDS_PER_VOLUME * $volume, 1748c2e8227SGreg Roach ))->fetchAll(); 1758c2e8227SGreg Roach foreach ($rows as $row) { 17624ec66ceSGreg Roach $records[] = Individual::getInstance($row->xref, $tree, $row->gedcom); 1778c2e8227SGreg Roach } 1788c2e8227SGreg Roach break; 1798c2e8227SGreg Roach case 's': 1808c2e8227SGreg Roach $rows = Database::prepare( 18124ec66ceSGreg Roach "SELECT s_id AS xref, s_gedcom AS gedcom" . 1828c2e8227SGreg Roach " FROM `##sources`" . 1838c2e8227SGreg Roach " WHERE s_file = :tree_id" . 1848c2e8227SGreg Roach " ORDER BY s_id" . 1858c2e8227SGreg Roach " LIMIT :limit OFFSET :offset" 1868c2e8227SGreg Roach )->execute(array( 1878c2e8227SGreg Roach 'tree_id' => $ged_id, 1888c2e8227SGreg Roach 'limit' => self::RECORDS_PER_VOLUME, 1898c2e8227SGreg Roach 'offset' => self::RECORDS_PER_VOLUME * $volume, 1908c2e8227SGreg Roach ))->fetchAll(); 1918c2e8227SGreg Roach foreach ($rows as $row) { 19224ec66ceSGreg Roach $records[] = Source::getInstance($row->xref, $tree, $row->gedcom); 1938c2e8227SGreg Roach } 1948c2e8227SGreg Roach break; 1958c2e8227SGreg Roach case 'r': 1968c2e8227SGreg Roach $rows = Database::prepare( 19724ec66ceSGreg Roach "SELECT o_id AS xref, o_gedcom AS gedcom" . 1988c2e8227SGreg Roach " FROM `##other`" . 1998c2e8227SGreg Roach " WHERE o_file = :tree_id AND o_type = 'REPO'" . 2008c2e8227SGreg Roach " ORDER BY o_id" . 2018c2e8227SGreg Roach " LIMIT :limit OFFSET :offset" 2028c2e8227SGreg Roach )->execute(array( 2038c2e8227SGreg Roach 'tree_id' => $ged_id, 2048c2e8227SGreg Roach 'limit' => self::RECORDS_PER_VOLUME, 2058c2e8227SGreg Roach 'offset' => self::RECORDS_PER_VOLUME * $volume, 2068c2e8227SGreg Roach ))->fetchAll(); 2078c2e8227SGreg Roach foreach ($rows as $row) { 20824ec66ceSGreg Roach $records[] = Repository::getInstance($row->xref, $tree, $row->gedcom); 2098c2e8227SGreg Roach } 2108c2e8227SGreg Roach break; 2118c2e8227SGreg Roach case 'n': 2128c2e8227SGreg Roach $rows = Database::prepare( 21324ec66ceSGreg Roach "SELECT o_id AS xref, o_gedcom AS gedcom" . 2148c2e8227SGreg Roach " FROM `##other`" . 2158c2e8227SGreg Roach " WHERE o_file = :tree_id AND o_type = 'NOTE'" . 2168c2e8227SGreg Roach " ORDER BY o_id" . 2178c2e8227SGreg Roach " LIMIT :limit OFFSET :offset" 2188c2e8227SGreg Roach )->execute(array( 2198c2e8227SGreg Roach 'tree_id' => $ged_id, 2208c2e8227SGreg Roach 'limit' => self::RECORDS_PER_VOLUME, 2218c2e8227SGreg Roach 'offset' => self::RECORDS_PER_VOLUME * $volume, 2228c2e8227SGreg Roach ))->fetchAll(); 2238c2e8227SGreg Roach foreach ($rows as $row) { 22424ec66ceSGreg Roach $records[] = Note::getInstance($row->xref, $tree, $row->gedcom); 2258c2e8227SGreg Roach } 2268c2e8227SGreg Roach break; 2278c2e8227SGreg Roach case 'm': 2288c2e8227SGreg Roach $rows = Database::prepare( 22924ec66ceSGreg Roach "SELECT m_id AS xref, m_gedcom AS gedcom" . 2308c2e8227SGreg Roach " FROM `##media`" . 2318c2e8227SGreg Roach " WHERE m_file = :tree_id" . 2328c2e8227SGreg Roach " ORDER BY m_id" . 2338c2e8227SGreg Roach " LIMIT :limit OFFSET :offset" 2348c2e8227SGreg Roach )->execute(array( 2358c2e8227SGreg Roach 'tree_id' => $ged_id, 2368c2e8227SGreg Roach 'limit' => self::RECORDS_PER_VOLUME, 2378c2e8227SGreg Roach 'offset' => self::RECORDS_PER_VOLUME * $volume, 2388c2e8227SGreg Roach ))->fetchAll(); 2398c2e8227SGreg Roach foreach ($rows as $row) { 24024ec66ceSGreg Roach $records[] = Media::getInstance($row->xref, $tree, $row->gedcom); 2418c2e8227SGreg Roach } 2428c2e8227SGreg Roach break; 2438c2e8227SGreg Roach } 2448c2e8227SGreg Roach foreach ($records as $record) { 2458c2e8227SGreg Roach if ($record->canShowName()) { 2468c2e8227SGreg Roach $data .= '<url>'; 2478c2e8227SGreg Roach $data .= '<loc>' . WT_BASE_URL . $record->getHtmlUrl() . '</loc>'; 2488c2e8227SGreg Roach $chan = $record->getFirstFact('CHAN'); 2498c2e8227SGreg Roach if ($chan) { 2508c2e8227SGreg Roach $date = $chan->getDate(); 2518c2e8227SGreg Roach if ($date->isOK()) { 2522a05b1e4SGreg Roach $data .= '<lastmod>' . $date->minimumDate()->Format('%Y-%m-%d') . '</lastmod>'; 2538c2e8227SGreg Roach } 2548c2e8227SGreg Roach } 2558c2e8227SGreg Roach $data .= '</url>' . PHP_EOL; 2568c2e8227SGreg Roach } 2578c2e8227SGreg Roach } 2588c2e8227SGreg Roach $data = '<' . '?xml version="1.0" encoding="UTF-8" ?' . '>' . PHP_EOL . '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">' . PHP_EOL . $data . '</urlset>' . PHP_EOL; 2598c2e8227SGreg Roach // Cache this data - but only for visitors, as we don’t want 2608c2e8227SGreg Roach // visitors to see data created by logged-in users. 2618c2e8227SGreg Roach if (!Auth::check()) { 2628c2e8227SGreg Roach $this->setSetting('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.xml', $data); 2638c2e8227SGreg Roach $this->setSetting('sitemap-' . $ged_id . '-' . $rec_type . '-' . $volume . '.timestamp', WT_TIMESTAMP); 2648c2e8227SGreg Roach } 2658c2e8227SGreg Roach } 2668c2e8227SGreg Roach header('Content-Type: application/xml'); 2678c2e8227SGreg Roach header('Content-Length: ' . strlen($data)); 2688c2e8227SGreg Roach echo $data; 2698c2e8227SGreg Roach } 2708c2e8227SGreg Roach 2718c2e8227SGreg Roach /** 2728c2e8227SGreg Roach * Edit the configuration 2738c2e8227SGreg Roach */ 2748c2e8227SGreg Roach private function admin() { 2758c2e8227SGreg Roach $controller = new PageController; 2768c2e8227SGreg Roach $controller 2778c2e8227SGreg Roach ->restrictAccess(Auth::isAdmin()) 2788c2e8227SGreg Roach ->setPageTitle($this->getTitle()) 2798c2e8227SGreg Roach ->pageHeader(); 2808c2e8227SGreg Roach 2818c2e8227SGreg Roach // Save the updated preferences 2828c2e8227SGreg Roach if (Filter::post('action') == 'save') { 2838c2e8227SGreg Roach foreach (Tree::getAll() as $tree) { 2848c2e8227SGreg Roach $tree->setPreference('include_in_sitemap', Filter::postBool('include' . $tree->getTreeId())); 2858c2e8227SGreg Roach } 2868c2e8227SGreg Roach // Clear cache and force files to be regenerated 2878c2e8227SGreg Roach Database::prepare( 2888c2e8227SGreg Roach "DELETE FROM `##module_setting` WHERE setting_name LIKE 'sitemap%'" 2898c2e8227SGreg Roach )->execute(); 2908c2e8227SGreg Roach } 2918c2e8227SGreg Roach 2928c2e8227SGreg Roach $include_any = false; 2938c2e8227SGreg Roach 2948c2e8227SGreg Roach ?> 2958c2e8227SGreg Roach <ol class="breadcrumb small"> 2968c2e8227SGreg Roach <li><a href="admin.php"><?php echo I18N::translate('Control panel'); ?></a></li> 2978c2e8227SGreg Roach <li><a href="admin_modules.php"><?php echo I18N::translate('Module administration'); ?></a></li> 2988c2e8227SGreg Roach <li class="active"><?php echo $controller->getPageTitle(); ?></li> 2998c2e8227SGreg Roach </ol> 300adffb21dSGreg Roach <h1><?php echo $controller->getPageTitle(); ?></h1> 3018c2e8227SGreg Roach <?php 3028c2e8227SGreg Roach 3038c2e8227SGreg Roach echo 3048c2e8227SGreg Roach '<p>', 3058c2e8227SGreg Roach /* I18N: The www.sitemaps.org site is translated into many languages (e.g. http://www.sitemaps.org/fr/) - choose an appropriate URL. */ 3068c2e8227SGreg Roach I18N::translate('Sitemaps are a way for webmasters to tell search engines about the pages on a website that are available for crawling. All major search engines support sitemaps. For more information, see <a href="http://www.sitemaps.org/">www.sitemaps.org</a>.') . 3078c2e8227SGreg Roach '</p>', 3088c2e8227SGreg Roach '<p>', I18N::translate('Which family trees should be included in the sitemaps?'), '</p>', 3098c2e8227SGreg Roach '<form method="post" action="module.php?mod=' . $this->getName() . '&mod_action=admin">', 3108c2e8227SGreg Roach '<input type="hidden" name="action" value="save">'; 3118c2e8227SGreg Roach foreach (Tree::getAll() as $tree) { 312adffb21dSGreg Roach echo '<div class="checkbox"><label><input type="checkbox" name="include', $tree->getTreeId(), '" '; 3138c2e8227SGreg Roach if ($tree->getPreference('include_in_sitemap')) { 3148c2e8227SGreg Roach echo 'checked'; 3158c2e8227SGreg Roach $include_any = true; 3168c2e8227SGreg Roach } 317adffb21dSGreg Roach echo '>', $tree->getTitleHtml(), '</label></div>'; 3188c2e8227SGreg Roach } 3198c2e8227SGreg Roach echo 3208c2e8227SGreg Roach '<input type="submit" value="', I18N::translate('save'), '">', 3218c2e8227SGreg Roach '</form>', 3228c2e8227SGreg Roach '<hr>'; 3238c2e8227SGreg Roach 3248c2e8227SGreg Roach if ($include_any) { 3258c2e8227SGreg Roach $site_map_url1 = WT_BASE_URL . 'module.php?mod=' . $this->getName() . '&mod_action=generate&file=sitemap.xml'; 3268c2e8227SGreg Roach $site_map_url2 = rawurlencode(WT_BASE_URL . 'module.php?mod=' . $this->getName() . '&mod_action=generate&file=sitemap.xml'); 3278c2e8227SGreg Roach echo 3288c2e8227SGreg Roach '<p>', I18N::translate('To tell search engines that sitemaps are available, you should add the following line to your robots.txt file.'), '</p>', 3298c2e8227SGreg Roach '<pre>Sitemap: ', $site_map_url1, '</pre>', 3308c2e8227SGreg Roach '<hr>', 3318c2e8227SGreg Roach '<p>', I18N::translate('To tell search engines that sitemaps are available, you can use the following links.'), '</p>', 3328c2e8227SGreg Roach '<ul>', 3338c2e8227SGreg Roach // This list comes from http://en.wikipedia.org/wiki/Sitemaps 334fdab7e62SGreg Roach '<li><a href="http://www.bing.com/webmaster/ping.aspx?siteMap=' . $site_map_url2 . '">Bing</a></li>', 335fdab7e62SGreg Roach '<li><a href="http://www.google.com/webmasters/tools/ping?sitemap=' . $site_map_url2 . '">Google</a></li>', 3368c2e8227SGreg Roach '</ul>'; 3378c2e8227SGreg Roach 3388c2e8227SGreg Roach } 3398c2e8227SGreg Roach } 3408c2e8227SGreg Roach 3418c2e8227SGreg Roach /** {@inheritdoc} */ 3428c2e8227SGreg Roach public function getConfigLink() { 3438c2e8227SGreg Roach return 'module.php?mod=' . $this->getName() . '&mod_action=admin'; 3448c2e8227SGreg Roach } 3458c2e8227SGreg Roach} 346