SpinOneSolutions | I waste my time so that you don't have to…

Oct/10

28

Magento Custom Widget

With the latest release of Magento admins now have the ability to create custom “widgets” that can be dropped anywhere on the site to provide additional functionality.  The most common type of widget that I come across is a simple frontend presentation widget.  Basically the developer is asked to display some sort of data in a new way.

Widgets can basically be thought of as easily customizable blocks.  The main difference between standard blocks and widgets is that widgets can be added to CMS pages through the WYSIWYG editor and they can easily accept parameters, also defined through the WYSIWYG.  Thus a non-programmer can add quasi-dynamic content to their CMS pages, hurrah!

You should reference previous articles if you want more details about creating custom Modules and Blocks.

As an example I’m going to build a super simple slideshow widget called “Glider”.  It’s going to be a widget that takes four static block_id(s) as parameters and then displays each static block, in succession, as a slideshow.  If you let your imagination work a little you should be able to see some cool possibilities for such a thing, given that you extend it a little.

I’m using static blocks as the source material for each slide because this would allow a content manager to change out the content of a slide by either editing the static block that contains the content or by editing the block id being passed to the widget.  Either way it’s manageable through the interface.

Also note that the template (presentation layer) is going to be statically defined in this example, but you could easily make that a parameter and create multiple templates for the content manager to choose from!

Finally, I’ve used jQuery to build the actual slideshow.  I’m not going to go into very much detail about the presentation of the slideshow as that’s not really the focus of this article.  Feel free to write in if you want to see the details on how to implement jQuery (or any other script).

First let’s setup the Module:

/app/etc/modules/Spinonesolutions_WidgetGlider.xml

<?xml version="1.0"?>
 <config>
 <modules>
 <Spinonesolutions_WidgetGlider>
   <active>true</active>
   <codePool>local</codePool>
   <depends>
     <Mage_Cms />
   </depends>
 </Spinonesolutions_WidgetGlider>
 </modules>
 </config>

/app/code/local/Spinonesolutions/WidgetGlider/etc/config.xml

<?xml version="1.0"?>
 <config>
 <modules>
 <Spinonesolutions_WidgetGlider>
   <version>1.0.0</version>
 </Spinonesolutions_WidgetGlider>
 </modules>
 <global>
 <blocks>
   <spinonesolutions_widgetglider>
     <class>Spinonesolutions_WidgetGlider_Block</class>
   </spinonesolutions_widgetglider>
 </blocks>
 </global>
 </config>

OK!  The next thing we need to do is define our widget’s interface.  To do that we create a widget.xml file inside our module’s “etc” folder.

/app/code/local/Spinonesolutions/WidgetGlider/etc/widget.xml

<?xml version="1.0"?>
<widgets>
<glider type="spinonesolutions_widgetglider/glider">
   <name>SpinoneSolutions: Glider</name>
   <description>Displays the given HTML Sections in a Glider Slideshow</description>
   <parameters>
     <section1>
       <required>0</required>
       <visible>1</visible>
       <label>Section1</label>
       <type>text</type>
     </section1>
     <section2>
       <required>0</required>
       <visible>1</visible>
       <label>Section2</label>
       <type>text</type>
     </section2>
     <section3>
       <required>0</required>
       <visible>1</visible>
       <label>Section3</label>
       <type>text</type>
     </section3>
     <section4>
       <required>0</required>
       <visible>1</visible>
       <label>Section4</label>
       <type>text</type>
     </section4>
     <template>
       <visible>0</visible>
       <value>widgetglider/banner.phtml</value>
     </template>
   </parameters>
</glider>
</widgets>

You can define any number of widgets in here.  We’re only creating one so I’ve only got a single entry, glider.

The type attribute tells Magento what class to use when instantiating objects.  I’ve set it as spinonesolutions_widgetglider/glider.  If you go back and inspect the config.xml and remember your Magento naming conventions you can surmise that this is going to cause Magento to try and instantiate an object of type Spinonesolutions_WidgetGlider_Block_Glider.  That class doesn’t exist yet so we should create it.

/app/code/local/Spinonesolutions/WidgetGlider/Block/Glider.php

<?php
class Spinonesolutions_WidgetGlider_Block_Glider extends Mage_Core_Block_Template
implements Mage_Widget_Block_Interface {
  const MAXSECTIONS = 4;
  public $sectionArr = array();

  protected function _construct() {
    parent::_construct();
  }

  protected function _toHtml() {
    for ($i=1;$i <= self::MAXSECTIONS;$i++) {
      if ($this->getData("section$i")) {
        $blockHTML = $this->getLayout()->createBlock('cms/block')->setBlockId($this->getData("section$i"))->toHtml();
        $this->sectionArr[$i] = $blockHTML;
      }
    }
    return parent::_toHtml();
  }
}

Let’s inspect the class from top to bottom.  The first thing to notice is that in the declaration it implements Mage_Widget_Block_Interface.  This is a requirement for Widgets.

Notice my constant MAXSECTIONS is set to 4, the same number of section parameters that I defined in widget.xml.  There’s probably some room for improvement here: one could probably figure out the number of parameters dynamically and then remove the constant.  That would make the widget more flexible for future uses.

I call the _construct function so that everything gets setup the way it’s supposed to.

Finally the real work gets done in _toHtml.  This function will be called automagically by Magento when it goes to render this object to the screen.

What I do is load up each block that gets passed into the widget and I stuff it’s HTML into an array element.  This way the widget can render any block, independently, by referencing a key in the array.

It’s not the classes job to do the rendering, that’s left to the presentation layer.  This class is just gathering everything that the presentation layer needs.

To move on with the tutorial we need to look back at our widget declaration in widget.xml.  I’m sure you noticed the last parameter template that I haven’t discussed yet.  Notice that the attribute visible is set to false.  What this parameter does is define the template that our widget is going to use for presentation.  My value is widgetglider/banner.phtml this template doesn’t exist by default so let’s create it.

/app/design/frontend/default/spinonesolutions/template/widgetglider/banner.phtml

<style>
.slideshow {
  position:relative;
}

.slideshow .items div {
  float:left;
  opacity:0.0;
  position:absolute;
  z-index:8;
}

.slideshow .items div.active {
  opacity:1.0;
  z-index:10;
}
</style>

<script>
function slideSwitch() {
  var active = jQuery('.slideshow .items .active');
  // use this to pull the images in the order they appear in the markup
  var next =  jQuery(active).next().length ? jQuery(active).next() : jQuery('.slideshow .items div:first');
  jQuery(next).css({opacity: 0.0})
  .addClass('active')
  .animate({opacity: 1.0}, 1000, function() {
    jQuery(active).removeClass('active');
  });

  jQuery(active).animate({opacity:0.0}, 1000, function(){
  });
}

// execute your scripts when the DOM is ready. this is mostly a good habit
jQuery('document').ready(function() {
  var active = jQuery('.slideshow .items .active');
  if ( active.length == 0 ) {
    active = jQuery('.slideshow .items div:first');
    active.addClass('active').animate({opacity: 1.0}, 1000);
  }

  jQuery(function() {
    setInterval( "slideSwitch()", 5000 );
  });
});
</script>
<div class="slideshow">
  <div class="items">
    <?php foreach($this->sectionArr as $key => $section) { ?>
    <div class="">
      <?php echo $section; ?>
    </div>
    <?php } ?>
  </div>
</div>

The first part of that path is determined by the theme that you’ve set in Configuration.

Inspecting this file the real takeaway is simply the foreach loop.  All it does it loop over the array that was defined in the Business Layer and output the HTML stored in each element.  The template file does all the presentation.

The reason for doing things this way is that one can easily envision some department manager coming to you and asking for another, different, presentation of the same data for some other location of your website.  Since you’ve done a good job of separating your layers all you have to do is make a new .phtml file, and then change the template parameter of your widget.xml file and viola, you’ve got a new presentation of your data.

That does it for the code, all we need to do now is build a little demo using the interface.

Load up the admin and navigate to CMS -> Static Blocks.  Create four static blocks and put an image file into each one.  If you hover your mouse over the row you’ll see the block_id.  Make note of these as you’ll need them for when you create the widget.  Mine are: 6,8,9,10.

static-blocks

Go to CMS -> Pages and create a new CMS page to hold the widget.  Alternatively you could add the widget to a preexisting page.  Switch to the Content Tab.  Click the add Widget icon to add your widget.

add-widget-button

Choose your new widget from the dropdown menu.

insert-widget-choose

Fill in the block_id(s) of your static blocks.

insert-widget-filledin

Hit Insert.

As a learning exercise click the “Show/HideEditor” button.

widget-markup

Notice what was generated!  It should be pretty similar to what’s in your widget.xml file.  As the smart and curious type the you are also realize that you can change these parameters right here.  Thus the widget.xml file serves a template for your widget, which can be customized later to suit your specific needs.

Ok, save your CMS page.  That’s it!

glider-demo

You can see my demo here.

As always, questions and comments welcomed!

Be Sociable, Share!

· ·

25 comments

  • Magento Custom Widget – SpinOneSolutions | e-commerce News · October 28, 2010 at 5:54 pm

    [...] Magento Custom Widget – SpinOneSolutions [...]

    Reply

  • valeria · March 8, 2011 at 4:26 pm

    hi
    i did everything you said but slideshowdoesn’t work … i think i miss something in this bit which i dont understand … “Since you’ve done a good job of separating your layers all you have to do is make a new .phtml file, and then change the template parameter of your widget.xml file and viola, you’ve got a new presentation of your data.”
    do i have to create another phtml file? please help .. thanks valeria

    Reply

    • Admin comment by Will Wright · March 9, 2011 at 6:39 am

      What I mean is the following:

      I the example I create a template file to display the data. The one I originally used was “widgetglider/banner.phtml”. This would go in your Theme folder. However since we’re making a Widget I could make multiple templates to display the data. Maybe one that uses Divs, one that uses Tables, and one that uses Uls.

      I simply change the value in the XML and that will change the template that the Widget uses. You could even make the “template” variable a dropdownlist and let the user choose what template to use.

      Hope that helps.

      Reply

  • Dave Kaye · March 9, 2011 at 3:27 pm

    Great tutorial!

    Is the path right for:

    /app/etc/modules/widget.xml

    Should it be /app/code/local/Spinonesolutons/WidgetGlider/etc/widget.xml ?

    Then in:
    /app/code/local/Spinonesolutions/WidgetGlider/Blcok/Glider.php

    Should “Blcok” be “Block?”

    Just checkin’

    Dave.

    Reply

    • Admin comment by Will Wright · March 10, 2011 at 8:08 am

      Yes and Yes!

      Thanks!

      Reply

  • Mark · March 22, 2011 at 3:50 am

    Hi,

    Nice post. I have followed all the steps above. Admin part works fine but in frontend nothing is shown.

    Even the with ids “section1″ & so on are not generated as they are on your demo url. I think something is going wrong or I am missing something can you help me?

    Thanks in advance. :)

    Reply

  • Frank · April 11, 2011 at 11:00 am

    same problem here, shows up on back-end not front-end. Great straight forward tutorial btw.

    Reply

  • Dave Kaye · April 14, 2011 at 5:42 pm

    Another question. You write about config.xml:

    “If you go back and inspect the config.xml and remember your Magento naming conventions you can surmise that this is going to cause Magento to try and instantiate an object of type Spinonesolutions_WidgetGlider_Block_Glider.”

    Maybe there’s something I don’t get about naming conventions, but should the line in config.xml that you have listed as:

    Spinonesolutions_WidgetGlider_Block

    Actually be:

    Spinonesolutions_WidgetGlider_Block_Glider

    ? I agree with the above comments, great tutorial! But I’m also having trouble getting it working on the front end. Any other sources to look at?

    Reply

  • Dave Kaye · April 18, 2011 at 10:20 am

    Forget that last comment. Here’s my new comment.

    Two issues with banner.phtml

    1) Magento (1.4) goes looking for banner.phtml in:
    /app/design/frontend/base/default/template/widgetglider/banner.phtml

    2) The PHP generated HTML on your demo page is different from what comes out in the app in your tutorial.

    On your sample page the div and image tag read:

    But following the tutorial that same tag reads:

    So somehow that ID tag is not generated.

    Reply

    • Admin comment by Will Wright · April 18, 2011 at 11:01 am

      Thanks for the detailed comments, I’m looking at it and I’ll try and post a fix if I find the issue.

      Reply

  • Dave Kaye · April 18, 2011 at 1:05 pm

    I got this to work on the front end by adding the following to banner.phtml:

    [code]

    sectionArr as $key => $section) {
    $i = 1;
    ?>
    <div class="" id=">

    [/code]

    Reply

  • Joe Wag · June 2, 2011 at 8:31 am

    A question. We’ve got this working but the first image load is very slow. It looks like you have a “placeholder” image in the first frame of your demo? How did you get this to work?

    Reply

  • krite · November 9, 2011 at 12:49 am

    How to add jqFancyTransitions.1.8.min.js and jQuery.js into widget for slide picture
    from create picture in static block [img]http://i1219.photobucket.com/albums/dd427/Tidy005/pb05.gif[/img]
    and if i want add jqFancyTransitions.1.8.min.js and jQuery.js for use with the Fisher Price picture with a widget to do. please help me thank you very much.

    Reply

  • krite · November 9, 2011 at 12:52 am

    and i create picture Fiser Price and Other in Static block
    Note : this code in static block

    please help me thank you very much.

    Reply

  • krite · November 11, 2011 at 8:50 am

    1) i download code in http://nivo.dev7studios.com/ and put jquery.nivo.slider.js in magento\skin\frontend\default\mytheme\css Yes or No
    2 ) in edit code in banner.phtml How to edit code banner.phtml if i want show size picture 655 *372 px
    please help me again thank you for help me.

    Reply

  • krite · November 15, 2011 at 10:50 pm

    thank you for reply but
    if i want edit in banner.phtml
    in this code

    helper(‘core/js’)->includeSkinScript(‘js/jquery.nivo.slider.js’); ?>

    I would put this code section of the file banner.phtml.

    Note : i add jQurey in skin\frontend\default\Toys\js\jquery.nivo.slider.js

    Reply

  • krite · November 17, 2011 at 11:33 pm

    location banner.phtml : app\design\frontend\default\Toys\template\widgetglider\banner.phtml

    I have attached banner.phtml file and pictures. and send to your please help me again because my site is not complete

    Reply

  • krite · November 20, 2011 at 11:45 pm

    location banner.phtml : app\design\frontend\default\Toys\template\widgetglider\banner.phtml
    and location image : skin\frontend\default\EducationToys\images\media
    and location jQurey : js\prototype\jquery.nivo.slider.js
    js\prototype\jquery-1.6.1.min.js
    if i want add in banner.phtml <script src='’>

    where is add in line in banner.phtml? help me again thank you very much.

    I have attached banner.phtml file

    Reply

  • krite · November 20, 2011 at 11:58 pm

    is my current code banner.phtml
    [code]
    ?>

    .slideshow {
    position:relative;
    }

    .slideshow .items div {
    float:left;
    opacity:0.0;
    position:absolute;
    z-index:8;
    }

    .slideshow .items div.active {
    opacity:1.0;
    z-index:10;
    }

    function slideSwitch() {
    var active = jQuery('.slideshow .items .active');
    // use this to pull the images in the order they appear in the markup

    var next = jQuery(active).next().length ? jQuery(active).next() : jQuery('.slideshow .items div:first');
    jQuery(next).css({opacity: 0.0})
    .addClass('active')
    .animate({opacity: 1.0}, 1000, function() {
    jQuery(active).removeClass('active');
    });

    jQuery(active).animate({opacity:0.0}, 1000, function(){
    });
    }

    // execute your scripts when the DOM is ready. this is mostly a good habit
    <script src=''>

    sectionArr as $key => $section) { ?>

    [/code]
    it i change code yes or No please tech me thank you.

    Reply

  • krite · November 23, 2011 at 8:04 am

    It not work ?

    location jQurey : C:\xampp\htdocs\magento\js\jquery.nivo.slider.js
    code in my banner.phtml

    ?>

    .slideshow {
    position:relative;
    }

    .slideshow .items div {
    float:left;
    opacity:0.0;
    position:absolute;
    z-index:8;
    }

    .slideshow .items div.active {
    opacity:1.0;
    z-index:10;
    }

    <script src='’>

    sectionArr as $key => $section) { ?>

    please tech me. please.

    Reply

  • new businesses · May 2, 2013 at 10:35 am

    Hi my family member! I wish to say that this post is amazing,
    great written and include almost all significant infos.
    I would like to see more posts like this .

    Reply

  • günstige türkei · May 12, 2013 at 4:57 pm

    I in no way post, but now I will, Thanks a whole lot
    for the final weblog.

    Reply

  • DJ Naples FL · March 7, 2014 at 7:33 pm

    When someone writes an piece of writing he/she maintains the
    image of a user in his/her mind that how a
    user can know it. So that’s why this article is outstdanding.
    Thanks!

    Reply

  • child photographer dallas tx · March 15, 2014 at 8:55 pm

    Oh my goodness! Awesome article dude! Many thanks, However I am encountering problems with your RSS.

    I don’t understand why I can’t subscribe to it.
    Is there anyone else having identical RSS problems?
    Anyone that knows the solution can you kindly respond?

    Thanx!!

    Reply

  • Lawn Sprinklers NJ · June 6, 2014 at 10:43 pm

    Hmm is anyone else encountering problems with the images on this blog
    loading? I’m trying to determine if its a problem on my
    end or if it’s the blog. Any suggestions would be greatly
    appreciated.

    Reply

Leave a Reply

<<

>>

Theme Design by devolux.nh2.me