12

I've developed a bespoke module which lists a series of people on the site. Each person has their own URL (a bespoke Magento controller, which does basic CRUD on Person models) and I need to feed these public URLs into a Google Sitemap XML file.

I want to use Magento's own sitemap generation and the cron if I can.

The Mage_Sitemap_Model_Observer already pulls all the Sitemap records from the sitemaps table and one-by-one calls their generateXml() methods.

$collection = Mage::getModel('sitemap/sitemap')->getCollection();
/* @var $collection Mage_Sitemap_Model_Mysql4_Sitemap_Collection */
foreach ($collection as $sitemap) {
    /* @var $sitemap Mage_Sitemap_Model_Sitemap */

    try {
        $sitemap->generateXml();
    }
    catch (Exception $e) {
        $errors[] = $e->getMessage();
    }
}

I think I need to add my new Sitemap in the sitemaps table which will then be called to generate my (separate) XML file for my custom model records. However, I don't know how to tell Magento to use my extended My_Module_Model_Sitemap instead of just Mage_Sitemap_Model_Sitemap, the latter of which will just give me an XML file listing all the same categories, products, and CMS pages as the main sitemaps.

The sitemaps table has a sitemap_type column, but this is never referenced in the Magento codebase as far as I can tell.

How can I use Magento's inbuilt sitemap engine while overwriting the Mage_Sitemap_Model_Sitemap to have my own generateXml() method? Or must I build an alternative sitemap system just for my own purposes here?

3
  • you want to extend the Mage_Sitemap_Model_Sitemap class and overwrite generateXml() right? what have you tried? Jan 23, 2013 at 11:44
  • Have tried that, but Magento just uses the Mage_Sitemap_Model_Sitemap and gives me another sitemap containing the products, categories, CMS pages - it doesn't use my extended version. I'm not sure how to tell it how to do so. Jan 23, 2013 at 11:48
  • Working on perhaps rewriting the entire Mage_Sitemap_Model_Sitemap site wide, and adding in my own model under the category and product calls. Will update soon with progress. Jan 23, 2013 at 11:55

3 Answers 3

6

The steps I ended up using were as follows, and the comments and answers so far got me started in the right direction.

First I added a row to the "sitemap" table. Since we have multi-store set up, and because I want to keep my module store agnostic, I didn't hard code this INSERT into a MySQL migration, but just ran it on the store manually:

INSERT INTO sitemap (sitemap_type, sitemap_filename, sitemap_path, store_id)
    VALUES ('people', 'people.xml', '/sitemap/', 2);

Then I overwrote the Mage_Sitemap_Model_Sitemap model inside the global/models section in my own module's config.xml file:

<global>
    <models>
        <sitemap>
            <rewrite>
                <sitemap>Mymod_People_Model_Sitemap</sitemap>
            </rewrite>
        </sitemap>
    </models>
</global>

This overwrites any calls to Mage_Sitemap_Model_Sitemap site-wide with my custom model, but I didn't want to copy and paste too much code there. Using Petar Dzhambazov's suggestion, I used a conditional to defer to the parent class unless the sitemap_type is "people".

class Mymod_People_Model_Sitemap extends Mage_Sitemap_Model_Sitemap
{
    const PAGE_REFRESH_FREQUENCY = 'weekly';
    const PAGE_PRIORITY = '1.0';

    public function generateXml()
    {
        if ($this->getSitemapType() != 'people') {
            return parent::generateXml();
        }

        $io = new Varien_Io_File();
        $io->setAllowCreateFolders(true);
        $io->open(array('path' => $this->getPath()));

        if ($io->fileExists($this->getSitemapFilename()) && !$io->isWriteable($this->getSitemapFilename())) {
            Mage::throwException(Mage::helper('sitemap')->__('File "%s" cannot be saved. Please, make sure the directory "%s" is writeable by web server.', $this->getSitemapFilename(), $this->getPath()));
        }

        $io->streamOpen($this->getSitemapFilename());

        $io->streamWrite('<?xml version="1.0" encoding="UTF-8"?>' . "\n");
        $io->streamWrite('<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">');

        $storeId = $this->getStoreId();
        $date    = Mage::getSingleton('core/date')->gmtDate('Y-m-d');
        $baseUrl = Mage::app()->getStore($storeId)->getBaseUrl(Mage_Core_Model_Store::URL_TYPE_LINK);

        /**
         * Generate people sitemap
         */
        $changefreq = Mymod_People_Model_Sitemap::PAGE_REFRESH_FREQUENCY;
        $priority   = Mymod_People_Model_Sitemap::PAGE_PRIORITY;
        $collection = Mage::getModel('people/person')->getCollection();
        foreach ($collection as $item) {
            $xml = sprintf('<url><loc>%s</loc><lastmod>%s</lastmod><changefreq>%s</changefreq><priority>%.1f</priority></url>',
                htmlspecialchars($item->getUrl()),
                $date,
                $changefreq,
                $priority
            );
            $io->streamWrite($xml);
        }
        unset($collection);

        $io->streamWrite('</urlset>');
        $io->streamClose();

        $this->setSitemapTime(Mage::getSingleton('core/date')->gmtDate('Y-m-d H:i:s'));
        $this->save();

        return $this;
    }
}

Is there a better way, that avoids copying and pasting so much from the parent class?

1

You can either extend Mage_Sitemap_Model_Sitemap and in it check sitemap_type if it is your type, generate your xml, else generate parent xml. Or you can add an observer for collection load_after event and add your sitemap model to collection.

0

Is there a better way, that avoids copying and pasting so much from the parent class?

If you have Magento >= 1.9.0.0 and do not care about using products or catalog priority/change frequency setting, you can use an observer on sitemap_products_generating_before

public function addPagesToSitemap(Varien_Event_Observer $observer)
{
    $collection = $observer->getCollection();
    $myPages = # your data: array('url_1', 'url_2')
    foreach ($myPages as $url) {
        $item = new Varien_Data_Object;
        $item->setUrl($url);
        $collection->addItem($item);
    }
}

If you want to complete differnt behavior for on sitemap pages maybe read Sitemap.xml change home and/or dispatch a more generic event.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.