11

I want to be able to pass data to the getChildHtml() call. The reason is, the output of the block is dependant upon a product type. So i want to pass the product to the getChildHtml so that it can decide on the output.

I am doing this inside template/checkout/cart/item/default.phtml.

Ideally, the call would look like:

echo $this->getChildHtml('child_block_name', $_item);

Then my block can get the product type from the item and display the correct output.

Since it is definitely not possible to pass this data to getChildHtml - how else can this type of behaviour be achieved without having to rewrite the core block

The two solutions i currently have are as follows (neither very attractive):

1 - Create a helper and access the html output via the helper instead of letting a block and template render it ala $this->helper('my_module')->getItemHtml($_item);

2 - Access the child block and setData on it inside the template:

 $this->getChild('child_name')->setData('item', $_item);
 echo $this->getChildHtml('child_name')

I think in terms of the Magento architecture, number 2 is the lesser of two evils, but it is darn ugly looking inside a template.

  • Can you instead provide the 'data' in the registry or session that the child block makes use of? Are you using this in an iterator? What's the use case? – philwinkle May 15 '13 at 22:19
  • I dont think the registry would help here as the desired output is dependent upon a cart items product type. So this must be passed to the block in some way so that the correct data can be output. The use case is display some extra info on the cart item, but it depends on product type – Marty Wallace May 15 '13 at 22:21
  • You can create product-type attributes - perhaps you create differing attributes based on product types? If you'd rather create your own block we can certainly advise in that direction but there may be some other built-in win here that I'm trying to sniff out... – philwinkle May 15 '13 at 22:24
  • Well, it is a product level attribute that i am accessing, but the way it is displayed depends on the product type. A grouped product will render the same attribute slightly differently than say a simple product. I am using a block and template for each different flavour of output – Marty Wallace May 15 '13 at 22:28
  • I have updated my question with some ideas i have which i am contemplating but am not 100% comfortable with – Marty Wallace May 15 '13 at 22:33
2

You can add a method on the parent block to fetch the child depending on the product type (I've seen this kind of logic a couple of times in core or something similar):

class ParentBlock 
{
    public function getIntuitiveNameChild($item)
    {
        return $this->getChild("intuitive_child")
                    ->setProductType($item->getProductType()) 
                    // You can also decide the product type in this setter, in the Child block.
                    ->setItem($item);
    }

    public function getIntuitiveNameChildDinamically($item)
    {
        return $this->getChild("intuitive_child_" . $item->getProductType())
                    ->setItem($item); 
    }    
}

// parent tpl
// i suggest you avoid getChildHtml(), unless you're certain that methods won't need to be called from the tpl
echo $this->getIntuitiveNameChild($_item)
          // ->someOtherMethod()
          ->toHtml();

Still, seeing how you modify the layout xml to add children blocks, you may be interested in how Magento decided to work with rendering markup depending on product types in Mage_Sales_Block_Items_Abstract::getItemHtml() and Mage_Checkout_Block_Cart_Abstract::getItemHtml().

  • This method bypasses the layout structure and produces blocks that are tightly coupled (like everything in Magento...) – Victor Schröder Feb 21 at 17:20
11

The above solution wont work if you are displaying child block in foreach loop.

For that you need to use following code:

<?php
foreach ($blocks as $block) {
    $this->getChild("child.block")->setData("my_data", $any_data);
    echo $this->getChildHtml('child.block', false);
}
?>

In child.block you can use $this->getMyData() to get the data. Using this strategy the child block will always get the latest data from parent.

The second parameter of getChildHtml() is $useCache. Setting it to false prevents the first output to be cached and forces rendering the child again.

4

A block that can receive data is called a widget; though this can be done via multiple block definitions (based on the properties of $_item).

Magento does something very similar in the core by loading the payment method block based on the method's short code:

<dd>
    <?php echo $this->getChildHtml('payment.method.'.$_code) ?>
</dd>

You could do the same with this pseudo-code:

if($type = $_item->getTypeId()){
    $this->getChildHtml('my.block.' . $type);
}

All that would require would be to have a different block type for each product type - bundle, simple, configurable, virtual, grouped. Not so bad, really.

If you really want to use a widget - it would be something to the effect of your second idea in your edited question:

<?php
echo $this->getLayout()->createBlock('yourcompany/widget_class')->setType($_item->getTypeId())->toHtml();

Creating a widget probably outside of the scope of this answer - but it's not terribly difficult, and has the advantage of being able to be repurposed for CMS blocks, though for your use case I don't think that is applicable.

For more information on creating a widget:

http://www.magentocommerce.com/knowledge-base/entry/tutorial-creating-a-magento-widget-part-1

  • I am not 100% convinced this is a good approach to this which I havent accepted the answer. – Marty Wallace May 16 '13 at 8:20
  • 1
    Only a widget block can receive data? What do you mean? All blocks can receive data. A widget is something different in Magento terms. – nevvermind May 16 '13 at 15:55
  • I never said they couldn't; I'm saying, by definition, a widget requires data input to display something conditionally. – philwinkle May 16 '13 at 15:57
0

For Magento 2, you can use

<?php
foreach ($blocks as $block) {
    $block->getChildBlock("child.block")->setData("my_data", $any_data);
    echo $block->getChildHtml('child.block', false);
}
?>

To get the data,

$block->getMyData();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.