Subesh Pokhrel

Magento Developers Blog

Generating Backend-Admin URL With Key and Parameters in Magento

When you log into adminstrator part of the Magento webshop, and look into the url you may see something like this. [caption id=”attachment_230” align=”alignnone” width=”419” caption=”Admin URL with Keys and Parameters”]Admin URL with Keys and Parameters[/caption]

The part in “RED” are module controller(router)/action. And the part in “GREEN” is what we call as ”Paramerters” and the “BLUE” part is the ”Key”. The Key (which is also a URL parameter) in the URL has been added for security reasons and is checked against the session’s values for every action. If store owner does not want to use the key in admin url, then it can be set off from administrator settings.

My point in this post is, if you are a developer and creating a module that has Admin controller and you are simply calling some action of your controller lets say, mymodule/adminhtml_mycontroller/myaction/param1/1/param2/2 the it does not redirect you to your intended page, but will redirect to dashboard, IF key is enabled. You will have to add the key parameter to the URL to go to your page. So here is a simple snippet of code that will help you to build your URL with valid keys.

[source language=”php”] echo Mage::helper("adminhtml")->getUrl("mymodule/adminhtml_mycontroller/myaction/",array("param1"=>1,"param2"=>2)); [/source]

The “adminhtml” helper will automatically create url with keys attached to the URL.

Next thing, if you see the key of various pages in admin you will see that those keys are not same, there is a different logic behind creating those key values. The keys generated depends upon the controller and action you are about to execute. Keys can be seperatly generated as follows.

[source language=”php”] Mage::getSingleton(‘adminhtml/url’)->getSecretKey("adminhtml_mycontroller","myaction"); [/source]

Hope this helps, and this can be particularly helpful when you are using templates in admin modules and adding buttons to redirect to some other location. At least that was my case!

Magento Module Release: Uses Layout to List Post, Made by AW Blog, on the Basis of Category Identifier

I’ve always wanted to contribute something in Magento Community and I think today the day has arrived. The module is named as Sirius Blog Helper, just a name, Who cares about the “Name” unless it works :D. The basic function of the Module is to list the post made via AW Blog extension, categorized by category identifier of the post, using Layout. Yes, only through layout you can list the post anywhere you want. Not only that you can also restrict the size of the list through layout as well. Suppose you want to list 5 recent post made under “news” category identifier. Here’s how you can do it easily, of course you have to install the module first. The Module can be currently downloaded from Here, and will be soon available in Magento Connect as well. [source language=”xml”] <reference name="right"> <block type="sbloghelper/helper" name="news.list"> <action method="addCategoryIdentifier"> <identifier>news</identifier> </action> <action method="addListSize"> <size>5</size> </action> </block> </reference> [/source] Simple isn’t it? You can place similar kind of code in layout out to list other post categorically. Hope this helps to someone. Please do post your feedbacks. [caption id=”attachment_226” align=”alignnone” width=”253” caption=”Frontend Screen Shots”]Frontend Screen Shots[/caption]

Creating Product Links in Magento Using Custom Query

I’ve already made a post in this blog about Adding Related Product and other links to Product in Magento . But when I used the method to creating links among product’s, while importing very large number of products and creating large number of product links, it took a lot of time and resource. So I thought why not give it a try by direclty creating a link using SQL? And YES! it worked. Below is the code how I created those links using Custom SQL. But I have to tell you that the former methods looks organized, this is just a work around to a situation. You might know what I am trying to say! [source language=”php”] $resource = Mage :: getSingleton( ‘core/resource’ ); $read= $resource -> getConnection( ‘core_read’ ); $write= $resource->getConnection(‘core_write’); $linkTable=$resource->getTableName(‘catalog/product_link’); // Creating Upsell Product link $write->query("INSERT into $linkTable SET product_id=’".$productId."’, linked_product_id=’".$linkProduct."’, link_type_id=’".Mage_Catalog_Model_Product_Link::LINK_TYPE_UPSELL."’ "); // Creating Related Product link $write->query("INSERT into $linkTable SET product_id=’".$productId."’, linked_product_id=’".$linkProduct."’, link_type_id=’".Mage_Catalog_Model_Product_Link::LINK_TYPE_RELATED."’ "); // Creating Crosssell Product Link $write->query("INSERT into $linkTable SET product_id=’".$productId."’, linked_product_id=’".$linkProduct."’, link_type_id=’".Mage_Catalog_Model_Product_Link::LINK_TYPE_CROSSSELL."’ "); [/source] Happy Coding!

Creating Collection of Objects in Magento Using a “Magical Class”:Varien_Data_Collection

Have you ever wondered how Collection in Magento are built, containing array of individual Entity Objects of Magento? Collections are one of the most important data structure (if I am right) used in Magento. Most of the queries in Magento will result into collection, and then you will apply a foreach loop to access individual Entity Objects and their values. Today I came into a different situation where I had individual objects but needed to create a collection of those objects, so that I could return the collection from a function. I have not drilled down to the details of collection, untill today when I really need it! Do you think its very late? because I have been into Magento for more than a year now!. Better late than never! So, I got the way of working out my situation. Here is how I created a collection from Magento’s “Magical Class” Varien_Data_Collection. I call this “Magical Class”, because it worked like a Magic to me :D [source language=”php”] $collection=new Varien_Data_Collection(); $collection->addItem($objProduct); [/source] There are various other functions in this class you might need to “work around” a problem. So, have a look and certainly do comment if you also think this class to be a Magical Class!

Getting Ordered Items and Their Detail From Order ID in Magento

Here is a small snippet of code, yet useful, to get ordered items and its details. I’ve deviced this code a lot before and posted in Magento Commerce’s Forum as well. But felt like writting it again, so that I can have a quick refrence to it as well. Next thing, I’ve tried a lot to get all orders and their items details by single query, but have not yet come up with a solution. If you have any method of finding order and its details by a single query, then please do response. The code below first needs an order ID as it parameters to give order details. [source language=”php”] $order = Mage::getModel(‘sales/order’)->load($order_id); $items = $order->getAllItems(); $itemcount=count($items); $name=array(); $unitPrice=array(); $sku=array(); $ids=array(); $qty=array(); foreach ($items as $itemId => $item) { $name[] = $item->getName(); $unitPrice[]=$item->getPrice(); $sku[]=$item->getSku(); $ids[]=$item->getProductId(); $qty[]=$item->getQtyToInvoice(); } [/source] Hope this might “just” help somebody in need.

Create and Download XLS Report File Using Magento’s Core

Reporting can be a very important part of the Module you might be developing for Mageneto. If you are showing your data in Grid that’s good, but it will be better if you add XLS file generation action on that grid, so that the site administrator can see the report in paper. And if you have in paper you can visualize more clearly than on screen. I came this condition recently, and found out that Magento has functions to chanage your Grid (in Admin) to XLS files and if you dig more than you can change your data Array to XLS file using Magento’s function. First let me say you about exporing data from the Admin Grid you have already populated. You need do the following in your grid Block’s _prepareColumn function. [source language=”php”] $this->addExportType(‘router/controller/action’, Mage::helper(‘reports’)->__(‘Excel’)); [/source] And in your controller you will have to do this. [source language=”php”] /** * Export grid to Excel XML format in Controller * @class Mynamespace_Mymodule_Adminhtml_controllerController */ public function actionAction() { $fileName = ‘grid.xls’; /** * This is the part where Grid Columns and Data are created as Excel XML and returned as stream. * The implementation of this code is done in the parent class of Grid Mynamespace_Mymodule_Block_Adminhtml_Grid * And that class should be Mage_Adminhtml_Block_Widget_Grid */ $content = $this->getLayout()->createBlock(‘mymodule_adminhtml/mygrid_grid’) ->getExcel($fileName); /** * This is for Force Download implemented below */ $this->_prepareDownloadResponse($fileName, $content); } /** * Force Download Code block in your controller * Declare headers and content file in responce for file download * * @param string $fileName * @param string $content set to null to avoid starting output, $contentLength should be set explicitly in that case * @param string $contentType * @param int $contentLength explicit content length, if strlen($content) isn’t applicable * @return Mage_Adminhtml_Controller_Action */ protected function _prepareDownloadResponse($fileName, $content, $contentType = ‘application/octet-stream’, $contentLength = null) { $session = Mage::getSingleton(‘admin/session’); if ($session->isFirstPageAfterLogin()) { $this->_redirect($session->getUser()->getStartupPageUrl()); return $this; } $this->getResponse() ->setHttpResponseCode(200) ->setHeader(‘Pragma’, ‘public’, true) ->setHeader(‘Cache-Control’, ‘must-revalidate, post-check=0, pre-check=0’, true) ->setHeader(‘Content-type’, $contentType, true) ->setHeader(‘Content-Length’, is_null($contentLength) ? strlen($content) : $contentLength) ->setHeader(‘Content-Disposition’, ‘attachment; filename=’ . $fileName) ->setHeader(‘Last-Modified’, date(‘r’)); if (!is_null($content)) { $this->getResponse()->setBody($content); } return $this; } [/source] Now you can export your Grid data to XLS sheet. But what about your array you are not displaying in the grid? This should be fun too.. for you now.. because it was not fun for me to find out in the first hand :P. Lets take the same controller now. [source language=”php”] /** * Export Array to Excel XML format in Controller * @class Mynamespace_Mymodule_Adminhtml_controllerController */ public function actionAction() { $filename = ‘array.xls’; $exportData=Mage::getSingleton("adminhtml/session")->getMyData(); /** * Example Data Format * $data[0][‘product_id’]=10 * $data[0][‘product_name’]=HTC Diamond * $data[0][‘vendor_name’]=HTC JMKYZY * $data[1][‘product_id’]=11 * $data[1][‘product_name’]=HTC Ruby * $data[1][‘vendor_name’]=HTC JMKYZY * */ // Setting headers columns $data[0]=array($this->__("Product ID"),$this->__("Product Name"),$this->__("Vendors")); // Setting Column Data $i=1; foreach($exportData as $key=>$value){ $data[$i]=array($value[‘product_id’],$value[‘product_name’],$value[‘vendor_name’]); $i++; } // Unparsing in Excel Format $xmlObj = new Varien_Convert_Parser_Xml_Excel(); $xmlObj->setVar(‘single_sheet’, $filename); $xmlObj->setData($data); $xmlObj->unparse(); $content=$xmlObj->getData(); // Force Download $this->_prepareDownloadResponse($filename,$content); } [/source] So by comparing the two export controller methods, you can see that the Admin Grid’s Parent already has the functionality to get data from Grid and set that data to Varien_Convert_Parser_Xml_Excel Object and unparse its. As I said we need to dig further to know what going on inside Magento. Happy Coding.

Debugging Magento Using Eclipse PDT & Zend Debugger

Latest Post on Debugging Magento: Debugging Magento Using Eclipse on Ubuntu I had always thought of using Eclipse to debug Magento’s complex code flow, and tried number of times before. But without any success I had to abandon it, and thought was not applicable for Magento, remember the fox and the sour grapes :D I also tried using Trial Version of Zend Studio, but with no sucess. But today I was looking at fontis’s blog http://www.fontis.com.au/blog/magento/debugging-with-xdebug and they had indeed used XDebugger and are debugging Magento through command line. So, I thought why not give it a try once again! And as you have already expected i was successfull today!! Wasn’t easy though :P Here’s what I’ve done to get it working on WAMP. Before getting this done I assume you have created a new PHP Project and imported all files, beforehand in Eclipse. Step 1. A very good explanation of downloading Eclipse PDT with Zend Debugger can be found here Installing_the_Zend_Debugger Step 2. Configuring the Zend Debugger can also be found on same location but I would like to emphasize on its setting here, coz I missed myself on first run :D Use these settings for For Zend debugger in php.ini [Zend] zend_extension_ts=D:/wamp/bin/php/php5.2.5/ext/ZendDebugger.dll zend_debugger.allow_hosts=127.0.0.1 zend_debugger.expose_remotely=always You should not forget to enable Zend Debugger extension on WAMP. Now restart Wamp. You are now well set with Eclipse PDT and Zend Debugger. Next thing you need to do is make debugging settings in your Eclipse. Step 3. In you Eclipse Go to Windows–>Preference–>Debug and set as follows debugsettings Step 4. Then Windows–>Preference–>Server and set as follows Debug Server While setting Server configuration you will be prompt to add server path in path mapping, place that relative to your www root Example: /mysite (which will open as localhost/mysite) and select the files in your workspace. Step 5. Now all your settings are done. Now let me tell you about debugging a Block Class of Magento, say Mage_Catalog_Block_Product_List. Go to the class file and add a breakpoint anywhere inside _getProductCollection function. Step 6. Go to Run–>Open Run Dialog and configure as following Run Profile1 Profile 2 Step 7. All set to go now, Run profile as web page Run–>Debug As–>PHP Webpage. You can now see PHP Debug perspective, and use Step Over or Step Into to debug your values. Here is what I got. debugging Hope this might be a life changer.. at least it is for me!

Getting Customer’s Info Using Single Query Including Billing and Shipping Addresses

Query in Magento can be quite troublesome, if you are a starter..or non-starter. So I’ve tried to share some of the difficult queries using collection in Magento, so that it will be helpful to my blog readers and also a place where I can later refer to. Here is one of them, may not be dificult to all, but for me I had a very bad time initially, when I first started on Magento about a year ago. I had always thought to post on my blog, but when one of my collegue asked me about this I remembered and here’s the query. [source language=”php”] $collection = Mage::getResourceModel(‘customer/customer_collection’) ->addNameToSelect() ->addAttributeToSelect(‘email’) ->addAttributeToSelect(‘created_at’) ->addAttributeToSelect(‘group_id’) ->joinAttribute(‘billing_street’, ‘customer_address/street’, ‘default_billing’, null, ‘left’) ->joinAttribute(‘billing_postcode’, ‘customer_address/postcode’, ‘default_billing’, null, ‘left’) ->joinAttribute(‘billing_city’, ‘customer_address/city’, ‘default_billing’, null, ‘left’) ->joinAttribute(‘billing_telephone’, ‘customer_address/telephone’, ‘default_billing’, null, ‘left’) ->joinAttribute(‘billing_fax’, ‘customer_address/fax’, ‘default_billing’, null, ‘left’) ->joinAttribute(‘billing_region’, ‘customer_address/region’, ‘default_billing’, null, ‘left’) ->joinAttribute(‘billing_country_code’, ‘customer_address/country_id’, ‘default_billing’, null, ‘left’) ->joinAttribute(‘shipping_street’, ‘customer_address/street’, ‘default_shipping’, null, ‘left’) ->joinAttribute(‘shipping_postcode’, ‘customer_address/postcode’, ‘default_shipping’, null, ‘left’) ->joinAttribute(‘shipping_city’, ‘customer_address/city’, ‘default_shipping’, null, ‘left’) ->joinAttribute(‘shipping_telephone’, ‘customer_address/telephone’, ‘default_shipping’, null, ‘left’) ->joinAttribute(‘shipping_fax’, ‘customer_address/fax’, ‘default_shipping’, null, ‘left’) ->joinAttribute(‘shipping_region’, ‘customer_address/region’, ‘default_shipping’, null, ‘left’) ->joinAttribute(‘shipping_country_code’, ‘customer_address/country_id’, ‘default_shipping’, null, ‘left’) ->joinAttribute(‘taxvat’, ‘customer/taxvat’, ‘entity_id’, null, ‘left’); [/source] Hope this helps somebody!

Getting Configurable Attributes (Super Attributes) of a Configurable Product

In one of those time when you need to know what attributes of a product is used to make the current configurable product “configurable”, then here it goes :D Those configurable attributes are called as “Super Attributes”. Looking into the lower level at the Database level the attributes id are saved in the table “catalog_product_super_attribute”. In this configurable product’s Id and the attribute are saved. To get the attribute’s id you can directly write a custom query and fetch it. But to get its attribute code, attribute level you will then have to create an object attribute using the fetched id. But there is one shot option as well to do the same, in a managed Magento Way! Here is the way. The code comments are self explanatory I guess!! [source language=”php”] /** * Load Product you want to get Super attributes of */ $product=Mage::getModel("catalog/product")->load(52520); /** * Get Configurable Type Product Instace and get Configurable attributes collection */ $configurableAttributeCollection=$product->getTypeInstance()->getConfigurableAttributes(); /** * Use the collection to get the desired values of attribute */ foreach($configurableAttributeCollection as $attribute){ echo "Attr-Code:".$attribute->getProductAttribute()->getAttributeCode()."<br/>"; echo "Attr-Label:".$attribute->getProductAttribute()->getFrontend()->getLabel()."<br/>"; echo "Attr-Id:".$attribute->getProductAttribute()->getId()."<br/>"; } [/source] Happy Codding!

Creating Custom Sourced Multiselect Product Attribute

Creating Multiselect type of product attribute whose source will be the Magento’s core tables is pretty simple. Just go to Manage Attributes and create a new one. But if you want the attribute’s source table be a custom table, then you need to think. Some times a case pops up that the store admin wants to save custom type of data for attribute’s option and you need to manage an image according to the attribute’s option. So for each option of the multiselect attribute option there is an image associated with it. In this case one of the method to sort out the things is to create a module that gives you an GUI to save option’s data in custom table and give option to upload the image along with it. Later, use this tables data as source of the attribute for product. The first part, saving the data in custom option is not our concern. You can go through this for doing those. But the main point of this article is to use the custom source as source of the muliselect attributes. Assumming that first part, i.e. the saving of options are already done, you will now need to create a product attributes through SQL Setup [source language=”php”] <?php $installer = $this; $setup = new Mage_Eav_Model_Entity_Setup(‘core_setup’); $installer->startSetup(); $setup->addAttribute(‘catalog_product’, ‘my_attribute’, array( ‘input’ => ‘multiselect’, ‘required’ => false, ‘type’ => ‘text’, ‘label’ => ‘My Attribute Label’, ‘source’ => ‘mymodule/source_option’, ‘backend’ => ‘mymodule/backend_option’, ‘global’ => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_STORE, ‘visible’ => 1, )); $installer->startSetup(); $installer->endSetup(); [/source] The source of the attribute is set to some Model, Ynamespace_Mymodule_Model_Source_Option. This file should look like this. [source language=”php”] <?php class Ynamespace_Module_Model_Source_Option extends Mage_Eav_Model_Entity_Attribute_Source_Table { public function getAllOptions() { return $this->getOptionFromTable(); } private function getOptionFromTable(){ $return=array(); $col=Mage::getModel("modules/model")->getCollection(); /** * Given that table has column as id,title,image_name * */ foreach($col as $row){ array_push($return,array(‘label’=>$row->getTitle(),’value’=>$row->getId())); } return $return; } public function getOptionText($value) { $options = $this->getAllOptions(); foreach ($options as $option) { if(is_array($value)){ if (in_array($option[‘value’],$value)) { return $option[‘label’]; } } else{ if ($option[‘value’]==$value) { return $option[‘label’]; } } } return false; } } [/source] As you can see that the option are retrieved from the custom table in label and value pair. Remember that getAllOptions is called during product export/import as well. Next important thing you must know is the backend model. Backend model comes into play when you save and load the product. Let me explain. Let us consider a case when you are saving product. The option of this multiselect attribute is sent in post variables as array, but the values cannot be saved as array, either you have to serialize it or implode it into string to save. So to do this change, backend model is there. Similarly, on load you need to explode or unserialize the data from the database to array. So the major functions of backend model are beforeSave() and afterLoad(), which are triggerd as product is saved or loaded. The backend model should look like this: [source language=”php”] <?php class Ynamespace_Modules_Model_Backend_Option extends Mage_Eav_Model_Entity_Attribute_Backend_Abstract { /** * Before Attribute Save Process * * @param Varien_Object $object * @return Mage_Catalog_Model_Category_Attribute_Backend_Sortby */ public function beforeSave($object) { $attributeCode = $this->getAttribute()->getName(); if ($attributeCode == ‘my_attribute’) { $data = $object->getData($attributeCode); if (!is_array($data)) { $data = array(); } $object->setData($attributeCode, join(‘,’, $data)); } return $this; } public function afterLoad($object) { $attributeCode = $this->getAttribute()->getName(); if ($attributeCode == ‘my_attribute’) { $data = $object->getData($attributeCode); if ($data) { $object->setData($attributeCode, split(‘,’, $data)); } } return $this; } } [/source] Now you are all set, you should have the values of the multiselect attribute saved in database joined by comma seperated values and while on load those values will be exploded as array. Last thing you can do is export the product data using default profile and check if the error shows up or not regarding this attributes. Must not! I think I’ve checked its integrity with import and export as well. If it shows any, feel free to contact me.