Making Magento flying like a rocket!
A set of valuable tips for developers
Ivan Chepurnyi
Co Owner / Trainer
EcomDev BV
Ivan Chepurnyi
About me
Developers Paradise
• Technical Consultant, Co-owner at EcomDev B.V.
• Was one of the first five d...
Ivan Chepurnyi
Lecture Overview
Developers Paradise
• Common Developer Mistakes
• Tips for regular Magento Stores
• Dealin...
Ivan Chepurnyi
Mistake #0
Developers Paradise
Developing a store without turning on flat
version of products and categories
Ivan Chepurnyi
Mistake #1
Developers Paradise
Using of model load in the template to
access property that is not available...
Ivan Chepurnyi
Mistake #1
Developers Paradise
public getMySuperProductAttribute($product)
{
$myProduct = Mage::getModel(„c...
Ivan Chepurnyi
Mistake #1
Developers Paradise
<p class=“my-attribute”>
<?php echo $this->helper(„my_helper‟)
->getMySuperP...
Ivan Chepurnyi
Mistake #1
Developers Paradise
• Usually Affected Models
– Product Model
• Caused by need to access some cu...
Ivan Chepurnyi
Solution for Product Listing
Developers Paradise
// In case of new attribute
$this->addAttribute(„catalog_p...
Ivan Chepurnyi
Solution for Category Collection
Developers Paradise
<frontend>
<category>
<collection>
<your_custom_attrib...
Ivan Chepurnyi
Solution for Category Tree (Flat)
Developers Paradise
<frontend>
<events>
<catalog_category_flat_loadnodes_...
Ivan Chepurnyi
Solution for Category Tree (Flat)
Developers Paradise
public function addCustomAttribute($observer)
{
$sele...
Ivan Chepurnyi
Solution for Category Tree (Flat)
Developers Paradise
public function addAttributesToSelect ($select, $attr...
Ivan Chepurnyi
Solution for Stock Item
Developers Paradise
<frontend>
<events>
<catalog_product_collection_load_after>
<cl...
Ivan Chepurnyi
Solution for Stock Item
Developers Paradise
public function addStockItemData($observer)
{
$collection = $ob...
Ivan Chepurnyi
Mistake #2
Developers Paradise
Using of full collection load where it is not
needed.
Ivan Chepurnyi
Mistake #2
Developers Paradise
public function isCategoryHasSaleableProducts($category)
{
$collection = Mag...
Ivan Chepurnyi
Solutions
Developers Paradise
• Write a resource model for making query to find this data in
stock and prod...
Ivan Chepurnyi
Summary
Developers Paradise
• Always develop with flat version of catalog turned on
• Never use model load ...
Ivan Chepurnyi
If you write your code correctly…
Developers Paradise
It is time to get your hands dirty in core
optimizati...
Ivan Chepurnyi
Regular Store Bottlenecks
Developers Paradise
• Overall Problems
• Category Pages
• Product Pages
• Checkou...
Ivan Chepurnyi Developers Paradise
Overall Problems
Ivan Chepurnyi
Problem #1
Developers Paradise
Non optimized layout handles usage
Magento adds on every category and produc...
Ivan Chepurnyi
Solution
Developers Paradise
Add an observer to controller_action_layout_load_before,
check loaded handles ...
Ivan Chepurnyi
Solution
Developers Paradise
public function optimizeLayout($observer)
{
$update = $observer->getLayout()->...
Ivan Chepurnyi
Problem #2
Developers Paradise
No cache for CMS Blocks
Magento doesn‟t cache them by default. On average pr...
Ivan Chepurnyi
Solution
Developers Paradise
Add an observer to core_block_abstract_to_html_before,
and specify required ca...
Ivan Chepurnyi
Solution
Developers Paradise
public function optimizeCmsBlocksCache($observer)
{
if ($block instanceof Mage...
Ivan Chepurnyi
Problem #3
Developers Paradise
Magento top menu
Since CE 1.7 version of Magento, they moved menu to another...
Ivan Chepurnyi
Solution
Developers Paradise
1. Add a cache tags via observer similar to optimization of
CMS blocks. The di...
Ivan Chepurnyi
Solution
Developers Paradise
public function optimizeNavigationCache($observer)
{
if ($block instanceof Mag...
Ivan Chepurnyi
Solution
Developers Paradise
protected function _getMenuItemClasses(Varien_Data_Tree_Node $item)
{
$classes...
Ivan Chepurnyi
Solution
Developers Paradise
JS implementation is up to you.
I believe you can do that yourself :)
Ivan Chepurnyi Developers Paradise
Category Pages & Product Pages
Ivan Chepurnyi
Problem #1
Developers Paradise
Layered Navigation
For each attribute you have in Magento and that is marked...
Ivan Chepurnyi
Solution
Developers Paradise
• Remove collection usage usage for each item by rewriting
Mage_Eav_Model_Enti...
Ivan Chepurnyi
What it does?
Developers Paradise
// This one will use collection getData() method
// to retrieve array ite...
Ivan Chepurnyi
Problem #2
Developers Paradise
Dropdown Options on Product Page
The problem is the same as with layered nav...
Ivan Chepurnyi
Problem #3
Developers Paradise
Configurable Products
Magento is not using flat version of products for conf...
Ivan Chepurnyi
Solution
Developers Paradise
1. Rewrite the class with this long name:
Mage_Catalog_Model_Resource_Product_...
Ivan Chepurnyi
Solution
Developers Paradise
public function isEnabledFlat()
{
return Mage_Catalog_Model_Resource_Product_C...
Ivan Chepurnyi Developers Paradise
Checkout Pages
Ivan Chepurnyi
Problem #1
Developers Paradise
Catalog Price Rules
Each time when Magento calls collectTotals() method on
q...
Ivan Chepurnyi
Solution
Developers Paradise
1. Rewrite Mage_CatalogRule_Model_Observer class and
create a new method that ...
Ivan Chepurnyi
Solution
Developers Paradise
public function beforeCollectTotals(Varien_Event_Observer $observer)
{
// … Om...
Ivan Chepurnyi
There are more issues…
Developers Paradise
But it is too much for one presentation :)
Let‟s better talk abo...
Ivan Chepurnyi Developers Paradise
Are you using Varnish for your projects?
Ivan Chepurnyi
Varnish Issues
Developers Paradise
Common issues caused by developers, when they use
Varnish on the project...
Ivan Chepurnyi
ESI include is an evil for Magento
Developers Paradise
Only when the content for ESI include can be cached ...
Ivan Chepurnyi
AJAX Callbacks Issue
Developers Paradise
AJAX call should be done only when needed.
Do not perform a bunch ...
Ivan Chepurnyi
Use Cookies & HTML5!
Developers Paradise
• You can always set a custom cookie in Magento when
customer:
– A...
Ivan Chepurnyi
How it can help you?
Developers Paradise
• You can decrease amount of AJAX calls to the number of
real user...
Ivan Chepurnyi
Recently Viewed Products
Developers Paradise
For recently viewed products, you even don‟t need to make any
...
Ivan Chepurnyi
Conclusion
Developers Paradise
Be smart and use Varnish correctly!
Ivan Chepurnyi
There is more to come…
Developers Paradise
EcomDev is currently working on replacing of Magento flat
catalo...
Ivan Chepurnyi Developers Paradise
Thank You!
Questions?
Upcoming SlideShare
Loading in...5
×

Making Magento flying like a rocket! (A set of valuable tips for developers)

22,943

Published on

Published in: Technology
3 Comments
26 Likes
Statistics
Notes
No Downloads
Views
Total Views
22,943
On Slideshare
0
From Embeds
0
Number of Embeds
14
Actions
Shares
0
Downloads
201
Comments
3
Likes
26
Embeds 0
No embeds

No notes for slide

Making Magento flying like a rocket! (A set of valuable tips for developers)

  1. 1. Making Magento flying like a rocket! A set of valuable tips for developers Ivan Chepurnyi Co Owner / Trainer EcomDev BV
  2. 2. Ivan Chepurnyi About me Developers Paradise • 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
  3. 3. Ivan Chepurnyi Lecture Overview Developers Paradise • Common Developer Mistakes • Tips for regular Magento Stores • Dealing with high loaded projects
  4. 4. Ivan Chepurnyi Mistake #0 Developers Paradise Developing a store without turning on flat version of products and categories
  5. 5. Ivan Chepurnyi Mistake #1 Developers Paradise Using of model load in the template to access property that is not available in the collection
  6. 6. Ivan Chepurnyi Mistake #1 Developers Paradise public getMySuperProductAttribute($product) { $myProduct = Mage::getModel(„catalog/product‟)->load($product- >getId()); return $myProduct->getMySuperProductAttribute(); } Some Helper
  7. 7. Ivan Chepurnyi Mistake #1 Developers Paradise <p class=“my-attribute”> <?php echo $this->helper(„my_helper‟) ->getMySuperProductAttribute($product);?> </p> Product List Template
  8. 8. Ivan Chepurnyi Mistake #1 Developers Paradise • 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
  9. 9. Ivan Chepurnyi Solution for Product Listing Developers Paradise // 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 ); Your install script
  10. 10. Ivan Chepurnyi Solution for Category Collection Developers Paradise <frontend> <category> <collection> <your_custom_attribute_code /> </collection> </category> </frontend> Your config.xml file
  11. 11. Ivan Chepurnyi Solution for Category Tree (Flat) Developers Paradise <frontend> <events> <catalog_category_flat_loadnodes_before> <class>your_module/observer</class> <method>addCustomAttribute</method> </catalog_category_flat_loadnodes_before> </events> </frontend> In your config.xml
  12. 12. Ivan Chepurnyi Solution for Category Tree (Flat) Developers Paradise public function addCustomAttribute($observer) { $select = $observer->getSelect(); $attributes = array(„attribute_code1‟, „attribute_code2‟, „attribute_code3‟); Mage::getResourceSingleton(„your_module/observer) ->addAttributesToSelect($select, $attributes); } In your Observer
  13. 13. Ivan Chepurnyi Solution for Category Tree (Flat) Developers Paradise public function addAttributesToSelect ($select, $attributes) { $select->columns($attributes, „main_table‟); } In your Observer Resource
  14. 14. Ivan Chepurnyi Solution for Stock Item Developers Paradise <frontend> <events> <catalog_product_collection_load_after> <class>your_module/observer</class> <method>addStockItemData</method> </catalog_product_collection_load_after> </events> </frontend> In your config.xml
  15. 15. Ivan Chepurnyi Solution for Stock Item Developers Paradise public function addStockItemData($observer) { $collection = $observer->getCollection(); Mage::getSingleton('cataloginventory/stock') ->addItemsToProducts($collection); } In your Observer
  16. 16. Ivan Chepurnyi Mistake #2 Developers Paradise Using of full collection load where it is not needed.
  17. 17. Ivan Chepurnyi Mistake #2 Developers Paradise 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(); } Code in block
  18. 18. Ivan Chepurnyi Solutions Developers Paradise • 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.
  19. 19. Ivan Chepurnyi Summary Developers Paradise • 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.
  20. 20. Ivan Chepurnyi If you write your code correctly… Developers Paradise It is time to get your hands dirty in core optimizations!
  21. 21. Ivan Chepurnyi Regular Store Bottlenecks Developers Paradise • Overall Problems • Category Pages • Product Pages • Checkout Pages
  22. 22. Ivan Chepurnyi Developers Paradise Overall Problems
  23. 23. Ivan Chepurnyi Problem #1 Developers Paradise 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!
  24. 24. Ivan Chepurnyi Solution Developers Paradise 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.
  25. 25. Ivan Chepurnyi Solution Developers Paradise 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); } } } Example of Observer
  26. 26. Ivan Chepurnyi Problem #2 Developers Paradise No cache for CMS Blocks Magento doesn‟t cache them by default. On average projects you have up to 10-20 CMS blocks that can be edited by customer on every page.
  27. 27. Ivan Chepurnyi Solution Developers Paradise 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).
  28. 28. Ivan Chepurnyi Solution Developers Paradise 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); } } Example of Observer
  29. 29. Ivan Chepurnyi Problem #3 Developers Paradise 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 100-300mson building top menu! And the more categories you have, the more time is spent!
  30. 30. Ivan Chepurnyi Solution Developers Paradise 1. 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 2. Rewrite Mage_Page_Block_Html_Topmenu to add category id into the menu node class name. Yes, there is no event for this :( 3. Add JS on the page that will use current category id for highlighting top menu item.
  31. 31. Ivan Chepurnyi Solution Developers Paradise 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); } } Example of Observer
  32. 32. Ivan Chepurnyi Solution Developers Paradise protected function _getMenuItemClasses(Varien_Data_Tree_Node $item) { $classes = parent::_getMenuItemClasses($item); // Will be something like category-node-#id $classes[] = $item->getId(); return $classes; } Overridden Block Method
  33. 33. Ivan Chepurnyi Solution Developers Paradise JS implementation is up to you. I believe you can do that yourself :)
  34. 34. Ivan Chepurnyi Developers Paradise Category Pages & Product Pages
  35. 35. Ivan Chepurnyi Problem #1 Developers Paradise 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.
  36. 36. Ivan Chepurnyi Solution Developers Paradise • 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: http://bit.ly/mageoption
  37. 37. Ivan Chepurnyi What it does? Developers Paradise // 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(); On the first call to getAllOptions() it will preload all attribute values for current store in array format.
  38. 38. Ivan Chepurnyi Problem #2 Developers Paradise 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.
  39. 39. Ivan Chepurnyi Problem #3 Developers Paradise 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.
  40. 40. Ivan Chepurnyi Solution Developers Paradise 1. Rewrite the class with this long name: Mage_Catalog_Model_Resource_Product_Type_Configurable_Product_Collection 2. Overriden isEnabledFlat() method that should return the real information about flat availability. 1. Make sure that attributes, that your customer is using, are included into the flat version of catalog. Mark them as “used_in_product_listing”.
  41. 41. Ivan Chepurnyi Solution Developers Paradise public function isEnabledFlat() { return Mage_Catalog_Model_Resource_Product_Collection::isEnabledFlat(); } Overriden Collection Method
  42. 42. Ivan Chepurnyi Developers Paradise Checkout Pages
  43. 43. Ivan Chepurnyi Problem #1 Developers Paradise 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.
  44. 44. Ivan Chepurnyi Solution Developers Paradise 1. Rewrite Mage_CatalogRule_Model_Observer class and create a new method that will preload rule prices for quote. 2. Define $_preloadedPrices property to cache results per quote object. 3. 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: http://bit.ly/magerule
  45. 45. Ivan Chepurnyi Solution Developers Paradise 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; } } Created method code
  46. 46. Ivan Chepurnyi There are more issues… Developers Paradise But it is too much for one presentation :) Let‟s better talk about high loaded projects!
  47. 47. Ivan Chepurnyi Developers Paradise Are you using Varnish for your projects?
  48. 48. Ivan Chepurnyi Varnish Issues Developers Paradise 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
  49. 49. Ivan Chepurnyi ESI include is an evil for Magento Developers Paradise 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.
  50. 50. Ivan Chepurnyi AJAX Callbacks Issue Developers Paradise 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.
  51. 51. Ivan Chepurnyi Use Cookies & HTML5! Developers Paradise • 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.
  52. 52. Ivan Chepurnyi How it can help you? Developers Paradise • 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!
  53. 53. Ivan Chepurnyi Recently Viewed Products Developers Paradise 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!
  54. 54. Ivan Chepurnyi Conclusion Developers Paradise Be smart and use Varnish correctly!
  55. 55. Ivan Chepurnyi There is more to come… Developers Paradise 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: http://www.ecomdev.org/contact-us Or email us: info@ecodmev.org
  56. 56. Ivan Chepurnyi Developers Paradise Thank You!
  57. 57. Questions?
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×