Thursday, March 20, 2014

Enable/Disable some common blocks from Magento 1.8

Here, we are going to discuss how we can enable/disable some basic blocks which appear at the front-end with Magento Default installation. Most of the task can be achieved using Admin Panel.

1. Remove default Welcome Message shown at the top right corner.
   

   
   Goto System > Cofiguration > General > Design
   In "Header" section, Remove the value in "Welcome Text" field.
   
2. Change the main website logo
   
     

   
   Goto System > Cofiguration > General > Design
   
   In "Header" section, change the "Logo Image Src" field. If you remove this field's content, <img> tag will be generated with a incomplete "src" property. 

3. Change the Copyright information at footer   
       


   
   Goto System > Cofiguration > General > Design
   
   In the "Footer" section, change the content in "Copyright" field.
   
   To add any additional text below the Copyright message, enter such HTMLs in "Miscellaneous HTML" field. Here we can enter CSS style statements as shown below.
   
   <style>
   .footer { background-color : white; color:blue;}
 </style>
   
   The above CSS style would change the font-color and background-color of the DIV with class "footer".
  
   We can add new paragraph, DIV etc also. The blue string "General Tester" in the picture above was added in this "Miscellaneous HTML" section.
   
4. Remove the Footer links "About Us", "Customer Service", "Privacy Policy".

   Goto CMS > Static Blocks
   
   Click on the static block named "Footer Links" to modify its content. When in Edit mode, clear/modify the content in "Content" field. If you want to add link to any CMS page here, add the following <li> within the existing <ul>. Below, we are adding a link to Homepage.
   
   <a href="{{store direct_url="home"}}">Home</a>
   
5. Remove the footer links "Site Map", "Search Terms", "Contact Us", "RSS"

   i. Site Map, Search Term :: 
     
      Goto System > Configuration > Catalog > Catalog 
      In "Search Engine Optimization" panel, "Autogenerated Site Map" and "Popular Search Terms" can be set to "Disable"
   
   ii. For "Contact Us" :: 

        Goto System > Configuration > General > Contacts
       "Enable Contact Us" option can be set to "No" to remove this.
 
   iii. For "Rss" :: 

       Goto System > Configuration > Catalog > RSS Feeds
       In "RSS Config" panel, set "Enable RSS" to "Disable"

6.  Remove the "Help Us to Keep Magento Healthy - Report All bugs"  
   
   i. The above section appears within a DIV element <div class='bugs'>. So we can add a style statement in "Miscellaneous HTML" field as shown in point 3 above ::
          <style>
      p.bugs { display:none; }
    </style>
   
 ii. Or we can modify the template file footer.phtml within our current theme :: 
       
       <!-- Commenting the following section would do it:: 
  
  <p class="bugs">
   <?php echo $this->__('Help Us to Keep Magento Healthy') ?>
   <a href="http://www.magentocommerce.com/bug-tracking" onclick="this.target='_blank'">
    <strong>
      <?php echo $this->__('Report All Bugs') ?>
    </strong>
   </a> 
   <?php echo $this->__('(ver. %s)', Mage::getVersion()) ?>
 </p>
  -->  
   
7. To disable various Blocks like "Tags", "Newsletter", "Community Poll" and "Paypal Logo"
   
   

   
   i. To remove "Tags" section,
       Goto System > Configuration > Advanced > Advanced, Disable "Mage_Tag"
 
   ii. To remove "Newsletter" signup section from all layout : 
         In the same section described above, Disable the "Mage_Newsletter" module.

   iii. To Disable all "Polls" :
          In the same section described above, Disable the "Mage_Poll" module.

    iv. To Disable "PayPal Logo" :
         a. We can add a CSS style to "Miscellaneous HTML" as shown below : 
  <style>div.paypal-logo { display : none; } </style>
          
          b. Or, we can edit the following file ::
  app/design/frontend/PACKAGE/THEME/template/paypal/partner/logo.phtml
  and then comment the entire stuff.

8.  Disabling blocks like "Compare Products", "My Cart", "My WishList" and "Recently Viewed Products" ...

    

   
   i. Disable WishList :: 
          a. Goto System > Configuration > Advanced > Advanced, Disable "Mage_Wishlist"
         b. Or Goto System > Configuration > Customer > Wishlist, In "General Options" panel, set "Enabled" to "No"
   
   ii. Disable My Cart at Sidebar :: 
       Goto System > Configuration > Sales > CheckOut, In "Shopping Cart Sidebar" section, set "Display Shopping Cart Sidebar" to "No"
  
  iii. To disable "Compare Products", we need to work on the layout XML files.
          We need to open "catalog.xml" file in "layout" folder. Comment the related block as shoen below.
  
     <reference name="right">
            <!-- <block type="catalog/product_compare_sidebar" before="cart_sidebar" name="catalog.compare.sidebar" template="catalog/product/compare/sidebar.phtml"/> 
           -->
  
  iv. To Disable "Recently viewed Products"
       Goto System > Configuration > Advanced > Advanced, Disable "Mage_Reports"

Friday, March 14, 2014

How to get Logged in Customer's Information in Magento 1.8

This is quite simple. When a user is logged in, his/her details are stored in session. so, we need to get the Session Object and then extract information out of it. Check the code below ..

<?php
 // Get the Customer Information from Session
 $customer = Mage::getSingleton('customer/session')->getCustomer();
   
 // Print Details
 echo "<br>First Name : ". $customer->getFirstname() ;
 echo "<br>Middle Name : ". $customer->getMiddlename() ;
 echo "<br>Last Name : ". $customer->getLastname();
 echo "<br>Name : ". $customer->getName() ;
 echo "<br>Email : ". $customer->getEmail();
 echo "<br>DOB : ". $customer->getDob();

 // Gender : 123 for Male, 124 for female
 echo "<br>Gender : ". $customer->getGender();     
 echo "<br>Tax/VAT : ". $customer->getTaxvat();

 // Group ID : 1- General, 2 - Wholesale 3 - Retailer 4 - QAAA
 echo "<br>Group ID : ". $customer->getGroupId();  
 echo "<br>Store Name : ". $customer->getCreatedIn();

 // Is Active : 1 for TRUE
 echo "<br>Is Active : ". $customer->getIsActive(); 
   
 /// Whether Subscribed to any Newsletter
 /// 1 for TRUE
 $subscriber = Mage::getModel('newsletter/subscriber')->loadByEmail($customer->getEmail()); 

 echo "<br>Is Subscribed to NewsLetter : " . $subscriber->isSubscribed();
   
 /// Extract Customer's DEFAULT Billing Address
 $customerAddressId = $customer->getDefaultBilling();
   
 if ($customerAddressId)
 {
   $address = Mage::getModel('customer/address')->load($customerAddressId);
   $cust_data = $address->getData();
   echo "<br>Billing First Name : " . $cust_data['firstname'];
   echo "<br>Billing Last Name : " . $cust_data['lastname'];
   echo "<br>Billing Company : " . $cust_data['company'];
   echo "<br>Billing Telephone : " . $cust_data['telephone'];
   echo "<br>Billing Fax : " . $cust_data['fax'];
   echo "<br>Billing Street : " . $cust_data['street'];
   echo "<br>Billing City : " . $cust_data['city'];
   echo "<br>Billing Region : " . $cust_data['region'];
   echo "<br>Billing Country : " . $cust_data['country_id'];
   echo "<br>Billing Zip : " . $cust_data['postcode'];
 }
   
 /// Extract Customer's DEFAULT Shipping Address
 $customerAddressId = $customer->getDefaultShipping();
 if ($customerAddressId)
 {
   $address = Mage::getModel('customer/address')->load($customerAddressId);
   $cust_data = $address->getData();
   echo "<br>Shipping First Name : " . $cust_data['firstname'];
   echo "<br>Shipping Last Name : " . $cust_data['lastname'];
   echo "<br>Shipping Company : " . $cust_data['company'];
   echo "<br>Shipping Telephone : " . $cust_data['telephone'];
   echo "<br>Shipping Fax : " . $cust_data['fax'];
   echo "<br>Shipping Street : " . $cust_data['street'];
   echo "<br>Shipping City : " . $cust_data['city'];
   echo "<br>Shipping Region : " . $cust_data['region'];
   echo "<br>Shipping Country : " . $cust_data['country_id'];
   echo "<br>Shipping Zip : " . $cust_data['postcode'];
 }
?>

To check whether the customer was subscribed to any newsletter, we took help of the following function : 
Mage::getModel('newsletter/subscriber')->loadByEmail()

For further notes on Magento, check other articles :
Magento Notes I, Magento Notes II

Saturday, March 08, 2014

Capturing Digits on a Textbox

We have already discussed on how we can capture keyboard events in textbox in article "Capturing KeyBoard Events in Javascript". Here, we would do some calculation using Javascript as user enters digits in a textbox. In the following example, we would ask user to enter a number in Inch, and we would instantly convert it to Feet and show it within a span element.

So, we have a textbox as shown below :
<input type='text' id='txtbox' onkeyup="fkeyup(event)" onkeydown="return fkeydown(event)"  >

and a span element next to it, where the result will be shown :
<span id='result'></span>

On this textbox, we would have the following effects ::

1. Only digits are accepted, no characters are allowed except Right & left Arrow, Del, Backspace and Dot (decimal point '.') characters.

2. The calculation will be done as soon as user enters a digit.

So, for the point no. 1 above, we need to capture 'keydown' event on the textbox. The 'keydown' event is fired when a key is pressed on an textbox element and before the character is rendered within the textbox. After the character is rendered or cursor is moved or some other action takes place within the textbox, the 'keyup' event is fired.

For point no. 2 above, we will do the calculation taking the digit rendered within the textbox. So, we'll capture the 'keyup' event.

So, the above input element has 2 events captured : 'keydown' and 'keyup'. So, check the Javascript functions below, we would discuss every piece of it soon.

<script type='text/javascript'>
// This function restricts 'character key entry' on the textbox
function fkeydown(e)
{
   var key = e.keyCode ; 
   if(!((key >= 48 && key <= 57 ) || key == 190 || key == 8  || key == 37 || key == 39 || key == 46)) return false;
}

// The function DOES the calculation
function fkeyup(e)
{
 var val = document.getElementById('txtbox').value;
 val =  (val == '' ? 0 : val);
 var result = !isNaN(val) ? parseFloat(val/12) : 'Error';
  document.getElementById('result').innerHTML = result + " Feet";
}
</script>

This is a simple Inch >> Feet converter. Enter Inch in this TextBox :: 
<input type='text' id='txtbox' onkeyup="fkeyup(event)" onkeydown="return fkeydown(event)"  >
<span id='result'></span>

Two events 'keyup' and 'keydown' events are handled by two separate functions "fkeyup()" and "fkeydown()". Let's check the fkeydown() function first. 

The keyCode is stored in variable 'key'. Next we check if the key is a valid digit 0-9 or dot (.) or Backspace or left/right Arrows or Delete key. If we get something else, we simply return 'false' and as a result, nothing is rendered on the textbox. So, the word "return" is very important when we are setting the 'keydown' handler on the input element by saying "onkeydown='return fkeydown(event)'".

Next, in the 'keyup' event, after the entered digit is rendered within the textbox, fkeyup() function is called. Within this 'fkeyup()' function :

a. we get the textbox's value and store it in a variable called 'val'. 
b. We check whether the given value is a valid number by calling isNaN() function, if it is valid, we divide it by 12 and get the resultant value as a float number.
c. Then we show the result in the '#result' span element.

Check the screenshot below : 



Capturing KeyBoard Events in Javascript

While working with simple Javascript and HTML, we have come across various events to be used with input fields. For example :

<input type="text" id="name" onkeypress="track_key()">

The function "track_key" is called when any key is pressed (or 'keypress' event is fired) upon the input element.

There are three keyboard events, namely "keydown", "keypress" and "keyup". There are certain point which should be noted here.

1. We can enter character keys ('A','1' etc) and non-character keys ('F9', 'Del' etc)

2. If any character key is pressed, 'keydown' event is fired first, then 'keypress' event is fired. These events occur before the textbox/textarea element gets the character.

3. When the said textbox/textarea has got the character and key was released, the 'keyup' event is now fired.

4. So, if a character key is pressed and held for some time, two events "keydown" and "keypress" events are fired repeatedly until the key is released and 'keyup' event is fired. This behaviour is almost same on all browsers including IE7, Firefox and Chrome.

5. If you press any a non-character key 'F2' (or 'shift' or 'ctrl' or 'F9' etc) and hold it for a while, only "keydown" event is fired repeatedly. However firefox may fire 'keypress' event after it.

6. Which key was fired - can be tracked down by using the 'event' object's 'keyCode' property. This 'event' object is available within the browser environment. If the key is any alphanumeric one, the 'keyCode' property will hold the ASCII value against the key pressed. So, if 'A' was pressed, its ASCII value 65 will be stored in 'keyCode' property. 'A' and 'a' produce the same ASCII 65 as 'keyCode'.

7. Latest Firefox, Chrome, IE 9+ and Safari support 'charCode' property on the 'event' object which holds corresponding ASCII value during the 'keypress' event. Otherwise, old IE (may be older version of other browsers) filled 'keyCode' property in 'keyPress' event.

CheckOut some example :

Character 'a' on IE 9, Chrome 33, Firefox Nightly 29: (IE 7,8 gets 97 in 'keyCode' property)
keyDown event, (keyCode : 65) (ASCII for 'A')
keyPress event, (charCode : 97) (ASCII for 'a')
keyUp event, (keyCode : 65) (ASCII for 'A')

However, 'Shift' + 'a' ( means 'A' ) : generates ASCII 65 on all three events.

Non-character key 'ESC' generates 27 in 3 events as shown below :
IE 9 : keyDown (keyCode : 27), keyPress (charCode:27), keyUp (keyCode : 27)
Chrome 33 : keyDown (keyCode : 27), keyPress event is not fired, keyUp (keyCode : 27)
Nightly 29 : keyDown (keyCode : 27), keyPress (keyCode : 27), keyUp (keyCode : 27)


For semi-colon character, the following behaviour is seen ::
IE 9 : keyDown (keyCode : 59), keyPress (charCode : 59), keyUp (keyCode : 59)
Chrome 33 : keyDown (keyCode : 186), keyPress (charCode : 59), keyUp (keyCode : 186)
Nightly 29 : keyDown (keyCode : 59), keyPress (charCode : 59), keyUp (keyCode : 59)

The above behaviour is very puzzling. 186 is the key's position code on Keyboard.

I think, if it is a character key, we can track it by its 'charCode' property on all modern browsers.

How the above keyCodes/charCodes were obtained? Check the Javascript code below. This would show you the corresponding keyCode/charCode as you enter keys on a textbox. You can see the output on your browser console.

<script type='text/javascript'>
// The function which is called on 'keyUp' event
function keyup(e)
{
 var str = '';
 if( e.keyCode ) str = "keyCode : "+e.keyCode;
 console.log('keyUp event, ' + str);
}

// The function which is called on 'keyDown' event
function keydown(e)
{
 var str = '';
 if( e.keyCode ) str = "keyCode : "+e.keyCode;
 console.log('keyDown event, ' + str);
}

// The function which is called on 'keypress' event
function keypress(e)
{
 var str = '';
 if( e.keyCode ) str = "keyCode : "+e.keyCode;
 else if( e.charCode ) str = "charCode : "+e.charCode;
 console.log('keyPress event, ' + str);
}
</script>

<!-- The 'input' element which receives the keystrokes -->
<input type='text' name='val' onkeyup="keyup(event)" onkeydown="keydown(event)" onkeypress="keypress(event)" >

In our next tutorial Capturing Digits on a Textbox, we will do small calculation on the digits entered in a textbox.

Thursday, February 20, 2014

Building a basic Hello World module in Magento 1.8

To create a small "Hello World" module in Magento is very easy. This would require a Namespace (say, "Test") and ModuleName (say, "Helloworld"). Next follow these steps.

1. Create an XML file in app/etc/modules folder called "Test_Helloworld.xml". This name has a format {namespace name}{underscore}{module name}
   
  Write the following code in it :: 
  
  <?xml version="1.0"?>
 <config>
  <modules>
   <!-- Specify the NamespaceName_ModuleName -->
<Test_Helloworld>
     <!-- If we need to Disable it, we do it here -->
    <active>true</active>
    <!-- Which CodePool to Use -->
     <codePool>local</codePool>
</Test_Helloworld>
  </modules>
 </config>

  Magento has 3 codepools namely "core", "community" and "local". We won't be touching the "core", rather we would be creating our modules in "Community" or "local" codepool. If we choose "community", we need to change one line in the above XML to "<codePool>community</codePool>". Here we are creating modules in "local" folder.
  
  This XML is needed to tell Magento that we are going to add a new Module and this module's code can be found inside "local" codepool. Now we can see our new module to appear in the admin panel. In System > Configuration > Advanced > Advanced section, you'll that our new module is listed there.





2. Now, we need to create a folder with the Namespace name "Test" inside app/code/local folder

3. Next, we need to create a folder with Module Name "Helloworld" inside the "Test" folder

4. Now create 2 subfolders "controllers" and "etc" inside app/code/local/Test/Helloworld/

5. Next we need another configuration file called config.xml ( inside 'etc' folder ) where all the module's basic configuration will be stored. Here is the content for app/code/local/Test/Helloworld/etc/config.xml ::
   
  <?xml version="1.0" encoding="UTF-8"?>
  <config>
    <modules>
     <!-- Again, NamespaceName and ModuleName -->
     <Test_Helloworld>
      <!-- Not too much of importance here -->
      <version>1.0.0</version>
     </Test_Helloworld>
    </modules>
    
    <frontend>
     <routers>
     <!-- How we are going to access the module from front-end? Router name is "helloworld" -->  
       <helloworld> 
         <use>standard</use> 
           <args>
   <!-- Which module will start to work for the 'helloworld' router -->
              <module>Test_Helloworld</module> 
              <frontName>helloworld</frontName> 
           </args>
        </helloworld>
      </routers>
    </frontend>
  </config>

8. Next, we create the main controller IndexController.php inside app/code/local/Test/Helloworld folder. Check its content ::

  <?php
 class Test_Helloworld_indexController extends Mage_Core_Controller_Front_Action
 {
   // Default action 
   public function indexAction()
   {
     echo " <b>Index Action</b>";
   }
 
   // Another action called 'view'
   public function viewAction()
   {
     echo " <b>View Action</b>";
   }
 
 }
 ?>

Here, we have created a class with naming convention {NamespaceName}_{ModuleName}_{ControllerName}. Then we create two actions called "indexAction" ( which is default action ) and "viewAction". Check relationships between URLs and these actions below ..
     
http://localhost/magento/helloworld                :: Index Controller > index Action
http://localhost/magento/helloworld/index        :: Index Controller > index Action
http://localhost/magento/helloworld/index/view      :: Index Controller > view Action
http://localhost/magento/helloworld/index/view/index :: Index Controller > view Action
    
Check the Output below :




If we want to load default template and theme onto our page, the index Controller's actions must be changed as shown below :

<?php

class Test_Helloworld_indexController extends Mage_Core_Controller_Front_Action
{
  // Default action 
  public function indexAction()
  {
      $this->load_theme();
      echo " <b>[Index Action]</b>";
  }
 
  // Another action called 'view'
  public function viewAction()
  {
$this->load_theme();
echo " <b>[View Action]</b>";
  }
 
  // Another action 
  public function say_hiAction()
  {
$this->load_theme();
echo " <b>[Say_Hi Action]</b>";
  }
 
  // Private Function
  private function load_theme()
  {
$this->loadLayout();
$this->renderLayout();

// Print Template and Theme Information
echo "Current Theme Information : Package [" . Mage::getSingleton('core/design_package')->getPackageName() . "], Theme : [";

echo Mage::getSingleton('core/design_package')->getTheme('frontend') . "]";
  }
}
?>
  
 We have created a private function load_theme() which loads layout and renders it on the browser. It also prints the current Package and Theme name on the screen.
    
A new public function say_hiAction() has also been added. So if we call http://127.0.0.1/magento1.8/helloworld/index/say_hi, Index Controller's say_hiAction() function will be called. 
   
Check the Output below :





The Template and Theme information is printed at the top of the screen.  The statements $this->loadLayout()and $this->renderLayout() loads and renders the templates on the browser.

Magento Notes - II

Let's discuss some more Magento 1.8 stuffs ::

1. On your Cart page, how to get each product's category names?
    
   Put the following code where you want to show Category Name in  app\design\frontend\YOUR_PACKAGE\YOUR_THEME\template\checkout\cart\item\default.phtml   

<?php
   // GEt Product ID
   $proid = $this->getProduct()->getId();

   // GEt Category IDs
   $ids = $this->getProduct()->getCategoryIds();

   // Show Category Names
   $cat_name = "";

   foreach($ids as $val) 
   {
$cat_name .= Mage::getModel('catalog/category')->load($val)->getName() . ", ";
   }
   echo "Category : " . rtrim( $cat_name, ", ");
 ?>

2. How to get custom text attribute of a product?

   Suppose you have created a new text attribute called 'custom_desc'. Now, on various pages, you want to get this attribute's value. Insert any of the following codes to get it done.

   <?php
  // Method 1
  $custom_desc =  $_product->getData("custom_desc"); 
   
  // Method 2
  $custom_desc = $_helper->productAttribute($_product, nl2br($_product->getCustomDesc()), 'custom_desc'); 
   
  // MEthod 3 :: Easiest
  $custom_desc = $_product->getCustomDesc(); 
 ?>
   
   Amazing is the fact that if we create a property/attribute called "test", calling "$_product->getTest()" would return value of that property for the product "$_product". Such custom named functions will be automatically available with the product object. Check more examples below.
   
   "short_description"      => $_product->getShortDescription()
   "country_of_manufacture" => $_product->getCountryOfManufacture()
   
3. How to get Customer’s Email Address into the Order Notification Email Templates ?
  
  You need to insert the following shortcode into various email template files stored in app\locale\en_US\template\email\sales\ folder.
  
  {{htmlescape var=$order.getCustomerEmail()}}
  
4. How to identify whether current page is the home page?
   
   Use the following code snippet to help ...

   <?php
   
  $is_homepage = Mage::getBlockSingleton('page/html_header')->getIsHomePage();  
   if( $is_homepage )
   {
      // Do, if Home Page
      // However this won't work if you are sitting
      // on Home Page, but you have extra slashes in
      // URL like abcd.com/?p=2 or abcd.com/home?page=2
   }
 ?>

Another most trustworthy solution is ::

   <?php
  if( Mage::getSingleton('cms/page')->getIdentifier() == 'home' )   {
      // Do, If Home Page
      // This would work most of the times as usually 'home'
      // identifier (for page) is what we always set as Home
  }
 ?>  

5. What to do when Products are not showing up in Category page or Search results?

    1. Check if product is enabled
    2. Check product Quantity is valid. However if "Display out of stock products" is set to "yes", then products will be shown even if it has zero quantity.
    3. Check if product is assigned to a category
    4. Check Attribute settings, check if product attributes like "name" etc are "Searchable"
    5. Check if "name" attribute is having a "Global" scope
    6. Clear Cache
    7. Re-Index all the indexes

6. How to get Stock Quantity of the current product?
    
Use the following code to get current product's stock quantity. You may replace the product object "$_product" with other object you are working with.

   <?php
    $_quantity = intval(Mage::getModel('cataloginventory/stock_item')->loadByProduct($_product)->getQty());
 ?>

Check out Magento Notes - I