15

Separating data from execution in osCommerce boxes

multimixer | learn | Monday January 3 2011

I was in the need to be able to access the data of each box in osCommerce without having the box being “executed”, that means in this case, added to the left or right column. Why this, you may want to ask. There are several reasons for, lets say I want to add the contents of the box into an other group and to have it displayed in the footer, header or in the middle of the page, whatever.

Let’s take things from the beginning on a concrete example and let’s understand first how things work by default before doing any changes. Thats always a good idea.

Let’s take a simple box, the one that displays the links to “contact us”, “shipping and returns”, “conditions of use” etc. This box, the “information” box is getting created in file catalog/includes/modules/boxes/bm_information.php

Opening the file, we see that it is a class with various functions in it. We are interested in function “execute()” that looks like this

    function execute() {
      global $oscTemplate;

      $data = '<div class="ui-widget infoBoxContainer">' .
              '  <div class="ui-widget-header infoBoxHeading">' . MODULE_BOXES_INFORMATION_BOX_TITLE . '</div>' .
              '  <div class="ui-widget-content infoBoxContents">' .
              '    <a href="' . tep_href_link(FILENAME_SHIPPING) . '">' . MODULE_BOXES_INFORMATION_BOX_SHIPPING . '</a><br />' .
              '    <a href="' . tep_href_link(FILENAME_PRIVACY) . '">' . MODULE_BOXES_INFORMATION_BOX_PRIVACY . '</a><br />' .
              '    <a href="' . tep_href_link(FILENAME_CONDITIONS) . '">' . MODULE_BOXES_INFORMATION_BOX_CONDITIONS . '</a><br />' .
              '    <a href="' . tep_href_link(FILENAME_CONTACT_US) . '">' . MODULE_BOXES_INFORMATION_BOX_CONTACT . '</a>' .
              '  </div>' .
              '</div>';

      $oscTemplate->addBlock($data, $this->group);
    }

Two things are going on here. The first is that $data is getting defined, so we say that $data is this and this and this, in this example $data is a collection of links to various pages

Second thing that happens is to add this data to a group. What group? The one that got defined just before in function “bm_information()” :

        $this->group = ((MODULE_BOXES_INFORMATION_CONTENT_PLACEMENT == 'Left Column') ? 'boxes_column_left' : 'boxes_column_right');

This here says that the group is either the left or the right column, depending on what the value in the configuration table of our database is. Thats in other words the setting we have when configuring the boxes in the admin area, setting the option to “left column” or “right column”

Back to the execution function, and the part where the $data is getting added to a group

      $oscTemplate->addBlock($data, $this->group);

We see that a function of class $oscTemplate is getting used, thats in the file catalog/includes/classes/osc_template.php, and the function looks like this

    function addBlock($block, $group) {
      $this->_blocks[$group][] = $block;
    }

It’s simply adding our $data (of the box file) to the array of blocks, the group, again defined in the box file.

To complete the picture, we should also know that the whole “execution system” is getting activated via the function buildBlocks() (file catalog/ includes/classes/osc_template.php starting at line 70) and this function again is called in file catalog/includes/template_top.php, just at the beginning, at line 13

Now, that we know how the system works, we can go back to the original question, that is: To separate the “data” (in our example the creation of the list of links) from the “execution” (in our example to add this list of links to the left or right column)

I hope that now, the reasons why to do this are more clear than before: I want simply to have the option to access the plain (well, ok, including it’s html) data of each box, so that I can do with it whatever I want, without having to access each time the box file.

There is for example a addon available (Box content placement), that is adding 3 more optional positions for the boxes, and for this it is altering each box file. Thats all fine, but what if you want to add one more position? And what if you want to have some boxes to appear under some conditions only? For example jut on some pages? Or to have the boxes appearing on all pages but the front page? And so on and so forth.

Thats why I ended up with the approach I’m presenting here, to separate data from execution. In our box example (file includes/modules/boxes/bm_information.php), all I do is to split the function execute into 2 separate functions, so it looks like this

    function dataF() {

      $data = '<div class="ui-widget infoBoxContainer">' .
              '  <div class="ui-widget-header infoBoxHeading">' . MODULE_BOXES_INFORMATION_BOX_TITLE . '</div>' .
              '  <div class="ui-widget-content infoBoxContents">' .
              '    <a href="' . tep_href_link(FILENAME_SHIPPING) . '">' . MODULE_BOXES_INFORMATION_BOX_SHIPPING . '</a><br />' .
              '    <a href="' . tep_href_link(FILENAME_PRIVACY) . '">' . MODULE_BOXES_INFORMATION_BOX_PRIVACY . '</a><br />' .
              '    <a href="' . tep_href_link(FILENAME_CONDITIONS) . '">' . MODULE_BOXES_INFORMATION_BOX_CONDITIONS . '</a><br />' .
              '    <a href="' . tep_href_link(FILENAME_CONTACT_US) . '">' . MODULE_BOXES_INFORMATION_BOX_CONTACT . '</a>' .
              '  </div>' .
              '</div>';

	  return $data;
    }

    function execute() {
      global $oscTemplate;

      $oscTemplate->addBlock($this->dataF(), $this->group);
    }

You see that I created a new function, called “dataF()” (could be “kuku()”) where the “data creation process” happens and then I use the output of this function for the function execute(), that is now just executing any data that was “created” before. Same of course I need to do for all boxes

After done once, things are getting really easy. Each time I need a box (out of the regular left/right schema), all I need to do is to “activate” the class of the box I need and to output the contents of dataF() anywhere I want. Or, I can create a new group of boxes, called eg “boxes_footer, add to it any boxes I like, and then display the whole thing in the footer, or wherever I want. Or I can move all boxes together to the left or to the right. In general: I have the total control over the boxes display, without doing anything to the boxes files themselves

This approach is used in mini template system, for example when moving all boxes to the left or to the right, or when making the “information” or “search” box to disappear when a certain template is activated

Update on 5/5/2010: Because some of you asked how to output the content of dataF(), here is the way to do it.

Let’s say you want to display the contents of box “shopping cart” at the bottom of file shipping.php. That’s not very realistic, it’s just an example to demonstrate that you can display anything anywhere

What you need to do in this case? first thing is to “activate” the class in this way

$boxdata = new bm_shopping_cart;

Next step is to echo the variable $boxdata wherever you want, not that the variable could be called anything, eg $kuku

echo $boxdata->dataF();

Now, there is the “danger” to get an error on the page in case the shopping cart box is not present, that means installed. To avoid this, we need to check if the class exists and to activate it only if this is the case, like this

if (class_exists(bm_shopping_cart)) {
$boxdata = new bm_shopping_cart;
echo $boxdata->dataF();
}

The result on shipping.php looks like this

Shopping cart box at the bottom of privacy.php

In the same way you can output any box at any place of your store, for example the cart in the header, or the information box in the footer, or whatever

You will want of course to wrap everything into proper html and/or to use some css to style everything. Enjoy

Click +1 to recommend this to your friends when they search.

multimixer

follow multimixer on Twitter

Follow me on twitter. I'm not tweeting all day long and guaranteed no spam and no advertising.

If you like what you read and if you think it will help you in your online business, then please consider a donation.

There is no obligation to do so and all information provided here is free to use.

It will however help to keep this blog alive, free of advertising and full of content.

  • couba 05/04/2011 at 11:40

    Very helpful, but how do I “activate” the class of the box I need and output the contents of dataF() anywhere I want?

  • Dirk Tromp 04/05/2011 at 15:55

    Just like @couba, I woudl also like to know how to “activate” the class of the box. I have tried a number of different things but have had no luck to output the content of dataF().

  • multimixer 05/05/2011 at 15:27

    Hi people. Please find my updated post above, there is a simple example on how to output dataF() on your page

  • Steve 02/01/2012 at 19:03

    Great article. One question does this work with all the boxes, I tried it with manufacturer_info, it doesn’t thow up any errors but the info doesn’t show?

    here’s the code.

    function dataA() {

    if (isset($HTTP_GET_VARS['products_id'])) {
    $manufacturer_query = tep_db_query(“select m.manufacturers_id, m.manufacturers_name, m.manufacturers_image, mi.manufacturers_url from ” . TABLE_MANUFACTURERS . ” m left join ” . TABLE_MANUFACTURERS_INFO . ” mi on (m.manufacturers_id = mi.manufacturers_id and mi.languages_id = ‘” . (int)$languages_id . “‘), ” . TABLE_PRODUCTS . ” p where p.products_id = ‘” . (int)$HTTP_GET_VARS['products_id'] . “‘ and p.manufacturers_id = m.manufacturers_id”);
    if (tep_db_num_rows($manufacturer_query)) {
    $manufacturer = tep_db_fetch_array($manufacturer_query);

    $manufacturer_info_string = ”;
    if (tep_not_null($manufacturer['manufacturers_image'])) $manufacturer_info_string .= ” . tep_image(DIR_WS_IMAGES . $manufacturer['manufacturers_image'], $manufacturer['manufacturers_name']) . ”;
    if (tep_not_null($manufacturer['manufacturers_url'])) $manufacturer_info_string .= ‘- ‘ . sprintf(MODULE_BOXES_MANUFACTURER_INFO_BOX_HOMEPAGE, $manufacturer['manufacturers_name']) . ‘‘;
    $manufacturer_info_string .= ‘- ‘ . MODULE_BOXES_MANUFACTURER_INFO_BOX_OTHER_PRODUCTS . ‘‘ .
    ”;

    $data = ” .
    ‘ ‘ . MODULE_BOXES_MANUFACTURER_INFO_BOX_TITLE . ” .
    ‘ ‘ . $manufacturer_info_string .
    ”;

    return $data;
    }
    }
    }

    function execute() {
    global $HTTP_GET_VARS, $languages_id, $oscTemplate;

    $oscTemplate->addBlock($this->dataA(), $this->group);
    }

    ***** added this to the page *********

    dataA();
    }
    ?>

  • multimixer 03/01/2012 at 15:23

    Hi Steve

    From a first sight I think that you need to do following to get it working

    1) Add all “globals” that you have now in function execute() to function dataA(), except $oscTemplate that should stay in function execute()

    2) Add to the page the complete piece of code like it is done for the shopping cart example. Simply “dataA()” says nothing

    3) make sure you have the manufacturer info box installed in admin. It has not to be enabled, but it need to be active

    Hope it helps

    • Steve 04/01/2012 at 13:27

      Yep it was point 1 that solved it, I had the code correct in the data A call, it just didnt show when I posted it.

      thanks alot

  • Rick 03/07/2012 at 23:38

    This all makes great sense and thank you for posting this tutorial.

    However I am confused where to split the function in the bm_categories.php file so that I can call it where I would like to?

    Thanks for any help in advance.

    • multimixer 04/07/2012 at 08:19

      There is no difference for box bm_categories.php, its the same process like for any other boxes: You slit the function execute() into 2 functions, the one is dataF() that return the output, the other execute() that add the box to a “group”

      Concrete, in bm_categories.php you have

      function execute() {
      global $SID, $oscTemplate;

      if ((USE_CACHE == ‘true’) && empty($SID)) {
      $output = tep_cache_categories_box();
      } else {
      $output = $this->getData();
      }

      $oscTemplate->addBlock($output, $this->group);
      }

      This you can replace with following

      function dataF() {
      global $SID;

      if ((USE_CACHE == ‘true’) && empty($SID)) {
      $output = tep_cache_categories_box();
      } else {
      $output = $this->getData();
      }

      return $output;
      }

      function execute() {
      global $oscTemplate;

      $oscTemplate->addBlock($this->dataF(), $this->group);
      }

  • Ludwig Arcache 04/08/2012 at 12:21

    Hello, well thank you for this posting this article.
    i understood very well how to split the execute function. but i want to know:

    -should i leave the rest of the code ? (function isEnabled(), function check(), ect…)

    -after editing the file (bm_manufacturer_info), should i upload and replace the existing file?

  • Ludwig Arcache 04/08/2012 at 13:13

    never mind, its done… thank you for the information, sir!!

  • Zeeshan 20/06/2013 at 10:06

    Very Useful topic.
    Thanks for writing this.

  • Alexandra 18/03/2014 at 00:00

    Hi George,
    I followed your instructions and was able to separate data from the bm_information box and output the data into another file.
    I am trying to separate data now for bm_currencies. I get a Fatal error: Call to undefined method bm_currencies::execute()

    This is what I have done. Any idea as to what I have done wrong? Thank you in advance.

    function dataF() {
    global $PHP_SELF, $currencies, $HTTP_GET_VARS, $request_type, $currency;

    if (substr(basename($PHP_SELF), 0, 8) != ‘checkout’) {
    if (isset($currencies) && is_object($currencies) && (count($currencies->currencies) > 1)) {
    reset($currencies->currencies);
    $currencies_array = array();
    while (list($key, $value) = each($currencies->currencies)) {
    $currencies_array[] = array(‘id’ => $key, ‘text’ => $value['title']);
    }

    $hidden_get_variables = ”;
    reset($HTTP_GET_VARS);
    while (list($key, $value) = each($HTTP_GET_VARS)) {
    if ( is_string($value) && ($key != ‘currency’) && ($key != tep_session_name()) && ($key != ‘x’) && ($key != ‘y’) ) {
    $hidden_get_variables .= tep_draw_hidden_field($key, $value);
    }
    }

    $data = ” .
    ‘ ‘ . MODULE_BOXES_CURRENCIES_BOX_TITLE . ” .
    ‘ ‘ .
    ‘ ‘ . tep_draw_form(‘currencies’, tep_href_link(basename($PHP_SELF), ”, $request_type, false), ‘get’) .
    ‘ ‘ . tep_draw_pull_down_menu(‘currency’, $currencies_array, $currency, ‘onchange=”this.form.submit();” style=”width: 100%”‘) . $hidden_get_variables . tep_hide_session_id() . ” .
    ‘ ‘ .
    ”;

    return $data;
    }
    function execute() {
    global $oscTemplate;
    $oscTemplate->addBlock($this->dataF(), $this->group);
    }
    }
    }

    • Alexandra 18/03/2014 at 00:39

      Ok, I figured it out. :)
      This part should be below the curly braces
      return $data;
      }
      }
      }
      function execute() {
      global $oscTemplate;

Leave a Reply