Tutorial: Creating a Magento Widget - Part 2

This is the second part of the widgets tutorial. It's highly recommended that you start with the introductory blog post on Magento Widgets to grasp the concepts and terminology, then read the first part of the tutorial at Tutorial: Creating a Magento Widget, Part 1.

Introduction

We've already learned how to create a simple widget (i.e. create a module, define widgets and create frontend blocks). Now we are going to try to go deeper into the available widget configuration options to see what makes Magento widgets so beneficial to both the store owners and extension developers.

Learn available widget configuration options, types and definitions

Let's look into an abstract widget.xml file:

<?xml version="1.0"?>
<widgets>
    <
some_unique_widget_name type="block_group/block_path" translate="name description" module="modulename">
        <
name>Widget name</name>
        
        <
description>Short widget description</description>
        
        <!-- 
Additional javascript files to be loaded
            on the widget configuration edit form 
if needed. -->
        <
js>mage/adminhtml/first.js,mage/adminhtml/second.js</js>
        
        <!--
            
It should contain comma separated list
            
of javascript files paths under the /js directory.
            
This tag is optional.
        -->

        <
parameters>
            <
first_option translate="label">
                <!-- 
General option properties -->

                <!-- 
Defines if the option is allowed to be empty -->
                <
required>1</required>

                <!-- 
Defines if the option is visible in the edit form -->
                <
visible>1</visible>
                <!--
                    
In case if you need some hidden input
                    in the widget configuration form
,
                    
set 'visible' to 0
                
-->

                <!-- 
Label for the edit form -->
                <
label>Option name</label>

                <!-- 
Option type -->
                <
type>select</type>
                <!--
                    
It can be either one of the simple form element typese.g.:
                        <
type>text</type>
                        <
type>select</type>
                        <
type>multiselect</type>
                        <
type>label</type>
                    ...
                    
                    or 
it can define a renderer which will be used to create
                    this configuration field in the edit form
.
                    
Renderer is supposed to be a block reference
                    in 
'block_group/block_path' formate.g.:
                        <
type>mymodule/some_custom_block</type>
                -->

                <!-- 
Source values for drop-downs and multiselects -->
                
                <!--
                    
There are two possible ways to define a set of available values.
                    
The first way is to specify the list of available values right here:
                -->
                <
values>
                    <
value_one translate="label">
                        <
value>1</value>
                        <
label>One</label>
                    </
none>
                    <
two translate="label">
                        <
value>2</value>
                        <
label>Two</label>
                    </
two>
                    <
three translate="label">
                        <
value>3</value>
                        <
label>Three</label>
                    </
three>
                </
values>
                
                <!--
                    
The second way is to specify the source model,
                    
which must have toOptionArray() public method available.
                    
The method should return an array of values and labels
                    in the following format
:
                        array(
                            array(
'value' => 'value1''label' => 'Label 1'),
                            array(
'value' => 'value2''label' => 'Label 2'),
                            array(
'value' => 'value2''label' => 'Label 3'),
                        );
                    
Source model name is specified in usual
                    
'model_group/model_path' formate.g.:
                -->
                <
source_model>adminhtml/system_config_source_yesno</source_model>

                <!-- 
Additional helper block to be created on the edit form pageoptional -->
                <
helper_block>
                    <!-- 
Helper block reference in regular 'block_group/block_path' format -->
                    <
type>module/block_type</type>

                    <!-- 
Arguments for the block constructoroptional  -->
                    <
data>
                        <
value1>Value1</value1>
                        <
value2>Value1</value2>
                        <
value3>
                            <
one>One</one>
                            <
two>Two</two>
                        </
value3>
                    </
data>
                </
helper_block>

                <!--
                    
Here is the full example of helper block definition
                    from catalog module widgets
:

                    <
helper_block>
                        <
type>adminhtml/catalog_product_widget_chooser</type>
                        <
data>
                            <
button translate="open">
                                <
open>Select Product...</open>
                            </
button>
                        </
data>
                    </
helper_block>

                -->
            </
first_option>

            <!--
                ...
                
any number of other widget configuration options goes here
                
...
            -->
        </
parameters>
    </
some_unique_widget_name>

    <!--
        ...
        
other widgets declarations go here
        
...
    -->
</
widgets>

Create a module

Let's create a module directory structure and necessary files

Declare a widget

app/code/local/Sample/WidgetTwo/etc/widget.xml:

<?xml version="1.0"?>
<widgets>
    <
widgettwo_list type="widgettwo/list" translate="name description" module="widgettwo">
        <
name>Social Bookmarking Links</name>
        <
description>Adds a simple list of social bookmarking links</description>
        <
parameters>
            <
enabled_services>
                <
label>Enabled Services</label>
                <
visible>1</visible>
                <
required>1</required>
                <
type>multiselect</type>
                <
source_model>widgettwo/services</source_model>
            </
enabled_services>
            <
template translate="label">
                <
label>Frontend Template</label>
                <
visible>1</visible>
                <
required>1</required>
                <
type>select</type>
                <
values>
                    <
text translate="label">
                        <
value>widgettwo/text.phtml</value>
                        <
label>Text Links</label>
                    </
text>
                    <
icons translate="label">
                        <
value>widgettwo/icons.phtml</value>
                        <
label>Icon Links</label>
                    </
icons>
                </
values>
            </
template>
        </
parameters>
    </
widgettwo_list>
</
widgets>

Create a source model to use it with service multiselect in widget configuration

app/code/local/Sample/WidgetTwo/Model/Services.php:

<?php
class Sample_WidgetTwo_Model_Services
{
    
/**
     * Provide available options as a value/label array
     *
     * @return array
     */
    
public function toOptionArray()
    
{
        
return array(
            array(
'value' => 'digg''label' => 'Digg'),
            array(
'value' => 'delicious''label' => 'Delicious'),
            array(
'value' => 'twitter''label' => 'Twitter'),
        );
    
}
}

Create a frontend widget block

app/code/local/Sample/WidgetTwo/Block/List.php:

<?php
class Sample_WidgetTwo_Block_List
    
extends Mage_Core_Block_Template
    
implements Mage_Widget_Block_Interface
{
    
/**
     * A model to serialize attributes
     * @var Varien_Object
     */
    
protected $_serializer null;

    
/**
     * Initialization
     */
    
protected function _construct()
    
{
        $this
->_serializer = new Varien_Object();
        
parent::_construct();
    
}

    
/**
     * Produce links list rendered as html
     *
     * @return string
     */
    
protected function _toHtml()
    
{
        $html 
'';
        
$config $this->getData('enabled_services');
        if (empty(
$config)) {
            
return $html;
        
}
        $services 
explode(','$config);
        
$list = array();
        foreach (
$services as $service{
            $item 
$this->_generateServiceLink($service);
            if (
$item{
                $list[] 
$item;
            
}
        }
        $this
->assign('list'$list);
        return 
parent::_toHtml();
    
}

    
/**
     * Generate link attributes
     *
     * The method returns an array, containing any number of link attributes,
     * All values are optional
     * array(
     *  'href' => '...',
     *  'title' => '...',
     *  '_target' => '...',
     *  'onclick' => '...',
     * )
     *
     * @param string $service
     * @return array
     */
    
protected function _generateServiceLink($service)
    
{
        
/**
         * Page title
         */
        
$pageTitle '';
        
$headBlock $this->getLayout()->getBlock('head');
        if (
$headBlock{
            $pageTitle 
$headBlock->getTitle();
        
}

        
/**
         * Current URL
         */
        
$currentUrl $this->getUrl('*/*/*', array('_current' => true'_use_rewrite' => true));

        
/**
         * Link HTML
         */
        
$attributes = array();
        
$icon '';
        switch (
$service{
            
case 'digg':
                
$attributes = array(
                    
'href'  => 'http://www.digg.com/submit?url=' rawurlencode($currentUrl) . '&amp;phase=2',
                    
'title' => 'You Digg?',
                );
                
$icon 'digg.gif';
                break;
            case 
'delicious':
                
$attributes = array(
                    
'href'  => 'http://del.icio.us/post?url=' rawurlencode($currentUrl),
                    
'title' => 'Add to del.icio.us',
                    
'onclick'   => 'window.open(\'http://del.icio.us/post?v=4&amp;noui&amp;jump=close&amp;url='
                        
rawurlencode($currentUrl) . "&amp;title=" rawurlencode($pageTitle)
                        . 
"','delicious', 'toolbar=no,width=700,height=400'); return false;",
                );
                
$icon 'delicious.gif';
                break;
            case 
'twitter':
                
$attributes = array(
                    
'href'      => 'http://twitter.com/home?status='
                        
rawurlencode('Currently reading ' $pageTitle ' at ' $currentUrl ),
                    
'title'     => 'Tweet This!',
                    
'target'    => '_blank',
                );
                
$icon 'twitter.gif';
                break;
            default:
                return array();
                break;
        
}

        $item 
= array(
            
'text' => $attributes['title'],
            
'attributes' => $this->_serializer->setData($attributes)->serialize(),
            
'image' => $this->getSkinUrl("images/" $icon),
        );

        return 
$item;
    
}
}

Create templates

app/design/frontend/default/default/widgettwo/text.phtml:

<?php foreach ($list as $item) : ?>
    
<a <?php echo $item['attributes']?>><?php echo $this->escapeHtml($item['text']); ?></a>
<?php endforeach; ?>

app/design/frontend/default/default/widgettwo/icons.phtml:

<?php foreach ($list as $item) : ?>
    
<a <?php echo $item['attributes']?>><img src="<?php echo $item['image']; ?>" title="<?php echo $this->escapeHtml($item['text']); ?>" border="0" /></a>
<?php endforeach; ?>

Add widget instances in the admin panel

Let's go to CMS > Pages in the admin panel and add a widget instance to the homepage in a WYSIWYG editor or plain text mode:

Look how does the inserted widget look like in the plain text mode:

Check over the frontend

Conclusion

As you can see, there is no need anymore to follow the long complicated instructions, like ... and after you install our extension please insert this code into a CMS static block, and set proper IDs and values which you can find by looking into the ... or ... insert this code into ... template and then you will be able to add the following layout update instructions to your layout files or to the selected catalog categories on the 'Custom Design' tab ...

Magento Widgets allow a store owner with no technical knowledge to easily add configurable content block to frontend pages in his Magento store. That saves a lot of time and results in mutual benefit for store owners and extension developers.

 

This module is available on the Magento Connect.

You can also download the full source code archive in tar.gz, tar.bz2 or zip formats.

RSS: New Article posts

Explore the Knowledge Base