Anne van Kesteren

Implementing atom:modified in PHP

atom:modified, the one that is child of atom:feed can be quite tricky to implement. Wayne showed us that the popular weblog systems get the implementation wrong and should probably be updated. (Another option is of course to update the specification.) atom:modified should match the last time the feed was updated. So if the feed contains 10 items, it matches the modified date of the last updated item. If you have published over a hundred items and you update a (very) old post, because of a spelling mistake the feed modified date shouldn't change, because that item isn't in the feed anymore. So now we know how it works we want to know how to make a dirty implementation in PHP (according to Robbert, PHP can be clean, but you have to know how; just like with HTML).

$r = mysql_query("SELECT id_uri,title,slug,summary,published,modified FROM post ORDER BY published DESC LIMIT 10");
 $content = '';
 while($arr = mysql_fetch_array($r)){
  // store the content
  $content .= ' <entry>';
  $content .= '<title>'.$arr['title'].'</title>';
  $content .= '<link rel="alternate" type="text/html" href="'.date('Y/m/',strtotime($arr['published'])).$arr['slug'].'"/>';
  $content .= '<summary>'.$arr['summary'].'</summary>';
  $content .= '<id>'.$arr['id_uri'].'</id>';
  $content .= '<issued>'.date('Y-m-dTH:i:sZ',strtotime($arr['published'])).'</issued>';
  $content .= '<modified>'.date('Y-m-dTH:i:sZ',strtotime($arr['modified'])).'</modified>';
  $content .= '</entry>'."n";

  // create an array of modified dates
  $modified[] = $arr['modified'];
// sort the array

// voila!
$modified = $modified[9];

So of course you need to make some connection with the database and after this you need to print the variable modified in the element atom:modified but I guess you can figure that out yourself. (If not, I'm willing to post the complete code for this Atom feed in one of the comments.) I must say I quite like this solution, only one query needed for generating the Atom feed and it isn't a really complex one.


  1. It would be better if you changed the $modified = $modified[9]; part to $modified = $modified[(count($modified) - 1)]; in case you want to change the limit of your query. Also, if your going to create XML documents, why not use PHP's DOM XML functions?

    Posted by TumTum at

  2. …why not use PHP's DOM XML functions? Because this extension completely sucks, maybe? Because WordPress users don't always (read: never) have this extension installed (because it completely sucks), maybe? This probably isn't why Anne didn't use it, so I'll give you yet another reason: the extension calls itself a DOM implementation, while it is in fact not. Have you ever heard of the function get_element_by_id? Well, I hadn't until I read the DOM XML documentation pages last year. That's why.

    Posted by Robbert Broersma at

  3. Actually, matching "the modified date of the last updated item" isn't good enough. Eric Scheid:

    don't forget that feed:modified should also be updated if an entire entry has been deleted. This modified date value is something you can't discern by examining the list of existing entries.

    You've got to arrive at that time some other way, perhaps through template-level timestamps.

    Posted by Wayne at

  4. TumTum, it would be better if Anne hadn't used an array at all:

     $max_modified = 0; for(...) { . . .   if ($arr['modified'] > $max_modified) {     $max_modified = $arr['modified'];   } } 


    Posted by Breyten at

  5. The code fragment above is why I would very much like if my Web host would make SQLite (or some other database system capable of subqueries) available to me. Subqueries make it very easy to get the highest timestamp in a range of records without having to process the items beforehand.

    As for deleted entries, how often have you deleted entries, Wayne? My own system doesn't have any facilities for deleting entries, as I don't ever plan on doing such a thing. Sure, I may want to remove the content, but the document should, as far as I'm concerned, alwways be there.

    Granted, not everything that uses Atom is a Web log, but not every application that uses Atom is generated by PHP, either.

    Posted by J. King at

  6. J. King, sugqueries are in MySQL 4.1 as well, I believe. Or somewhere around that version number.

    Posted by Anne at

  7. J.King, you don't need subqueries to get the highest timestamp in a range of records. SELECT MAX(timestampcolumn) AS highest FROM sometable with optional WHERE clause, etc.

    Also, I would recommend PostgreSQL - the upcoming version 8 is just magnificent, and PGSQL has become incredibly fast nowadays. :) Of course, this is mostly just if you plan on using it for any complex work, not just easy-peasy stuff...

    You've got to arrive at that time some other way, perhaps through template-level timestamps.

    Just store a site-wide Last Modified date in the options or wherever is handy. If it shouldn't be site-wide, specify it for feed-wide site content.

    In my CMS (which I also use for my own blog), I keep track of a Last Modified date in my cache table in the database. Any time I add, remove or update content on the site, that db-item gets updated.

    Posted by Faruk Ates at