Download presentation
Presentation is loading. Please wait.
1
Making Magento flying like a rocket
Making Magento flying like a rocket! A set of valuable tips for developers Ivan Chepurnyi Co Owner / Trainer EcomDev BV
2
About me Technical Consultant, Co-owner at EcomDev B.V.
Was one of the first five developers in original Magento core team Providing trainings and coaching Magento Developers in Europe Main areas of my expertise: System Architecture Performance Optimization Test Driven Development Complex Customizations Developers Paradise
3
Lecture Overview Common Developer Mistakes
Tips for regular Magento Stores Dealing with high loaded projects Developers Paradise
4
Mistake #0 Developing a store without turning on flat version of products and categories Developers Paradise
5
Mistake #1 Using of model load in the template to access property that is not available in the collection Developers Paradise
6
Mistake #1 Some Helper public getMySuperProductAttribute($product) {
$myProduct = Mage::getModel(‘catalog/product’)->load($product->getId()); return $myProduct->getMySuperProductAttribute(); } Developers Paradise
7
Mistake #1 Product List Template <p class=“my-attribute”>
<?php echo $this->helper(‘my_helper’) ->getMySuperProductAttribute($product);?> </p> Developers Paradise
8
Mistake #1 Usually Affected Models Product Model
Caused by need to access some custom values from product in lists Category Model Caused by need to retrieve some custom text attribute in menu or layered navigation Stock Item Need to access available stock qty in product listings Developers Paradise
9
Solution for Product Listing
Your install script // In case of new attribute $this->addAttribute(‘catalog_product’, ‘custom_attribute_code’, array( // …. your attribute options “used_in_product_listing” => true )); // In case of updating existing attribute $this->updateAttribute( ‘catalog_product’, ‘customer_attribute_code’, ‘used_in_product_listing’, 1 ); Developers Paradise
10
Solution for Category Collection
Your config.xml file <frontend> <category> <collection> <your_custom_attribute_code /> </collection> </category> </frontend> Developers Paradise
11
Solution for Category Tree (Flat)
In your config.xml <frontend> <events> <catalog_category_flat_loadnodes_before> <class>your_module/observer</class> <method>addCustomAttribute</method> </catalog_category_flat_loadnodes_before> </events> </frontend> Developers Paradise
12
Solution for Category Tree (Flat)
In your Observer public function addCustomAttribute($observer) { $select = $observer->getSelect(); $attributes = array(‘attribute_code1’, ‘attribute_code2’, ‘attribute_code3’); Mage::getResourceSingleton(‘your_module/observer) ->addAttributesToSelect($select, $attributes); } Developers Paradise
13
Solution for Category Tree (Flat)
In your Observer Resource public function addAttributesToSelect ($select, $attributes) { $select->columns($attributes, ‘main_table’); } Developers Paradise
14
Solution for Stock Item
In your config.xml <frontend> <events> <catalog_product_collection_load_after> <class>your_module/observer</class> <method>addStockItemData</method> </catalog_product_collection_load_after> </events> </frontend> Developers Paradise
15
Solution for Stock Item
In your Observer public function addStockItemData($observer) { $collection = $observer->getCollection(); Mage::getSingleton('cataloginventory/stock') ->addItemsToProducts($collection); } Developers Paradise
16
Using of full collection load where it is not needed.
Mistake #2 Using of full collection load where it is not needed. Developers Paradise
17
Mistake #2 Code in block public function isCategoryHasSaleableProducts($category) { $collection = Mage::getResourceModel('catalog/product_collection'); $collection ->setStoreId(Mage::app()->getStore()->getId()) ->addCategoryFilter($category); Mage::getSingleton('catalog/product_status’) ->addVisibleFilterToCollection($collection); Mage::getSingleton('catalog/product_visibility') ->addVisibleInCatalogFilterToCollection($collection); return $collection->getFirstItem()->isSaleable(); } Developers Paradise
18
Solutions Write a resource model for making query to find this data in stock and product status tables. Write an indexer that will contain information about salable categories and add this as column to all categories select. Developers Paradise
19
Summary Always develop with flat version of catalog turned on
Never use model load on every collection item, there is always an option to add your custom attribute Never use collection to check for something, they are created to load subset of the data for loading, not for checking. Developers Paradise
20
If you write your code correctly…
It is time to get your hands dirty in core optimizations! Developers Paradise
21
Regular Store Bottlenecks
Overall Problems Category Pages Product Pages Checkout Pages Developers Paradise
22
Overall Problems Developers Paradise
23
Non optimized layout handles usage
Problem #1 Non optimized layout handles usage Magento adds on every category and product page a layout handle with its entity id, so you have layout cache unique for each product or category! Developers Paradise
24
Solution Add an observer to controller_action_layout_load_before, check loaded handles and remove items that match starts with CATEGORY_ and PRODUCT_, except PRODUCT_TYPE. Developers Paradise
25
Solution Example of Observer public function optimizeLayout($observer)
{ $update = $observer->getLayout()->getUpdate(); foreach ($update->getHandles() as $handle) { if (strpos($handle, 'CATEGORY_') === 0 || (strpos($handle, 'PRODUCT_') === 0 && strpos($handle, 'PRODUCT_TYPE_') === false)) { $update->removeHandle($handle); } Developers Paradise
26
Problem #2 No cache for CMS Blocks
Magento doesn’t cache them by default. On average projects you have up to CMS blocks that can be edited by customer on every page. Developers Paradise
27
Solution Add an observer to core_block_abstract_to_html_before, and specify required cache information for the block, like cache key (that is a block identifier) and cache tags (Mage_Cms_Model_Block::CACHE_TAG). Developers Paradise
28
Solution Example of Observer
public function optimizeCmsBlocksCache($observer) { if ($block instanceof Mage_Cms_Block_Widget_Block || $block instanceof Mage_Cms_Block_Block) { $cacheKeyData = array( Mage_Cms_Model_Block::CACHE_TAG, $block->getBlockId(), Mage::app()->getStore()->getId() ); $block->setCacheKey(implode('_', $cacheKeyData)); $block->setCacheTags( array(Mage_Cms_Model_Block::CACHE_TAG) $block->setCacheLifetime(false); } Developers Paradise
29
And the more categories you have, the more time is spent!
Problem #3 Magento top menu Since CE 1.7 version of Magento, they moved menu to another block, but forget to add caching to it. So now each page load spends from mson building top menu! And the more categories you have, the more time is spent! Developers Paradise
30
Solution Add a cache tags via observer similar to optimization of CMS blocks. The difference only, that you will need to add category cache tag instead: Mage_Catalog_Model_Category::CACHE_TAG Rewrite Mage_Page_Block_Html_Topmenu to add category id into the menu node class name. Yes, there is no event for this :( Add JS on the page that will use current category id for highlighting top menu item. Developers Paradise
31
Solution Example of Observer
public function optimizeNavigationCache($observer) { if ($block instanceof Mage_Page_Block_Html_Topmenu) { $cacheKeyData = array( Mage_Catalog_Model_Category::CACHE_TAG, 'NAVIGATION', Mage::app()->getStore()->getCode() ); $block->setCacheKey(implode('_', $cacheKeyData)); $block->setCacheTags( array(Mage_Catalog_Model_Category::CACHE_TAG) $block->setCacheLifetime(false); } Developers Paradise
32
Solution Overridden Block Method
protected function _getMenuItemClasses(Varien_Data_Tree_Node $item) { $classes = parent::_getMenuItemClasses($item); // Will be something like category-node-#id $classes[] = $item->getId(); return $classes; } Developers Paradise
33
Solution JS implementation is up to you.
I believe you can do that yourself :) Developers Paradise
34
Category Pages & Product Pages
Developers Paradise
35
Problem #1 Layered Navigation
For each attribute you have in Magento and that is marked as filtrable, it will make a call to getAllOptions() of attribute source model. Even if there is no filter results for it, it will invoke attribute option collection load. For merchants who have a lot of attributes, it is a huge performance bottleneck. Developers Paradise
36
Solution Remove collection usage usage for each item by rewriting Mage_Eav_Model_Entity_Attribute_Source_Table class. Implement a static method, that will load values for all attributes at once. If you will not use objects, it won’t take too much memory. Override getAllOptions() method to use your static method. You can find class by this url: Developers Paradise
37
What it does? On the first call to getAllOptions() it will preload all attribute values for current store in array format. // This one will use collection getData() method // to retrieve array items instead of collection of objects. Mage::getResourceModel('eav/entity_attribute_option_collection') ->setPositionOrder('asc') ->setStoreFilter($storeId) ->getData(); Developers Paradise
38
Dropdown Options on Product Page
Problem #2 Dropdown Options on Product Page The problem is the same as with layered navigation, but not that much visible if you don’t have too much dropdown attributes to show. Product getOptionText() uses the same getAllOptions() method call. This one is automatically fixed by fixing previous one. Developers Paradise
39
Configurable Products
Problem #3 Configurable Products Magento is not using flat version of products for configurable products children retrieval. So every configurable product page is a bottleneck, especially for fashion retailers. Developers Paradise
40
Solution Rewrite the class with this long name: Mage_Catalog_Model_Resource_Product_Type_Configurable_Product_Collection Overriden isEnabledFlat() method that should return the real information about flat availability. Make sure that attributes, that your customer is using, are included into the flat version of catalog. Mark them as “used_in_product_listing”. Developers Paradise
41
Solution Overriden Collection Method Developers Paradise
public function isEnabledFlat() { return Mage_Catalog_Model_Resource_Product_Collection::isEnabledFlat(); } Developers Paradise
42
Checkout Pages Developers Paradise
43
Problem #1 Catalog Price Rules
Each time when Magento calls collectTotals() method on quote object, it walks though all items in the quote and invoked getFinalPrice() method on your product. This method dispatches catalog_product_get_final_price event, that is observed by Mage_CatalogRule module. Developers Paradise
44
Solution Rewrite Mage_CatalogRule_Model_Observer class and create a new method that will preload rule prices for quote. Define $_preloadedPrices property to cache results per quote object. Add an observer in configuration for sales_quote_collect_totals_before event, for original core class alias, but with the method you’ve created. Full observer class can be found at this url: Developers Paradise
45
Solution Created method code
public function beforeCollectTotals(Varien_Event_Observer $observer) { // … Omited retrieval of product ids and customer group with website $cacheKey = spl_object_hash($quote); if (!isset($this->_preloadedPrices[$cacheKey])) { $this->_preloadedPrices[$cacheKey] = Mage::getResourceSingleton('catalogrule/rule') ->getRulePrices($date, $websiteId, $groupId, $productIds); } foreach ($this->_preloadedPrices[$cacheKey] as $productId => $price) { $key = implode('|', array($date, $websiteId, $groupId, $productId)); $this->_rulePrices[$key] = $price; Developers Paradise
46
There are more issues… But it is too much for one presentation :)
Let’s better talk about high loaded projects! Developers Paradise
47
Are you using Varnish for your projects?
Developers Paradise
48
Varnish Issues Common issues caused by developers, when they use Varnish on the project Developers usually hide poor code quality behind front cache server Doing backend callbacks for functionality that can be fully done by modern browser in JavaScript. Caching static files by Varnish Developers Paradise
49
ESI include is an evil for Magento
Only when the content for ESI include can be cached by Varnish. It doesn’t make to make ESI includes for shopping cart, compare and recently viewed reports. Developers Paradise
50
AJAX call should be done only when needed.
AJAX Callbacks Issue AJAX call should be done only when needed. Do not perform a bunch of calls just because the data should be loaded from the server. It is always possible to decrease amount of calls by using your frontend skills. Developers Paradise
51
Use Cookies & HTML5! You can always set a custom cookie in Magento when customer: Adds a product to a cart Logs in or logs out Adds a product to a compare list You always can store up to 2Mb of data into sessionStorage of your visitor browser! Only IE7 doesn’t support it. Developers Paradise
52
How it can help you? You can decrease amount of AJAX calls to the number of real user actions. Customer adds product to cart, you make an ajax call to update session storage Customer logs in, you make and ajax call to update the it again Customer adds product to wishlist or compare products list, you update a session storage. So in the end it should be1 action – 1 AJAX call, and NOT 1 page view – 1 AJAX call! Developers Paradise
53
Recently Viewed Products
For recently viewed products, you even don’t need to make any AJAX calls Render a hidden block on the product page When customer views a product, add this hidden block to session storage On any other page, just render data by JavaScript! Developers Paradise
54
Be smart and use Varnish correctly!
Conclusion Be smart and use Varnish correctly! Developers Paradise
55
There is more to come… Want to learn more about it?
EcomDev is currently working on replacing of Magento flat catalog with Sphinx search, that will gain incredibly fast response time for non-cached pages. Want to learn more about it? Visit our website: Or us: Developers Paradise
56
Thank You! Developers Paradise
57
Questions?
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.