Chapters Close

In this article, you will be learning about how we can use grunt in Magento 2.

Before starting the installation, Please rename the existing files package.json.sample and Gruntfile.js.sample in your root folder as package.json and Gruntfile.js respectively.

Follow the below steps to use grunt in Magento 2:

  • Step 1: Install Node.js
  • Step 2: Install Grunt CLI
  • Step 3: Install Node.js dependencies
  • Step 4: Add a theme to Grunt configuration
  • Step 5: Run Grunt commands

Step 1: Install Node.js

First, we need to install a stable version of Node.js.

Step 2: Install Grunt CLI

Now install the Grunt CLI tool globally by the following command:
npm install -g grunt-cli

Step 3: Install Node.js dependencies

Install the node.js project dependencies, including Grunt, for your Magento instance. To do this, run the following commands in the command prompt:
cd <your_Magento_instance_directory>
npm install
npm update

Step 4: Add a theme to Grunt configuration

Add your theme to Grunt configuration. To do this, in the dev/tools/grunt/configs/themes.js file, add your theme in module.exports as shown below:

module.exports = {
       ...
   <theme>: {
   area: 'frontend',
       name: '<Vendor>/<theme>',
       locale: '<language>',
       files: [
       '<path_to_file1>', //path to root source file
       '<path_to_file2>'
   ],
       dsl: 'less'
       ...
},

Where the following notations are used:

<theme>: Your theme code, conventionally should correspond to the theme directory name.
<language>: specified in the ‘code_subtag’ format, for example, en_US. Only one locale can be specified here. To debug the theme with another locale, create one more theme declaration, having specified another value for language.
<path_to_file >: the path to the root source file, relative to the directory app/design/frontend/<Vendor>/<theme/>/web. You need to specify all root source files of the theme. If your theme inherits from a certain theme and does not contain its root source files, specify the root source files of the parent theme.

Step 5: Run Grunt commands

Now the installation process is completed, the next step is to run the Grunt commands:

grunt clean: This command removes static files related to your theme in both pub/static and var directories.

grunt exec: This one republishes source files symlinks to
pub/static/frontend/<Vendor>/<theme>/<locale>

grunt less: This command compiles all the css file using the symlinks in this location
pub/static/frontend/<Vendor>/<theme>/<locale>

grunt watch: This command is used to start the grunt tool to track the changes done in the main files like .less and re-compiles into CSS files.

Every time you change any of this in the source file, grunt watch will show a notification in the terminal about the specific change and recompile the changes simultaneously.

Cheers!

Helpful resources:

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.

Helpful resources:

If you are new to create a custom component in Magento 2 and if you are in the requirement to have a working language component, you landed up at the right place.

In Magento 2, each component type has a different directory structure. To create a language-package component, we have to create a vendor directory and package directory under the following directory: app > i18n

Follow the below steps to create a language-package component:

  • Step 1: Create a directory for the language package
  • Step 2: Collect Phrases for translation
  • Step 3: Translate word or phrases
  • Step 4: Create registration.php, language.xml and composer.json file in the language package directory
  • Step 5: Flush the Magento cache and static file cache

Note: Replace Aureatelabs/it_ch from entries in this article to your module name.

Step 1: Create a directory for the language package

The directory structure for the language package will look like this: <root>/app/i18n/<Vendor>/<Package>

For example: <root> > app > i18n > Aureatelabs > it_ch

Step 2: Collect Phrases for translation

Generate a .csv file, using the command given below. But instead of specifying a module or theme directory for CSV generation, specify the Magento application root directory. Generated .csv file will contain any phrases that the command will find in the code.

bin/magento i18n:collect-phrases -o “/app/i18n/Aureatelabs/it_ch/it_CH.csv” -m

Step 3: Translate words and phrases

Use the following instruction for translating the words and phrases:

  • Change the content of the second column only. Translate the phrases from English to the respective language.
  • While translating, pay attention to placeholders like %1, %2 and so on. They are used by the Magento application to insert context values, they are not used for translations. For example:
    • Product ‘%1’ has been added to the shopping cart.
    • Product ‘Multimeter-2000’ has been added to the shopping cart.

Step 4: Create registration.php, language.xml and composer.json file in the language package directory

registration.php
Create a registration.php file on language package root directory for registering the component with the following code.

 
 
 
Copy Code
\Magento\Framework\Component\ComponentRegistrar::register(
   \Magento\Framework\Component\ComponentRegistrar::LANGUAGE,
   'aureatelabs_it_ch',
   __DIR__
);

language.xml
Create a language.php file on language package root directory with the following code.

 
 
 
Copy Code
<language xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/Language/package.xsd">
   <code>it_CH</code>
   <vendor>aureatelabs</vendor>
   <package>it_ch</package>
</language>

Where:

  • <code>: Language package locale (required)
  • <vendor>: Module’s vendor name (required)
  • <package>: Language package name (required)
  • <sort_order>: Priority of uploading a package when there are several language packages available for a store (optional)
  • <use>: Parent language package locale from which to inherit dictionaries (optional)

composer.json
Create a composer.json file on language package root directory with the following code.

 
 
 
Copy Code
{
 "name": "aureatelabs/language-it_ch",
 "description": "Italian language",
 "version": "100.0.2",
 "license": [
   "OSL-3.0",
   "AFL-3.0"
 ],
 "require": {
   "magento/framework": "100.0.*"
 },
 "type": "magento2-language",
 "autoload": {
   "files": [
     "registration.php"
   ]
 }
}

Step 5: Flush the Magento cache and static file cache

Now, run the following commands from the command line interface
bin/magento setup:upgrade
bin/magento setup:static-content:deploy -f
bin/magento cache:flush

That is all you need to set up and you are all good to go with the newly created language-package component. Though you faced any difficulties, queries even after following all the steps carefully, connect us anytime and we will be glad about solving your issues.

Happy Translating!

This piece of information will throw some light on how to setup authorize.net in Magento 2. 

The Authorize.net allows the customers to make payments directly on the website. All you need to do is to set it up and it will start accepting secured payments.

Follow below three steps to achieve it quickly:

  • Step 1: Setup a direct post for Authorize.net
  • Step 2: Connect to Authorize.net account
  • Step 3: Configure the system

Step 1: Setup a direct post for Authorize.net

To open Authorize.net configuration go to Stores > Configuration > Sales > Payment Methods > Authorize.net Direct Post

  • To Enabled select Yes
  • For Payment Action, you can select from multiple options, choose whichever is suitable for you. Below is the description of each of the two options for you to get a clear idea:
    • Authorize and Capture: Funds on the customer’s card are authorized and captured by Authorize.Net, and the order and invoice are created in your store’s Admin.
    • Authorize Only:  Funds on the customer’s card are authorized by Authorize.Net, and the order is created in your store’s Admin. You can later create an invoice and capture the funds.
  • Then, enter the name of the payment method in the Title field.

Step 2: Connect to Authorize.net account

  • As you can see in the screenshot above, we need to fill in the following data of our Authorize.net account:
    • API Login ID
    • Transaction Key
  • In Merchant MD5 box, you need to fill in the data from your Authorize.net account at Account > Settings > Security Settings > MD5-Hash.
  • Next you have to choose one of the two options for the New order status drop-down as shown below:
    • Suspected Fraud
    • Processing
  • With Authorize.net we can test the performance first in order to check if there is any bug.  We can test and turn it off once we are sure that everything is ok and our system is ready for running.
  • In Gateway URL box, we need to fill in the default link from Authorize.net, the default link for the same is: https://secure.authorize.net/gateway/transact.dll

Step 3: Configure the system

  • Set up Accepted Currency.
  • To save messages transmitted between your store and the Authorize.Net Direct Post system, set Debug to “Yes.”
  • In the Credit Card Types list, select each credit card that is accepted in your store.
  • If you want the customers to enter a card verification value (CVV), set Credit Card Verification to “Yes”.
  • For Payment from Applicable Countries you have 2 options
    • All Allowed Countries – Customers from all countries specified in your store configuration can use this payment method.
    • Specific Countries – After choosing this option, the Payment from Specific Countries list appears. Select each country in the list from where customers can make purchases from your store.
  • Enter the Minimum Order Total and Maximum Order Total for Direct Post transactions.
  • Enter a Sort Order number to determine the position of Direct Post in the list of payment methods during checkout.
  • Hit the Save Config button to complete the Authorize.net configuration.

In this post, I will be guiding you on how to use private content or sections while developing e-commerce store on 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.

Related resources:

PAD length refers to the minimum number of additional zeros assigned to each order number as “padding” until the order number becomes higher than the chosen increment pad length. For example:

  • Pad 3 = 001, 012, 123, 1234, 12345, 123456
  • Pad 4 = 0001, 0012, 0123, 1234, 12345, 123456
  • Pad 6 = 000001, 000012, 000123, 001234, 012345, 123456

In the above order increment ID consist of following parts:

  1. Prefix (store view id)
  2. Pad-length
  3. Suffix (Actual Increment id)

In Magento\SalesSequence\Model\Sequence the getCurrentValue() method set the pattern of the increment id number.

/**
* Retrieve current value
*
* @return string
*/
public function getCurrentValue()
{
   if (!isset($this->lastIncrementId)) {
       return null;
   }

   return sprintf(
       $this->pattern,
       $this->meta->getActiveProfile()->getPrefix(),
       $this->calculateCurrentValue(),
       $this->meta->getActiveProfile()->getSuffix()
   );
}

$this->pattern initially get value %s%’.09d%s from the constant DEFAULT_PATTERN.

/**
* Default pattern for Sequence
*/
const DEFAULT_PATTERN  = "%s%'.09d%s";

%’.09d sets 0 as the padding character and sets the number of digits to display as the value that follows, in this case, is 9. The d presents the number as a [signed] decimal. This means that by default, the increment-ID number will be a signed decimal with 9 digits, padded with 0s.

If you want to customize order’s Increment id PAD-length to be different than Magento 2 produces by default.

You can configure the class constructor arguments in your etc/di.xml in the argument node. The object manager injects these arguments into the class during creation. The name of the argument configured in the XML file must correspond to the name of the parameter in the constructor in the configured class.

<?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\SalesSequence\Model\Sequence">
       <arguments>
           <argument name="pattern" xsi:type="string">%s%'.05d%s</argument>
       </arguments>
   </type>
</config>

The following example creates instances of Magento\SalesSequence\Model\Sequence with the class constructor argument $pattern set to a value %s%’.05d%s

Finally, run php bin/magento setup:di:compile command and test by placing a new order, increment id will be changed from 9 to 5 digits.

In this post, I will be guiding you on how to add our custom link in header links and top links.

Header link will be displayed for both guest and logged in customer. But top links will only display if the customer is logged in.

To add custom link in the header and top links, I will create default.xml file in app/code/Aureatelabs/ModuleName/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>
    	<referenceBlock name="header.links">
        	<block class="Magento\Framework\View\Element\Html\Link" name="custom-header-link">
            	<arguments>
                	<argument name="label" xsi:type="string" translate="true">Custom Header Link</argument>
                	<argument name="path" xsi:type="string">*/*/*</argument>
            	</arguments>
        	</block>
    	</referenceBlock>
    	<referenceBlock name="top.links">
        	<block class="Magento\Framework\View\Element\Html\Link" name="custom-top-link">
            	<arguments>
                	<argument name="label" xsi:type="string" translate="true">Custom Top Link</argument>
                	<argument name="path" xsi:type="string">*/*/*</argument>
            	</arguments>
        	</block>
    	</referenceBlock>
	</body>
</page>

In the default.xml file, there is two referenceBlock we have defined

  • Header.links: To add custom link in header links
  • Top.links: To add custom link in Top links.

Here, we have passed two arguments

  • label: The label for anchor link that will display in frontend
  • path: The path of the anchor link. Here you can define the path of your page i.e: route/controller/index

After cache flush, you can see custom link in header links and top links.

If the customer is not logged in means for the guest user only custom header link will be shown.

If the customer is logged in then both custom header link and the top link will be shown.

Additional Information

Here, Magento\Framework\View\Element\Html\Link is core Magento block that is used to create a link. If you open Link.php file you will find these two functions

protected function _toHtml()
	{
    	if (false != $this->getTemplate()) {
        	return parent::_toHtml();
    	}

    	return '<li><a ' . $this->getLinkAttributes() . ' >' . $this->escapeHtml($this->getLabel()) . '</a></li>';
	}

	public function getHref()
	{
    	return $this->getUrl($this->getPath());
	}

If you want to add an external website link in your custom header or top link with path argument, it will be not possible.

So for the external website link, you have to create one custom block that extends \Magento\Framework\View\Element\Html\Link and define this block in default.xml file.

In default.xml file update the block name.

<referenceBlock name="header.links">
	<block class="Aureatelabs\ModuleName\Block\CustomLink" name="custom-header-link">
    	<arguments>
        	<argument name="label" xsi:type="string" translate="true">Custom Header Link</argument>
    	</arguments>
	</block>
</referenceBlock>

Next create CustomLink.php file.

<?php
namespace Aureatelabs\ModuleName\Block;

class CustomLink extends \Magento\Framework\View\Element\Html\Link
{
	public function getHref()
	{
    	return 'https://www.google.com/';
	}

	public function getTarget()
	{
    	return '_blank';
	}
}

Here we have created two function named getHref() and getTarget().

  • getHref(): define external link here
  • getTarget(): I have added target=”_blank” attribute

So now when clicking on header link it will open Google in a new page. You can use different attribute too.

If you refer  \Magento\Framework\View\Element\Html\Link file you will find $allowedAttributes array variable.

protected $allowedAttributes = [
    	'href',
    	'title',
    	'charset',
    	'name',
    	'target',
    	'hreflang',
    	'rel',
    	'rev',
    	'accesskey',
    	'shape',
    	'coords',
    	'tabindex',
    	'onfocus',
    	'onblur', // %attrs
    	'id',
    	'class',
    	'style', // %coreattrs
    	'lang',
    	'dir', // %i18n
    	'onclick',
    	'ondblclick',
    	'onmousedown',
    	'onmouseup',
    	'onmouseover',
    	'onmousemove',
    	'onmouseout',
    	'onkeypress',
    	'onkeydown',
    	'onkeyup', // %events
	];  

You can use these attribute add prefix get and first letter capital from above attribute

Ex. getHref(), getTitle(), getOnclick() etc.

FAQs

How to customize Magento 2 header?


To customize Magento 2 header, follow these ways:
1. Create a new layout XML file in your theme’s app/design/frontend/{Vendor}/{theme}/Magento_Theme/layout folder and add the required changes to the header block. 
2. Create a new template file in your theme’s app/design/frontend/{Vendor}/{theme}/Magento_Theme/templates folder and use it to override the default header template. 
3. Use Custom Extension that allows header customization.

How to add custom footer link in Magento 2?


To add a custom footer link in Magento 2, first create a new module as  app/code/CustomFooterLink/. Next, create a new file in this folder as app/code/CustomFooterLink/registration.php and place the below code –
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'CustomFooterLink',
    __DIR__
);

Further, create a new XML file as app/code/CustomFooterLink/etc/module.xml and add the code –
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="CustomFooterLink" setup_version="1.0.0"></module>
</config>

Now, create a new template file as app/code/CustomFooterLink/view/frontend/templates/link.phtml and add –
<li><a href="<?= $block->getLink() ?>"><?= $block->getLabel() ?></a></li>
After that, create a new file as app/code/CustomFooterLink/Block/Link.php and place the below code:
<?php

namespace CustomFooterLink\Block;
use Magento\Framework\View\Element\Template;
class Link extends Template
{
    public function getLink()
    {
        return 'http://www.example.com';
    }
    public function getLabel()
    {
        return 'Example Link';
    }
}

Then create a new di.xml file as app/code/CustomFooterLink/etc/di.xml and use the following code:
<?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\Footer">
        <block class="CustomFooterLink\Block\Link" name="custom.footer.link" template="CustomFooterLink::link.phtml" before="-" />
    </type>
</config>

At last, enable the module using php bin/magento module:enable CustomFooterLink. And refresh the cache + run the setup:upgrade command.

How to remove header top links in Magento 2?


To remove header top links in Magento 2, follow the below-mentioned steps –
1. Create a new layout XML file as app/design/frontend/{Vendor}/{theme}/Magento_Theme/layout/ default.xml.
2. Use the <referenceBlock> element to remove the header top links block using the code:
<referenceBlock name=”header.links” remove=”true” />
3. Now, deploy the static content by running the command:
php bin/magento setup:static-content:deploy
4. Refresh the cache and check the changes.

How to add custom header in Magento 2?


To add custom header in Magento 2, follow the below-mentioned steps –

1. Copy Magento/blank or Magento/luma theme and create a new one in the app/design/frontend/{Vendor}/{theme} directory.
2. Create an XML file as app/design/frontend/{Vendor}/{theme}/Magento_Theme/layout/default.xml.
3. Use the <referenceBlock> or <referenceContainer> to add blocks in the header –
<referenceContainer name=”header.container”>
<block class=”Magento\Framework\View\Element\Template” name=”custom-block” template=”path/to/template.phtml”/>
</referenceContainer>
4. Create a new template file as app/design/frontend/{Vendor}/{theme}/Magento_Theme/templates/html/customheader.phtml. And use it to override the default header template.
5. Customize it as required, and thereafter, add the below code –
<?php echo $this->getChildHtml(“store_language”); ?>
6. Now, deploy the static content by running the command:
php bin/magento setup:static-content:deploy
7. Refresh the cache and check the changes.

Magento 2 provides a configuration system in its backend where we can create our own configuration setting as per the module requirement.

We can go to Store->Setting->Configuration and check all the stored Magento configuration there. We can also add our own configuration menu and use them.

Table: core_config_data

  • All records of configuration are stored in the table mentioned above.
  • By default, there is no entry in the table when we create any configuration field.
  • However, when we save the configuration there will be an entry in this table with its respective value so that we can trace the actual configuration value from this table.

Step 1: Create system.xml file
Step 2: Set default configuration value
Step 3: Flush Magento cache
Step 4: Use configurations

Note: Replace Aureatelabs/LoginAsCustomer from entries in this article to your module name.

Step 1: Create system.xml file

Create a file at the path given below and add the following code:
app/code/VendorName/ThemeDirectoryName/etc/adminhtml/system.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
   <system>
       <tab id="aureate_tab" translate="label" sortOrder="1">
           <label>Aureate Labs</label>
       </tab>
       <section id="aureatelabs" translate="label" type="text" sortOrder="100" showInDefault="1"
                showInWebsite="1" showInStore="1">
           <label>Login As Customer</label>
           <tab>aureate_tab</tab>
           <resource>Aureatelabs_LoginAsCustomer::config</resource>
           <group id="general" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1"
                  showInStore="1">
               <label>General</label>
               <field id="login_as_customer_enabled" translate="label" type="select" showInDefault="1" canRestore="1"
                      showInWebsite="1" showInStore="1">
                   <label>Enabled</label>
                   <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
               </field>
           </group>
           <group id="button_visibility" translate="label" type="text" sortOrder="10" showInDefault="1"
                  showInWebsite="1" showInStore="1">
               <label>Button visibility</label>
               <field id="customer_grid_page" translate="label" type="select" showInDefault="1" canRestore="1"
                      showInWebsite="1" showInStore="1">
                   <label>Customer grid page</label>
                   <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
               </field>
           </group>
       </section>
   </system>
</config>

An overview of the code that you just saw:

In the above code, we have two groups
General and Button visibility
Below is the brief description of some of the tags we have used:

<system>: This tag is the starting tag to indicate that we are going to system settings.

Tab elements:

This tag is used to create our custom menu in configuration options.

  • id: unique tab id
  • label: tab title

Section Attributes:

  • id: unique section id
  • sortOrder: set the position of our configuration menu in the list.
  • showInDefaultconfiguration scope
  • showInWebsite: configuration scope
  • showInStore: configuration scope

Section elements:

  • Label: configuration menu title (In the example it’s Aureate Labs)
  • Tab: tab_id to display this configuration
  • Resource: ACL rule to access this configuration (In the example it’s Aureatelabs_LoginAsCustomer::config) 
  • Group: group of some configurations (In the example we created two groups general and  Button visibility)
  • Fields: configuration field to store dropdown or text or radio button. The field also has some attributes and elements.  

Fields Elements:

  • Label: field title (In Example for general we have Enabled text)
  • Source_model: store data of this field, we can use it for select, multi-select type (In the example we have used Magento\Config\Model\Config\Source\Yesno For Yes/No Dropdown)
  • We can use our own source_model for options in this example we are using yesno model provided by Magento. If you want to add our own you can add.

Step 2: Set default configuration value

Each field in system.xml after its creation will not have any value.

When we call them it will return Null value because at the time of field creation there is no entry in the core_config_data table. When we click on save config button then there is an entry as per the default value of the field.

If we have Yes/No field then it will show default No value (We will see how we can change it in the steps given below) but there is no entry in database level until we click on the save config button.

To set our default value for the field let’s consider in our example we have enabled the field for values Yes/No.

After the first step when we visit the admin configuration section then we have the default value set in the field as “No”.  Now we can change it as shown below:

Create a config.xml file at the path given below and add the following code:
app/code/VendorName/ThemeDirectoryName/etc/config.xml

Syntax:

<default>
<section>
   <group>
       <field>{value}</field>
   </group>
</section>
</default>

For our example:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
   <default>
       <aureatelabs>
           <general>
               <login_as_customer_enabled>1</login_as_customer_enabled>
           </general>
           <button_visibility>
               <customer_grid_page>1</customer_grid_page>
               <customer_edit_page>1</customer_edit_page>
           </button_visibility>
       </aureatelabs>
   </default>
</config>
  • <default>: default field value
  • <aureatelabs>: section id
  • <general>: group id
  • <login_as_customer_enabled>: field id which sets a default value for the field

For our example we have considered the field and its value as shown below:

  • <section>: <aureatelabs>
  • <group>: <general>
  • <field>: <login_as_customer_enabled> set this value 1 to show yes by default.

Step 3: Flush Magento cache

Now we need to clear the cache of Magento. Using the commands given below we can clear and flush our Magento cache:

  • For Clear cache : php bin\magento cache:clear OR php bin\magento c:c
  • For Flush cache : php bin\magento cache:flush OR php bin\magento c:f

Or we can also clear and flush the cache from the admin panel: System->tools->cache management

Step 4: Get value from the configuration

There are two ways to get value of the configuration

1. By simply calling it:

$this->scopeConfig->getValue(aureatelabs/general/login_as_customer_enabled
,\Magento\Store\Model\ScopeInterface::SCOPE_STORE);

Above code will return value of configuration value stored in the table for that field
Where:

  • Aureatelabs: Section id
  • General: Group id
  • Login_as_customer_enabled: Field id

2. Using the Helper Class (Recommended):

Create a file at the path given below and add the following code:
app/code/Vendor/module/Helper/Data.php

namespace Aureatelabs\LoginAsCustomer\Helper;
use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Store\Model\ScopeInterface;
class Data extends AbstractHelper
{
  const XML_PATH_FIELD = aureatelabs/general/';
   public function getConfigValue($field, $storeId = null)
   {
       return $this->scopeConfig->getValue(
           $field, ScopeInterface::SCOPE_STORE, $storeId
       );
   }
   public function getFieldConfig($code, $storeId = null)
   {
       return $this->getConfigValue(self::XML_PATH_FIELD.$code, $storeId);
   }
}

Now, we try to get it in the controller:

Create a file at the path given below and add the following code:
app/code/Aureatelabs/LoginAsCustomer/Controller/Login/index.php

namespace Aureatelabs\LoginAsCustomer\Controller\Login;
class Index extends \Magento\Framework\App\Action\Action
{
   protected $helperData;
   public function __construct(
       \Magento\Framework\App\Action\Context $context,
    \Aureatelabs\LoginAsCustomer\Helper\Data $helperData
   )
   {
       $this->helperData = $helperData;
       return parent::__construct($context);
   }
   public function execute()
   {
       // TODO: Implement execute() method.
       $CheckEnable=$this->helperData->getFieldConfig('enable');
      // You can check value of result by printing $CheckEnable value
   }
}

Hope this was helpful. If you have any queries regarding the same feel free to write to us in the comments section given below!

Time for another Magento web development hack. I will be guiding you on how to attach a file in the product admin form and display the attachment on the product detail page.

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

Step 1: Create module registration file

First, create a registration.php file in app/code/Aureatelabs/ProductAttachment directory

 
 
 
Copy Code
<?php

\Magento\Framework\Component\ComponentRegistrar::register(
   \Magento\Framework\Component\ComponentRegistrar::MODULE,
   'Aureatelabs_ProductAttachment',
   __DIR__
);

Next create a module.xml file in app/code/Aureatelabs/ProductAttachment/etc directory.

 
 
 
Copy Code
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
   <module name="Aureatelabs_ProductAttachment" setup_version="1.0.0" />
</config>

Step 2: Create InstallData script to add product attachment attribute

Next, we will create a script to add product attribute. So create an InstallData.php in app/code/Aureatelabs/ProductAttachment/Setup directory.

 
 
 
Copy Code
<?php
namespace Aureatelabs\ProductAttachment\Setup;

use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Eav\Setup\EavSetupFactory;

/**
 * Class InstallData
 * @package Aureatelabs\ProductAttachment\Setup
 *
 * @codeCoverageIgnore
 */
class InstallData implements InstallDataInterface
{
    /**
     * @var EavSetupFactory
     */
    protected $_eavSetupFactory;

    public function __construct(
        EavSetupFactory $eavSetupFactory
    ) {
        $this->_eavSetupFactory = $eavSetupFactory;
    }

    /**
     * {@inheritdoc}
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
     * @SuppressWarnings(PHPMD.NPathComplexity)
     */
    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $eavSetup = $this->_eavSetupFactory->create(["setup"=>$setup]);
        $eavSetup->addAttribute(
            \Magento\Catalog\Model\Product::ENTITY,
            'attachment',
            [
                'group' => 'Product Attachment',
                'type' => 'varchar',
                'label' => 'Attachment',
                'input' => 'file',
                'backend' => 'Aureatelabs\ProductAttachment\Model\Product\Attribute\Backend\File',
                'frontend' => '',
                'class' => '',
                'source' => '',
                'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL,
                'visible' => true,
                'required' => false,
                'user_defined' => true,
                'default' => '',
                'searchable' => false,
                'filterable' => false,
                'comparable' => false,
                'visible_on_front' => false,
                'unique' => false,
                'apply_to' => 'simple,configurable', // applicable for simple and configurable product
                'used_in_product_listing' => true
            ]
        );
    }
}

Here attachment is product attribute code.

  • group: Here we have used Product Attachment in the group. So new attribute created in product admin form will be added in a new tab named  Product Attachment.
  • type: Here we will define varchar in type. We will save file name in attribute so we need varchar in type.
  • label: Define the product attribute label, this label will be shown in product admin form.
  • input: Define file to display file type input in product admin form.
  • backend: In this define the backend model path. This backend model will handle the file upload and will save the value of the attribute when saving the product.
  • user_defined: It is custom attribute so will use true in this column.
  • apply_to: In this column define different product type so this attribute will work with only these product types.
  • used_in_product_listing: To use this attribute value in the frontend in product listing set this to true.

Next, we will create a backend model file to save uploaded file in the media folder and save the file name to this attribute value.

Step 3: Create backend model file to upload product attachment file and save value in attachment attribute

So create File.php in app/code/Aureatelabs/ProductAttachment/Model/Product/Attribute/Backend directory

 
 
 
Copy Code
<?php
namespace Aureatelabs\ProductAttachment\Model\Product\Attribute\Backend;

use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend;

class File extends AbstractBackend
{
    /**
     * @var \Magento\Framework\Filesystem\Driver\File
     */
    protected $_file;

    /**
     * @var \Psr\Log\LoggerInterface
     */
    protected $_logger;

    /**
     * @var \Magento\Framework\Filesystem
     */
    protected $_filesystem;

    /**
     * @var \Magento\MediaStorage\Model\File\UploaderFactory
     */
    protected $_fileUploaderFactory;


    /**
     * Construct
     *
     * @param \Psr\Log\LoggerInterface $logger
     * @param \Magento\Framework\Filesystem $filesystem
     * @param \Magento\MediaStorage\Model\File\UploaderFactory $fileUploaderFactory
     */
    public function __construct(
        \Psr\Log\LoggerInterface $logger,
        \Magento\Framework\Filesystem $filesystem,
        \Magento\Framework\Filesystem\Driver\File $file,
        \Magento\MediaStorage\Model\File\UploaderFactory $fileUploaderFactory
    ) {
        $this->_file = $file;
        $this->_filesystem = $filesystem;
        $this->_fileUploaderFactory = $fileUploaderFactory;
        $this->_logger = $logger;
    }

    public function afterSave($object)
    {

        $path = $this->_filesystem->getDirectoryRead(
            DirectoryList::MEDIA
        )->getAbsolutePath(
            'catalog/product/attachment/'
        );
        $delete = $object->getData($this->getAttribute()->getName() . '_delete');

        if ($delete) {
            $fileName = $object->getData($this->getAttribute()->getName());
            $object->setData($this->getAttribute()->getName(), '');
            $this->getAttribute()->getEntity()->saveAttribute($object, $this->getAttribute()->getName());
            if ($this->_file->isExists($path.$fileName))  {
                $this->_file->deleteFile($path.$fileName);
            }

        }

        if (empty($_FILES['product']['tmp_name'][$this->getAttribute()->getName()])) {
            return $this;
        }

        try {
            /** @var $uploader \Magento\MediaStorage\Model\File\Uploader */
            $uploader = $this->_fileUpzloaderFactory->create(['fileId' => 'product['.$this->getAttribute()->getName().']']);
            $uploader->setAllowRenameFiles(true);
            $result = $uploader->save($path);
            $object->setData($this->getAttribute()->getName(), $result['file']);
            $this->getAttribute()->getEntity()->saveAttribute($object, $this->getAttribute()->getName());
        } catch (\Exception $e) {
            if ($e->getCode() != \Magento\MediaStorage\Model\File\Uploader::TMP_NAME_EMPTY) {
                $this->_logger->critical($e);
            }
        }

        return $this;
    }

}

Now you can see the product attachment tab and input type file attribute in a new tab in product admin form.

Now after attaching file and save the product, the file is uploaded in pub/media/catalog/product/attachment directory and file name stored in attachment attribute value.

But after saving the product in product attachment tab file name is not showing up or how to remove file checkbox is not showing up.

So we will display an anchor tag that contains the file path and we will also add delete checkbox to remove the file in the product attachment tab.

We will use a modifier to add these changes in product attachment tab.

So we will create a di.xml in app/code/Aureatelabs/ProductAttachment/etc/adminhtml directory.

 
 
 
Copy Code
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
   <virtualType name="Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Pool" type="Magento\Ui\DataProvider\Modifier\Pool">
       <arguments>
           <argument name="modifiers" xsi:type="array">
               <item name="attachment" xsi:type="array">
                   <item name="class" xsi:type="string">Aureatelabs\ProductAttachment\Ui\DataProvider\Product\Form\Modifier\File</item>
                   <item name="sortOrder" xsi:type="number">1000</item>
               </item>
           </argument>
       </arguments>
   </virtualType>
</config>

Next, we will create File.php in app/code/Aureatelabs/ProductAttachment/Ui/DataProvider/Product/Form/Modifier directory.

 
 
 
Copy Code
<?php
namespace Aureatelabs\ProductAttachment\Ui\DataProvider\Product\Form\Modifier;

use Magento\Framework\Stdlib\ArrayManager;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier;

class File extends AbstractModifier
{
    /**
     * @var ArrayManager
     */
    protected $arrayManager;

    /**
     * @var StoreManagerInterface
     */
    protected $storeManager;

    /**
     * @param ArrayManager $arrayManager
     * @param StoreManagerInterface $storeManager
     */
    public function __construct(
        ArrayManager $arrayManager,
        StoreManagerInterface $storeManager
    ) {
        $this->arrayManager = $arrayManager;
        $this->storeManager = $storeManager;
    }

    public function modifyMeta(array $meta)
    {
        $fieldCode = 'attachment';
        $elementPath = $this->arrayManager->findPath($fieldCode, $meta, null, 'children');
        $containerPath = $this->arrayManager->findPath(static::CONTAINER_PREFIX . $fieldCode, $meta, null, 'children');

        if (!$elementPath) {
            return $meta;
        }

        $mediaUrl =  $this->storeManager->getStore()
            ->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA);

        $meta = $this->arrayManager->merge(
            $containerPath,
            $meta,
            [
                'children'  => [
                    $fieldCode => [
                        'arguments' => [
                            'data' => [
                                'config' => [
                                    'elementTmpl'   => 'Aureatelabs_ProductAttachment/elements/file',
                                    'media_url' => $mediaUrl
                                ],
                            ],
                        ],
                    ]
                ]
            ]
        );
        return $meta;
    }

    public function modifyData(array $data)
    {
        return $data;
    }
}

We have defined an HTML template file in the modifier.

So next we will create file.html in app/code/Aureatelabs/ProductAttachment/view/adminhtml/web/template/elements diectory.

 
 
 
Copy Code
<input class="admin__control-file" type="file" data-bind="
    hasFocus: focused,
    attr: {
        name: inputName,
        placeholder: placeholder,
        'aria-describedby': noticeId,
        id: uid,
        disabled: disabled,
        form: formId
    }"
/>
<!-- ko if: $parent.source.data.product[code] -->
<span>
    <a attr="href: media_url+'catalog/product/attachment/'+$parent.source.data.product[code]" text="$parent.source.data.product[code]" target="_blank"></a>
    <label attr="for: uid+'_delete'">
        <input type="checkbox" attr="name: 'product['+code + '_delete]', id: uid+'_delete', form: formId">
        <span data-bind="i18n:'Delete'"></span>
    </label>
</span>
<!-- /ko -->

Now after saving the product, it will display anchor tag with attachment file path and delete checkbox.

We have already added define delete file code in backend model app/code/Aureatelabs/ProductAttachment/Model/Product/Attribute/Backend/File.php.

Step 5: Display product attachment in product detail page in frontend

Next, we will create a new product attachment tab in the product detail page and will show product attachment for that product.

So next we will create a catalog_product_view.xml in app/code/Aureatelabs/ProductAttachment/view/frontend/layout directory.

 
 
 
Copy Code
<?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="product.info.details">
        	<block class="Aureatelabs\ProductAttachment\Block\Attachment" name="product.attachment.tab" template="Aureatelabs_ProductAttachment::product_attachment.phtml" group="detailed_info">
            	<arguments>
                	<argument translate="true" name="title" xsi:type="string">Product Attachment</argument>
            	</arguments>
        	</block>
    	</referenceBlock>
	</body>
</page>

As we have defined in layout file we will create block and phtml file.

So next we will create an Attachment.php in app/code/Aureatelabs/ProductAttachment/Block directory.

 
 
 
Copy Code
<?php
namespace Aureatelabs\ProductAttachment\Block;

class Attachment extends \Magento\Catalog\Block\Product\View {

	public function getMediaUrl() {
    	return $this->_storeManager->getStore()
        	->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA);
	}

	public function getProductAttachmentUrl($attachment) {

    	return $this->getMediaUrl()."catalog/product/attachment/".$attachment;

	}
}

Next we will create a product_attachment.phtml in app/code/Aureatelabs/ProductAttachment/view/frontend/templates directory.

 
 
 
Copy Code
<?php
// get current product data
$product = $block->getProduct();


if (!empty($product->getAttachment())) {

	$attachmentUrl = $block->getProductAttachmentUrl($product->getAttachment());
	?>
	<a href="<?php echo $attachmentUrl ?>" target="_blank"><?php echo $product->getAttachment() ?></a>
<?php
}

Now flush cache and open the product detail page. Now you can see the product attachment tab.

Also read:

  1. Add view button in admin grid
  2. Magento 2 Create Admin Button

FAQs

How to upload image in admin form Magento 2?


To upload image in admin form Magento 2, open the admin panel. Navigate to Products>Catalog tab and click on the product to which you add an image. Then, navigate to the Images and Videos tab and click on the camera icon. Here, you can select the required image from your local storage. Click on the orange save button to save all the images.

How do I display data in frontend in Magento 2?


To display data in frontend in Magento 2, follow the below steps:
1. Create a Resource Model for the data in the required table.
2. Create a collection model to fetch data from the table.
3. Extend the model by creating a data interface.
4. Implement the model and locate a block file. 
5. Input data in the phtml file and utilize commands to manage the data.

How to save admin form data in Magento 2?


To save admin form data in Magento 2, check the following steps:
1. Create a submit.php file to save form input data.
2. Locate the file in app\code\Extension\Controller\Index\Submit.php
3. Enter data saved message in the code to display when necessary.
4. Implement the code and test it to save data in the database.

How to upload image in Magento 2 backend?


To upload an image in Magento 2, follow the below-mentioned steps –

1. Inject the Magento\Framework\File\UploaderFactory class in your constructor –
protected $_uploaderFactory;
public function __construct(
// …
\Magento\Framework\File\UploaderFactory $uploaderFactory,
// …
) {
// …
$this->_uploaderFactory = $uploaderFactory;
// …
}

2. Now, use the create() function of the $_uploaderFactory object to create an instance of the \Magento\Framework\File\Uploader class -
$uploader = $this->_uploaderFactory->create(['fileId' => 'image']);

3. Next, set the path to the media folder where you want to upload the image –
$path = 'path/to/media/folder';
$uploader->setAllowCreateFolders(true);
$uploader->setAllowedExtensions(['jpg', 'jpeg', 'gif', 'png']);
$uploader->save($path);

4. Once the image is uploaded, you can use it in your products or pages.

Hello, if you want to learn regarding the configuration creation in Magento 2 then you are at the right place. In this blog, we will cover how to add custom system configuration located in Stores > Configuration

Config.xml in Magento 2

XML is a configuration file that creates configuration fields in Magento 2 System Configuration. You can create config.xml in Magento 2 in 3 simple steps. First, create a custom configuration field with Magento 2. Second, create ACL. And finally, add the default config value on Magento 2 module.

Now we will show you how to execute it in three steps with examples.

Note: Replace Aureatelabs/Jobs from entries in this article with your module name.

Step 1: Create a custom configuration field with Magento 2

Let’s assume that we have created a module for jobs. Now let’s create the system.xml file.

The system.xml file will be located at: app/code/Aureatelabs/Jobs/etc/adminhtml/system.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
<system>
   <tab id="jobs" translate="label" sortOrder="1000">
       <label>Jobs</label>
   </tab>
   <section id="jobs" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
       <label>Jobs</label>
       <tab>jobs</tab>
       <resource>Aureatelabs_Jobs::jobs</resource>
       <group id="department" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
           <label>Job configuration</label>
           <field id="view_list" translate="label comment" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
               <label>Show list</label>
               <comment>Show job list of the viewing department</comment>
               <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
           </field>
       </group>
   </section>
</system>
</config>
  • tab node creates a new tab. The attribute sortOrder allows you to change its position on the list.
  • section node adds a new element to our tab. You can change the text with the label value.
  • group node creates a group of the field on the form. We will create one group with the label Job configuration.
  • We have to set the select type and define the label. We will be using a native object from Magento which will return values “Yes/No”.

Step 2: ACL Creation

Next step is to create ACL for displaying the Configuration. Let’s create acl.xml file.

The acl.xml file will be located at: app/code/Aureatelabs/Jobs/etc/acl.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
<acl>
   <resources>
       <resource id="Magento_Backend::admin">
           <resource id="Aureatelabs_Jobs::job_head" title="Jobs" sortOrder="100" >
               <resource id="Aureatelabs_Jobs::department" title="Departments" sortOrder="10">
                   <resource id="Aureatelabs_Jobs::department_save" title="Save Department" sortOrder="10" />
                   <resource id="Aureatelabs_Jobs::department_delete" title="Delete Department" sortOrder="20" />
               </resource>
               <resource id="Aureatelabs_Jobs::job" title="Jobs" sortOrder="20">
               <resource id="Aureatelabs_Jobs::job_save" title="Save Job" sortOrder="10" />
                   <resource id="Aureatelabs_Jobs::job_delete" title="Delete Job" sortOrder="20" />
               </resource>
           </resource>
           <resource id="Magento_Backend::stores">
               <resource id="Magento_Backend::stores_settings">
                   <resource id="Magento_Config::config">
                       <resource id="Aureatelabs_Jobs::jobs" title="Jobs Section" />
                   </resource>
               </resource>
           </resource>
       </resource>
   </resources>
</acl>
</config>
  • We have added a new node named “Magento_Backend::stores”
  • The last node will be our module node : Aureatelabs_Jobs::jobs
  • The id is equal to the resource node in the system.xml file.

After performing the above steps you need to execute the commands given below:
php bin/magento cache:flush
php bin/magento setup:di:compile

Now refresh the store configuration page and you will find that the admin configuration will be available now.

Step 3: Add default config value on Magento 2 module

Let’s create a config.xml file. The config.xml file will be located at: app/code/Aureatelabs/Jobs/etc/config.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
<default>
   <jobs>
       <department>
           <view_list>1</view_list>
       </department>
   </jobs>
</default>
</config>
  • The default node states that it is the default scope.
  • The next nodes are section, group and field names that are set in system.xml
  • Here we set our default value to 1.

You can check DB value for configuration. Now find core_config_data MySQL table in Magento database. You can find the jobs/department/view_list inside path column in the MySQL table.

This is all. If you follow the above steps carefully you can certainly go live with the customs entry in the system configuration in Magento2. Even if you have any query or doubt regarding this article, you can reach us to make it clear.

Happy Customizing!

Grow your online business like 4,896 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.