Chapters Close

How to exclude specific js files from minify?

May 4th, 2020 4 min to read

In this post, I will be guiding you to excluding JavaScript files from minifying. Sometimes it is required to load third-party JavaScript files in our custom module/theme & .min file is not available.

Use Case

  • You are implementing a custom payment method module for the current project:
    • Here you found the payment gateway is providing minified javascript file(s) but file(s) name doesn’t have .min suffix like payment-abc.min.js
  • At this point, you have a tight budget and ETA. You can’t just tell the client or payment gateway refused your request.

How minify js files work in  Magento 2?

At first, you have to enable minify JavaScript JS from Admin or using the command line in production mode.

\> php bin/magento config:set dev/js/minify_files 1

Disable JS merge if enable:
\> php bin/magento config:set dev/js/merge_files 0
\> php bin/magento cache:flush

Then run deploy command:

\> php bin/magento setup:static-content:deploy

Now open the Magento 2 website on the browser and open DevTools, in Network panel it will show the minify js loader file: requirejs-min-resolver.min.js. This file is responsible to open all js files in .min and contains RegEx rules to exclude js files from adding .min suffix. Magento creates this file when JS minify & production mode is enabled.

Let’s do it

Using the above test case:

  • You are implementing a custom payment method module for the current project but JavaScript files of the payment gateway do not have .min suffix and you will  tell Magento 2 to add file path in the requirejs-min-resolver.min.js file.
  • We will add an after plugin on the getExcludes method of Magento\Framework\View\Asset\Minification class. So you got an idea this class is responsible for minifying files in Magento 2.

In your di.xml file at app/code/Vendor/Payment/etc directory:

<type name="Magento\Framework\View\Asset\Minification">
    <plugin name="vendor_prevent_minification" type="Vendor\PaymentModule\Plugin\View\MinificationPlugin" />
</type>

Then create a plugin file: MinificationPlugin.php at app/code/Vendor/Payment/Plugin/View directory:

<?php

namespace Vendor\PaymentModule\Plugin\View;

use \Magento\Framework\View\Asset\Minification;

class MinificationPlugin
{
    /**
     * Exclude static componentry files from being minified.
     *
     * Using the config node `minify_exclude` is not an option because it does
     * not get merged but overridden by subsequent modules.
     *
     * @see \Magento\Framework\View\Asset\Minification::XML_PATH_MINIFICATION_EXCLUDES
     *
     * @param Minification $subject
     * @param string[] $excludes
     * @param string $contentType
     * @return string[]
     */
    public function afterGetExcludes(Minification $subject, array $excludes, $contentType)
    {
         // Here we are checking if not “js” then skip it
         if ($contentType !== 'js') {
            return $excludes; // Skip if contentType is not “js”
         }


         // Array variable adds path to exclude minify
         $excludes[]= 'https://webservices.paymentgateway.net/';
         return $excludes;
     }
}

Now change the Vendor/PaymentModule name as per your module and then run below commands:

\> php bin/magento cache:flush
\> php bin/magento setup:di:compile
\> php bin/magento setup:static-content:deploy

In browser, now check the payment js will open properly because file path is added in requirejs-min-resolver.min.js file.

Conclusion

Excluding JS files from minifying is an out-of-box feature of Magento 2 and it is very helpful when working with third-party services like Google ReCaptcha, Payment methods, shipping methods, email marketing, etc.

Let me know if you found the article helpful so that it will encourage me to write new blogs.

Thank you.

How to call the helper method in phtml template file?

Aug 29th, 2019 3 min to read

A Helper is a class that provides functionalities for various features throughout the Magento website. Available for use anywhere on the website, Magento 2 Helper can be called in controllers, views, models and even in other helpers too!

Here, I will show you how to call a helper class methods in the template files. There’s a small tip for you, we suggest you use the second method.

Method 1: Using $this->helper directly in the template files

In Magento 2 templates there is an object: $this. It is an object of the class. Check below how to call the helper method using $this.

$this->helper('[Vendor]\[Module]\Helper\[Helper Name]')

Use this method as a last resort because as far as we know, calling a helper in your template is equal to using the object manager directly. Thus, we should inject the helper in the constructor of the block. See method 2 given below.

Method 2: By injecting helper in the  constructor of the block class

This is the best practice for using helper in Magento 2. Helper method can be called anywhere in Magento 2 using Dependency Injection. You should not call the helper directly in the template.

To use this helper method, check the below code snippet where you can see the helper instance is dependent on the block,  that renders the template and creates a method in your block, which then calls the helper and calls that method in the template.

Define your block as shown below:

protected $helper;
public function __construct(
    ....
    \{Vendor}\{Module}\Helper\Data $helper,
    ....
) {
    ....
    $this->helper = $helper;
    ....
}

public function callHelperMethod()
{
    return $this->helper->getDataFromHelper();
}

Then you can call the helper in your template with : $block->callHelperMethod()

Conclusion

In this article, I’ve shown you how to call the helper method in .phtml template files. If you still need any help regarding the helper class or Magento, we are happy to help you. Feel free to get in touch!

FAQs

What is template helper code?


Template helper code is the code used to build dynamic templates which are used to simplify HTML tasks. They are included as part of another template code to improve the functionality of the template. There are various helper codes depending on the function such as tag helpers, link helpers, etc.

What is built in helpers?


Built in helpers are helpers already included in the template engine. They are universally available to any developers using the template and usually simplify commonly used functions such as looping or formatting. Some of the commonly used built-in helpers include #if, #unless, #each, #with, and others.

How to use helper in magento2?


To use helper in Magento 2, add the newly created module in a Helper folder. Update the module directory to include the folder. Then, create a data.php file in the Helper folder and update the file with the required code. Edit the index.php file and clear cache to check the helper.

How to call Phtml in Magento 2?


To call phtml in Magento 2, you need to use block code. First, login to the admin dashboard and write the block code in the content of any CMS page. After deploying the code, the phtml appears on the CMS page. You can also call phtml on all CMS pages by using a layout file.

Easiest way to load your custom JS Component in Magento 2

Jun 17th, 2019 6 min to read

In this post, I will be guiding you on creating a JavaScript Component and load it on any page you need.

Let’s do it

Understanding the JS Components in Magento 2

  1. KnockoutJS component – ‘ko’
    • Checkout page is full of knockout js bindings
  2. jQueryUI component – ‘jquery/ui’
    • Add to cart on the product page & product listing page

Note: You cannot mix both the components code within a single JS component.

Technologies usage

  1. RequireJs
    • It is used for dependency management for all the javascript files
  2. KnockoutJs
    • MVVM pattern using data-bind
  3. jQuery UI Widgets
    • Create stateful jQuery plugins using the same abstraction as all jQuery UI widgets.

First create a custom module

KnockoutJS component

In your module’s web directory, create a simple.js.
Like, app/code/Aureatelabs/JSComponent/view/frontend/web/js/simple.js

define([
        'ko',
        'uiComponent'
    ],
    function(ko, Component) {
        'use strict';
        return Component.extend({
            firstName: ko.observable(''),
            initialize: function() {
                this._super();
            }
        });
    });

Create a simple.phtml file in the frontend or CMS block and add below content:

<div data-bind="scope: 'component-name'">First name:
<div><input type="text" data-bind="textInput: firstName" /></div>
</div>
<p>Notes: Magento_Ui/js/core/app - this js is responsible for binding Knockout JS components with the DOM elements then you can use ko methods. Scope attribute - it is used to chain the JS and the HTML DOM together using the knockoutjs. Component-name - Must be unique on the current page. It can be any meaningful word and could be js file name. Use same name used in the</p>

Advantages

  1. You can make use of MVVM technique via data-bind & methods of knockoutjs
  2. Assign external HTML template after js component is loaded
  3. Less dependent on jQuery and use of data-bind any elements is recommended.
  4. Changing the HTML template without modifying .PHTML template file.
  5. i18n translation supported
  6. You can set the default options if not given from the frontend
  7. Reusable code
  8. It can contain a list of components in a group like on the checkout page

Disadvantages

  1. Template is rendered after the JS is loaded in the browser and takes time to display.
  2. External html template is already loaded then the new version will be loaded from the browser cache.

jQuery UI component

This method is used to add events to the HTML element when the JS component is loaded. Here you don’t cannot use the scope binding. While your JS component will get the DOM element object to implement the logic on it.How to use
data-mage-init
attribute is used to bind the HTML DOM with the JS component.
simple2.js

define([
    'jquery',
    'jquery/ui'
], function($) {
    'use strict';

    $.widget('mage.simple2', { // component name = simple2
        options: {
            text: null,
            displayEle: null
        },
        /**
         * Bind handlers to events
         */
        _create: function() {
            console.info(this.options); // print the options in console
            // Save options to the element for later
            this.element.data('options', this.options);
            // Add event and method to the element
            this._on({
                'keyup': $.proxy(this._method, this.element)
            });
        },
        _method: function() {
            // fetch the element options
            var options = this.data('options');
            $(options.displayEle).text(this.val());
        }
    });

    return $.mage.simple2; // return simple2 component
});

Then in your HTML template file use like the below:

<div>
<h2>Simple2 demo</h2>
<label> Name: <input type="text" data-mage-init="{"Aureatelabs_Simple2/js/simple2": { "text": "to-send-in-the-js-file", "displayEle": "#text"} }" /> </label>
<h2>Your text here: <small></small></h2>
</div>
<p>Notes: You can use the alias from the requirejs-config(1) or use the full path of the js file(2): For example: 1. RequireJS alias: <input type="text" data-mage-init="{"simple2": { "text": "to-send-in-the-js-file", "displayEle": "#text"} }" /> 2. RequireJS full path: <input type="text" data-mage-init="{"Aureatelabs_Simple2/js/simple2": { "text": "to-send-in-the-js-file", "displayEle": "#text"} }" /> 3. The data json inside the simple2 object is optional so you can use the empty object like: {} I.e. { "text": "to-send-in-the-js-file", "displayEle": "#text"}</p>

You will see the jQueryUI component:

Advantages

  1. You can use the jQuery UI Widget to create a component
  2. This component has a constructor function _create to initialize your logic
  3. You can set the default options if not given from the frontend
  4. You can trigger this component from the element itself so you don’t have to rely on the page load using data-mage-init.
  5. Reusable code

Disadvantages

  1. You cannot use the knockout js methods and data-bind here.
  2. You cannot use it in the checkout layout customizations.

FAQs

Which JavaScript component is used in magento 2?


The JavaScript component used in Magento 2 is a package of JavaScript libraries & frameworks to build a powerful and flexible front end. These are jQuery, Knockout.js, RequireJS, LESS (CSS preprocessor), UI Widgets, and reusable UI elements. Along with creating custom themes, modules, and features, they dramatically increase page speed and seamlessly handle JS dependency.

How do I merge CSS and js in Magento 2?


To merge CSS and JS in Magento 2, follow the below-mentioned steps –

For CSS:
1. Log in to your Admin Panel and go to Stores —> Settings —> Configuration.
2. Navigate the left panel and expand Developers.
3. Next, select CSS Settings and expand the options.
4. Further, go to Merge CSS Files and set Yes from the dropdown list.
5. Thereafter, click on Save Config

For JS:
1. Repeat the first two steps mentioned above.
2. Now, select JavaScript Settings and expand the options.
3. Next, go to Merge JavaScript Files and set Yes from the dropdown list.
4. Then, click on Save Config.

How to add custom js in checkout page magento 2?


To add custom JS to the checkout page in Magento 2, follow the below-mentioned steps –
1. Create a web directory in the root of your custom module, and inside it, create a js directory.
2. Now, place your custom JS file inside this js directory.
3. Next, create a requirejs-config.js file in the root of your custom module.
4. Inside the above file, define the path of your custom JS file
5. Further, create a layout XML file in your custom module as app/code/Vendor/Module/view/frontend/layout/checkout_index_index.xml.
6. Inside the above file, add the following code to include the custom JS file for the checkout page:
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
 <head>
<script src="Vendor_Module::js/checkout_custom.js"/>
 </head>
</page>

7. Thereafter, run the command php bin/magento setup:static-content:deploy and clear the cache.

How do you add the JS and CSS files into a custom module in magento 2?


To add the JS and CSS into a custom module in Magento 2, follow the below-mentioned steps –
1. Create a web directory in the root of your custom module, and inside it, create two directories: js and css.
2. Place your JS and CSS files inside their respective directories.
3. Create a requirejs-config.js file in the root of your custom module.
4. Define the path of your JS and CSS files
5. Include the JS and CSS files in specific layout/page.
6. Run the command static-content:deploy to enable changes.

Theme Development Best Practices

Mar 11th, 2019 8 min to read

Magento theme structure

Storefront custom themes are located at the app/design/frontend/<Vendor>/ directory.

Magento built-in themes are located at the vendor/magento/theme-frontend-<theme_code> directory when magento is installed using composer.

The structure of a Magento theme directory

theme.xml file

Create theme.xml file to initialize the theme. It contains theme title, the preview image of theme, parent theme from which all layouts, CSS can be inherited by default.

To set parent theme is one of the best practices if you want to inherit default Magento theme and customize it.

There are unlimited levels of parent theme that you can inherit, and they will fall back sequentially until there are no more parents defined.

<theme xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Config/etc/theme.xsd">
     <title>New Theme</title>
     <parent>Magento/luma</parent>
     <media>
         <preview_image>media/preview.jpg</preview_image>
     </media>
</theme>

view.xml file

Create view.xml file to change the type and size of the image or create your own type in the app/design/frontend/<VendorName>/<ThemeName>/etc directory.

<view xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Config/etc/view.xsd">
<media>
<images module="Magento_Catalog">
…
     <image id="category_page_grid" type="small_image">
        <width>250</width>
        <height>250</height>
      </image>
...
    </images>
</media>
</view>

Module and theme layout files

Base layouts:

Layout files provided by modules. Location :
– Page configuration and generic layout files: <module_dir>/view/frontend/layout
– Page layout files: <module_dir>/view/frontend/page_layout

Theme layouts:

Layout files provided by themes. Location :
– Page configuration and generic layout files: <theme_dir>/<Namespace>_<Module>/layout
– Page layout files: <theme_dir>/<Namespace>_<Module>/page_layout

Best practice: Do not modify base design files instead of follow coding standards and extend or override a layout for any modification.

Extend Layout

You can create extending layout files, and modify your code as per your needs. To extend the layout, add layout file at the following location:

<theme_dir>/<Namespace_Module>/layout/layout.xml

For example,
To customize the layout defined in /view/frontend/layout/catalog_product_view.xml, you need to add a layout file with the same name in your custom theme, like the following: /Magento_Catalog/layout/catalog_product_view.xml

Override Layout

If you want to change a large amount of customization, you have to override layout file, This means that the new file that you place in the theme will be used instead of the parent theme layout file of the base layout file.

Override base layouts

To override base layout file, put a layout file with same name at the following location:

<theme_dir>/<Namespace_Module>/layout/override/base/layout.xml

For example,
/Magento_Checkout/layout/override/base/checkout_cart_index.xml

Override theme layouts

To override theme layout file, put a layout file with same name at the following location:

<theme_dir>/<Namespace_Module>/layout/override/theme/<Parent_Vendor>/<Parent_Theme>/layout.xml

For example,
/Magento_Checkout/layout/override/theme/Magento/luma/checkout_cart_index.xml

Do not remove generic blocks from *.phtml files or xml layouts.

If you may have deleted generic blocks from XML layouts, some extensions won’t work. Magento third party extension makes use of the generic block to insert its own new block, if you remove a generic block, there’s a possibility that the third party extension won’t work properly.

Containers and blocks

A container is a structure without content which holds other blocks and containers.

<move> element is used to change the position of block or container, to move an element, you have to refer it with its name and then set destination attribute which can either be a container or a block.

Example:

<move element="name.of.an.element" destination="name.of.destination.element" as="new_alias" before="-"/>

Remove block and container using remove and display attribute of <referenceBlock> / <referenceContainer> element.

  • You can remove block or container from layout by setting value of remove attribute to true, default value of remove attribute is false.

Example:

<referenceBlock name="block.name" remove="true" />
  • <remove> is used to remove static resources linked in a page from the <head> section.

Example:

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
   <head>
        <!-- Remove local resources -->
        <remove src="css/styles-m.css" />
        <!-- Remove external resources -->
        <remove src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"/>
        <remove src="http://fonts.googleapis.com/css?family=Montserrat" /> 
   </head>
</page>
  • You can disable a block or a container with its child element from the layout by setting the value of display attribute to a true, default value of display attribute is false. You can always overwrite the display attribute, but in case if the remove attribute is set to true, the value of the display attribute is ignored.

Example:

<referenceContainer name="container.name" display="false" />

You can reorder block and container using after and before attributes of the <referenceBlock> / <referenceContainer> element.

  • both after and before attributes are present, after attribute takes precedence.
  • both after and before attributes are absent or empty, all elements are considered as non-positioned. All other elements are positioned at their specified locations.
  • multiple elements have before or after set to dash (-), all elements are displayed at the top (or bottom in case of after attribute).but the ordering of these elements is undefined.

CSS

When the theme is inherited from the parent theme, make changes in _extend.less or _theme.less file instead of overriding the .less files. 

Your theme’s _theme.less file overrides your parent’s theme. So, if you have assign parent theme to your theme, copy the entire content from the parent theme’s _theme.less file.

Use Magento generic CSS classes wherever possible.

There are many CSS classes, that are defined in Magento default installation, whenever you are going to create new store template, it is a good practice to use generic CSS classes because there are many third-party extensions that uses Magento generic CSS classes.

Override or extend Magento Ui library component

To customize UI component, you can override or extend the Magento library components.

For Example, if you want to change the style of a button, you can extend or override _button.less file.

Extend component’s styles

Add _buttons_extend.less and _extend.less files in <theme_dir>/web/css/source directory. Then add your custom style of button in _buttons_extend.less file, and register it in the  _extend.less file by adding the following code:

@import '_buttons_extend.less';

Override component’s styles

Create _button.less file in <theme_dir>/web/css/source directory. And add your custom style of button in it.

Magento Ui Component Files are located at lib/web/css directory:

You can also include your own custom CSS by adding it in default_head_blocks.xml file which is located in the Magento_Theme module.

Example

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
        <css src="css/styles-m.css" />
        <css src="css/styles-l.css" media="screen and (min-width: 768px)"/>
        <css src="css/print.css" media="print" />
    </head>
</page>

If you want to make major customization in the existing style of a particular module, copy _module.less file from Magento core module to your own theme in the same path, and add your customization to it.

Translation

If you need to change the phrases in the user interface, add custom CSV dictionary files instead of overriding .phtml templates.

In case if the location is changed for a store, Magento searches for translations in the related dictionaries at the following location: 

  1. Module translations: <module_dir>/i18n/
  2. Theme translations:
    • <parent_theme_dir>/i18n/ (iterated through all ancestor themes)
    • <current_theme_dir>/i18n/
  3. Translation package: app/i18n/
  4. Magento database

How to extend existing jquery widget in Magento 2?

Jan 14th, 2019 2 min to read
Table of Contents

This article will help you to understand how to extend an existing jquery widget in Magento 2. Sometimes, there may arise situations where a project requires specific/custom approach, in that case, developers need to modify the default logic.

Let’s take an example where we will make certain changes to the main navigation javascript part.

The chief file responsible for the functioning of the navigation menu is menu.js located at [project_root]/lib/web/mage/ with other default js system components.

Now, if you want to extend or overwrite it, you’ll have to make sure that you follow the steps given below:

Step 1

To properly extend the parts of menu.js with our custom content, the first step is to map our js file so that the system loads it instead of the default file.

Magento uses equirejs-config.js files to successfully map js components on the system. The first thing that matters is to understand where to place requirejs-config.js. It can be placed at several levels.

We will create a file that will replace the menu.js file. Let’s call it menu-custom.js and place it under [our theme]/web/js/ directory.

Step 2

Next, we will have to create the requirejs-config.js file and place it under [our theme]/root directory. This will help us to map our file so as to replace the default one. 

var config = {
   "map": {
       "*": {
           "menu": "js/menu-custom"
       }
   }
};

Step 3

We will extend default functionality and for this, we will be using the jQuery widget factory. We will place the following code in our newly created menu-custom.js file.

define([
       'jquery',
       'jquery/ui',
       'mage/menu'],
   function($){
       $.widget('kiwicommerce.menu', $.mage.menu, {
           _init: function () {
               console.log("This message is from menu-custom.js");
           },
           toggle: function () {
               console.log("This message is from menu-custom.js");
           }
       });
       return $.kiwicommerce.menu;
   });

Our custom widget instance called kiwicommerce.menu is extending default $.mage.menu and in this example, we will be extending two methods, that are _init and toggle. Toggle method is in charge of toggle navigation on mobile phones while the _init method is in charge of the component initialization.

Here we can add our custom logic as needed. Currently, we have added a simple console message for testing.

How to add a link in the top menu in Magento 2

Nov 19th, 2018 3 min to read

Let’s learn about how to add a link in the top menu with the help of this article. In this example we will add “Order History” link in the top menu. 

First thing you need to do is to create a default.xml file in your theme or module.

If you want to add a link in your theme, then the path should be:

app/design/<VendorName>/<ThemeName>/Magento_Customer/layout/default.xml

In case if you want to add a link in your module, then the path should be: app/code/<VendorName>/<ModuleName>/view/frontend/layout/default.xml

Now, for creating the default.xml file at above given path we need to add the following code in it:

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
  <body>
      <referenceBlock name="top.links">
          <block class="Magento\Customer\Block\Account\SortLink" name="order-history-top-link" after="wish-list-link">
              <arguments>
                  <argument name="path" xsi:type="string">sales/order/history</argument>
                  <argument name="label" xsi:type="string" translate="true">Order History</argument>
              </arguments>
          </block>
      </referenceBlock>
  </body>
</page>

After following the example given above you will see that the link must have been added in the top menu and will appear as given below:

image

Now, Let’s learn to add link into top header section instead of top link dropdown. In this example, we will add “Contact Us” link in header. For that you need to add the following code in default.xml file.

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
  <body>
      <referenceBlock name="header.links">
          <block class="Magento\Framework\View\Element\Html\Link" name="contact-top-header-link">
              <arguments>
                  <argument name="path" xsi:type="string">contact</argument>
                  <argument name="label" xsi:type="string" translate="true">Contact Us</argument>
              </arguments>
          </block>
      </referenceBlock>
  </body>
</page>

For the example given above the link will be added in the top header section and will look like this:

Feel free to leave the comments below and contact us if you need any help to customize your Magento store.

Happy coding!

How to add a link in your account navigation for Magento 2?

Nov 7th, 2018 2 min to read

Today you will be learning about how to add a link in your account navigation.

First of all, you need to create customer_account.xml file in your theme or module. The path of this file is given below.

If you want to add a link in your module, then the path should be app/code/<VendorName>/<ModuleName>/view/frontend/layout/customer_account.xml

If you want to add a link in your theme, then the path should be app/design/<VendorName>/<ThemeName>/Magento_Customer/layout/customer_account.xml

Now, we need to create customer_account.xml at the respective paths given above. Add the following code in the file just created.

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
  <body>
      <referenceBlock name="customer_account_navigation">
          <block class="Magento\Customer\Block\Account\Delimiter" name="customer-account-navigation-delimiter-demo" template="Magento_Customer::account/navigation-delimiter.phtml" before="customer-account-navigation-demo-link" />
          <block class="Magento\Framework\View\Element\Html\Link\Current" name="customer-account-navigation-demo-link">
              <arguments>
                  <argument name="label" xsi:type="string">Demo Link</argument>
                  <argument name="path" xsi:type="string">module/controller/action</argument>
              </arguments>
          </block>
      </referenceBlock>
  </body>
</page>

In the above example we have used delimiter block (name with “customer-account-navigation-delimiter-demo”) to add a separator. In case you don’t want the separator, remove that block.

The result will same as the below image.

Thanks

How to add non-category link to navigation menu in Magento 2?

Oct 29th, 2018 2 min to read

In this post, I will be guiding you on how to add non-category link to the navigation menu in Magento 2.

If you still think that the container navigation.sections which holds the category links it can be referenced and passing following arguments can create a new category link under navigation menu, you are highly mistaken.

<referenceContainer name="navigation.sections">
    <block class="Magento\Framework\View\Element\Html\Links" name="mylink">
        <arguments>
            <argument name="label" xsi:type="string">Custom link</argument>
            <argument name="path" xsi:type="string">*/*/*</argument>
        </arguments>
    </block>
</referenceContainer>

The latest Magento 2 doesn’t support this kind of approach anymore.

You can use a plugin to add non-category link in the navigation menu. Follow below steps to add non-category link to the navigation menu.

Step-1: Define plugin in di.xml file

Create di.xml file in app/code/Aureatelabs/ModuleName/etc/frontend directory.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Theme\Block\Html\Topmenu">
        <plugin name="aureatelabs-non-category-link" type="Aureatelabs\ModuleName\Plugin\NonCategoryLink" />
    </type>
</config>

Step-2: Create a plugin file

Next, create NonCategoryLink.php in app/code/Aureatelabs/ModuleName/Plugin directory.

<?php
namespace Aureatelabs\ModuleName\Plugin;

use Magento\Framework\Data\Tree\NodeFactory;

class NonCategoryLink
{
    protected $nodeFactory;

    public function __construct(
        NodeFactory $nodeFactory
    ) {
        $this->nodeFactory = $nodeFactory;
    }

    public function beforeGetHtml(
        \Magento\Theme\Block\Html\Topmenu $subject,
        $outermostClass = '',
        $childrenWrapClass = '',
        $limit = 0
    ) {

        $node = $this->nodeFactory->create(
            [
                'data' => $this->getNodeAsArray(),
                'idField' => 'id',
                'tree' => $subject->getMenu()->getTree()
            ]
        );
        $subject->getMenu()->addChild($node);
    }

    protected function getNodeAsArray()
    {
        return [
            'name' => __('Custom Link'),
            'id' => 'some-unique-id-here',
            'url' => 'http://www.example.com/',
            'has_active' => false,
            'is_active' => false
        ];
    }

}

Here,

  • name: Define a label that will display in the navigation menu
  • id: Add some unique id here
  • url: Add the URL for category link
  • Is_active: To determine if a menu item is selected or not

Next, run the below commands

php bin/magento setup:di:compile
php bin/magento cache:flush

Now you can see your custom non-category link in the navigation menu.

How to use Private Content or Sections in Magento 2?

Oct 23rd, 2018 7 min to read

In this post, I will be guiding you on how to use private content or sections in Magento 2.

Since private content is specific to individual users, it’s reasonable to handle it on the client side i.e. web browser.

A section is a piece of customer data grouped together. Each section is represented by the key that is used to access and manage data itself.

Magento loads sections by AJAX request to /customer/section/load/ and caches loaded data in the browser local storage under the key mage-cache-storage. Magento tracks when some section is changed and load updated section automatically.

Here we will be using Aureatelabs as the Vendor name and CustomSection as the name of the module.  You can change this according to your Vendor and Module name.

Follow the below steps to define the custom section and use the data of the custom section in our custom phtml file.

Step 1: Define a custom section

We will define a custom section in the di.xml file by adding a new section into sections pool.

Create di.xml file in app/code/Aureatelabs/CustomSection/etc/frontend directory.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
	<type name="Magento\Customer\CustomerData\SectionPoolInterface">
    	<arguments>
        	<argument name="sectionSourceMap" xsi:type="array">
            	<item name="custom_section" xsi:type="string">Aureatelabs\CustomSection\CustomerData\CustomSection</item>
        	</argument>
    	</arguments>
	</type>
</config>

Next, create CustomSection.php file in app/code/Aureatelabs/CustomSection/CustomerData directory.

<?php
namespace Aureatelabs\CustomSection\CustomerData;
use Magento\Customer\CustomerData\SectionSourceInterface;

class CustomSection implements SectionSourceInterface
{
	public function getSectionData()
	{
    	return [
        	'customdata' => "We are getting data from custom section",
    	];
	}
}

In getSectionData() method we will define our data that we want to store in section.

Step 2: Display custom section data in frontend

We will display our custom section data in the product view page. You can get section data in any Magento pages.

Next, we will create catalog_product_view.xml in app/code/Aureatelabs/CustomSection/view/frontend/layout directory.

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
	<body>
    	<referenceContainer name="product.info.main">
        	<block class="Magento\Catalog\Block\Product\View" name="aureatelabs_custom_section" after="-" template="Aureatelabs_CustomSection::custom_section.phtml" />
    	</referenceContainer>
	</body>
</page>

Next, we will create a custom_section.phtml in app/code/Aureatelabs/CustomSection/view/frontend/templates directory.

<div class="aureatelabs-custom-section"data-bind="scope: 'section'">
	<p data-bind="text: customsection().customdata"></p>
</div>
<script type="text/x-magento-init">
	{
    	"*": {
        	"Magento_Ui/js/core/app": {
            	"components": {
                	"section": {
                    	"component": "Aureatelabs_CustomSection/js/section"
                	}
            	}
        	}
    	}
	}
</script>

Next, We will create section.js in app/code/Aureatelabs/CustomSection/view/frontend/web/js directory.

define([
	'uiComponent',
	'Magento_Customer/js/customer-data'
], function (Component, customerData) {
	'use strict';

	return Component.extend({
    	initialize: function () {
        	this._super();
        	this.customsection = customerData.get('custom_section');
    	}
	});
});

Now run the below command and check on any product view page.

php bin/magento setup:upgrade
php bin/magento setup:di:compile
php bin/magento cache:flush

You can see the custom section data in the product view page.

You can also verify custom section is loaded or not by running below url

{store_url}/customer/section/load/?sections=custom_section

You can see custom section data in browser local storage.

In the section.js file, we have used Magento_Customer/js/customer-data as this Magento js library file is responsible for set section data and get section data. Section data gets updated when ajax call with the post, put, delete requests are made.

Additional Information

When caching is enabled the whole page content is cached so sections help us to dynamically manage the components of the page.

For example, the complete page is cached, Now when the customer logs in or logs out only the components get updated with the value from the section as you can see the customer name, cart, wish list are all managed by section.

All sections data are fetched in one single ajax call, hence the number of ajax requests are reduced to a huge number.

Magento assumes that section data is changed when a customer sends some state modification request (POST, PUT, DELETE). To minimize the load on the server, developers should specify which action (or request) updates which customer data section in etc/frontend/sections.xml.

You can refer Magento/Catalog/etc/frontend/sections.xml file.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd">
	<action name="catalog/product_compare/add">
    	<section name="compare-products"/>
	</action>
	<action name="catalog/product_compare/remove">
    	<section name="compare-products"/>
	</action>
	<action name="catalog/product_compare/clear">
    	<section name="compare-products"/>
	</action>
	<action name="customer/account/logout">
    	<section name="recently_viewed_product"/>
    	<section name="recently_compared_product"/>
	</action>
</config>

In the section.xml file, they have defined update the compare-products section when one of these actions catalog/product_compare/addcatalog/product_compare/remove, catalog/product_compare/clear are requested.

If the action name is * that means that section will be updated on each POST and PUT request. If the section tag is missed then all sections will be updated.

You can refer Magento/Theme/etc/frontend/sections.xml file.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd">
    <action name="*">
        <section name="messages"/>
    </action>
</config>

In the section.xml file, they have defined update the messages section on each POST and PUT request.

If you want to reload your custom section data when the page refreshed then you have to reload your custom section data in your js file.

define([
	'uiComponent',
	'Magento_Customer/js/customer-data'
], function (Component, customerData) {
	'use strict';

	return Component.extend({
    	initialize: function () {
        	this._super();
        	customerData.reload('custom_section');
        	this.customsection = customerData.get('custom_section');
    	}
	});
});

Here we have added customerData.reload('custom_section'); to reload section data whenever we refresh the page.

FAQs

What is private content in Magento 2?


Private content in Magento 2 is data accessible only to a particular user, based on the configurational changes made by them. This can be anything from purchase history to payment information. Magento 2 uses customer-data.js library to check if a customer is logged in, and then sends server requests to reload only a part of the data without refreshing the entire page cache.

How do I override layout XML in Magento 2?


To override layout XML in Magento 2, create a folder structure with the same name in themes as present in view/frontend. Then, change the etc/module.xml file and replace it by the new file created. You can do this by placing the file in app/design/frontend/[Vendor]/[Theme_Name]/Vendor_ModuleName/layout/some_layout.xml

Where is config xml in Magento?


The config.xml in Magento is located in the DOMAIN_HOME/config directory. The servers get their configuration data from these files. Each server has its own configuration file in the domain which can be accessed through <module_folder>/etc/adminhtml/system.xml. The config.xml files are used to set specific values for the configuration of the system.

How to use section XML in Magento 2?


To use section XML in Magento 2, create a new layout XML file in the app/code/[VendorName]/[ModuleName]/view/frontend/layout directory. Then, refresh the cache and view any product page to view section data. In Magento 2, sections define the layout configuration for different store areas, such as the header, footer, and content.

In this Magento web development hack, we will be guiding you on how to add custom phtml in the admin product ui-component form in the Magento 2.

Here we will be using Aureatelabs as the Vendor name and CustomTab as the name of the module.  You can change this according to your Vendor and Module name.

To start with, we will create a custom tab in the product admin form after which we will call our custom block and phtml file inside our custom tab.

Step 1: Create Product_form.xml file

For this, you have to create a product_form.xml file in app/code/Aureatelabs/CustomTab/view/adminhtml/ui_component directory

<?xml version="1.0" encoding="UTF-8"?>
	<!--For calling custom block -->
	<fieldset name="custom_tab">
    	<argument name="data" xsi:type="array">
        	<item name="config" xsi:type="array">
            	<item name="label" xsi:type="string" translate="true">Custom tab</item>
            	<item name="collapsible" xsi:type="boolean">true</item>
<!-- this attribute is, if you want your custom section by default opened when product form calls, if not then set the value as false -->
            	<item name="opened" xsi:type="boolean">true</item> 
            	<item name="canShow" xsi:type="boolean">true</item>
            	<item name="sortOrder" xsi:type="string">1</item>
        	</item>
    	</argument>
    	<container name="custom_tab_container">
        	<argument name="data" xsi:type="array">
            	<item name="config" xsi:type="array">
                	<item name="sortOrder" xsi:type="string">1</item>
            	</item>
        	</argument>
        	<htmlContent name="html_content">
            	<argument name="block" xsi:type="object">Aureatelabs\CustomTab\Block\Adminhtml\Product\CustomTab</argument>
        	</htmlContent>
    	</container>
	</fieldset>
</form>

Here you can see that we have set custom block inside our custom tab.

Step 2: Create Block file for custom tab

Next we will be creating CustomTab.php in  app/code/Aureatelabs/CustomTab/Block/Adminhtml/Product directory.

<?php
namespace Aureatelabs\CustomTab\Block\Adminhtml\Product;

class CustomTab extends \Magento\Backend\Block\Template
{
	/**
 	* Block template.
 	*
 	* @var string
 	*/
	protected $_template = 'custom_tab.phtml';

}

We have defined the phtml file in the block file.

Step 3: Create phtml file that defined in block

So next we will be creating is a  custom_tab.phtml file in app/code/Aureatelabs/CustomTab/view/adminhtml/templates directory

<?php
echo "Hello World";
?>

Now flush the cache and open the product admin form, now you can see the custom phtml file content in our custom tab.

Custom template in product edit form

Well, that was an easy one, wasn’t it? Let us know in the comments section below.

Related Sources

  1. How to create an admin button in Magento 2
  2. How to display a custom admin system notification

Grow your online business like 3,764 subscribers

    * This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
    envelope

    Thank You!

    We are reviewing your submission, and will be in touch shortly.