SlideShare a Scribd company logo
1 of 65
Download to read offline
REAL USE CASES OF PERFORMANCE OPTIMISATION
MAGENTO 2
by Max Pronko
ABOUT ME
➤ former Magento core member
➤ CTO at TheIrishStore and
GiftsDirect
➤ Founder of Pronko Consulting
➤ 7+ years of Magento Experience
➤ Magento 2 Blog
AGENDA
➤ Performance Optimisation
➤ eCommerce Website Data
➤ Real Improvements
➤ Varnish
➤ Q&A
www.maxpronko.com
PERFORMANCE
www.maxpronko.com
PERFORMANCE
Refers to the speed in which pages are
downloaded and displayed on the user’s browser
www.maxpronko.com
IS PERFORMANCE IMPORTANT?
➤ Customer Experience
➤ Conversion Rate
➤ Organic Search
www.maxpronko.com
PERFORMANCE OPTIMISATION
www.maxpronko.com Image: Fast and Furious
STEPS OF PERFORMANCE TUNING
➤ Assess the problem
➤ Measure performance
➤ Identify part of the system critical for performance
improvement
➤ Modify part of system to remove the bottleneck
➤ Measure the performance after modification
➤ If better, adopt it or revert
https://en.wikipedia.org/wiki/Performance_tuningwww.maxpronko.com
ECOMMERCE WEBSITE PROFILE
➤ Seasonal business
➤ 4k products
➤ 500 Configurable Products
➤ 2k Configurable Variations
➤ 1.5k Simple Products
➤ 500 Categories
➤ Average Order Value: $100
➤ 2-3 products per Order
www.maxpronko.com
BEFORE VS AFTER OPTIMISATION
Before
Category Page
Product Page
Shopping Cart
Checkout Index
0 500 1000 1500 2000
Magento 2 Application
www.maxpronko.com
BEFORE VS AFTER OPTIMISATION
After
Category Page
Product Page
Shopping Cart
Checkout Index
0 500 1000 1500 2000
Magento 2 Application
www.maxpronko.com
MAGENTO 2 APPLICATION
www.maxpronko.com
MAGENTO 2 APPLICATION
Optimisations
www.maxpronko.com
MAGENTO 2 APPLICATION
914 318ms ms
Before After
www.maxpronko.com
LET’S START
Image: mezzotint.dewww.maxpronko.com
DISABLE UNUSED
CORE MODULES
www.maxpronko.com
FOR EXISTING MAGENTO 2 INSTALLATION
> bin/magento module:disable Magento_Downloadable
> bin/magento setup:upgrade
> bin/magento setup:di:compile
> bin/magento setup:static-content:deploy
www.maxpronko.com
COMPOSER.JSON
{
"repositories": [

{

"type": "composer",

"url": "https://repo.magento.com/"

}

],
"require": {
"magento/composer": "~1.0.0",

"magento/framework": "100.1.1",

"magento/language-en_us": "100.1.0",

"magento/magento-composer-installer": "*",

"magento/magento2-base": “2.1.1”,
...
},
}
www.maxpronko.com
WHAT TO DISABLE?
➤ Extra Languages
➤ Offline shipping and payments
➤ Backup, Captcha, Persistent, Rss
➤ Msrp, Send Friend, Weee
➤ Multishipping, Checkout Agreements
➤ Product types?
➤ More… depends on project
www.maxpronko.com
DISABLE UNUSED FEATURES
www.maxpronko.com
HOW TO DISABLE
FEATURES?
www.maxpronko.com
DISABLING FEATURES
➤ Observer
➤ Plugin
➤ Layout
www.maxpronko.com
MAGENTO REPORTS
➤ vendor/magento/module-reports/etc/frontend/events.xml
<config>

<event name="catalog_product_compare_remove_product">

<observer name="reports" instance="MagentoReportsObserverCatalogProductCompareClearObserver" />

</event>

<event name="customer_login">

<observer name="reports" instance="MagentoReportsObserverCustomerLoginObserver" />

</event>

<event name="customer_logout">

<observer name="reports" instance="MagentoReportsObserverCustomerLogoutObserver" />

</event>

<event name="catalog_controller_product_view">

<observer name="reports" instance="MagentoReportsObserverCatalogProductViewObserver" />

</event>

<event name="sendfriend_product">

<observer name="reports" instance="MagentoReportsObserverSendfriendProductObserver" />

</event>

<event name="catalog_product_compare_add_product">

<observer name="reports" instance="MagentoReportsObserverCatalogProductCompareAddProductObserver" />

</event>

<event name="catalog_product_compare_item_collection_clear">

<observer name="reports" instance="MagentoReportsObserverCatalogProductCompareClearObserver" />

</event>

<event name="sales_quote_item_save_before">

<observer name="reports" instance="MagentoReportsObserverCheckoutCartAddProductObserver" />

</event>

<event name="wishlist_add_product">

<observer name="reports" instance="MagentoReportsObserverWishlistAddProductObserver" />

</event>

<event name="wishlist_share">

<observer name="reports" instance="MagentoReportsObserverWishlistShareObserver" />

</event>

</config>

www.maxpronko.com
DISABLE OBSERVERS
➤ app/code/Pronko/Performance/etc/frontend/events.xml


<config>

<event name="catalog_product_compare_remove_product">

<observer name="reports" disabled="true" />

</event>

<event name="catalog_controller_product_view">

<observer name="reports" disabled="true" />

</event>

<event name="sendfriend_product">

<observer name="reports" disabled="true" />

</event>

<event name="catalog_product_compare_add_product">

<observer name="reports" disabled="true" />

</event>

<event name="catalog_product_compare_item_collection_clear">

<observer name="reports" disabled="true" />

</event>

<event name="wishlist_add_product">

<observer name="reports" disabled="true" />

</event>

<event name="wishlist_share">

<observer name="reports" disabled="true" />

</event>

</config>

www.maxpronko.com
DISABLE VIA PLUGIN
➤ app/code/Pronko/Performance/etc/di.xml


<config>

<type name="MagentoBackendModelMenu">

<arguments>

<argument name="logger" xsi:type="object">PsrLogNullLogger</argument>

</arguments>

</type>

<type name="MagentoFrameworkCacheInvalidateLogger">

<plugin name="DisableCacheInvalidateLog" type="PronkoPerformancePluginInvalidateLoggerPlugin" />

</type>

</config>
www.maxpronko.com
REMOVE BLOCKS FROM LAYOUT
➤ Debug Hints
➤ Find non-used Blocks
➤ Remove it
www.maxpronko.com
REMOVE BLOCKS FROM LAYOUT
➤ default.xml


<referenceBlock name="copyright" remove="true" />

<referenceBlock name="store_switcher" remove="true" />

<referenceBlock name="store_language" remove="true" />

<referenceBlock name="store.settings.language" remove="true" />

<referenceBlock name="translate" remove="true" />
➤ catalog_product_view.xml


<referenceBlock name="product.price.tier" remove="true"/>

<referenceBlock name="product.info.upsell" remove="true"/>

<referenceBlock name="product.info.extrahint.qtyincrements" remove="true"/>

<referenceBlock name="product.tooltip" remove="true"/>

<referenceBlock name="product.info.mailto" remove="true"/>
www.maxpronko.com
HOW ABOUT BLOCK
CACHE?
www.maxpronko.com
BLOCK CACHE
➤ Reduce number of Database queries
➤ Collection Load
➤ Template processing
➤ Eliminate Inline Translation
www.maxpronko.com
ABSTRACT BLOCK CLASS
public function toHtml()

{

$html = $this->_loadCache();

if ($html === false) {



$this->_beforeToHtml();

$html = $this->_toHtml();

$this->_saveCache($html);



}

$html = $this->_afterToHtml($html);



return $html;

}
www.maxpronko.com
ABSTRACT BLOCK CLASS
public function toHtml()

{

$html = $this->_loadCache();

if ($html === false) {



$this->_beforeToHtml();

$html = $this->_toHtml();

$this->_saveCache($html);



}

$html = $this->_afterToHtml($html);



return $html;

}
no more final :)
www.maxpronko.com
ABSTRACT BLOCK CLASS
protected function _loadCache()

{

if ($this->getCacheLifetime() === null || !$this->_cacheState-
>isEnabled(self::CACHE_GROUP)) {

return false;

}

$cacheKey = $this->getCacheKey();

$cacheData = $this->_cache->load($cacheKey);

if ($cacheData) {

$cacheData = str_replace(//placeholder, //value,

$cacheData

);

}

return $cacheData;

}
www.maxpronko.com
CATEGORY PAGE
www.maxpronko.com
CACHED BLOCKS
Navigation
Product
Price
www.maxpronko.com
Breadcrumb
Layered
Navigation
Product
Product List
NON-CACHED BLOCKS
www.maxpronko.com
LETS USE BLOCK CACHE
www.maxpronko.com
BREADCRUMBS BLOCK
default.xml
<referenceBlock name="breadcrumbs">

<arguments>

<argument name="cache_lifetime" xsi:type="string">604800</argument>

</arguments>

</referenceBlock>
www.maxpronko.com
LAYERED NAVIGATION BLOCK
➤ Layer State Key
➤ Category
➤ Customer Group
➤ Store
➤ Filters
➤ Currency
www.maxpronko.com
LAYERED NAVIGATION BLOCK
<referenceBlock name="catalog.leftnav">

<arguments>

<argument name="cache_lifetime" xsi:type="number">604800</argument>

</arguments>

</referenceBlock>
catalog_category_view.xml
www.maxpronko.com
LAYERED NAVIGATION PLUGIN DECLARATION
di.xml
<config>

<type name="MagentoLayeredNavigationBlockNavigation">

<plugin name="LayeredNavigationCacheKey" type="PronkoPerformancePlugin
LayeredNavigationPlugin"/>

</type>

<type name="MagentoLayeredNavigationBlockNavigationCategory">

<plugin name="LayeredNavigationCacheKey" type="PronkoPerformancePlugin
LayeredNavigationPlugin"/>

</type>

</config>
www.maxpronko.com
LAYERED NAVIGATION PLUGIN
class LayeredNavigationPlugin

{

public function afterGetCacheKey(Navigation $block, $cacheKey)

{

$cacheKey .= $this->priceCurrency->getCurrency()->getCurrencyCode();



$category = $block->getLayer()->getCurrentCategory();

if ($category) {

$cacheKey .= $category->getId();

}



$stateKey = $block->getLayer()->getStateKey();

if ($stateKey) {

$cacheKey .= $stateKey;

}



$cacheKey .= $this->toolbarModel->getCurrentPage();

$cacheKey .= $this->toolbarModel->getDirection();

$cacheKey .= $this->toolbarModel->getLimit();

$cacheKey .= $this->toolbarModel->getMode();

$cacheKey .= $this->toolbarModel->getOrder();



return $cacheKey;

}

}
www.maxpronko.com
PRODUCT LIST
<?php

$_productCollection = $block->getLoadedProductCollection();

$_helper = $this->helper('MagentoCatalogHelperOutput');

?>

<?php if (!$_productCollection->count()): ?>

<div class="message info empty"><div><?php /* @escapeNotVerified */ echo __('We can't find products matching the selection.') ?></div></div>

<?php else: ?>

<?php echo $block->getToolbarHtml() ?>

<?php echo $block->getAdditionalHtml() ?>

<?php

if ($block->getMode() == 'grid') {

$viewMode = 'grid';

$image = 'category_page_grid';

$showDescription = false;

$templateType = MagentoCatalogBlockProductReviewRendererInterface::SHORT_VIEW;

} else {

$viewMode = 'list';

$image = 'category_page_list';

$showDescription = true;

$templateType = MagentoCatalogBlockProductReviewRendererInterface::FULL_VIEW;

}

/**

* Position for actions regarding image size changing in vde if needed

*/

$pos = $block->getPositioned();

?>

<div class="products wrapper <?php /* @escapeNotVerified */ echo $viewMode; ?> products-<?php /* @escapeNotVerified */ echo $viewMode; ?>">

<?php $iterator = 1; ?>

<ol class="products list items product-items">

<?php /** @var $_product MagentoCatalogModelProduct */ ?>

<?php foreach ($_productCollection as $_product): ?>

<?php /* @escapeNotVerified */ echo($iterator++ == 1) ? '<li class="item product product-item">' : '</li><li class="item product product-item">' ?>

<div class="product-item-info" data-container="product-grid">

<?php

$productImage = $block->getImage($_product, $image);

if ($pos != null) {

$position = ' style="left:' . $productImage->getWidth() . 'px;'

. 'top:' . $productImage->getHeight() . 'px;"';

}

?>

<?php // Product Image ?>

<a href="<?php /* @escapeNotVerified */ echo $_product->getProductUrl() ?>" class="product photo product-item-photo" tabindex="-1">

<?php echo $productImage->toHtml(); ?>

</a>

<div class="product details product-item-details">

<?php

$_productNameStripped = $block->stripTags($_product->getName(), null, true);

?>

<strong class="product name product-item-name">

<a class="product-item-link"

href="<?php /* @escapeNotVerified */ echo $_product->getProductUrl() ?>">

<?php /* @escapeNotVerified */ echo $_helper->productAttribute($_product, $_product->getName(), 'name'); ?>

</a>

</strong>

<?php echo $block->getReviewsSummaryHtml($_product, $templateType); ?>

<?php /* @escapeNotVerified */ echo $block->getProductPrice($_product) ?>

<?php echo $block->getProductDetailsHtml($_product); ?>



<div class="product-item-inner">

<div class="product actions product-item-actions"<?php echo strpos($pos, $viewMode . '-actions') ? $position : ''; ?>>

<div class="actions-primary"<?php echo strpos($pos, $viewMode . '-primary') ? $position : ''; ?>>

<?php if ($_product->isSaleable()): ?>

<?php $postParams = $block->getAddToCartPostParams($_product); ?>

<form data-role="tocart-form" action="<?php /* @escapeNotVerified */ echo $postParams['action']; ?>" method="post">

<input type="hidden" name="product" value="<?php /* @escapeNotVerified */ echo $postParams['data']['product']; ?>">

<input type="hidden" name="<?php /* @escapeNotVerified */ echo Action::PARAM_NAME_URL_ENCODED; ?>" value="<?php /* @escapeNotVerified */ echo $postParams['data'][Action::PARAM_NAME_URL_ENCODED]; ?>">

<?php echo $block->getBlockHtml('formkey')?>

<button type="submit"

title="<?php echo $block->escapeHtml(__('Add to Cart')); ?>"

class="action tocart primary">

<span><?php /* @escapeNotVerified */ echo __('Add to Cart') ?></span>

</button>

</form>

<?php else: ?>

<?php if ($_product->getIsSalable()): ?>

<div class="stock available"><span><?php /* @escapeNotVerified */ echo __('In stock') ?></span></div>

<?php else: ?>

<div class="stock unavailable"><span><?php /* @escapeNotVerified */ echo __('Out of stock') ?></span></div>

<?php endif; ?>

<?php endif; ?>

</div>

<div data-role="add-to-links" class="actions-secondary"<?php echo strpos($pos, $viewMode . '-secondary') ? $position : ''; ?>>

<?php if ($this->helper('MagentoWishlistHelperData')->isAllow()): ?>

<a href="#"

class="action towishlist"

title="<?php echo $block->escapeHtml(__('Add to Wish List')); ?>"

aria-label="<?php echo $block->escapeHtml(__('Add to Wish List')); ?>"

data-post='<?php /* @escapeNotVerified */ echo $block->getAddToWishlistParams($_product); ?>'

data-action="add-to-wishlist"

role="button">

<span><?php /* @escapeNotVerified */ echo __('Add to Wish List') ?></span>

</a>

<?php endif; ?>

<?php

$compareHelper = $this->helper('MagentoCatalogHelperProductCompare');

?>

<a href="#"

class="action tocompare"

title="<?php echo $block->escapeHtml(__('Add to Compare')); ?>"

aria-label="<?php echo $block->escapeHtml(__('Add to Compare')); ?>"

data-post='<?php /* @escapeNotVerified */ echo $compareHelper->getPostDataParams($_product); ?>'

role="button">

<span><?php /* @escapeNotVerified */ echo __('Add to Compare') ?></span>

</a>

</div>

PRODUCT LIST
➤ Copy list.phtml and move foreach from the template
➤ Create new ProductList block class
➤ Create new Product/Item block class and item.phtml template
➤ Don’t forget about unique cacheKeyInfo
➤ Layered navigation, filter, toolbar, currency
➤ Set cache_lifetime value for both block classes
www.maxpronko.com
NEW PRODUCT LIST TEMPLATE
<?php if (!$block->getLoadedProductCollection()->count()): ?>

<div class="message info empty"><div><?php /* @escapeNotVerified */ echo __('We can't find products matching the selection.') ?></
div></div>

<?php else: ?>

<?php echo $block->getToolbarHtml() ?>

<?php echo $block->getAdditionalHtml() ?>

<div class="products wrapper <?php /* @escapeNotVerified */ echo $block->getViewMode(); ?> products-<?php /* @escapeNotVerified */
$block->getViewMode(); ?>">

<ol class="products list items product-items" itemscope itemtype="http://schema.org/ItemList">

<?php echo $block->getProductsListHtml(); ?>

</ol>

</div>

<?php echo $block->getToolbarHtml() ?>

<?php if (!$block->isRedirectToCartEnabled()) : ?>

<script type="text/x-magento-init">

{

"[data-role=tocart-form], .form.map.checkout": {

"catalogAddToCart": {}

}

}

</script>

<?php endif; ?>

<?php endif; ?>
app/design/Pronko/default/Magento_Catalog/templates/product/list.phtml
www.maxpronko.com
CATEGORY PAGE - CACHED
www.maxpronko.com
RELATED PRODUCTS
Product Page
www.maxpronko.com
PRODUCT PAGE
www.maxpronko.com
33 Attributes EAV Tables
ACTIONS
➤ Don’t use getAttributesUsedInProductListing() method
➤ Decrease number of attributes loaded
➤ Decrease number of EAV Tables usage on product page
➤ Enable block cache for each related product
ATTRIBUTES CONFIG
namespace MagentoCatalogModel;



class Config extends MagentoEavModelConfig

{
public function getProductAttributes()

{

if (is_null($this->_productAttributes)) {

$this->_productAttributes = array_keys($this->getAttributesUsedInProductListing());

}

return $this->_productAttributes;

}
}
ATTRIBUTES CONFIG
namespace PronkoPerformanceModelConfig;



class Related extends MagentoCatalogModelConfig

{

const XML_PATH_PRODUCT_RELATED_ATTRIBUTES = 'catalog/related_product_attributes';



public function getProductAttributes()

{

return array_keys($this->_scopeConfig->getValue(self::XML_PATH_PRODUCT_RELATED_ATTRIBUTES));

}

}

CONFIGURATION
<virtualType name="PronkoPerformanceProductRelatedContext" type="MagentoCatalogBlockProductContext">

<arguments>

<argument name="catalogConfig" xsi:type="object">PronkoPerformanceModelConfigRelated</argument>

</arguments>

</virtualType>



<type name="PronkoPerformanceBlockProductListRelated">

<arguments>

<argument name="context" xsi:type="object">PronkoPerformanceProductRelatedContext</argument>

</arguments>

</type>
di.xml
<config>

<default>

<catalog>

<related_product_attributes>

<name />

<tax_class_id />

<small_image />

<image_label />

<special_price />

</related_product_attributes>

</catalog>

</default>

</config>

config.xml
CATALOG_PRODUCT_VIEW.XML
<referenceBlock name="catalog.product.related" remove="true" />
<referenceContainer name="content.aside">

<block class="PronkoPerformanceBlockProductListRelated" name="pronko.catalog.product.related"
template="Magento_Catalog::product/list/items.phtml">

<arguments>

<argument name="type" xsi:type="string">related</argument>

</arguments>

</block>

</referenceContainer>
3RD PARTY MODULES
www.maxpronko.com
DOUBLE CHECK
➤ HTTP POST requests
➤ Collections usage
➤ Slow file/database operations
➤ Performance Tests on staging server
www.maxpronko.com
VARNISH
www.maxpronko.com
X-MAGENTO-VARY
➤ Customer Logged In
➤ Customer Group
➤ Customer Segment (EE only)
➤ Store
➤ Currency
➤ Tax Rates
www.maxpronko.com
X-MAGENTO-VARY
X-Magento-Vary = MD5(context data)
sub vcl_hash {

if (req.http.cookie ~ "X-Magento-Vary=") {

hash_data(regsub(req.http.cookie, "^.*?X-Magento-Vary=([^;]+);*.*$", "1"));

}



if (req.http.host) {

hash_data(req.http.host);

} else {

hash_data(server.ip);

}

}
www.maxpronko.com
VARNISH HASH DATA
➤ 1 Website, no customer groups, same content for guest and logged in
➤ GeoIP functionality
sub vcl_hash {

if (req.url ~ "(?|&)(utm_source|utm_medium|utm_campaign|utm_content|gclid)=") {
set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|utm_content|
gclid)=([^&]+)", "");
set req.url = regsuball(req.url, "?(utm_source|utm_medium|utm_campaign|utm_content|
gclid)=([^&]+)", "?");
set req.url = regsub(req.url, "?&", "?");
set req.url = regsub(req.url, "?$", "");
}
hash_data(req.http.X-Currency);

}
www.maxpronko.com
VARNISH PERFORMANCE BEST PRACTICES
➤ Warmup pages after website content update
➤ Plan content changes ahead
➤ Run cron to clean up cache, reindex and warmup
www.maxpronko.com
WHAT ELSE?
www.maxpronko.com
MORE PERFORMANCE OPTIMISATIONS
➤ Remove Compare Products feature
➤ Minify and merge JavaScript and CSS
➤ Enable Async Order Grid
➤ Enable Async Transactional Emails
www.maxpronko.com
TRACKING AND MARKETING
➤ Asynchronous script loading for everything
➤ Google Tag Manager is good for async
➤ Avoid additional collection loads for Facebook, adWords, etc.
www.maxpronko.com
PERFORMANCE TOOLS
www.maxpronko.com
SUMMARY
➤ Disable functionality
➤ Use block cache
➤ Optimise/reduce database queries
➤ Remove unused blocks, observers
➤ Warmup all pages
➤ Never stop improving your website
www.maxpronko.com
THANK YOU
max_pronko
Q&A Time
www.maxpronko.com

More Related Content

What's hot

What's hot (20)

Git and git workflow best practice
Git and git workflow best practiceGit and git workflow best practice
Git and git workflow best practice
 
Service Oriented Architecture in Magento 2
Service Oriented Architecture in Magento 2Service Oriented Architecture in Magento 2
Service Oriented Architecture in Magento 2
 
Minimum Viable Architecture - Good Enough is Good Enough
Minimum Viable Architecture - Good Enough is Good EnoughMinimum Viable Architecture - Good Enough is Good Enough
Minimum Viable Architecture - Good Enough is Good Enough
 
Introduction to Feature Toggle and FF4J
Introduction to Feature Toggle and FF4JIntroduction to Feature Toggle and FF4J
Introduction to Feature Toggle and FF4J
 
Gitflow - Branching and Merging Flow for Git
Gitflow - Branching and Merging Flow for GitGitflow - Branching and Merging Flow for Git
Gitflow - Branching and Merging Flow for Git
 
Git & Github for beginners
Git & Github for beginnersGit & Github for beginners
Git & Github for beginners
 
International SEO for E-Commerce Websites #SEJLive #SEJeSummit
International SEO for E-Commerce Websites #SEJLive #SEJeSummitInternational SEO for E-Commerce Websites #SEJLive #SEJeSummit
International SEO for E-Commerce Websites #SEJLive #SEJeSummit
 
Trunk-based Development with Feature toggles
Trunk-based Development with Feature togglesTrunk-based Development with Feature toggles
Trunk-based Development with Feature toggles
 
GitLab Premium 라이선스 기능소개 - 인포그랩
GitLab Premium 라이선스 기능소개 - 인포그랩GitLab Premium 라이선스 기능소개 - 인포그랩
GitLab Premium 라이선스 기능소개 - 인포그랩
 
Git training v10
Git training v10Git training v10
Git training v10
 
Trunk based development for Beginners
Trunk based development for BeginnersTrunk based development for Beginners
Trunk based development for Beginners
 
Magento 2 Design Patterns
Magento 2 Design PatternsMagento 2 Design Patterns
Magento 2 Design Patterns
 
Magento2.3 - GraphQL introduction
Magento2.3  - GraphQL introductionMagento2.3  - GraphQL introduction
Magento2.3 - GraphQL introduction
 
Key Insights into Development Design Patterns for Magento 2 - Magento Live UK
Key Insights into Development Design Patterns for Magento 2 - Magento Live UKKey Insights into Development Design Patterns for Magento 2 - Magento Live UK
Key Insights into Development Design Patterns for Magento 2 - Magento Live UK
 
Svelte
SvelteSvelte
Svelte
 
Go micro framework to build microservices
Go micro framework to build microservicesGo micro framework to build microservices
Go micro framework to build microservices
 
Gerrit Code Review: how to script a plugin with Scala and Groovy
Gerrit Code Review: how to script a plugin with Scala and GroovyGerrit Code Review: how to script a plugin with Scala and Groovy
Gerrit Code Review: how to script a plugin with Scala and Groovy
 
GITS Class #16: CI/CD (Continuous Integration & Continuous Deployment) with G...
GITS Class #16: CI/CD (Continuous Integration & Continuous Deployment) with G...GITS Class #16: CI/CD (Continuous Integration & Continuous Deployment) with G...
GITS Class #16: CI/CD (Continuous Integration & Continuous Deployment) with G...
 
The secret web performance metric no one is talking about
The secret web performance metric no one is talking aboutThe secret web performance metric no one is talking about
The secret web performance metric no one is talking about
 
InnoDB Locking Explained with Stick Figures
InnoDB Locking Explained with Stick FiguresInnoDB Locking Explained with Stick Figures
InnoDB Locking Explained with Stick Figures
 

Similar to Real use cases of performance optimization in magento 2

Exploiting the newer perl to improve your plugins
Exploiting the newer perl to improve your pluginsExploiting the newer perl to improve your plugins
Exploiting the newer perl to improve your plugins
Marian Marinov
 
Widget Summit 2008
Widget Summit 2008Widget Summit 2008
Widget Summit 2008
Volkan Unsal
 
WordPress Security - ওয়ার্ডপ্রেসের সিকিউরিটি
WordPress Security - ওয়ার্ডপ্রেসের সিকিউরিটিWordPress Security - ওয়ার্ডপ্রেসের সিকিউরিটি
WordPress Security - ওয়ার্ডপ্রেসের সিকিউরিটি
Faysal Shahi
 

Similar to Real use cases of performance optimization in magento 2 (20)

Using Geeklog as a Web Application Framework
Using Geeklog as a Web Application FrameworkUsing Geeklog as a Web Application Framework
Using Geeklog as a Web Application Framework
 
More Secrets of JavaScript Libraries
More Secrets of JavaScript LibrariesMore Secrets of JavaScript Libraries
More Secrets of JavaScript Libraries
 
Php
PhpPhp
Php
 
How Bitbucket Pipelines Loads Connect UI Assets Super-fast
How Bitbucket Pipelines Loads Connect UI Assets Super-fastHow Bitbucket Pipelines Loads Connect UI Assets Super-fast
How Bitbucket Pipelines Loads Connect UI Assets Super-fast
 
Exploiting the newer perl to improve your plugins
Exploiting the newer perl to improve your pluginsExploiting the newer perl to improve your plugins
Exploiting the newer perl to improve your plugins
 
WordPress APIs
WordPress APIsWordPress APIs
WordPress APIs
 
Network Automation: Ansible 102
Network Automation: Ansible 102Network Automation: Ansible 102
Network Automation: Ansible 102
 
Google Back To Front: From Gears to App Engine and Beyond
Google Back To Front: From Gears to App Engine and BeyondGoogle Back To Front: From Gears to App Engine and Beyond
Google Back To Front: From Gears to App Engine and Beyond
 
Magento Performance Optimization 101
Magento Performance Optimization 101Magento Performance Optimization 101
Magento Performance Optimization 101
 
T5 Oli Aro
T5 Oli AroT5 Oli Aro
T5 Oli Aro
 
Widget Summit 2008
Widget Summit 2008Widget Summit 2008
Widget Summit 2008
 
企业级软件的组件化和动态化开发实践
企业级软件的组件化和动态化开发实践企业级软件的组件化和动态化开发实践
企业级软件的组件化和动态化开发实践
 
JUDCon London 2011 - Bin packing with drools planner by example
JUDCon London 2011 - Bin packing with drools planner by exampleJUDCon London 2011 - Bin packing with drools planner by example
JUDCon London 2011 - Bin packing with drools planner by example
 
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac..."Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
 
WordPress Security - ওয়ার্ডপ্রেসের সিকিউরিটি
WordPress Security - ওয়ার্ডপ্রেসের সিকিউরিটিWordPress Security - ওয়ার্ডপ্রেসের সিকিউরিটি
WordPress Security - ওয়ার্ডপ্রেসের সিকিউরিটি
 
Aug Xml Net Forum Dynamics Integration
Aug Xml Net Forum Dynamics IntegrationAug Xml Net Forum Dynamics Integration
Aug Xml Net Forum Dynamics Integration
 
Profiling PHP with Xdebug / Webgrind
Profiling PHP with Xdebug / WebgrindProfiling PHP with Xdebug / Webgrind
Profiling PHP with Xdebug / Webgrind
 
Accelerated Mobile Pages (AMP) in Magento
Accelerated Mobile Pages (AMP) in MagentoAccelerated Mobile Pages (AMP) in Magento
Accelerated Mobile Pages (AMP) in Magento
 
Things to consider for testable Code
Things to consider for testable CodeThings to consider for testable Code
Things to consider for testable Code
 
Intro To Django
Intro To DjangoIntro To Django
Intro To Django
 

More from Max Pronko

Zepplin_Pronko_Magento_Festival Hall 1_Final
Zepplin_Pronko_Magento_Festival Hall 1_FinalZepplin_Pronko_Magento_Festival Hall 1_Final
Zepplin_Pronko_Magento_Festival Hall 1_Final
Max Pronko
 

More from Max Pronko (6)

Mastering Declarative Database Schema - MageConf 2019
Mastering Declarative Database Schema - MageConf 2019Mastering Declarative Database Schema - MageConf 2019
Mastering Declarative Database Schema - MageConf 2019
 
Checkout Customizations in Magento 2 - MageTitansMCR 2017
Checkout Customizations in Magento 2 - MageTitansMCR 2017Checkout Customizations in Magento 2 - MageTitansMCR 2017
Checkout Customizations in Magento 2 - MageTitansMCR 2017
 
Magento 2 Deployment Automation: from 6 hours to 15 minutes - Max Pronko
Magento 2 Deployment Automation: from 6 hours to 15 minutes - Max PronkoMagento 2 Deployment Automation: from 6 hours to 15 minutes - Max Pronko
Magento 2 Deployment Automation: from 6 hours to 15 minutes - Max Pronko
 
Checkout in Magento 2 by Max Pronko
Checkout in Magento 2 by Max PronkoCheckout in Magento 2 by Max Pronko
Checkout in Magento 2 by Max Pronko
 
Ups and Downs of Real Projects Based on Magento 2
Ups and Downs of Real Projects Based on Magento 2Ups and Downs of Real Projects Based on Magento 2
Ups and Downs of Real Projects Based on Magento 2
 
Zepplin_Pronko_Magento_Festival Hall 1_Final
Zepplin_Pronko_Magento_Festival Hall 1_FinalZepplin_Pronko_Magento_Festival Hall 1_Final
Zepplin_Pronko_Magento_Festival Hall 1_Final
 

Recently uploaded

%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
masabamasaba
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
masabamasaba
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
VishalKumarJha10
 

Recently uploaded (20)

%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban
 

Real use cases of performance optimization in magento 2

  • 1. REAL USE CASES OF PERFORMANCE OPTIMISATION MAGENTO 2 by Max Pronko
  • 2. ABOUT ME ➤ former Magento core member ➤ CTO at TheIrishStore and GiftsDirect ➤ Founder of Pronko Consulting ➤ 7+ years of Magento Experience ➤ Magento 2 Blog
  • 3. AGENDA ➤ Performance Optimisation ➤ eCommerce Website Data ➤ Real Improvements ➤ Varnish ➤ Q&A www.maxpronko.com
  • 5. PERFORMANCE Refers to the speed in which pages are downloaded and displayed on the user’s browser www.maxpronko.com
  • 6. IS PERFORMANCE IMPORTANT? ➤ Customer Experience ➤ Conversion Rate ➤ Organic Search www.maxpronko.com
  • 8. STEPS OF PERFORMANCE TUNING ➤ Assess the problem ➤ Measure performance ➤ Identify part of the system critical for performance improvement ➤ Modify part of system to remove the bottleneck ➤ Measure the performance after modification ➤ If better, adopt it or revert https://en.wikipedia.org/wiki/Performance_tuningwww.maxpronko.com
  • 9. ECOMMERCE WEBSITE PROFILE ➤ Seasonal business ➤ 4k products ➤ 500 Configurable Products ➤ 2k Configurable Variations ➤ 1.5k Simple Products ➤ 500 Categories ➤ Average Order Value: $100 ➤ 2-3 products per Order www.maxpronko.com
  • 10. BEFORE VS AFTER OPTIMISATION Before Category Page Product Page Shopping Cart Checkout Index 0 500 1000 1500 2000 Magento 2 Application www.maxpronko.com
  • 11. BEFORE VS AFTER OPTIMISATION After Category Page Product Page Shopping Cart Checkout Index 0 500 1000 1500 2000 Magento 2 Application www.maxpronko.com
  • 14. MAGENTO 2 APPLICATION 914 318ms ms Before After www.maxpronko.com
  • 17. FOR EXISTING MAGENTO 2 INSTALLATION > bin/magento module:disable Magento_Downloadable > bin/magento setup:upgrade > bin/magento setup:di:compile > bin/magento setup:static-content:deploy www.maxpronko.com
  • 18. COMPOSER.JSON { "repositories": [
 {
 "type": "composer",
 "url": "https://repo.magento.com/"
 }
 ], "require": { "magento/composer": "~1.0.0",
 "magento/framework": "100.1.1",
 "magento/language-en_us": "100.1.0",
 "magento/magento-composer-installer": "*",
 "magento/magento2-base": “2.1.1”, ... }, } www.maxpronko.com
  • 19. WHAT TO DISABLE? ➤ Extra Languages ➤ Offline shipping and payments ➤ Backup, Captcha, Persistent, Rss ➤ Msrp, Send Friend, Weee ➤ Multishipping, Checkout Agreements ➤ Product types? ➤ More… depends on project www.maxpronko.com
  • 22. DISABLING FEATURES ➤ Observer ➤ Plugin ➤ Layout www.maxpronko.com
  • 23. MAGENTO REPORTS ➤ vendor/magento/module-reports/etc/frontend/events.xml <config>
 <event name="catalog_product_compare_remove_product">
 <observer name="reports" instance="MagentoReportsObserverCatalogProductCompareClearObserver" />
 </event>
 <event name="customer_login">
 <observer name="reports" instance="MagentoReportsObserverCustomerLoginObserver" />
 </event>
 <event name="customer_logout">
 <observer name="reports" instance="MagentoReportsObserverCustomerLogoutObserver" />
 </event>
 <event name="catalog_controller_product_view">
 <observer name="reports" instance="MagentoReportsObserverCatalogProductViewObserver" />
 </event>
 <event name="sendfriend_product">
 <observer name="reports" instance="MagentoReportsObserverSendfriendProductObserver" />
 </event>
 <event name="catalog_product_compare_add_product">
 <observer name="reports" instance="MagentoReportsObserverCatalogProductCompareAddProductObserver" />
 </event>
 <event name="catalog_product_compare_item_collection_clear">
 <observer name="reports" instance="MagentoReportsObserverCatalogProductCompareClearObserver" />
 </event>
 <event name="sales_quote_item_save_before">
 <observer name="reports" instance="MagentoReportsObserverCheckoutCartAddProductObserver" />
 </event>
 <event name="wishlist_add_product">
 <observer name="reports" instance="MagentoReportsObserverWishlistAddProductObserver" />
 </event>
 <event name="wishlist_share">
 <observer name="reports" instance="MagentoReportsObserverWishlistShareObserver" />
 </event>
 </config>
 www.maxpronko.com
  • 24. DISABLE OBSERVERS ➤ app/code/Pronko/Performance/etc/frontend/events.xml 
 <config>
 <event name="catalog_product_compare_remove_product">
 <observer name="reports" disabled="true" />
 </event>
 <event name="catalog_controller_product_view">
 <observer name="reports" disabled="true" />
 </event>
 <event name="sendfriend_product">
 <observer name="reports" disabled="true" />
 </event>
 <event name="catalog_product_compare_add_product">
 <observer name="reports" disabled="true" />
 </event>
 <event name="catalog_product_compare_item_collection_clear">
 <observer name="reports" disabled="true" />
 </event>
 <event name="wishlist_add_product">
 <observer name="reports" disabled="true" />
 </event>
 <event name="wishlist_share">
 <observer name="reports" disabled="true" />
 </event>
 </config>
 www.maxpronko.com
  • 25. DISABLE VIA PLUGIN ➤ app/code/Pronko/Performance/etc/di.xml 
 <config>
 <type name="MagentoBackendModelMenu">
 <arguments>
 <argument name="logger" xsi:type="object">PsrLogNullLogger</argument>
 </arguments>
 </type>
 <type name="MagentoFrameworkCacheInvalidateLogger">
 <plugin name="DisableCacheInvalidateLog" type="PronkoPerformancePluginInvalidateLoggerPlugin" />
 </type>
 </config> www.maxpronko.com
  • 26. REMOVE BLOCKS FROM LAYOUT ➤ Debug Hints ➤ Find non-used Blocks ➤ Remove it www.maxpronko.com
  • 27. REMOVE BLOCKS FROM LAYOUT ➤ default.xml 
 <referenceBlock name="copyright" remove="true" />
 <referenceBlock name="store_switcher" remove="true" />
 <referenceBlock name="store_language" remove="true" />
 <referenceBlock name="store.settings.language" remove="true" />
 <referenceBlock name="translate" remove="true" /> ➤ catalog_product_view.xml 
 <referenceBlock name="product.price.tier" remove="true"/>
 <referenceBlock name="product.info.upsell" remove="true"/>
 <referenceBlock name="product.info.extrahint.qtyincrements" remove="true"/>
 <referenceBlock name="product.tooltip" remove="true"/>
 <referenceBlock name="product.info.mailto" remove="true"/> www.maxpronko.com
  • 29. BLOCK CACHE ➤ Reduce number of Database queries ➤ Collection Load ➤ Template processing ➤ Eliminate Inline Translation www.maxpronko.com
  • 30. ABSTRACT BLOCK CLASS public function toHtml()
 {
 $html = $this->_loadCache();
 if ($html === false) {
 
 $this->_beforeToHtml();
 $html = $this->_toHtml();
 $this->_saveCache($html);
 
 }
 $html = $this->_afterToHtml($html);
 
 return $html;
 } www.maxpronko.com
  • 31. ABSTRACT BLOCK CLASS public function toHtml()
 {
 $html = $this->_loadCache();
 if ($html === false) {
 
 $this->_beforeToHtml();
 $html = $this->_toHtml();
 $this->_saveCache($html);
 
 }
 $html = $this->_afterToHtml($html);
 
 return $html;
 } no more final :) www.maxpronko.com
  • 32. ABSTRACT BLOCK CLASS protected function _loadCache()
 {
 if ($this->getCacheLifetime() === null || !$this->_cacheState- >isEnabled(self::CACHE_GROUP)) {
 return false;
 }
 $cacheKey = $this->getCacheKey();
 $cacheData = $this->_cache->load($cacheKey);
 if ($cacheData) {
 $cacheData = str_replace(//placeholder, //value,
 $cacheData
 );
 }
 return $cacheData;
 } www.maxpronko.com
  • 36. LETS USE BLOCK CACHE www.maxpronko.com
  • 37. BREADCRUMBS BLOCK default.xml <referenceBlock name="breadcrumbs">
 <arguments>
 <argument name="cache_lifetime" xsi:type="string">604800</argument>
 </arguments>
 </referenceBlock> www.maxpronko.com
  • 38. LAYERED NAVIGATION BLOCK ➤ Layer State Key ➤ Category ➤ Customer Group ➤ Store ➤ Filters ➤ Currency www.maxpronko.com
  • 39. LAYERED NAVIGATION BLOCK <referenceBlock name="catalog.leftnav">
 <arguments>
 <argument name="cache_lifetime" xsi:type="number">604800</argument>
 </arguments>
 </referenceBlock> catalog_category_view.xml www.maxpronko.com
  • 40. LAYERED NAVIGATION PLUGIN DECLARATION di.xml <config>
 <type name="MagentoLayeredNavigationBlockNavigation">
 <plugin name="LayeredNavigationCacheKey" type="PronkoPerformancePlugin LayeredNavigationPlugin"/>
 </type>
 <type name="MagentoLayeredNavigationBlockNavigationCategory">
 <plugin name="LayeredNavigationCacheKey" type="PronkoPerformancePlugin LayeredNavigationPlugin"/>
 </type>
 </config> www.maxpronko.com
  • 41. LAYERED NAVIGATION PLUGIN class LayeredNavigationPlugin
 {
 public function afterGetCacheKey(Navigation $block, $cacheKey)
 {
 $cacheKey .= $this->priceCurrency->getCurrency()->getCurrencyCode();
 
 $category = $block->getLayer()->getCurrentCategory();
 if ($category) {
 $cacheKey .= $category->getId();
 }
 
 $stateKey = $block->getLayer()->getStateKey();
 if ($stateKey) {
 $cacheKey .= $stateKey;
 }
 
 $cacheKey .= $this->toolbarModel->getCurrentPage();
 $cacheKey .= $this->toolbarModel->getDirection();
 $cacheKey .= $this->toolbarModel->getLimit();
 $cacheKey .= $this->toolbarModel->getMode();
 $cacheKey .= $this->toolbarModel->getOrder();
 
 return $cacheKey;
 }
 } www.maxpronko.com
  • 42. PRODUCT LIST <?php
 $_productCollection = $block->getLoadedProductCollection();
 $_helper = $this->helper('MagentoCatalogHelperOutput');
 ?>
 <?php if (!$_productCollection->count()): ?>
 <div class="message info empty"><div><?php /* @escapeNotVerified */ echo __('We can't find products matching the selection.') ?></div></div>
 <?php else: ?>
 <?php echo $block->getToolbarHtml() ?>
 <?php echo $block->getAdditionalHtml() ?>
 <?php
 if ($block->getMode() == 'grid') {
 $viewMode = 'grid';
 $image = 'category_page_grid';
 $showDescription = false;
 $templateType = MagentoCatalogBlockProductReviewRendererInterface::SHORT_VIEW;
 } else {
 $viewMode = 'list';
 $image = 'category_page_list';
 $showDescription = true;
 $templateType = MagentoCatalogBlockProductReviewRendererInterface::FULL_VIEW;
 }
 /**
 * Position for actions regarding image size changing in vde if needed
 */
 $pos = $block->getPositioned();
 ?>
 <div class="products wrapper <?php /* @escapeNotVerified */ echo $viewMode; ?> products-<?php /* @escapeNotVerified */ echo $viewMode; ?>">
 <?php $iterator = 1; ?>
 <ol class="products list items product-items">
 <?php /** @var $_product MagentoCatalogModelProduct */ ?>
 <?php foreach ($_productCollection as $_product): ?>
 <?php /* @escapeNotVerified */ echo($iterator++ == 1) ? '<li class="item product product-item">' : '</li><li class="item product product-item">' ?>
 <div class="product-item-info" data-container="product-grid">
 <?php
 $productImage = $block->getImage($_product, $image);
 if ($pos != null) {
 $position = ' style="left:' . $productImage->getWidth() . 'px;'
 . 'top:' . $productImage->getHeight() . 'px;"';
 }
 ?>
 <?php // Product Image ?>
 <a href="<?php /* @escapeNotVerified */ echo $_product->getProductUrl() ?>" class="product photo product-item-photo" tabindex="-1">
 <?php echo $productImage->toHtml(); ?>
 </a>
 <div class="product details product-item-details">
 <?php
 $_productNameStripped = $block->stripTags($_product->getName(), null, true);
 ?>
 <strong class="product name product-item-name">
 <a class="product-item-link"
 href="<?php /* @escapeNotVerified */ echo $_product->getProductUrl() ?>">
 <?php /* @escapeNotVerified */ echo $_helper->productAttribute($_product, $_product->getName(), 'name'); ?>
 </a>
 </strong>
 <?php echo $block->getReviewsSummaryHtml($_product, $templateType); ?>
 <?php /* @escapeNotVerified */ echo $block->getProductPrice($_product) ?>
 <?php echo $block->getProductDetailsHtml($_product); ?>
 
 <div class="product-item-inner">
 <div class="product actions product-item-actions"<?php echo strpos($pos, $viewMode . '-actions') ? $position : ''; ?>>
 <div class="actions-primary"<?php echo strpos($pos, $viewMode . '-primary') ? $position : ''; ?>>
 <?php if ($_product->isSaleable()): ?>
 <?php $postParams = $block->getAddToCartPostParams($_product); ?>
 <form data-role="tocart-form" action="<?php /* @escapeNotVerified */ echo $postParams['action']; ?>" method="post">
 <input type="hidden" name="product" value="<?php /* @escapeNotVerified */ echo $postParams['data']['product']; ?>">
 <input type="hidden" name="<?php /* @escapeNotVerified */ echo Action::PARAM_NAME_URL_ENCODED; ?>" value="<?php /* @escapeNotVerified */ echo $postParams['data'][Action::PARAM_NAME_URL_ENCODED]; ?>">
 <?php echo $block->getBlockHtml('formkey')?>
 <button type="submit"
 title="<?php echo $block->escapeHtml(__('Add to Cart')); ?>"
 class="action tocart primary">
 <span><?php /* @escapeNotVerified */ echo __('Add to Cart') ?></span>
 </button>
 </form>
 <?php else: ?>
 <?php if ($_product->getIsSalable()): ?>
 <div class="stock available"><span><?php /* @escapeNotVerified */ echo __('In stock') ?></span></div>
 <?php else: ?>
 <div class="stock unavailable"><span><?php /* @escapeNotVerified */ echo __('Out of stock') ?></span></div>
 <?php endif; ?>
 <?php endif; ?>
 </div>
 <div data-role="add-to-links" class="actions-secondary"<?php echo strpos($pos, $viewMode . '-secondary') ? $position : ''; ?>>
 <?php if ($this->helper('MagentoWishlistHelperData')->isAllow()): ?>
 <a href="#"
 class="action towishlist"
 title="<?php echo $block->escapeHtml(__('Add to Wish List')); ?>"
 aria-label="<?php echo $block->escapeHtml(__('Add to Wish List')); ?>"
 data-post='<?php /* @escapeNotVerified */ echo $block->getAddToWishlistParams($_product); ?>'
 data-action="add-to-wishlist"
 role="button">
 <span><?php /* @escapeNotVerified */ echo __('Add to Wish List') ?></span>
 </a>
 <?php endif; ?>
 <?php
 $compareHelper = $this->helper('MagentoCatalogHelperProductCompare');
 ?>
 <a href="#"
 class="action tocompare"
 title="<?php echo $block->escapeHtml(__('Add to Compare')); ?>"
 aria-label="<?php echo $block->escapeHtml(__('Add to Compare')); ?>"
 data-post='<?php /* @escapeNotVerified */ echo $compareHelper->getPostDataParams($_product); ?>'
 role="button">
 <span><?php /* @escapeNotVerified */ echo __('Add to Compare') ?></span>
 </a>
 </div>

  • 43. PRODUCT LIST ➤ Copy list.phtml and move foreach from the template ➤ Create new ProductList block class ➤ Create new Product/Item block class and item.phtml template ➤ Don’t forget about unique cacheKeyInfo ➤ Layered navigation, filter, toolbar, currency ➤ Set cache_lifetime value for both block classes www.maxpronko.com
  • 44. NEW PRODUCT LIST TEMPLATE <?php if (!$block->getLoadedProductCollection()->count()): ?>
 <div class="message info empty"><div><?php /* @escapeNotVerified */ echo __('We can't find products matching the selection.') ?></ div></div>
 <?php else: ?>
 <?php echo $block->getToolbarHtml() ?>
 <?php echo $block->getAdditionalHtml() ?>
 <div class="products wrapper <?php /* @escapeNotVerified */ echo $block->getViewMode(); ?> products-<?php /* @escapeNotVerified */ $block->getViewMode(); ?>">
 <ol class="products list items product-items" itemscope itemtype="http://schema.org/ItemList">
 <?php echo $block->getProductsListHtml(); ?>
 </ol>
 </div>
 <?php echo $block->getToolbarHtml() ?>
 <?php if (!$block->isRedirectToCartEnabled()) : ?>
 <script type="text/x-magento-init">
 {
 "[data-role=tocart-form], .form.map.checkout": {
 "catalogAddToCart": {}
 }
 }
 </script>
 <?php endif; ?>
 <?php endif; ?> app/design/Pronko/default/Magento_Catalog/templates/product/list.phtml www.maxpronko.com
  • 45. CATEGORY PAGE - CACHED www.maxpronko.com
  • 48. ACTIONS ➤ Don’t use getAttributesUsedInProductListing() method ➤ Decrease number of attributes loaded ➤ Decrease number of EAV Tables usage on product page ➤ Enable block cache for each related product
  • 49. ATTRIBUTES CONFIG namespace MagentoCatalogModel;
 
 class Config extends MagentoEavModelConfig
 { public function getProductAttributes()
 {
 if (is_null($this->_productAttributes)) {
 $this->_productAttributes = array_keys($this->getAttributesUsedInProductListing());
 }
 return $this->_productAttributes;
 } }
  • 50. ATTRIBUTES CONFIG namespace PronkoPerformanceModelConfig;
 
 class Related extends MagentoCatalogModelConfig
 {
 const XML_PATH_PRODUCT_RELATED_ATTRIBUTES = 'catalog/related_product_attributes';
 
 public function getProductAttributes()
 {
 return array_keys($this->_scopeConfig->getValue(self::XML_PATH_PRODUCT_RELATED_ATTRIBUTES));
 }
 }

  • 51. CONFIGURATION <virtualType name="PronkoPerformanceProductRelatedContext" type="MagentoCatalogBlockProductContext">
 <arguments>
 <argument name="catalogConfig" xsi:type="object">PronkoPerformanceModelConfigRelated</argument>
 </arguments>
 </virtualType>
 
 <type name="PronkoPerformanceBlockProductListRelated">
 <arguments>
 <argument name="context" xsi:type="object">PronkoPerformanceProductRelatedContext</argument>
 </arguments>
 </type> di.xml <config>
 <default>
 <catalog>
 <related_product_attributes>
 <name />
 <tax_class_id />
 <small_image />
 <image_label />
 <special_price />
 </related_product_attributes>
 </catalog>
 </default>
 </config>
 config.xml
  • 52. CATALOG_PRODUCT_VIEW.XML <referenceBlock name="catalog.product.related" remove="true" /> <referenceContainer name="content.aside">
 <block class="PronkoPerformanceBlockProductListRelated" name="pronko.catalog.product.related" template="Magento_Catalog::product/list/items.phtml">
 <arguments>
 <argument name="type" xsi:type="string">related</argument>
 </arguments>
 </block>
 </referenceContainer>
  • 54. DOUBLE CHECK ➤ HTTP POST requests ➤ Collections usage ➤ Slow file/database operations ➤ Performance Tests on staging server www.maxpronko.com
  • 56. X-MAGENTO-VARY ➤ Customer Logged In ➤ Customer Group ➤ Customer Segment (EE only) ➤ Store ➤ Currency ➤ Tax Rates www.maxpronko.com
  • 57. X-MAGENTO-VARY X-Magento-Vary = MD5(context data) sub vcl_hash {
 if (req.http.cookie ~ "X-Magento-Vary=") {
 hash_data(regsub(req.http.cookie, "^.*?X-Magento-Vary=([^;]+);*.*$", "1"));
 }
 
 if (req.http.host) {
 hash_data(req.http.host);
 } else {
 hash_data(server.ip);
 }
 } www.maxpronko.com
  • 58. VARNISH HASH DATA ➤ 1 Website, no customer groups, same content for guest and logged in ➤ GeoIP functionality sub vcl_hash {
 if (req.url ~ "(?|&)(utm_source|utm_medium|utm_campaign|utm_content|gclid)=") { set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|utm_content| gclid)=([^&]+)", ""); set req.url = regsuball(req.url, "?(utm_source|utm_medium|utm_campaign|utm_content| gclid)=([^&]+)", "?"); set req.url = regsub(req.url, "?&", "?"); set req.url = regsub(req.url, "?$", ""); } hash_data(req.http.X-Currency);
 } www.maxpronko.com
  • 59. VARNISH PERFORMANCE BEST PRACTICES ➤ Warmup pages after website content update ➤ Plan content changes ahead ➤ Run cron to clean up cache, reindex and warmup www.maxpronko.com
  • 61. MORE PERFORMANCE OPTIMISATIONS ➤ Remove Compare Products feature ➤ Minify and merge JavaScript and CSS ➤ Enable Async Order Grid ➤ Enable Async Transactional Emails www.maxpronko.com
  • 62. TRACKING AND MARKETING ➤ Asynchronous script loading for everything ➤ Google Tag Manager is good for async ➤ Avoid additional collection loads for Facebook, adWords, etc. www.maxpronko.com
  • 64. SUMMARY ➤ Disable functionality ➤ Use block cache ➤ Optimise/reduce database queries ➤ Remove unused blocks, observers ➤ Warmup all pages ➤ Never stop improving your website www.maxpronko.com