forked from magento/devdocs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmage-for-dev-4.html
491 lines (350 loc) · 24.4 KB
/
mage-for-dev-4.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
---
---
<!DOCTYPE html>
<html lang=en>
<head>
<meta charset=utf-8>
<link rel="stylesheet" type="text/css" href="{{ site.baseurl }}common/css/stylesheet.css"/>
<link rel="stylesheet" href="{{ site.baseurl }}common/css/stylesheet-fonts.css" type="text/css" charset="utf-8">
<link rel="icon" href="{{ site.baseurl }}common/css/favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="{{ site.baseurl }}common/css/favicon.ico" type="image/x-icon">
<title>Magento for Developers: Part 4—Magento Layouts, Blocks and Templates</title>
</head>
<body>
<a name="top"></a>
<img src="{{ site.baseurl }}common/images/m1x/m1xheader.png" width="1024" alt="header" />
<body>
<a name="top"></a>
<div id="content">
<h1>Magento for Developers: Part 4—Magento Layouts, Blocks and Templates</h1>
<p><em>by Alan Storm</em>, updated for Magento 1.12</p>
<p><a href="{{ site.m1xgithuburl }}/magefordev/mage-for-dev-4.html" target="_blank">Edit this page on GitHub <img src="{{ site.baseurl }}common/images/github_icon.png" height="15px"></a></p>
<!-- Magento for Developers: Part 4—Magento Layouts, Blocks and Templates -->
<!-- magento-for-dev-part-4-magento-layouts-blocks-and-templates
<style type="text/css">
#kb-entry .series {float: right; width: 175px; margin-left: 10px; font-size: 12px; }
#kb-entry .series ul {margin-left: 15px;}
</style>
<div class="r-box-rss series"> -->
<h5>Other articles in this series:</h5>
<ul>
<li><a href="{{ site.m1xgdeurl }}magefordev/mage-for-dev-1.html">Part 1—Introduction to Magento</a>
<li><a href="{{ site.m1xgdeurl }}magefordev/mage-for-dev-2.html">Part 2—The Magento Config</a>
<li><a href="{{ site.m1xgdeurl }}magefordev/mage-for-dev-3.html">Part 3—Magento Controller Dispatch</a>
<li><a href="{{ site.m1xgdeurl }}magefordev/mage-for-dev-4.html">Part 4—Magento Layouts, Blocks and Templates</a>
<li><a href="{{ site.m1xgdeurl }}magefordev/mage-for-dev-5.html">Part 5—Magento Models and ORM Basics</a>
<li><a href="{{ site.m1xgdeurl }}magefordev/mage-for-dev-6.html">Part 6—Magento Setup Resources</a>
<li><a href="{{ site.m1xgdeurl }}magefordev/mage-for-dev-7.html">Part 7—Advanced ORM: Entity Attribute Value</a>
<li><a href="{{ site.m1xgdeurl }}magefordev/mage-for-dev-8.html">Part 8—Varien Data Collections</a>
</ul>
</div>
<p class="para1">Developers new to Magento are often confused by the Layout and View system. This article will take a look at Magento's Layout/Block approach, and show you how it fits into Magento MVC worldview.</p>
<p>Unlike many popular MVC systems, Magento's Action Controller does <strong>not</strong> pass a data object to the view or set properties on the view object (with a few exceptions). Instead, the View component directly references system models to get the information it needs for display. </p>
<p>One consequence of this design decision is that the View has been separated into Blocks and Templates. Blocks are PHP objects, Templates are "raw" PHP files (with a .phtml extension) that contain a mix of HTML and PHP (where PHP is used as a templating language). Each Block is tied to a single Template file. Inside a phtml file, PHP's <tt>$this</tt> keyword will contain a reference to the Template's Block object.</p>
<br clear="all" />
<h2>A quick example</h2>
<p>Take a look at the default product Template at the file at</p>
<pre>app/design/frontend/base/default/template/catalog/product/list.phtml</pre>
<p>You'll see the following PHP template code.</p>
<pre>
<?php $_productCollection=$this->getLoadedProductCollection() ?>
<?php if(!$_productCollection->count()): ?> <div class="note-msg">
<?php echo $this->__("There are no products matching the selection.") ?>
</div> <?php else: ?>
...
</pre>
<p>The <tt>getLoadedProductCollection</tt> method can be found in the Template's Block class, <tt>Mage_Catalog_Block_Product_List</tt> as shown:
<pre>File: app/code/core/Mage/Catalog/Block/Product/List.php</pre>
<pre>
...
public function getLoadedProductCollection()
{
return $this->_getProductCollection();
}
...
</pre>
<p>The block's <tt>_getProductCollection</tt> then instantiates models and reads their data, returning a result to the template.</p>
<h2>Nesting Blocks</h2>
<p>The real power of Blocks/Templates come with the <tt>getChildHtml</tt> method. This allows you to include the contents of a secondary Block/Template inside of a primary Block/Template. </p>
<p>Blocks calling Blocks calling Blocks is how the entire HTML layout for your page is created. Take a look at the one column layout Template.</p>
<pre>File: app/design/frontend/base/default/template/page/one-column.phtml</pre>
<pre>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="?php echo $this->getLang() ?>" lang="<?php echo $this->getLang() ?>">
<head>
<?php echo $this->getChildHtml('head') ?>
</head>
<body class="page-popup <?php echo $this->getBodyClass()?$this->getBodyClass():'' ?>">
<?php echo $this->getChildHtml('content') ?>
<?php echo $this->getChildHtml('before_body_end') ?>
<?php echo $this->getAbsoluteFooter() ?>
</body>
</pre>
<p>The template itself is only 11 lines long. However, each call to <tt>$this->getChildHtml(...)</tt> will include and render another Block. These Blocks will, in turn, use <tt>getChildHtml</tt> to render other Blocks. It's Blocks all the way down.</p>
<h2>The Layout</h2>
<p>So, Blocks and Templates are all well and good, but you're probably wondering</p>
<ol>
<li>How do I tell Magento which Blocks I want to use on a page?</li>
<li>How do I tell Magento which Block I should start rendering with?</li>
<li>How do I specify a particular Block in <tt>getChildHtml(...)</tt>? Those argument strings don't look like Block names to me.</li>
</ol>
<p>This is where the Layout Object enters the picture. The Layout Object is an XML object that will define which Blocks are included on a page, and which Block(s) should kick off the rendering process.</p>
<p><a href="mage-for-dev-3.html" title="Link to Magento for Developers: Part 3—Magento Controller Dispatch">Last time</a> we were echoing content directly from our Action Methods. This time let's create a simple HTML template for our Hello World module.</p>
<p>First, create a file at</p>
<pre>app/design/frontend/base/default/layout/local.xml</pre>
<p>with the following contents</p>
<pre>
<layout version="0.1.0">
<default>
<block type="page/html" name="root" output="toHtml" template="magentotutorial/helloworld/simple_page.phtml" />
</default>
</layout>
</pre>
<p>Then, create a file at </p>
<pre>app/design/frontend/base/default/template/magentotutorial/helloworld/simple_page.phtml</pre>
<p>with the following contents
<pre>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Hello World</title>
<style type="text/css">
body {
background-color:#f00;
}
</style>
</head>
<body>
</body>
</html>
</pre>
<p>Finally, each Action Controller is responsible for kicking off the layout process. We'll need to add two method calls to the Action Method.</p>
<pre>
public function indexAction() {
//remove our previous echo
//echo 'Hello Index!';
$this->loadLayout();
$this->renderLayout();
}
</pre>
<p>Clear your Magento cache and reload your Hello World controller page. You should now see a website with a bright red background and an HTML source that matches what's in simple_page.phtml. </p>
<h2>What's Going On</h2>
<p>So, that's a lot of voodoo and cryptic incantations. Let's take a look at what's going on.</p>
<p>First, you'll want to install the <a href="http://alanstorm.com/2005/projects/MagentoLayoutViewer.tar.gz">Layoutviewer</a> module. This is a module similar to the <a href="http://alanstorm.com/2005/projects/MagentoConfigViewer.tar.gz">Configviewer</a> module you built in the Hello World article that will let us peek at some of Magento's internals.</p>
<p>Once you've installed the module (similar to how you setup the <a href="http://alanstorm.com/2005/projects/MagentoConfigViewer.tar.gz">Configviewer</a> module), go to the following URL</p>
<pre>http://example.com/helloworld/index/index?showLayout=page</pre>
<p>This is the layout xml for your page/request. It's made up of <block />, <reference /> and <remove /> tags. When you call the <tt>loadLayout</tt> method of your Action Controller, Magento will </p>
<ol>
<li><p>Generate this Layout XML </p></li>
<li><p>Instantiate a Block class for each <block /> tag, looking up the class using the tag's type attribute as a global config path and store it in the internal <tt>_blocks</tt> array of the layout object, using the tag's name attribute as the array key.</p></li>
<li><p>If the <block /> tag contains an output attribute, its value is added to the internal <tt>_output</tt> array of the layout object.</p></li>
</ol>
<p>Then, when you call the <tt>renderLayout</tt> method in your Action Controller, Magento will iterate over all the Blocks in the <tt>_output</tt> array, using the value of the output attribute as a callback method. This is always <tt>toHtml</tt>, and means the starting point for output will be that Block's Template.</p>
<p>The following sections will cover how Blocks are instantiated, how this layout file is generated, and finishes up with kicking off the output process.</p>
<h2>Block Instantiation</h2>
<p>So, within a Layout XML file, a <block /> has a "type" that's actually a Grouped Class Name URI</p>
<pre>
<block type="page/html" ...
<block type="page/template_links" ...
</pre>
<p>The URI references a location in the (say it with me) global config. The first portion of the URI (in the above examples <tt>page</tt>) will be used to query the global config to find the page class name. The second portion of the URI (in the two examples above, <tt>html</tt> and <tt>template_links</tt>) will be appended to the base class name to create the class name Magento should instantiate.</p>
<p>We'll go through <tt>page/html</tt> as an example. First, Magento looks for the global config node at file</p>
<pre>app/code/core/Mage/Page/etc/config.xml</pre>
<p>and finds
<pre>
<page>
<class>Mage_Page_Block</class>
</page>
</pre>
<p>This gives us our base class prefix <tt>Mage_Page_Block</tt>. Then, the second part of the URI (<tt>html</tt>) is appended to the class name to give us our final Block class name <tt>Mage_Page_Block_Html</tt>. This is the class that will be instantiated.</p>
<p>If we create a block with the same name as an already existing block, the new block instance will replace the original instance. This is what we've done in our local.xml file from above.</p>
<pre>
<layout version="0.1.0">
<default>
<block type="page/html" name="root" output="toHtml" template="magentotutorial/helloworld/simple_page.phtml" />
</default>
</layout>
</pre>
<p>The Block named <tt>root</tt> has been replaced with our Block, which points at a different phtml Template file.</p>
<h2>Using references</h2>
<p><reference name="" /> will hook all contained XML declarations into an existing block with the specified name. Contained <block /> nodes will be assigned as child blocks to the referenced parent block.</p>
<pre>
<layout version="0.1.0">
<default>
<block type="page/html" name="root" output="toHtml" template="page/2columns-left.phtml">
<!-- ... sub blocks ... -->
</block>
</default>
</layout>
</pre>
<p>In a different layout file:</p>
<pre>
<layout version="0.1.0">
<default>
<reference name="root">
<!-- ... another sub block ... -->
<block type="page/someothertype" name="some.other.block.name" template="path/to/some/other/template" />
</reference>
</default>
</layout>
</pre>
<p>Even though the root block is declared in a separate layout XML file, the new block is added as a child block. Magento initially creates a <tt>page/html</tt> Block named <tt>root</tt>. Then, when it later encounters the reference with the same name (<tt>root</tt>), it will assign the new block <tt>some.other.block.name</tt> as a child of the root block.
</p>
<h2>How Layout Files are Generated</h2>
<p>So, we have a slightly better understanding of what's going on with the Layout XML, but where is this XML file coming from? To answer that question, we need to introduce two new concepts; Handles and the Package Layout.</p>
<h3>Handles</h3>
<p>Each page request in Magento will generate several unique Handles. The Layoutview module can show you these Handles by using a URL something like</p>
<pre>http://example.com/helloworld/index/index?showLayout=handles</pre>
<p>You should see a list similar to the following (depending on your configuration)</p>
<ol>
<li><tt>default</tt></li>
<li><tt>STORE_bare_us</tt></li>
<li><tt>THEME_frontend_default_default</tt></li>
<li><tt>helloworld_index_index</tt></li>
<li><tt>customer_logged_out</tt></li>
</ol>
<p>Each of these is a Handle. Handles are set in a variety of places within the Magento system. The two we want to pay attention to are <tt>default</tt> and <tt>helloworld_index_index</tt>. The <tt>default</tt> Handle is present in <strong>every</strong> request into the Magento system. The <tt>helloworld_index_index</tt> Handle is created by combining the route name (helloworld), Action Controller name (index), and Action Controller Action Method (index) into a single string. This means each possible method on an Action Controller has a Handle associated with it. </p>
<p>Remember that "index" is the Magento default for both Action Controllers and Action Methods, so the following request</p>
<pre>http://example.com/helloworld/?showLayout=handles</pre>
<p>Will also produce a Handle named <tt>helloworld_index_index</tt></p>
<h2>Package Layout</h2>
<p>You can think of the Package Layout similar to the global config. It's a large XML file that contains <strong>every possible layout configuration</strong> for a particular Magento install. Let's take a look at it using the Layoutview module</p>
<pre>http://example.com/helloworld/index/index?showLayout=package</pre>
<p>This may take a while to load. If your browser is choking on the XML rendering, try the text format</p>
<pre>http://example.com/helloworld/index/index?showLayout=package&showLayoutFormat=text</pre>
<p>You should see a very large XML file. This is the Package Layout. This XML file is created by combining the contents of all the XML layout files for the current theme (or package). For the default install, this is at</p>
<pre>app/design/frontend/base/default/layout/</pre>
<p>Behind the scenes there are <strong><frontend><layout><updates /></strong> and <strong><adminhtml><layout><updates /></strong> sections of the global config that contains nodes with all the file names to load for the respective area. Once the files listed in the config have been combined, Magento will merge in one last xml file, local.xml. This is the file where you're able to add your customizations to your Magento install. </p>
<h2>Combining Handles and The Package Layout</h2>
<p>So, if you look at the Package Layout, you'll see some familiar tags such as <block /> and <reference />, but they're all surrounded by tags that look like </p>
<pre>
<default />
<catalogsearch_advanced_index />
etc...
</pre>
<p>These are all Handle tags. The Layout for an individual request is generated by grabbing all the sections of the Package Layout that match any Handles for the request. So, in our example above, our layout is being generated by grabbing tags from the following sections</p>
<pre>
<default />
<STORE_bare_us />
<THEME_frontend_default_default />
<helloworld_index_index />
<customer_logged_out />
</pre>
<p>There's one additional tag you'll need to be aware of in the Package Layout. The <update /> tag allows you to include another Handle's tags. For example</p>
<pre>
<customer_account_index>
<!-- ... -->
<update handle="customer_account"/>
<!-- ... -->
</customer_account_index>
</pre>
<p>Is saying that requests with a customer_account_index Handle should include <blocks />s from the <customer_account /> Handle.</p>
<h2>Applying What We've Learned</h2>
<p>OK, that's a lot of theory. Lets get back to what we did earlier. Knowing what we know now, adding</p>
<pre>
<layout version="0.1.0">
<default>
<block type="page/html" name="root" output="toHtml" template="magentotutorial/helloworld/simple_page.phtml" />
</default>
</layout>
</pre>
<p>to <tt>local.xml</tt> means we've overridden the "root" tag. with a different Block. By placing this in the <default /> Handle we've ensured that this override will happen for <strong>every page request</strong> in the system. That's probably not what we want. </p>
<p>If you go to any other page in your Magento site, you'll notice they're either blank white, or have the same red background that your hello world page does. Let's change your <tt>local.xml</tt> file so it only applies to the hello world page. We'll do this by changing default to use the full action name handle (<tt>helloworld_index_index</tt>).</p>
<pre>
<layout version="0.1.0">
<helloworld_index_index>
<block type="page/html" name="root" output="toHtml" template="magentotutorial/helloworld/simple_page.phtml" />
</helloworld_index_index>
</layout>
</pre>
<p>Clear your Magento cache, and the rest of your pages should be restored. </p>
<p>Right now this only applies to our index Action Method. Let's add it to the goodbye Action Method as well. In your Action Controller, modify the goodbye action so it looks like</p>
<pre>
public function goodbyeAction() {
$this->loadLayout();
$this->renderLayout();
}
</pre>
<p>If you load up the following URL, you'll notice you're still getting the default Magento layout.</p>
<pre>http://example.com/helloworld/index/goodbye</pre>
<p>We need to add a Handle for the full action name (<tt>helloworld_index_goodbye</tt>) to our local.xml file. Rather than specify a new <block />, lets use the update tag to include the <tt>helloworld_index_index</tt> Handle.</p>
<pre>
<layout version="0.1.0">
<!-- ... -->
<helloworld_index_goodbye>
<update handle="helloworld_index_index" />
</helloworld_index_goodbye>
</layout>
</pre>
<p>Loading the following pages (after clearing your Magento cache) should now produce identical results.</p>
<pre>http://example.com/helloworld/index/index
http://example.com/helloworld/index/goodbye</pre>
<h2>Starting Output and getChildHtml</h2>
<p>In a standard configuration, output starts on the Block named root (because it has an output attribute). We've overridden root's Template with our own</p>
<pre>template="magentotutorial/helloworld/simple_page.phtml"</pre>
<p>Templates are referenced from the root folder of the current theme. In this case, that's</p>
<pre>app/design/frontend/base/default</pre>
<p>so we need to drill down to our custom page. Most Magento Templates are stored in </p>
<pre>app/design/frontend/base/default/templates</pre>
<p>Combining this gives us the full path</p>
<pre>app/design/frontend/base/default/templates/magentotutorial/helloworld/simple_page.phtml</pre>
<h2>Adding Content Blocks</h2>
<p>A simple red page is pretty boring. Let's add some content to this page. Change your <tt><helloworld_index_index /></tt> Handle in local.xml so it looks like the following</p>
<pre>
<helloworld_index_index>
<block type="page/html" name="root" output="toHtml" template="magentotutorial/helloworld/simple_page.phtml">
<block type="customer/form_register" name="customer_form_register" template="customer/form/register.phtml"/>
</block>
</helloworld_index_index>
</pre>
<p>We're adding a new Block nested within our root. This is a Block that's distributed with Magento, and will display a customer registration form. By nesting this Block within our root Block, we've made it available to be pulled into our <tt>simple_page.html</tt> Template. Next, we'll use the Block's getChildHtml method in our <tt>simple_page.phtml</tt> file. Edit <tt>simple_page.html</tt> so it looks like this</p>
<pre>
<body>
<?php echo $this->getChildHtml('customer_form_register'); ?>
</body>
</pre>
<p>Clear your Magento cache and reload the page and you should see the customer registration form on your red background. Magento also has a Block named top.links. Let's try including that. Change your simple_page.html file so it reads</p>
<pre>
<body>
<h1>Links</h1>
<?php echo $this->getChildHtml('top.links'); ?>
</body>
</pre>
<p>When you reload the page, you'll notice that your <h1>Links</h1> title is rendering, but nothing is rendering for top.links. That's because we didn't add it to local.xml. The <tt>getChildHtml</tt> method can only include Blocks that are specified as sub-Blocks in the Layout. This allows Magento to only instantiate the Blocks it needs, and also allows you to set difference Templates for Blocks based on context.</p>
<p>Let's add the top.links Block to our local.xml</p>
<pre>
<helloworld_index_index>
<block type="page/html" name="root" output="toHtml" template="magentotutorial/helloworld/simple_page.phtml">
<block type="page/template_links" name="top.links"/>
<block type="customer/form_register" name="customer_form_register" template="customer/form/register.phtml"/>
</block>
</helloworld_index_index>
</pre>
<p>Clear your cache and reload the page. You should now see the top.links module. </p>
<h2>Time for action</h2>
<p>There is one more important concept to cover before we wrap up this lesson, and that is the <action /> tag. Using the <action /> tag enables us to call public PHP methods of the block classes. So instead of changing the template of the root block by replacing the block instance with our own, we can use a call to <tt>setTemplate</tt> instead.</p>
<pre>
<layout version="0.1.0">
<helloworld_index_index>
<reference name="root">
<action method="setTemplate">
<template>magentotutorial/helloworld/simple_page.phtml</template>
</action>
<block type="page/template_links" name="top.links"/>
<block type="customer/form_register" name="customer_form_register" template="customer/form/register.phtml"/>
</reference>
</helloworld_index_index>
</layout>
</pre>
<p>This layout XML will first set the template property of the root block, and then will add the two blocks we use as child blocks. Once we clear the cache, the result should look just as before. The benefit of using the <action /> is the same block instance is used that was created earlier, and all other parent/child associations still exist. For that reason this is a more upgrade proof way of implementing our changes.</p>
<p>All arguments to the action's method need to be wrapped in an individual child node of the <action /> tag. The name of that node doesn't matter, only the order of the nodes. We could have written the action node from the previous example as follows with the same effect.
</p>
<pre>
<action method="setTemplate">
<some_new_template>magentotutorial/helloworld/simple_page.phtml</some_new_template>
</action>
</pre>
<p>This is just to illustrate that the action's argument node names are arbitrary.</p>
<h2>Wrapup</h2>
<p>That covers Layout fundamentals. We have covered the tags <block />, <reference />, <update /> and <action />, and also layout update handles like <default /> and <cms_index_index />. These make up most of the layout configuration used in Magento. If you found it somewhat daunting, don't worry, you'll rarely need to work with layouts on such a fundamental level. Magento provides a number of pre-built layouts which can be modified and skinned to meet the needs of your store. Understanding how the entire Layout system works can be a great help when you're trouble shooting Layout issues, or adding new functionality to an existing Magento system.</p>