While writing a test harness for a module I wrote, I discovered my implementation of hook_xmlsitemap_links wasn't actually called anymore.

The module doesn't work with nodes but gets data from sources other than Drupal and themes that. It implemented hook_xmlsitemap_links to add its urls to the sitemap.

Is there some documentation on how to replace a hook implementation with its equivalent(s) in the new 6.x-2.x API, that breaks my search-fu style?

I found it is "kinda hard to explain" and was reading the code like suggested.

  • Do you know if the 6.x-2.x API is the same as 7.x-2.x? I have an approach that is less that ideal, but worked for my case. – mpdonadio Feb 26 '13 at 19:09
  • the 6.x-2.x API contains a lot that looks like backports from 7.x API. So your 7.x-2.x approach might prove valuable. – Chris Wesseling Feb 26 '13 at 19:48

There doesn't seem to be hook anymore to return links for further processing, but adding and deleting links is done with calls to xmlsitemap_link_save and xmlsitemap_link_delete(_multiple)

I implemented a hook_xmlsitemap_index_links, which normally is only called when the command drush xmlsitemap-index is issued:

function my_xmlsitemap_index_links($limit) {
  $sql = "SELECT x.id FROM {xmlsitemap} x WHERE x.type = 'my'";
  $query = db_query($sql);
  $indexed = xmlsitemap_db_fetch_col($query);
  //there isn't a lot of stuff, it fits in memory, but fetching it is costly.
  $indexed = array_flip($indexed);
  $mystuff = __my_get_stuff();
  $i = 0;
  foreach ( $mystuff as $thing ) {
    if ( !isset($indexed[$thing->id]) ) {
      # new thing
      xmlsitemap_link_save(__my_make_xmlsitemap_link($thing), $thing->id);
    if ( $i == $limit )
  #Done indexing new stuff;
  if ( $indexed ) {
    $deleted = array_flip($indexed);
    xmlsitemap_link_delete_multiple(array('type'=>'my', 'id'=>$deleted));

I'm still puzzling on what to return from my hook_xmlsitemap_link_info. It's not at all clear when those callbacks are called.

  • The process callback is useless for this usecase; xmlsitemap has no way of knowing any foreign IDs.
  • The rebuild callback is afaik only called by drush and manual action, not a means of keeping the links up to date, but it remains unclear if such a callback is required or optional (although xmlsitemap_custom seems to manage without one)
  • The settings callback is still a mistery to me, but it's used for the admin.

This hook_xmlsitemap_link_info with my_xmlsitemap_index_links as rebuild callback, makes my module reindex when I issue a rebuild command from the admin.

function my_xmlsitemap_link_info() {
  return array(
    'my' => array(
      'label' => t('My Stuff'),
      'xmlsitemap' => array(
        'rebuild callback' => 'my_xmlsitemap_index_links',

I ended up implementing a hook_cron that periodically calls my_xmlsitemap_index_links, to keep it in sync.

I might update my hook_load, to issue a xmlsitemap_link_delete on failed loads (404's).

| improve this answer | |

My basic apprach for 7.x-2.x is (assume the module is called mymodule_xmlsitemap).

 * Implements hook_cron().
function mymodule_xmlsitemap_cron() {

 * Implements hook_xmlsitemap_index_links().
function mymodule_xmlsitemap_xmlsitemap_index_links($limit) {

    'type' => 'mymodule',

  $results = mymodule_query();

  foreach ($results as $result) {
    $link = _mymodule_xmlsitemap_make_link($result->path, $result->id);

    xmlsitemap_link_save($link, $result->id);


  * Helper for link object creation.
function _mymodule_xmlsitemap_make_link($path, $id) {
  return array(
    'loc' => $path,
    'type' => 'mymodule',
    'id' => $id,
    'lastmod' => 0,
    'changefreq' => 0,
    'changecount' => 0,
    'language' => LANGUAGE_NONE,

As you mentioned, hook_xmlsitemap_index_links doesn't get invoked unless you have things defined with hook_xmlsitemap_link_info. In the 7.x version, I didn't see how to divorce this from database tables. If you are truly coming from an external database, this may not be possible.

So, if you look at xmlsitemap_node (that was the inspiration for my version), you will see that the hook_xmlsitemap_index_links() is manually called from hook_cron(). With an external database, I had no idea on whether anything was new or deleted, so I blasted out all of the links, and rebuilt them. In my case, I ignore the $limit. You then make you query, and save off links.

Also note that there is some user switching going on to ensure that you are only indexing things that the anonymous user can access.

If you get indication when things are added / deleted from your external database, you can get rid of the hook_xmlsitemap_index_links(), and implement your own callbacks to xmlsitemap_link_save() and xmlsitemap_link_delete().

| improve this answer | |
  • This is exactly the direction I was thinking in, but I suspect re-indexing all mymodule-links on every cron run might prove to expensive; It will always result in a regenerate because xmlsitemap_link_save sets xmlsitemap_regenerate_needed. Actually hook_xmlsitemap_index_links is only called on drush command xmlsitemap-index. – Chris Wesseling Feb 26 '13 at 21:36
  • Yeah, just use this for inspiration and the essential mechanics. In my case, cron is a nightly thing and the load hasn't been a problem. I also don't get indications when there are insertions/deletions in the remote database. If this ever becomes a problem, then I query my remote database, query {xmlsitemap}, and then figure out what needs to be added and deleted. I think you are right about hook_xmlsitemap_index_links (), memory hazy on that aspect. – mpdonadio Feb 26 '13 at 21:52
  • This is what I ended up doing. – Chris Wesseling Feb 27 '13 at 0:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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