The Case For Feeds As Classes
(If you were expecting something on life in Japan here, sorry to bore you! Normal service will resume shortly, I promise).
A few days ago, I made a suggestion to the Wordpress Hackers lists to restructure WP’s feed handling into a class-based system. There has been a lot of discussion recently on the list of where to go with feeds, with people arguing both for a complete overhaul and for minor tweaks. There was also quite a debate on whether to drop support for some older feed types to reduce maintenance.
My suggestion was greeted with deafening silence, largely in part because I totally misconstrued Owen Winkler’s meaning in the original thread, resulting in a post wildly out of context, but also maybe because many people don’t see the need to rewrite what works now. Either that, or they just totally disagreed and were too polite to say so.
I was still interested, however, so I spent an hour or two putting together a basic prototype for a class-based feed architecture. You can find this file here. You should note that the code is definitely a prototype, is far from complete and hasn’t actually even been parsed. The framework is what is important here, not the details at the moment, especially if this is shot down in short order. But anyway, following is a rationale for why I think this is a good route to go:
- Centralised Data Source: At the moment, each feed gets the data it requires as it is being built. This means four duplications of data-grabbing code that need not happen. A centralised source can hold all the information needed by all flavours of feeds, reducing maintenance to a single point, which is easily updateable.
- Cacheable: With a centralised data source we can also cache easily and use that to build the feeds instead of making lots of function calls and database accesses each time a feed is required. This cached data source can be updated whenever a post or comment occurs, asynchronously, so that the user is not affected.
- Extensible: This structure enables plugins to add new feed types very easily, by simply creating a new class. This would allow for the addition of feed types that are standardised while WordPress is in a development cycle. A recent example of this is Atom 1.0, for which support still does not exist and currently could only be added by altering the core. The same ability to add feed types also allows us to remove outdated types from the core if we wanted and offload them into plugins.
- Pluggable: At the moment, with the available action hooks, you can add to feeds, but you can’t modify or remove data. Allowing access to the data source allows us to make data alterations before the feed is written. These could either be pre-processed and cached, or on-the-fly as the feed is about to be constructed. Separating the feed head, body and footer allows us to filter information at any point in the feed for maximum flexibility.
- Simplification: With a list of defined feed types and classes, we can automatically generate the correct type of feed using PHP’s dynamic binding to the right class. A call to $wpfeed->output() gets the job done, for all kinds of feeds, even plugin-defined ones. We can use the defined feeds array to generate rewrite rules simply too, so that we don’t have to add them by hand each time.
- Backwards Compatibility: Recent changes to WordPress, dubbed the Changeset of Destruction will break lots of plugins, so I’m not sure if this is even an issue, but it would probably be possible to maintain backwards compatibility with existing action hooks by output buffering their actions and adding them to the feed.
-
Anyway, there are probably reasons I haven’t thought of why this is all viable, so please feel free to let me know why this is all a bad idea. The one point I would argue with is that it’s fine as it it. I really think this area of WordPress could do with a bit of a workover, even if this isn’t the solution.
February 15th, 2006 at 9:14 pm
The only real argument I’ve heard against it is that people are satisfied with what the feeds do now, and adding the class you suggest will increase the code size by several hundred lines and all of the complexity that involves, especially if we choose to use a 3rd-party feed building solution like the one originally suggested.
Your feed class is interesting, but still it’s not a lot better than using an output buffer. If I follow along, it just assembles the feed output as a string, passing the various sections through WordPress filters. You would have to do the same regular expression search and replaces to add new nodes into the XML as you would if you used an output buffer.
The primary problem with using hooks to insert things into feeds is that you would have to include a hook in every location where a plugin might want to insert new XML elements. This makes the number of potentially required hook locations extremely large.
If you really want to do something constructive to a feed, you should be able to insert and remove arbitrary elements from the XML directly via DOM or a DOM-like process. Then there would be no string manipulation.
I can see passing any of the existing output to a routine that turns the feed into an array or object, then feeding that array or object through WP filters, then outputting the modified array or object as XML. Assuming there was some standard format we used for the array or object, this same type of structure might eventually be passed through a sort of XSLT engine, allowing output in whatever format we needed.
These folks who “just want a few more hooks” don’t get it. There will always be a need for a few more hooks as long as you’re not able to modify the XML directly and not willling to use output buffering. Throwing a handful of new hooks is a stopgap solution that isn’t very beneficial to future development.
February 15th, 2006 at 9:41 pm
Appreciate your point of view Owen, thanks.
I don’t think it would really increase the code that much at all actually. The code for the example WPrss2 class is taken directly from wp-rss2.php, which it could replace. The base feed class is the only overhead and that’s not so much. The removal of old feed-types from the core (which I think you advocated, is that right?) would take the numbers down further. The lack of duplication in code is far more important as far as I’m concerned.
You’re right about output filtering and string replacements not being ideal of course. But, the filter in the base constructor allows us to remove, modify and add to the datasource by altering the array contents - not as nice as DOM manipulation, I’ll grant you, but enough to allow for a lot of flexibility. Combined with the filters in the other 3 sections, which could work on data that has been added in the base filter, (like the table filters on the manage page in wp-admin) would allow for lots of modifications. I can’t think of many situations where I’d want to remove parts of information from the feeds, but I can think of lots of ways of wanting to add to or edit it, which this method makes easy. Again, I may just suffer from a lack of imagination!
In an case, the output buffering is not what I imagine to be the greatest benefit here. The caching of a centralised data source and easy extensibility are much more useful, in my opinion.
PS: I like your monkey!
February 16th, 2006 at 12:49 am
Maybe this is the blindspot: Imagine that you wanted to optionally add an additional tag inside each item element in the RSS feed. Perhaps this could be geographic coordinates, one of the Dublin Core tag extensions, or maybe a whole new add-on namespace.
You can add this data to the feed’s data structure easily via the construct that you’re proposing in your code (although does that array creation syntax actually work?) but outputting that data is an entirely different matter. The feed is still (for example) RSS2.0, but it should have new tags from an additional namespace. The only way I can see to do it is by using your feed_body hook, and then using preg_replace() just like I would with an output buffer. Yuck.
Your next reaction would be to have a hook that executes for each item to allow insertion of new elements. But suppose that the extension you’re using simply adds an attribute to an existing element, or replaces an existing element with something else. It’s once again not as simple as using DOM.
In a perfect world, you should be able to create a class like you have WPFeed to build a data structure with any potentially useful feed data. You would do something like:
$wpfeed = new WPFeed();$wpfeed->output_transform('rss2.xsl');
The unfortunate part is that PHP’s XML/XSL support isn’t ubiquitous, so you can’t rely on the internal functions. As I said in my email on wp-hackers, there are a few classes around that parse XML to and from an internal PHP structure. If we used one of these to build the feed, a hook could inject whatever elements it wants before the array/object is returned to XML, preferrably via some kind of transform.
The monkey is what happens when you have a daughter of four, too much time with Corel Knockout, and no good headshot.
February 16th, 2006 at 7:47 am
You are right of course, the hooks aren’t the most efficient way to go about things. I’d say that they were much better than what is on offer now, but I guess if a whole rewrite was going to be considered, you might as well go all the way. The DOM based version would be ideal, I admit. I can see the benefit of editing existing elements and attributes (which is actually what I wanted to do in the first place - it’s impossible at the moment to alter the language tag in feeds [elegantly]), but adding new tags would still cause problems, wouldn’t it? Sure, you could add your information to the XML datasource, but if the XSL doesn’t know how to transform it, what would happen? It would just be ignored, without something there to say “Here’s how to transform this new element I added”.
As for the array creation syntax - it might work, it might not! Just the idea was important!
February 28th, 2006 at 10:55 pm
Hello. I’m very sad to here you’re going to move. Actuary, I wasn’t surprised. Because you were taking about it a few times and I know you’ve been in Japan for two years. I like meeting new people but don’t like saying good-bye. No one like it. I think if I meet a new person, soon or later, I have to say good-bye. It’s very sad. But If I always worry about it and stay in my room all day, my life will be boring and I can’t learn anything and If I were in their place, I would probably be excited with new life. So I hope you’ll have a great life in Australia. I think you are like Japanese. I mean you start new life from April and you know, it is same as Japanese. I’ve never moved so It’s kind of difficult to think about your feeling. But I can see how people feel when they start a new thing. I like challenging new things. It was kind of challenging for me to start English at the school. My life was changed by seeing you. I was learn many things from you. I appreciate you. I’m going to come this school as ofen as I can to meet you and learn many things.
よã‚Âã—ãÂÂãÂÂ。How can I say it in English? Are there any ways to express it in English?
p.s. Your home page is very useful because I can see your life and send e-mails. You are so smart to think of this. I want to make my home page someday.
August 18th, 2007 at 3:30 pm
Cell Phones Tracer…
I couldn’t understand some parts of this article, but it sounds interesting…