Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Magento: Programmatically change a widget's configuration

I want to change and save a widget's configuration from within the widget's code. I'm looking for something like this:

class My_Module_Block_Widget
    extends Mage_Catalog_Block_Product_List
    implements Mage_Widget_Block_Interface
{
    // ...
    protected function _beforeToHtml()
    {
        // ...
        if(/* data needs to be changed */)
        {
            // assuming "widget_config_data" to be one of the widget's
            // parameters configured in the etc/widget.xml file of my module
            $this->setData("widget_config_data", "New Data");
            $this->save();
        }
        // ...
    }
    // ...
}

Since widgets are no models, they don't have a save() method. So how can I save the changed data of my widget?

like image 416
Subsurf Avatar asked May 22 '12 16:05

Subsurf


1 Answers

That's going to be tricky, and probably more involved that a single Stack Overflow question. Here's some background to get you started. The class/object you're dealing with above is a block class. Blocks are used to render HTML. They are, as you've noted, stateless.

The block gets its data from a widget instance model object.

Mage::getModel('widget/widget_instance');
Mage_Widget_Model_Widget_Instance

The state for these objects (the data you're trying to change) is located in the table widget_instance

The problem is, a block object doesn't know anything about the widget instance object. Widgets are inserted into the page layout with special layout handles stored in the database (that's an over-simplification, because you could write a book on the layout system). The reason your instance widget shows up on a page is because the page layout's been updated with information something like this

<reference name="content">
    <block type="cms/widget_page_link" name="48fc761f38fa9838fcc3a3b498c47f72" template="cms/widget/link/link_block.phtml">
        <action method="setData">
            <name>anchor_text</name>
            <value>asdfasdfsad</value>
        </action>
        <action method="setData">
            <name>title</name>
            <value>asdfasdfasdfasd</value>
        </action>
        <action method="setData">
            <name>page_id</name>
            <value>2</value>
        </action>
    </block>
</reference>

There's no reference to the widget instance id, which means you can't load the instance object.

In theory, you could try to load the widget instance based on the paramater values, since those are stored in the database. However, they're stored in the widget_paramater column, with is a serialized string. That means you can't use SQL or model fileters to query for it. You'd have to load all the widget instances of a particular instance type/theme/store, and then manually foreach through until you found the right object. This might be performant for a small number of widgets, but would quickly become non-performant for a large number of widgets. Also, this wouldn't be guarantied to work, as it's possible (although unlikely) that the values of your widgets parameters may have been changed by other layout update code.

The better, (and more time consuming), approach would be to rewrite the widget inserting code such that it includes a page id in the layout update XML. This would pass the instance id to the widget block code, allowing you to instantiate a widget instance object and save it. You might also be able to add a field to a widget whose custom class would always save the instance id.

Good luck!

like image 177
Alan Storm Avatar answered Sep 28 '22 15:09

Alan Storm