From the loaded config we take the names of all layout files, described for each module. Put them all into the $updateFiles array. And at the end local.xml is added into the same array.

And now we load all the received files from the same theme where it has been found. And all this thanks to the class Mage_Core_Model_Design_Package.

This is how we get a single XML from all our modules.
$this->_packageLayout – will save it for the further processing.

This way we can quickly get an XML file of the currently processed handle and with any new handle, appearing in marge, fetch it from the already generated object.

Going back to the function fetchPackageLayoutUpdates we see the following:

foreach ($this->_packageLayout->$handle as $updateXml) {

$this->fetchRecursiveUpdates($updateXml);

$this->addUpdate($updateXml->innerXml());

}

1

2

3

4

5

6

7

8

9

10

11

publicfunctionfetchRecursiveUpdates($updateXml)

{

foreach($updateXml->children()as$child){

if(strtolower($child->getName())=='update'&&isset($child['handle'])){

$this->merge((string)$child['handle']);

// Adding merged layout handle to the list of applied hanles

$this->addHandle((string)$child['handle']);

}

}

return$this;

}

Running through the currently processed handle, the function fetchRecursiveUpdates is searching for extra handles, which have been input directly via the <update> tag. If such handles are found, they are added to the end of the array.

The function $this->addUpdate adds the XML of the found handles into another array $this->_updates

This is how the marge() function assembles a small XML file which is related only to the current page. And nothing more. But this is not the end yet. Magento can also perform one more task: If possible, the marge() function can try extend our XML file a littler more for each of the handles.

The thing is that the marge function is ended with a condition, which, if necessary, searches for an extra XML file for the currently processed handle. $this->fetchDbLayoutUpdates($handle);

To carry out a search, there are two tables from the Magento database:

core_layout_link and core_layout_update.

How does an XML file get there? At the stage of development it is not necessary to use these options, but it is very convenient if there is no access to FTP. There is CMS/Widgets section on the admin panel which allows making additional changes in some handles.
So now we are finished with the class Mage_Core_Model_Layout_Update. The main functions of the class have been described although you may have an impression that there are still some points missing. For instance, for each product its own layout can be added in the admin panel and logically it should be related to the same class. So when is it loaded?

There is no magic here. If necessary, we can always create our own version of the loadLayout() function for controllers. It is already made in this way for products view and is implemented in Helper. For example, you can check yourself the function Mage_Catalog_Helper_Product_View:: initProductLayout($product, $controller).

_generateBlock

XML for the current page has been assembled. Consequently, we know all the Templates and Blocks which will be used to build up the page. And before we start outputting HTML, the loadLayout function starts generating all classes which work with the templates.

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

protectedfunction_generateBlock($node,$parent)

{

...

$className=(string)$node['type'];

$blockName=(string)$node['name'];

...

$block=$this->createBlock($className,$blockName);

...

if(!empty($node['parent'])){

$parentBlock=$this->getBlock((string)$node['parent']);

}else{

$parentName=$parent->getBlockName();

if(!empty($parentName)){

$parentBlock=$this->getBlock($parentName);

}

}

if(!empty($parentBlock)){

$alias=isset($node['as'])?(string)$node['as']:'';

if(isset($node['before'])){

$sibling=(string)$node['before'];

if('-'===$sibling){

$sibling='';

}

$parentBlock->insert($block,$sibling,false,$alias);

}elseif(isset($node['after'])){

$sibling=(string)$node['after'];

if('-'===$sibling){

$sibling='';

}

$parentBlock->insert($block,$sibling,true,$alias);

}else{

$parentBlock->append($block,$alias);

}

}

if(!empty($node['template'])){

$block->setTemplate((string)$node['template']);

}

if(!empty($node['output'])){

$method=(string)$node['output'];

$this->addOutputBlock($blockName,$method);

}

...

}

The _generateBlock() function:

Calls createBlock(), which starts getBlockInstance(). Thus we have declared a class. There is also an Observer there.

Next we get the parent Block, as it is exactly where the just created block is used.

Alias is processed for the parent template. In XML, this is the ‘as’ parameter of the block. Under this name the block is added into its parent through the command Mage_Core_Block_Abstract :: insert($block, $sibling, false, $alias).

You are sure to notice that there is also the function append. It gets executed if no ‘after’ and ‘before’ parameters haven’t been found there, which determine before or after which block the described one should be placed. It is all very simple here.

1

2

3

4

5

publicfunctionappend($block,$alias='')

{

$this->insert($block,'',true,$alias);

return$this;

}

How does it work?
$this->setChild($name, $block);

It is assumed that $name is alias, but when it has not been defined then just the block name is used. But what happens if neither ‘as’ nor ‘name’ parameter has been defined in XML?

If a Block has neither name nor alias – then it is considered as anonymous but is still added, just the name is generated automatically.

Next part of the Insert function is the sorting function. Blocks names get added into the array $this->_sortedChildren in the same order as they were declared in Layout, taking into account the ‘after’ and ‘before’ parameters, if they have been defined.

– If in Layout the template name has been defined though the ‘template’ parameter in the tag <block> then it gets added into the created class.

– at the end, the ‘output’ parameter gets verified. If it has been defined, then $this->addOutputBlock($blockName, $method); gets executed.

In Layout this parameter defines the name of the first parent Block (from where the HTML rendering will be started) and name of the function which will launch the whole process. We can find an example in page.xml

So now we are ready to start building up our theme. This is how Magento understands that the HTML output should start exactly from the ‘root’ block and that it should launch the toHTML() function for that. If there are several of such blocks, Magento will output them one

– The first one is ‘ifconfig’. If this parameter has been defined, the value of getStoreConfig (set under System / Configuration section in the admin panel) gets verified, Action gets executed only when the value does exist and is true.

– The next one is the ‘method’ parameter, which defines the name of the function that should be executed in the block class.

– The ‘block’ parameter is also possible, which is quite interesting. Defining this parameter you can execute a function not from the parent block, but from any other declared block.

– The ‘json’ paremeter. As you know, the <action> tag in Layout has its internal tags which content is passed as the parameters of the executed function. But what happens if any of the parameters appear as an array – there is still a workaround to solve this! Take the <action> tag and in the ‘json’ parameter specify the names of those internal tags, where json and their values will be successfully transformed into an array (names should be separated by spaces).

– The last one is the ‘translate’ parameter. The function
$this->_translateLayoutNode($node, $args)
will translate the value of the listed tags, separated by spaces.

The function _generateAction has one more secret: ‘helper’ can be used as the parameter of internal tags. Here is a simple example:

1

2

3

4

5

6

7

8

9

10

<action method="addLink"translate="label title"module="customer">

<label>My Account</label>

<url helper="customer/getAccountUrl">

<value></value>

</url>

<title>My Account</title>

<prepare/>

<urlParams/>

<position>10</position>

</action>

Before action is executed it is possible to pass any value into the ‘helper’ function (or do not pass as in our example) and the final result will become the value for this internal tag. In our case the tag <action> has internal tag <url> which will be given the value returned by the function. Mage::helper(‘customer’)->getAccountUrl($value)

So, what is next in our list? Looks like everything is ready now so it is time to output HTML. See you in the next article!

First of all, we’d like to extend the topic to “How to create a web site using the Magento CMS”. The reason for it is that it is the theme(s) creation (including the mobile ones) the user starts the development of the store with.

The principal thing in theme creation is the desire to update to a new Magento version without facing problems. For now the final versions of Magento Community 1.7 and Enterprise 1.12 came out, and you would say “Why think of updating, Magento 2 is already being designed, whereas the development of the first version has been brought to a stop”. Well, what about updating the extensions then? If we do something, we prefer it to be done faultlessly. It will always stand us in good stead using the second Magento version. (more…)