Jump to content

Show the weight according to the options


Recommended Posts

Just wanted to see if there is a way to show an updated weight when different product options are selected that have weights entered. I would be fine adding some code to pull it from the CC_option_assign table. Just don't know where to start.

 

Edited by MarkBlank
Link to post
Share on other sites

We will be editing four files:
the skin template content.product.php
the skin template element.product.options.php (unless the target code is found elsewhere)
the skin file 2.cubecart.js (if dynamic price updates can be done)
the code file /classes/catalogue.class.php

Normally, when an item is added to the cart, the cart contents accumulates the base weight and adds in the weights of all selected options. But that is then, and we need the data when viewing the product, before it gets added to the cart.

We need to provide one more piece of data to the skin template that shows the product's details -- the weight stated for each option assigned to the product. That happens in the catalogue class, public function displayProductOptions(). Using a programmer's text editor, open that file and find the function. We need to add the new data in two places: in the selectable options (radio, drop-down) and in the textual options.

Find:
                    case self::OPTION_SELECT:  ## Dropdown options
                    case self::OPTION_RADIO:  ## Radio options

In this area, about 20 lines later, find:
                                $option_list[$value['option_id']]['values'][] = array(

On a new blank line after that, add:
                                    'option_weight' => $value['option_weight'],

Then find:
                    case self::OPTION_TEXTBOX:  ## Textbox options
                    case self::OPTION_TEXTAREA:  ## Textarea option

In this area, about 8 lines later, find:
                            $option_list[$option[0]['option_id']] = array(

On a new blank line after that, add:
                                'option_weight' => $option[0]['option_weight'],

Save this file.

The skin already has the item's base weight. It is contained in the Smarty variable {$PRODUCT.product_weight}. But there are no identifying attributes in the containing HTML tags for any kind of dynamic updating under javascript control.

Find all the locations in the skin files where you have the item's weight shown. In Foundation, that will be in a table near line 74. We will put the weight value inside <span> tags with a couple of attributes. The <span> tag does not change the layout or appearance of what it encloses.

Change:
                     <td>{$PRODUCT.product_weight}{$CONFIG.product_weight_unit|lower}</td>

To:
                     <td><span id="otw" data-weight="{$PRODUCT.product_weight}">{$PRODUCT.product_weight}</span>{$CONFIG.product_weight_unit|lower}</td>

Save this file.

Now that we have provided new data to the skin, we need to use it. Foundation has the skin template element.product.options.php, which is included by a parent template. In this template, there are six locations to change: radio (only one required choice or several choices), drop-down (only one required choice or several choices), text input, and textarea.

Find:
<input type="hidden" name="productOptions[{$option.option_id}]" id="option_{$option.option_id}" value="{$option.values.0.assign_id}"{if !$CTRL_HIDE_PRICES} data-price="{$option.values.0.decimal_price}"{/if}>

Change to:
<input type="hidden" name="productOptions[{$option.option_id}]" id="option_{$option.option_id}" value="{$option.values.0.assign_id}"{if !$CTRL_HIDE_PRICES} data-price="{$option.values.0.decimal_price}"{/if} data-weight="{$option.values.0.option_weight}">

Find:
<div><input type="radio" name="productOptions[{$option.option_id}]" id="rad_option_{$value.assign_id}" value="{$value.assign_id}" class="nomarg{if $value.absolute_price == '1'} absolute{/if}"{if empty($_POST) && !empty($value.option_default)} checked="checked"{/if}{if !$CTRL_HIDE_PRICES} data-price="{$value.decimal_price}"{/if}{if $smarty.foreach.options.first} rel="error_option_{$option.option_id}" {if $option.required}required{/if}{/if}>

Change to:
<div><input type="radio" name="productOptions[{$option.option_id}]" id="rad_option_{$value.assign_id}" value="{$value.assign_id}" class="nomarg{if $value.absolute_price == '1'} absolute{/if}"{if empty($_POST) && !empty($value.option_default)} checked="checked"{/if}{if !$CTRL_HIDE_PRICES} data-price="{$value.decimal_price}"{/if} data-weight="{$value.option_weight}"{if $smarty.foreach.options.first} rel="error_option_{$option.option_id}" {if $option.required}required{/if}{/if}>

Find:
<input type="hidden" name="productOptions[{$option.option_id}]" id="option_{$option.option_id}" value="{$option.values.0.assign_id}"{if !$CTRL_HIDE_PRICES} data-price="{$option.values.0.decimal_price}"{/if}>

Change to:
<input type="hidden" name="productOptions[{$option.option_id}]" id="option_{$option.option_id}" value="{$option.values.0.assign_id}"{if !$CTRL_HIDE_PRICES} data-price="{$option.values.0.decimal_price}"{/if} data-weight="{$option.values.0.option_weight}">

Find:
<option value="{$value.assign_id}"{if $value.absolute_price == '1'}class="absolute"{/if}{if empty($_POST) && !empty($value.option_default)} selected="selected"{/if}{if !$CTRL_HIDE_PRICES} data-price="{$value.decimal_price}"{/if}>{$value.value_name}{if $value.price} {$value.symbol}{$value.price}{/if}</option>

Change to:
<option value="{$value.assign_id}"{if $value.absolute_price == '1'}class="absolute"{/if}{if empty($_POST) && !empty($value.option_default)} selected="selected"{/if}{if !$CTRL_HIDE_PRICES} data-price="{$value.decimal_price}"{/if} data-weight="{$value.option_weight}">{$value.value_name}{if $value.price} {$value.symbol}{$value.price}{/if}</option>

Find:
<input type="text" name="productOptions[{$option.option_id}][{$option.assign_id}]" id="option_{$option.option_id}"{if $option.absolute_price == '1'} class="absolute"{/if}{if !$CTRL_HIDE_PRICES} data-price="{$option.decimal_price}"{/if} {if $option.required}required{/if}>

Change to:
<input type="text" name="productOptions[{$option.option_id}][{$option.assign_id}]" id="option_{$option.option_id}"{if $option.absolute_price == '1'} class="absolute"{/if}{if !$CTRL_HIDE_PRICES} data-price="{$option.decimal_price}"{/if} data-weight="{$option.option_weight}" {if $option.required}required{/if}>

Find:
<textarea name="productOptions[{$option.option_id}][{$option.assign_id}]" id="option_{$option.option_id}"{if $option.absolute_price == '1'} class="absolute"{/if}{if !$CTRL_HIDE_PRICES} data-price="{$option.decimal_price}"{/if} {if $option.required}required{/if}></textarea>

Change to:
<textarea name="productOptions[{$option.option_id}][{$option.assign_id}]" id="option_{$option.option_id}"{if $option.absolute_price == '1'} class="absolute"{/if}{if !$CTRL_HIDE_PRICES} data-price="{$option.decimal_price}"{/if} data-weight="{$option.option_weight}" {if $option.required}required{/if}></textarea>

Save this file.

We now have the data available to the template, and are showing it. Currently, there is javascript code that will dynamically update the item's price by summing the base price and the price offsets of all the selected options. Foundation does that in the file 2.cubecart.js.

There now needs to be some javascript to dynamically sum the base weight and the weights of all the selected options. We will piggy-back on that pricing function to calculate the total weight.

Find near line 428:
function price_inc_options() {

On a new blank line after that, add:
var weight_total = 0;

Then find:
            total += parseFloat($(this).attr("data-price"));

On a new blank line after that, add:
            weight_total += parseFloat($(this).attr("data-weight"));

Then find:
                total += parseFloat($(this).find("option:selected").attr("data-price"));

On a new blank line after that, add:
                weight_total += parseFloat($(this).find("option:selected").attr("data-weight"));

Then find:
                total += parseFloat($(this).attr("data-price"));

On a new blank line after that, add:
                weight_total += parseFloat($(this).attr("data-weight"));

Then find:
    ptp = ptp + total;

On a new blank line after that, add:
    $("#otw").text( function () { return parseFloat($("#otw").attr("data-weight")) + weight_total; });

(The ajax stuff you see in the function is just getting a properly formatted string,
 including currency symbol, for the dynamic price.)

Save this file.

Note: when changing a page resource (in this case, the 2.cubecart.js file),
one needs to force their browser to reload those resources. Otherwise, the
browser will use the code it has cached for itself. Forcing a reload is
usually done with CTRL-F5.

If you have any questions, please ask.

Edited by bsmither
Link to post
Share on other sites
Posted (edited)

Wow! bsmither! Thank you for the info. You have answered my question and then some. I agree with havenswift-hosting, maybe it should be in the core.

I just wanted to know where to start and figure out what file or code I was overlooking. You took it to "Infinite and beyond". Does the b in bsmither stand for Buzz? 

To be honest with you, I am working on a site that is just a catalog-type site and have been asked to show the stock of different sizes of products. The shipping part doesn't matter in this case, but I will definitely save this info for the future. Since the question has been asked on the forums several times about using the option matrix and stock levels, with no "fix", just a min-max range, I decided that I would use the weight option and pull it in since it is nothing more than a number. I can label it however I want on the site. I have written a piece of software to access/change the database because the owner didn't want to try thru the, in his opinion, "overwhelming" admin to keep the stock levels live for his customers. He is not a computer literate person. I was actually working on writing a little PHP script to select from the databases to select/change the info. I don't need to do that now. And, I understand that if I upgrade, I will have to redo some stuff, but figure it will be good for a few years.

Just a suggestion as I was thinking about adding another column to the table - the whole  option matrix table could be included in the options table(s) with an incremental number/id to change the product code (where it adds an incremental ending number to the original product code depending on the option). It seems like that is the only difference in that table along with the stock level. That may make it easier to do more with it without as much work. I may be wrong there, and I assume it would be difficult to upgrade that way, but just wanted to say it. You have WAY more knowledge about all of the other places that would be affected.

I have been using CC for a few years now on several sites and have not been able to find ANYTHING out there that compares to or has the support that you all provide. You completely and perfectly answered a question 2-3 years ago for me also. If I ever get out to the West Coast, I am going to look you up and take you out for dinner or a drink or something. You are a person of integrity, unsung hero and care about the users of CC.

Kudos to you and THANKS!

Edited by MarkBlank
Link to post
Share on other sites

Hi again bsmither,

I followed all of your directions to a T. However, if I use $PRODUCT.product_weight, it is not changed from the options. It is showing the weight entered in the General tab in Admin.

If I try to use $value.option_weight, it is null.

Any thoughts?

Link to post
Share on other sites

Bsmither, I found the problem. I also had to ad:  'option_weight' => $value['option_weight'], to the array a few lines lower in the catalog.class.php file. 

It works like I need it too now. The only other question I have is where does the option weight get formatted to 4 decimal places? I would like to remove them.

Thanks

Link to post
Share on other sites

I would like more info as to what additional edits you found necessary to make.

I should mention, and I will make an edit above, that when changing the code to a page resource (in this case, the 2.cubecart.js file), one needs to force their browser to reload those resources. Otherwise, the browser will use the code it has cached for itself. Forcing a reload is usually done with CTRL-F5.

The base format on expressing the weight is in the database table CubeCart_option_assign, 'option_weight' column, declared as DECIMAL 10,4.

Because CubeCart (currently) only allows options to add weight, it seems unnecessary to format the value tighter than that.

Edited by bsmither
Link to post
Share on other sites

In the catalogue.class.php file, you said:

 

Find:
                    case self::OPTION_SELECT:  ## Dropdown options
                    case self::OPTION_RADIO:  ## Radio options

In this area, about 20 lines later, find:
                                $option_list[$value['option_id']]['values'][] = array(

On a new blank line after that, add:
                                    'option_weight' => $value['option_weight'],
"

In that same section, I had to add it also about another 20 lines below so that it was in the array- shown in bold, red below:

$option_list[$value['option_id']]['values'][] = array(
                                    'assign_id'  => $value['assign_id'],
                                    'decimal_price'   => (string)$decimal_price_sign.$value['option_price'],
                                    'price'   => (isset($value['option_price']) && $value['option_price']!=0) ? Tax::getInstance()->priceFormat($value['option_price'], true) : false,
                                    'symbol'  => ($value['absolute_price']=='1' && $symbol=='+') ? '' : $symbol,
                                    'value_id'  => $value['value_id'],
                                    'value_name' => $value['value_name'],
                                    'option_weight' => number_format($value['option_weight']),
                                    'option_default' => (bool)$value['option_default'],
                                    'selected' => isset($selected[$value['assign_id']]) ? true : false,
                                    'absolute_price' => $value['absolute_price']
                                );

I just went ahead and formatted it there, but thanks for letting me know where it is formatted. Also, I am aware of clearing the cache and data.

Thanks again for all your help!

Link to post
Share on other sites

That's what I'm saying. I had to place it in 2 places in that section. Below is my code now with the 2 places in red bold. It is from about line 506 to 541 in catalogue.class.php.

foreach ($optionArray as $type => $group) {
                    switch ($type) {
                    case self::OPTION_SELECT:  ## Dropdown options
                    case self::OPTION_RADIO:  ## Radio options
                        foreach ($group as $key => $option) {
                            $group_priority = $option['priority'];
                            unset($option['priority']);
                            foreach ($option as $value) {
                                if (!isset($option_list[$value['option_id']])) {
                                    $option_list[$value['option_id']] = array(
                                        'option_weight' => $value['option_weight'],
                                        'type'   => $value['option_type'],
                                        'option_id'  => $value['option_id'],
                                        'option_name' => $value['option_name'],
                                        'option_description' => $value['option_description'],
                                        'option_default' => (bool)$value['option_default'],
                                        'required'  => (bool)$value['option_required'],
                                        'selected' => isset($selected[$value['assign_id']]) ? true : false
                                    );
                                }
                    
                                $decimal_price_sign = $value['option_negative'] ? '-' : '';
                                $symbol = (isset($value['option_price']) && $value['option_price']!=0 && $value['option_negative'] == 0) ? '+' : '-';

                                $option_list[$value['option_id']]['values'][] = array(
                                    'assign_id'  => $value['assign_id'],
                                    'decimal_price'   => (string)$decimal_price_sign.$value['option_price'],
                                    'price'   => (isset($value['option_price']) && $value['option_price']!=0) ? Tax::getInstance()->priceFormat($value['option_price'], true) : false,
                                    'symbol'  => ($value['absolute_price']=='1' && $symbol=='+') ? '' : $symbol,
                                    'value_id'  => $value['value_id'],
                                    'value_name' => $value['value_name'],
                                    'option_weight' => number_format($value['option_weight']),
                                    'option_default' => (bool)$value['option_default'],
                                    'selected' => isset($selected[$value['assign_id']]) ? true : false,
                                    'absolute_price' => $value['absolute_price']
                                );

Link to post
Share on other sites

Your first addition, just after:

$option_list[$value['option_id']] = array(

is not correct - in that it is not usable here - and is not according to my instruction. That addition was instructed to be just after:

$option_list[$value['option_id']]['values'][] = array(

 

Link to post
Share on other sites

Oops, I went back and checked and you are correct. Sorry, I guess I was in a hurry and didn't pay close enough attention.

I do really appreciate your help though. (even if I do skim through and not follow your directions)

 

Link to post
Share on other sites
Posted (edited)

Hey bsmither,

I don't usually go onto forums. I try to look stuff up and do my own thing. Sometimes, I still get it wrong since I am just an old human being trying to keep up with today's tech.

Even when someone tells me what to do, I get it wrong.

However, I wanted to find out how I can send you something or support you for what you do, personally. I have asked a couple of questions over the past few years that you have helped me with. I stand by my initial reply to your answer that started with Wow! And, I usually go onto the forums to see previously answered questions to learn what I need to know about CC, but I'll have to say that most, if not all, of the resolved fixes have been made by you. You continually keep CC going for FREE on these forums.

Just wanted to see if I can repay you for your work. I don't like taking great stuff/info without giving back. Sorry if I should not be asking in this venue, but don't have another option.

Please let me know and thanks for all that you do here.

Mark

 

 

Edited by MarkBlank
Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...