(Note: There’s a bug in this that prevents the full ancestry from showing – only “root” and the current block are listed. I probably won’t get round to fixing this for a long time, since I’ve abandoned the Magento dev work I was planning when I wrote it, and since nobody seems to be interested in the extension.)
BlockSpy is a Magento extension that provides a bookmarklet, along the lines of CSS XRAY, for viewing the block-by-block structure of Magento pages. If all you’re after is the add-in itself to download, it’s here. Just unzip it and follow the instructions in INSTALL.txt. The article below explains how it works. Note that I’ve only tested this on Magento 184.108.40.206 with Chrome 21 and Firefox 15 (on Linux), and don’t intend to put much effort into further testing and maintaining it beyond my own needs. The extension is provided as-is, though I hope it proves useful. It’s released under the AFL, since that’s what Magento itself uses.
While learning my way around Magento, I became a bit irritated at the rigmarole that was involved in finding the details of the block that contains a given element on the page. For HTML, I’m used to having things like the major browsers’ dev functionality, together with external tools such as CSS XRAY, and I wanted something similar for viewing the block structure of Magento pages.
Magento itself provides some built-in functionality for viewing this information (
System -> Configuration -> Developer -> Debug -> Template Path Hints), but it is ugly, alters the page layout and only works for template blocks (which admittedly does account for the vast majority of blocks).
The major challenge comes from the fact that the block abstraction in Magento doesn’t work in terms of HTML as such, but rather in terms of strings. Each block produces a chunk of text, which becomes part of the generated document, but the processing at this stage is not aware of the node-by-node structure of the HTML.
The natural place to add block information to generated HTML without editing core files is in a handler for the
core_block_abstract_to_html_after event, which is fired after each block gets asked for its generated HTML. Via a “transport” object, the handler for this event is able to alter the generated HTML content.
text/html“, it seems the comment nodes get messed with sometimes – eg. comment nodes outside the root element (which are legal) can get moved into the body element. It may well be that this approach would work fine and would result in a simpler extension than what I ended up with, but I felt uneasy enough about it to take a different tack.
Theoretically, at least, Magento produces XHTML output, which in turn is valid XML and therefore can be tackled with a SAX parser. However, like the vast majority of web sites/apps out there that do so, it still serves it up with a Content-Type of “
text/html“, which means that on the browser side it gets processed as HTML “tag soup”. In practice there are a few minor problems with the output of Magento and more with the output of various extensions that may be present, so that you can’t really rely on the pages being truly valid XML/XHTML. (I’m not blaming Magento or the extension authors for this, BTW – it’s the common state of XHTML on the web resulting from the unfortunate difficulties you encounter when serving it up properly as “application/xhtml+xml”.)
And that’s a shame, because PHP does have a SAX (or near enough) parser together with an XMLWriter class (http://php.net/manual/en/book.xmlwriter.php), and between them these offer quite a nice way of processing the XML. The SAX parser is fed a stream of XML/XHTML (which it doesn’t mind arriving in chunks), and generates events as it sees interesting stuff happening, eg. calling the start and end element_handler functions as opening and closing tags are encountered. Meanwhile you can call corresponding functions on an XMLWriter, eg. startElement() and endElement() as the events are received. This effectively allows you to stream the document through your own handlers, which are aware of the structure of the document and are free to perform simple XML-aware transformations on it, such as adding attributes. By textually locating the markers that were added in the
core_block_abstract_to_html_after handler and feeding the chunks of XML data in between the markers into the SAX parser, it’s easy to keep track of which block we are in and add the necessary attributes as we go.
Fortunately, there is a get-out clause for the almost-but-not-quite-XHTML we have to deal with – PHP comes with HTML tidy built in! This library takes potentially messy inputs and generates guaranteed clean, groovy HTML. If configured appropriately, it can produce XHTML, too. Although the transformations it has to perform can theoretically affect the visual layout this should only happen if the input is invalid, and Magento produces output that is very close to valid. In practice, I haven’t seen any rendering changes resulting from this transformation.
So the approach is:
- Hook the
core_block_abstract_to_html_afterevent, using it to add XHTML comments marking the start and end of each block (and adding information like template locations).
- Hook the
controller_front_send_response_beforeevent and pass the entire generated document into HTMLTidy.
- Look through the resulting, valid XHTML document, textually locating the block inforation and passing everything else into a SAX parser. Keep track of the current block as we go.
- In the registered SAX parser handler functions, add “data-*” attributes containing block information.
There were lots of little quirks, trips and traps to find workarounds for, but I don’t have time to go into all the details. You’ll find the forensic evidence of them in the code if you’re interested, but the above gives the outline of the mechanism. The extension seems to work pretty well: it doesn’t conflict with any of the extensions I have installed, doesn’t produce any layout changes and has proven very handy already in learning my way around Magento. I hope it’s useful for somebody else.
One last thing, though. Once the extension is installed, there’s an admin page that gives you a bookmarklet to copy onto your toolbar to activate BlockSpy. On that page there is a health warning, which bears repeating here:
When BlockSpy is active, all pages are filtered through HTMLTidy on the server side and then parsed and processed to add metadata for block browsing. This may interfere with the display of some pages, is likely to obscure any errors you may commit in your markup (since HTMLTidy will always produce valid XHTML of some sort, whatever you do), and will be a major drag on site performance. This add-in should only be used for dev purposes, to explore the block-by-block structure of a site, and must be disabled for BOTH testing and production. The add-in must be disabled fully, by editing
app/etc/modules/and switching the ‘active’ attribute to false. Simply disabling module output in
System -> Configuration -> Advancedis not sufficient.