Magento: Product Image Upload Problem

My client was having an issue on his Godaddy shared hosting account with his Magento product image uploads. I went through a dozen or more troubleshooting steps to determine the cause of the issue. After careful comparison with a Magento instance just like it hosted on another hosting company server I determined Magento was not at fault! Magento tries to write to a tmp directory on your server when it uploads and if it doesn’t have the privileges to do so will fail on image upload everytime.

My solution on Godaddy shared hosting is to create a php5.ini in the root of your Magento installation. Inside the php5.ini file add the following line:

upload_tmp_dir = var/tmp

Then under your Magento var directory create a directory named “tmp” with 755 permissions.

If this does not resolve your issue please contact me as anyone of the other troubleshooting steps could resolve your issue!

Magento: Get RAW MySQL query information

Ok, so you have a project where the client asks you to bypass the Magento API because it’s so painfully slow…what do you do? Not wanting to start digging through the haystack that is Magento to find the needles of MySQL I began Googling for an answer. What I quickly learned is that Magento’s MySQL queries are abstracted through PDO. Therefore I wouldn’t be able to get what I wanted through digging through source code. At this point I began wondering if there was some sort of application that could act as a proxy and then it dawned on me. I wondered if there was some sort of logging that could be done in MySQL to capture every database transaction.

Surprise surprise, there is a very simple way to enable query logging in MySQL! First off you will need shell access to your Linux box so that you can open up /etc/my.cnf which is MySQL’s configuration file. Once you’ve opened that file insert the following and close/save:


[mysqld]
log=/var/log/mysqld.log

If /var/log/mysqld.log doesn’t exist on your system you will need to create it. You can do so by running:

bash> touch /var/log/mysqld.log

Then set owner and group owner for the mysqld.log file to allow MySQL server to write to the file

bash> chown mysql:mysql /var/log/mysqld.log

At this point you should restart MySQL server. On CentOS you can simply run:

bash> /sbin/service mysqld restart

Now you should be ready to watch real-time MySQL transactions. To see those transactions you can run the following command:

bash> tail -f /var/log/mysqld.log

What I suggest doing at this point is to navigate to a particular process in Magento that you are wanting to get RAW MySQL. Stop tailing the log file and then run:

bash> cat /dev/null > /var/log/mysqld.log

This will empty the contents of the MySQL log file.  Start your tail of the log file again and run the Magento process. You should now have an excellent snap shot of exactly what MySQL is being run for a given process.

Magento: Sort Product Options by Value

Today I was presented with a Magento configurable product that has options that were not appearing in order when you clicked the drop down. A quick look with Firebug showed me that the drop down option values would be in proper alpha numeric order if I simply sorted the values of the options. First thing I thought to do is fix it with jQuery. So I created and uploaded a JavaScript file with a jQuery function I found online for sorting the options by value. Here’s the contents of that file:


      jQuery.fn.sortOptionsByValue = function()
      {
      var byValueSortCallback = function(x, y)
      {
      var xVal = jQuery(x).val();
      var yVal = jQuery(y).val();
      return (xVal < yVal) ? -1 : (xVal > yVal) ? 1 : 0;
      };
      return this.sortOptions(byValueSortCallback);
      };




Next thing I did was open up my Magento layout/catalog.xml file and locate the XML block that begins with catalog_product_view. Below that you will find a reference name=”head”. In there I inserted the following action which includes the JavaScript file I created and mentioned above:


<action method="addJs"><script>jQuery/sortselectbox.js</script></action>




In order to specifically fix the option order on this one configurable product I opened up that product in the Magento backend and inserted the following javascript into the product’s short description:


<script type="text/javascript">
jQuery(document).ready(function() {
  jQuery('#attribute965').sortOptionsByValue();
  jQuery('#attribute965').val('').attr({selected: 'selected'});
});
</script>




This script will sort the options by value alpha numerically (a-z0-9) and then it will put the empty option for “Choose an Option” as the first option and sets selected=”selected” on that option. From there you should be good to go. If you have a much more elegant method to resolving this feel free to let me know.

Magento: Administration for Beginners

Magento For BeginnersSomeone asked me today how they can quickly come up to speed on Magento Administration. They said everything seems so overwhelming to manage. I recommend the Magento Beginner’s Guide book shown here in this post.

Amazon has this to say about this book: “Magento is the world’s most evolved e-commerce solution. It runs on the Apache/MySQL/PHP platform. From one installation, you can control multiple storefronts, all sharing customer and product information. Magento’s templates and themes enable you to customize the look and feel of your store, even optimizing it for mobile phones. Extensions enable you to connect Magento to a large number of payment gateways and shipping services. Modular code enables you to upgrade your Magento installation while retaining your customizations. Support is provided free by an active open source community and by subscription to Varien, the company behind Magento.

Magento is one of the most exciting, flexible, and customizable e-commerce systems. It offers you an extensive suite of powerful tools for creating and managing an online store. As your online store grows, you can be sure that this robust e-commerce system can handle your needs. However, getting started with Magento can be difficult without the right guidance.

This book provides that guidance in the form of a step-by-step approach to building a simple, effective online store. The book covers the key features of Magento that will help you get your store up and running. It guides you through installation, configuration, populating your store with products, accepting payments, maintaining relationships with your customers, and fulfilling orders.

When you create an online store with Magento, you usually follow a defined series of steps. This book is arranged to support that process. Each chapter shows you how to get the most from one step.

You will learn to customize the default Magento storefront so that it becomes your store and also about Magento’s directory structure and where some of the elements of a store are customized. This experience will help you if you decide to go beyond this book and install new themes or create your own themes.

As you work your way through each chapter, your store will grow in scope and sophistication. By the time you finish this book, you should have a basic but complete, working online store.”

I hope this book helps you get rolling with your own Magento Administration too!

Magento: Dynamic SKU display on Configurable Products

A client of mine requested that on a configurable product when a visitor chooses an option (i.e. a simple product) that I display that simple products SKU automatically on the configurable product page.

First thing I did was look at the Simple Configurable Product module by Matt Dean to see if that was an option I could toggle on. Unfortunately that was not an option. I have a feeling that is not an option because some configurable products may require multiple options to be selected in order to present the correct SKU and the code for that could be potentially daunting. Fortunate for me, my client only has one dropdown per configurable product.

To get things going on this little project I opened up app/design/frontend/base/default/template/catalog/product/view/type/options/configurable.phtml and used that page for writing my code. You may want to choose a different directory that is related you your site’s theme.

On about line 38 I changed it from this:

<select name="super_attribute[<?php echo $_attribute->getAttributeId() ?>]"
id="attribute<?php echo $_attribute->getAttributeId() ?>">

to this:

<select name="super_attribute[<?php echo $_attribute->getAttributeId() ?>]"
id="attribute<?php echo $_attribute->getAttributeId() ?>"
onchange="return changeSku(this);">

At the very bottom of the configurable.phtml page I wrote the following mix of PHP and Prototype code to solve the Dynamic SKU Display:

<?php
$_product    = $this->getProduct();
$_attributes = Mage::helper('core')->decorateArray($this->getAllowAttributes());
?>
<?php if ($_product->isSaleable() && count($_attributes)):?>
    <dl>
    <?php foreach($_attributes as $_attribute): ?>
        <dt><label class="required"><em>*</em><?php echo $_attribute->getLabel() ?></label></dt>
        <dd<?php if ($_attribute->decoratedIsLast){?> class="last"<?php }?>>
            <div class="input-box">
                <select name="super_attribute[<?php echo $_attribute->getAttributeId() ?>]" id="attribute<?php echo $_attribute->getAttributeId() ?>" class="required-entry super-attribute-select" onchange="return changeSku(this);">
                    <option><?php echo $this->__('Choose an Option...') ?></option>
                  </select>
              </div>
        </dd>
    <?php endforeach; ?>
    </dl>
    <script type="text/javascript">
        var spConfig = new Product.Config(<?php echo $this->getJsonConfig() ?>);
    </script>

<?php endif;?>

<?php
$conf = Mage::getModel('catalog/product_type_configurable')->setProduct($_product);
$col = $conf->getUsedProductCollection()->addAttributeToSelect('*')->addFilterByRequiredOptions();

echo '<script type="text/javascript">';

echo '
document.observe("dom:loaded", function() {
  $("sku-container").update("<strong>Product Id: </strong> Select an option to display Product Id");
});
';
echo ' function changeSku(sel){';     	

$itemId = array();
foreach($col as $simple_product){
$itemId[] = array($simple_product->getSelectLabel() => $simple_product->getSku());
} 

//echo "<pre>";
//print_r($itemId);
//echo "</pre>";

foreach($itemId as $val){
 foreach($val as $k => $v){
echo "\n".'if(sel.options[sel.selectedIndex].value == "'.$k.'"){'."\n";
echo '$("sku-container").update("<strong>Product Id: </strong>'.$v.'");'. "\n";
echo '}';
	}
}

echo "\n".'if(sel.options[sel.selectedIndex].value == ""){'."\n";
echo '$("sku-container").update("<strong>Product Id: </strong> Select an option to display Product Id");'. "\n";
echo '}'; 

echo "}";
echo "\n</script>";
?>

Please note that my client requested that the SKU not be shown for the configurable product itself so you will need to comment out and/or remove those areas of the code shown above that do not display the SKU for the configurable product.

If you have a questions or comments please reply to this post and I would be happy to discuss it with you.

Magento: IE8 adds wrong quantity to cart

Ran into a bug issued by a client where some of his customers reported that IE8 adds the wrong product quantity to the shopping cart.

After doing a little Googling I found that this resolves the issue for IE8 users:

Open the template yourdesign/template/catalog/product/view/addToCart.phtml

and replace
<input … onclick=”productAddToCartForm.submit()” type=”text” />

with

<input … onclick=”productAddToCartForm.submit(); return false;” type=”text” />

Magento: Category Products Sort Position

If you want to manually sort products in your category for any reason, assign numbers to each product, under the Category Products tab of your category, in order of your desired sort order and then go to the Category Display Settings Tab and uncheck the check box under Available Product Listing Sort By and then select “Best Value”.

Your products will now sort correctly using the position numbers you specified.

Magento: Tax Rules set, but customer not charged tax

This morning I received a job to troubleshoot why a customer was not charged sales tax even though the customer lived in the zip code that the Tax Rule was set for. My first inclination was that perhaps his billing address was different from his shipping address and that the rule applied to his shipping address and not his billing address. That was not the case though.

After closer examination I realized the customer inputted a ZIP+4 (XXXXX-XXXX) style US Zip Code. When I looked at the Tax Rules they were all written like this:

“US-FL-32304-Rate 1,US,FL,32304,7.5,”

In order to fix the issue I created a wildcarded rule for every Tax Rule set that looks like this:

“US-FL-32304-*-Rate 1,US,FL,32304-*,7.5,”

Special thanks to my new buddy <Groenleer> on #magento (freenodes) for helping me troubleshoot this!!!

Magento: display and round prices to 3rd decimal point

Second time now I’ve had the client request that set their Magento prices to display and round to the third (3rd) decimal point. This time I will share with you how I performed this change in Magento (ver. 1.3.2.4).

First I FTP to my lib/Zend/Currency.php file and change the following:


protected $_options = array(
 'position'  => self::STANDARD,
 'script'    => null,
 'format'    => null,
 'display'   => self::NO_SYMBOL,
 'precision' => 2,
 'name'      => null,
 'currency'  => null,
 'symbol'    => null
 );

to


protected $_options = array(
 'position'  => self::STANDARD,
 'script'    => null,
 'format'    => null,
 'display'   => self::NO_SYMBOL,
 'precision' => 3,
 'name'      => null,
 'currency'  => null,
 'symbol'    => null
 );

Please note that if you upgrade Magento this will be overwritten and this change will be required again after upgrade!!!

Second, copy app/code/core/Mage/Core/Model/Store.php to app/code/local/Mage/Core/Model/Store.php. By doing this you protect this file from being overwritten during upgrades. Next change the following code in that file from:


public function roundPrice($price)
 {
 return round($price, 2);
 }

to


public function roundPrice($price,$roundTo=3)
 {
 return round($price, $roundTo);
 }

Lastly, I suggest copying app/code/core/Mage/Adminhtml/Block/Catalog/Product/Helper/Form/Price.php to app/code/local/Mage/Adminhtml/Block/Catalog/Product/Helper/Form/Price.php. Then you can change the following code in that file from:


public function getEscapedValue($index=null)
 {
 $value = $this->getValue();

 if (!is_numeric($value)) {
 return null;
 }

 return number_format($value, 2, null, '');
 }

to


public function getEscapedValue($index=null)
 {
 $value = $this->getValue();

 if (!is_numeric($value)) {
 return null;
 }

 return number_format($value, 3, null, '');
 }

Clear your Magento Cache and now you have prices that extend to the third (3rd) decimal point both on the front end and in the admin section of Magento!!!

If you have any suggestions on how to improve this post please feel free to drop me a line!

Client says “proceed to checkout” empties cart and returns to homepage

A customer would come to the website, place items in their shopping cart, and then click the “proceed to checkout button” from the shopping cart. Rather than take them to the cart, our Magento website would immediately forward them to the home page and empty all the items from their cart.

Cause: ISPs like AOL, Comcast, and Shaw.ca use a technique of changing IP addresses that cause security settings in Magento to empty the cart and not allow people to check out.

Fix: Change the Session Validation settings in the Magento Admin, found under System > Configurations > Web, to ‘no’ on everything except “Validate HTTP_USER_AGENT.” After doing this, go to System > Cache Management and refresh the configuration cache to apply the changes.