rss
twitter
    Find out what I'm doing, Follow Me :)

Saturday, June 19, 2010

Whats New in Magento 1.4.1.0

Improvements

  • Added ability to use static URLs for media in WYSIWYG or image browser. Added ability to enable parsing store, skin and media directives on catalog frontend.
  • URL rewrites history: ability to auto-generate custom rewrite with redirect from old to new URL when changing product URL-key
  • Added ability to exclude a category from navigation menu
  • Various improvements in system configuration UI. Introduced ability to make actual configuration structure to be independent on the system.xml structure
  • Added "Only X left" inventory feature
  • Implemented Centinel functionality in iphone theme
  • Upgraded TinyMCE to v.3.3.2
  • Improved PayPal integration, includes:
    * Recurring payment profiles entity and purchasing of "subscription" products. In checkout they are treated as "nominal" items.
    * Billing agreements
    * "Pending Review" order state, "Pending Review" and "Suspected Fraud" order statuses and logic related with this. Triggers by PayPal IPR, FMF and Unilateral payments.
    * Functionality of transactions listing/searching and fetching from gateway
    * Fetching PayPal settlement reports via SFTP
    * Various improvements of PayPal integration on the frontend and admin UI
  • Added notice about creating offline creditmemo from order view page.
  • Added getter for recurring payment methods in payment helper.
  • Implemented abstract block ability to have arbitrary groups of child blocks and a method that returns such a group. Implemented a method that fetches data from child block by specified alias.
  • Implemented ability to specify "sort_order" instead of "before" and "after" in the totals declaration. All nominal totals declaration utilize "sort_order"
  • Added getter for specified object data by key in core/template block: method getObjectData()
  • Defined payment methods grouping, implemented getter for payment method list (with option to group them). Added ability to render grouped options in the "select" grid filter.
  • Moneybookers: utilized the payment methods grouping for all its methods; removed redundant "translate" attribute in the methods definition in config.
  • Utilized payment methods grouping for PayPal peyment methods.
  • Added more verbosity to PayPal NVP and IPN debugging

Changes

  • Sales module database structure changed from EAV into flat tables
  • Product custom URL rewrites redirect to SEF URL, rather than to catalog/product/view/id/
  • Reimplemented frontend top menu rendering logic (cross-browser and usability improvements)
  • Reviewed logic of the sales reports: Orders, Tax, Invoiced, Shipping, Refunds, Coupons
  • Reimplemented bestsellers report
  • Implemented 3D Secure validation for Maestro International and JCB cards
  • Changed Shopping cart methods output (top + bottom): removed
  • Moved the Payflow Pro payment method to PayPal module
  • Refactored sales/service_quote model: instead of submit() method the submitAll() should be used. It can submit nominal items separately from the order. The methods for submitting nominal items and order separately - are available as well.
  • Refactored onepage checkout model to use the new method sales/service_quote::submitAll(), added recurring profiles and billing agreements passing through the process until the success page
  • Utilized child blocks grouping to improve flexibility of rendering additional information in catalog/product/view template. The group is called "detailed_info"; any block from layout may insert itself to this group.
  • Removed redundant wrappers hard-coded into some catalog templates. Template of parent block is responsible for wrapping.
  • Refactored onepage checkout success block and template: simplified fetching related checkout information, added ability to render billing agreement and recurring profiles that might be created with the payment placement.

Saturday, June 5, 2010

Google Analytics code bug in Magento 1.4.0.1

We just released a site based on the latest community release of Magento 1.4.0.1. All went well until the point when we enabled Google Analytics for the site.

Firebug was showing an error: _gaq is not defined

google analytics error in magento 1.4.0.1

So there was a variable issue with the extra javascript analytics code inserted by Magento. A quick google search revealed that this issue was already reported in the Magento bug tracker and a solution/workaround provided.

The problem is in file: app/code/core/Mage/GoogleAnalytics/Block/Ga.php around line 170. Adding: var _gaq = _gaq || []; fixes the issue.

Easy fix, however, this sort of bug is something that shouldn’t have slipped through testing and quality control.

Friday, May 28, 2010

CSS In Magento

The first thing that you need to do with Magento is famililarise yourself with the CSS files, as you will be using these an awful lot. There are 7 different files in total, so you need to know what is located where and the things you will need to edit.

Most of the editing is done in the "boxes.css" file. All of the css files are located in ".../skin/frontend/YOUR_THEME/YOUR_THEME/css". If you have not changed the name of the theme or created a new one then it will be called "default" (".../skin/frontend/default/default/css") If you wish to change the colours or settings of any forms, tables, menus, buttons, error messages; then this is the place to be.

Ten Tips for Keeping your Magento Store Secure

Are you worried about the security of your Magento store? Magento has a number of built-in security features aimed at keeping you safe, but there are some steps you can take to make your site even more secure. Follow this ten-point security policy to protect your site from hackers and security breaches.

1. Choose a secure password

When you're choosing your Magento site's administrator passwords, choose wisely. Depending on your configuration and permissions, this password may give access to customer information and credit card data. This is probably review for most readers, but here are some guidelines for creating a really secure password:

Bigger is better. Use at least 10 characters.
Mix upper and lower case, punctuation, and numbers.
Making your password phonetic can make it easier to remember and type quickly.

2. Require HTTPS/SSL for all pages with logins

Each time you send data over an unencrypted connection you run a risk of this data being intercepted by an unwanted third-party. Login credentials are no exception. To minimize the risk of your username and password landing in unscrupulous hands, always send it over a secure connection. By always sending your login information over an encrypted connection, hackers are limited to expensive and extremely difficult brute-force attacks.

How to require HTTPS/SLL in Magento
In Magento you can require secure logins by selecting "yes" for both "Use Secure URLs in Frontend" and "Use Secure URLs in Admin" by going to the "Secure" section of the "Web" tab in the system configuration. In order to access the system configuration, go to the "System" menu and select "Configuration."

Magento Web Configuration Screenshot
Set "Use Secure URLs" to "yes" for both the frontend and admin

3. Don't use your Magento password for anything else

Do not use your Magento password with any other web services (such as email) or any other sites (such as Twitter, Facebook, Flickr, etc.). Third-party sites may not require or even support HTTPS/SSL to login, breaking rule number two. In the event that a third-party website is hacked, your password may be vulnerable.

4. Use a custom admin path

By default, you access your Magento admin panel by going to your-site.com/admin. Having the path to your admin panel path easily guessable means that someone or something (i.e. a password-guessing robot) can snoop around and try to guess your password. By having your admin path be a secret code word instead of the default /admin, you can prevent users from guessing your password or using it if they do somehow get a hold of your password.

How NOT to change your Magento admin path
Tucked in the "admin" section of the system configuration, the "Admin Base URL" setting looks like it offers the ability to set a custom admin URL and choose whether to use that custom URL or not. But BEWARE: this setting will break Magento by preventing you from accessing the admin panel (I've tested this and found this to be true as of Magento 1.4.0.1 and earlier).

Magento Web Configuration Screenshot

BEWARE: Do not use the admin base URL settings; it will break your site.

How to change your Magento admin path
Although the setting does not work, there is an easy way to change your Magento admin path.

Locate /app/etc/local.xml
Find <![CDATA[admin]]> and replace 'admin' with the path you would like to use

So if your local.xml file says <![CDATA[drawbridge]]>, your admin path will be /drawbridge.

5. Close email loopholes

Magento has a really convenient feature that allows administrators to reset their password if forgotten. In order to reset your password, you need to know the email account associated with the account. Then you need access to that email account to retrieve the new password. First, choose an email address that is not publicly known. Second, make sure the password for your email account is secure. Third, make sure that if your email account has a security question that allows you to reset your password, you choose a question and answer that is so obscure that it would be impossible to guess.

6. Use secure FTP

Guessing or intercepting FTP passwords is probably one of the number one ways sites get "hacked." In order to prevent unauthorized access to your sites FTP, use secure passwords and use SFTP (SSH File Transfer Protocol) or FTP-SSL (Explicit AUTH TLS). With SFTP, you can use Public Key Authentication to increase security even more by requiring a private key file and an optional de-encryption password to authenticate the FTP access.

7. Limit unsecured FTP access

If you do have to connect through regular (non-secure) FTP for some accounts (i.e. to upload photos), limit access for these accounts to a narrow set of directories. You can then use .htaccess and httpd.conf files to prevent scripts from running in these directories that can change other files and directories on the server that should not not be accessible through that FTP account.

If you have access to the httpd.conf file on your server, this is the best method to preventing scripts from running in a specific directory. Place this code in your httpd.conf file:

<directory path-to-directory-you-want-to-restrict="">
AddHandler cgi-script .php .pl .py .jsp .asp .htm .shtml .sh .cgi
Options -ExecCGI
</directory>

If you don't have access to httpd.conf, you'll have to use.htaccess. Include the following code in the .htaccess file of the directory you want to restrict:

AddHandler cgi-script .php .pl .py .jsp .asp .htm .shtml .sh .cgi
Options -ExecCGI

Because .htaccess does not support the tags, the .htaccess file must be placed in the directory you want to effect. Because of this, you need to set the permissions of the .htaccess file to 444 (read-only) to prevent modifications to the .htaccess file. You may also want to chown the file so the permissions cannot be changed. This method isn't fool-proof, but it's a good start to preventing naughty scripts from wreaking havoc.
 

Important: placing this code in a directory's .htaccess file will prevent scripts from running in that directory and all sub-directories.

8. Don't save passwords on your computer
 

Most modern computers and browsers offer the option to save passwords as a convenience so you don't have to enter your password every time. This is great most of the time, but can be a security problem because often saved passwords can be easily revealed in plain text. Anybody with access to the computer has access to the sensitive data. Even worse, someone could steal the computer and then use the saved passwords to access the sensitive data. To avoid unintended access to your Magento password or data, simply set your computer or browser to never save it— this might be a bit inconvenient, but it's a great security policy.

9. Keep up-to-date anti-virus software
 

Computer viruses and trojans can steal your data and log your key strokes. To minimize the risk of this happening, be sure to invest in reputable anti-virus software. Free anti-virus software like AVG may be great for home and personal use, but if you want indemnification or a warranty, you may want to look at commercial anti-virus software.

10. Restrict admin access to only approved IP addresses
 

You can use .htaccess to limit access to your admin area. In the .htaccess file for your admin directory, place the following code in order to block access to all IP addresses except those specifically listed:

AuthName "Protected Area"
AuthType Basic
order deny,allow
deny from all
allow from 11.111.111.11
allow from 22.2
</limit>


"allow from 11.111.111.11" blocks the specific IP address 11.111.111.11
"allow from 22.2" blocks a range of IP addresses beginning with 22.2

There is a downside to restricting access based on IP: if you travel a lot you may find this method very inconvenient as you'd have to manually add each new IP address or IP range to the .htaccess file in order to gain access.

Friday, May 21, 2010

How to remove index.php from Magento URLs

Hi, if you are using Magento and your store urls are looking this way,
http://www.soamjena.com/index.php/flavoured-condoms/moods-for-men.html

So, you must be looking , how to remove that index.php from the middle, as thats not good for Search Engine Indexing at all. So, here is the trick.

1. Goto your site root folder and you can find the .htaccess file. Just edit that. Open it on a text editor and find this line,  #Rewrite Base /magento/ . Just replace it with Rewrite Base / .

2. Then goto your Admin Panel and enable the Web Server Rewrites. You can find it at System > Configuration > Web > Search Engine Optimization.

3. Then goto your Cache Management page ( System > Cache Management) and refresh your Cache and also refresh the Web Redirects.
Thats all. Test at Frontend now..

Thursday, May 20, 2010

Magento-Moving Upselling products from content to right column

A simple solution to display upselling products in right column rather than at content part by default. Follow this steps. 

step 1:

go to catalog.xml

Hide this block as

<!–<block type=”catalog/product_list_upsell” name=”product.info.upsell” as=”upsell_products” template=”catalog/product/list/upsell.phtml”>
<action method=”setColumnCount”><columns>4</columns></action>
<action method=”setItemLimit”><type>upsell</type><limit>4</limit></action>
</block>–>

step 2:

Add the following code

<block type=”catalog/product_list_upsell” name=”product.info.upsell” before=”-” template=”catalog/product/list/upsellright.phtml” />

after this code

<block type=”catalog/product_list_related” name=”catalog.product.related” before=”-” template=”catalog/product/list/related.phtml”/>

step 3:

go to catalog/product/view.phtml

then remove the following line or commend it
<?php echo $this->getChildHtml(‘upsell_products’) ?>
like this <?php //echo $this->getChildHtml(‘upsell_products’) ?>

step 4:

create upsellright.phtml in catalog/product/list folder
and paste the following code fully

<?php if(count($this->getItemCollection()->getItems())): ?>
<div class=”box base-mini mini-related-items”>
<div class=”head”>
<h4><?php echo $this->__(‘Upselling Products’) ?></h4>
</div>
<div class=”content”>

<ol>
<?php foreach($this->getItems() as $_item): ?>
<li<?php if($_item->isComposite() || !$_item->isSaleable()): ?> class=”super-products”<?php endif; ?>>
<div class=”product-images”>
<a href=”<?php echo $_item->getProductUrl()?>” style=”margin-left:0px;”><img src=”<?php echo $this->helper(‘catalog/image’)->init($_item, ‘thumbnail’)->resize(50) ?>” alt=”<?php echo $this->htmlEscape($_item->getName()) ?>” width=”50″ height=”50″ /></a>
</div>
<div class=”product-details” style=”margin-left:70px;”>
<a href=”<?php echo $_item->getProductUrl() ?>”><?php echo $this->htmlEscape($_item->getName()) ?></a>
<?php echo $this->getPriceHtml($_item, true) ?>
<?php if ($this->helper(‘wishlist’)->isAllow()) : ?>
<a href=”<?php echo $this->getAddToWishlistUrl($_item) ?>” class=”link-cart”><?php echo $this->__(‘Add to Wishlist’) ?></a>
<?php endif; ?>
</div>
</li>
<?php endforeach ?>
</ol>
</div>
</div>
<?php endif ?>

Wednesday, May 19, 2010

Analysis & Usage of Collections in Magento

As a Magento Programmer I am fascinated by the use & simplicity of collection used in Magento. Simplicity, does not really mean being simple (it is rather complex structured) but easy to use. With the help of one of my colleague, I got down to understand how collection really represents the “collection” of data we are actually trying to get from database. Here is what I found drilling down into the Magento’s Core. I may be “not quite right” with the analysis, you can always comment.

Almost all the collections found inside app/code/codepool/Namespace/Module/Model/Mysql4/model/Collection.php are the child of parent Class Mage_Core_Model_Mysql4_Collection_Abstract. Primary thing done in the class constructor is initializing its resource and Model. If you look into one of the Collection class you can see in its constructor.

/**
    * @class Mage_Checkout_Model_Mysql4_Agreement_Collection
    * Initialize resource
    *
    */
    protected function _construct()
    {
      $this->_init('checkout/agreement');
    }

And this _init function has been implemented in its parent class as

/**
         * Standard resource collection initalization
         *
         * @param string $model
         * @return Mage_Core_Model_Mysql4_Collection_Abstract
         */
        protected function _init($model, $resourceModel=null)
        {
            $this->setModel($model);
            if (is_null($resourceModel)) {
                $resourceModel = $model;
            }
            $this->setResourceModel($resourceModel);
            return $this;
        }

The resource class can be found in app/code/codepool/Namespace/Module/Model/Mysql4/model.php. And this resource class in turn initializes the database table to be used in the Module along with the table’s primary key.

class Mage_Checkout_Model_Mysql4_Agreement extends Mage_Core_Model_Mysql4_Abstract
        {
     
        protected function _construct()
        {
            $this->_init('checkout/agreement', 'agreement_id');
        }
        ......
        }

It is this resource class that actually works out the database connections, read/write adapters and performs transactions. So this is the basic deduction about the link of collection with the database and its tables. But how are those collection formed still remains a mystery, not anymore! In this section of the post I will try to explain how are the collections really formed.

If I can, “collection” can be defined as collection or array of its resource. And in Magento case, most of the resources are database’s query results. Simply you can visualize “collection” to be array of your model’s resource. If a “query” in Magento returns a collection of all the products then it would mean that the very collection is an array of all the individual product’s object. But one question still remains how will the database query’s result transform into a Magento “collection“. To understand that we need to understand the collection class and its parents.

The class Structure for Mage_Core_Model_Mysql4_Collection_Abstract is like this.

Mage_Core_Model_Mysql4_Collection_Abstract
|__ Varien_Data_Collection_Db (C)
|__ Varien_Data_Collection (C)
|__ IteratorAggregate (I)
|__ Countable (I)

You can see that all collection implements two Interfaces IteratorAggregate & Countable.

IteratorAggregate is predefined in Standard PHP Library that extends Abstract Base Class Traversable. On using this Interface you can then Iterate Through Object using “foreach” construct. Countable returns the size of the Collection Object.

Among the two Interfaces, IteratorAggregate is particularly important. As you can see in Class Hierarchy both the interfaces are implemented by Varien_Data_Collection concrete class. IteratorAggregate has abstract public method getIterator() which returns the Iterator interface and the concrete Class has to implement the method on its own. It is this Iterator that provides the real iteration functionality.

So if you look into the Varien_Data_Collection you will find the getIterator() implemented like this.

/**
         * @class Varien_Data_Collection
         * Implementation of IteratorAggregate::getIterator()
         */
        public function getIterator()
        {
            $this->load();
            return new ArrayIterator($this->_items);
        }

As you can see that it first loads the “items” (I will get back to this Items) and instanciates the value to an internal Class ArrayIterator. And the Iterator returned by this function can then be iterated using foreach construct.

Looks like it is going to be a looonnnnng post, let be summarize what I’ve tried to point out until now. I’ve tried to show the link between the collection class or rather object with the database table and explain the iteration behavior of the collection object. But one question still remains how will the database query’s result transform into a Magento’s “collection“. This is where the “items” explanation need to be done.

“Items” are actually array if individual object (item) of the collection which represents the array of tuple of the database query result. As you see in the snippet above the ArrayIterator takes $this->_items are parameter. But $this->_items are not populated here on Varien_Data_Collection but rather on is child class Varien_Data_Collection_Db. Here’s the snippet from Varien_Data_Collection_Db.

/**
         * Load data
         * @class Varien_Data_Collection_Db
         * @return  Varien_Data_Collection_Db
         */
        public function load($printQuery = false, $logQuery = false)
        {
            if ($this->isLoaded()) {
                return $this;
            }
   
            $this->_renderFilters()
                 ->_renderOrders()
                 ->_renderLimit();
   
            $this->printLogQuery($printQuery, $logQuery);
   
            // Getting Data from DB
            $data = $this->getData();
   
            $this->resetData();
   
            if (is_array($data)) {
   
                // Looping on each result row
                foreach ($data as $row) {
                    // Creating Empty "item" Varien_Object's object
                    $item = $this->getNewEmptyItem();
   
                    if ($this->getIdFieldName()) {
                        $item->setIdFieldName($this->getIdFieldName());
                    }
   
                    // Setting Varien_Object's values to that of the row
                    $item->addData($row);
   
                    /**
                    * Adding the "item" to the collection @class Varien_Data_Collection
                    * So while referring to $this->_items @class Varien_Data_Collection it will return array of this "item"
                    */
                    $this->addItem($item);
                }
   
            }
   
            $this->_setIsLoaded();
            $this->_afterLoad();
            return $this;
        }
   
        /**
         * Get all data array for collection
         * @class Varien_Data_Collection_Db
         * @return array
         */
        public function getData()
        {
            if ($this->_data === null) {
                $this->_renderFilters()
                     ->_renderOrders()
                     ->_renderLimit();
   
                // Fetching all the row with the Select query set
                $this->_data = $this->_fetchAll($this->_select);
                $this->_afterLoadData();
            }
            return $this->_data;
        }

You can go through the inline comments I’ve added. This is it, I’ve finally worked out the explanation of structure & creation of Magento’s Collection and its iterative behavior. I’ve tried to show pictorially (below) what I have just described. Confused! Plz comment and of course please do comment if I am wrong, because there are “times” when you try to understand things even though they actually aren’t just like you think. I’d like to quote Paulo :“I see the world in terms of what I would like to see happen, not what actually does”!