Front end - letronghieu4897/magento GitHub Wiki

Front-end

Front-end


1.Override Order Confirmation Email

Marketing > Email Template > Add New Template > Choose New Order > Load
$ OVERRIDE ORDER CONFIRMATION EMAIL
. ________________________________________________________________________________________
β”œβ”€β”€ design
β”‚     └── frontend
|	     └── [Vendor]
|		     └── [Extention]
|			      └── Magento_Sales
|					 └── templates
|						 └── email
|							└── items
|							      └── order
|								     └── default.phtml
. _________________________________________________________________________________________
Go to registration.php 
\vendor\magento\module-sales\registration.php
<?php
/**
 * Copyright Β© Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Magento_Sales',
    __DIR__
);
Create folder in 

β”œβ”€β”€ design
β”‚     └── frontend
|	     └── [Vendor]
|		     └── [Extention]

With name is Magento_Sales : get from registration.php

Then create path source same path into file default.phtml [Look at Tree]

2.Override block, theme.........

1. Go into file registration.php : -> get name of folder : [Netpower_Ghn]
2. Go to design > frontend > [Vendor] > [Theme] > Create folder with name get from [Netpower_Ghn] [1].
3. Create file name the same with file is overrided [Same path] (from template/...)
Block 
<?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">
    <update handle="review_product_form_component"/>
    <body>
        <referenceBlock name="product.info.details">
            <referenceBlock name="reviews.tab" remove="true"/>
             <block class="Magento\Review\Block\Product\Review" name="trustpilot.review.tab" template="Trustpilot_Reviews::review.phtml" />
        </referenceBlock>
    </body>
</page>


1. referenceBlock : Only need the name. [Or referenceContainer]
2. Only reference container contain the block we want to override. 

3.Create new tab

<Example> Review Product </Example>
. ___________________________________________
β”œβ”€β”€ [Vendor]_[Extention]
β”‚            β”œβ”€β”€ layout
|	     β”‚     └── catalog_product_view.xml
|	     └── templates 
|		   └── review.phtml
. ____________________________________________

<1> Create theme </1>
<2> Create file same name in Core : catelog_product_view.xml</2>
<3> Create new block </3>
<4> Create template file : templates > review.phtml
catalog_product_view.xml

<?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">
            <referenceBlock name="reviews.tab" remove="true"/>
            <block class="Magento\Catalog\Block\Product\View" name="trustpilot.review.tab" as="trustpilot.reviews" template="Trustpilot_Reviews::review.phtml" group="detailed_info">
            	<arguments>
            		<argument translate="true" name="title" xsi:type="string">Review</argument>
            	</arguments>
            </block>
        </referenceBlock>
    </body>
</page>
$block : this variable use as Class in block declare above. [Magento\Catalog\Block\Product\View] 

We can you $block as View. 

4.Create new CMS page and add css

1
  • Create forlder follow below tree
. ________________________________________________________________________________________
β”œβ”€β”€ app
β”‚     └── code
|	     └── design
|		     └── frontend
|			      └── [Vendor Theme]
|					 	└── [Source Theme]
|								  └── web 
|									   └── scss
|											 β”œβ”€β”€ helper
|											 β”œβ”€β”€ layout
|											 └── mixins
. __________________________________________________________________________________________
2
  • Create gulpfile.js in root folder
var gulp = require('gulp');
var sass = require('gulp-sass');
var livereload = require('gulp-livereload');
//var sourcemaps = require('gulp-sourcemaps');

gulp.task('sass-porto_child', function(){
  return gulp.src('app/design/frontend/Smartwave/porto_child/web/css/custom.scss')
  	//.pipe(sourcemaps.init())
    .pipe(sass({outputStyle: 'compressed'})) //expanded, nested, compact, compressed
  	//.pipe(sourcemaps.write())
    .pipe(livereload())
    .pipe(gulp.dest('app/design/frontend/Smartwave/porto_child/web/css/'))
    .pipe(gulp.dest('pub/static/frontend/Smartwave/porto_child/nb_NO/css/'));
});

gulp.task('watch', function(){
    livereload.listen();
	  gulp.watch('app/design/frontend/Smartwave/porto_child/web/css/scss/**/*', ['sass-porto_child']);   
});
  • Change name folder in above file
3
  • Create new file package.json
  • Copy package.json.sample -> package.json
  • Run sudo npm install
4
  • Create content for CMS Page
EXAMPLE

<h1 style="color:#4A4A4A;"><strong>DEKK OG FELG GUIDE</strong></h1>
<p style="width: 484px;">Vi vet det kan vΓ¦r forrvirende Γ₯ bestille dekk. Her for du forklaringen som kanskje gjΓΈr det litt enkeler. Alle dekk stΓ₯r det et noen tall og bokstav kombinasjoner, som sier noe om type, stΓΈrrelse og kvaliteten pΓ₯ dekket.</p>
<h2 style="color:#4A4A4A;"><strong>205<span style="color: #b4b4b4;">/55 R 16 87V</span> | SLITEBANE</strong></h2>
<p style="width: 484px;">Det fΓΈrste tallet (205) er bredden pΓ₯ dekkets slitebane i millimeter, her 205 mm.</p>
<h2 style="color:#4A4A4A;"><strong><span style="color: #b4b4b4;">205/</span>55 <span style="color: #b4b4b4;">R 16 87V </span>| PROFIL</strong></h2>
<p style="width: 484px;">Dekkets profil sier noe om dekkets hΓΈyde i forhold til bredde. 55 betyr at dekkets hΓΈyde er 55 prosent av bredden.</p>
<h2 style="color:#4A4A4A;"><strong><span style="color: #b4b4b4;">205/55</span> R <span style="color: #b4b4b4;">16 87V</span> | KONSTRUKSJON</strong></h2>
<p style="width: 484px;">Indikerer konstruksjonsmΓ₯te, i dette tilfellet radialdekk. Kan ogsΓ₯ vΓ¦re D diagonale (gammel mΓ₯te).</p>
<h2 style="color:#4A4A4A;"><strong><span style="color: #b4b4b4;">205/55 R</span> 16 <span style="color: #b4b4b4;"> 87V</span> | FELG</strong></h2>
<p style="width: 484px;">Felgens stΓΈrrelse, diameter mΓ₯lt i tommer.</p>
<h2 style="color:#4A4A4A;"><strong><span style="color: #b4b4b4;">205/55 R 16</span> 87<span style="color: #b4b4b4;">V</span> | BELASTNINGSKLASSE</strong></h2>
<p style="width: 484px;">Belastningsklasse, egen tabel som, 87 = 545 kg. <br> <br> ESK: 545 kg x 4 hjul = 2&nbsp;180 kg totalvekt pΓ₯ bil.</p>
<h2 style="color:#4A4A4A;"><strong><span style="color: #b4b4b4;">205/55 R 16 87</span>V<span style="color: #b4b4b4;"></span> | HASTIGHETSKLASSE</strong></h2>
<p>Belastningsklasse, v = 240 km/h <br><br> Q = 160 km/h, <br><br> R = 170 km/h <br><br> S = 180 km/h <br><br> T = 190 km/h <br><br> H = 210 km/h <br><br> V = 240 km/h <br><br> W = 270 km/h <br><br> Y = 300 km/h</p>
5
  • Code css
    • Create file scss in folder layout has been already created above.
6
  • Create file custom.scss in folder scss has been already created above.
Import file scss into this file.
//EXAMPLE
//IMPORT SCSS ONLY, NO CSS HERE
@import "scss/helper/variables";
@import "scss/mixins/media";
@import "scss/mixins/css3-mixins";
@import "scss/mixins/custom";

@import "scss/layout/common";
@import "scss/layout/contact";
@import "scss/layout/cart";
@import "scss/layout/checkout";
@import "scss/layout/header";
@import "scss/layout/footer";
@import "scss/layout/home";
@import "scss/layout/category";
@import "scss/layout/new-product-list";
@import "scss/layout/product";
@import "scss/layout/product-list";
@import "scss/layout/login";
@import "scss/layout/register";
@import "scss/layout/blog";
@import "scss/layout/page";
@import "scss/layout/my-profile";
@import "scss/layout/search";
@import "scss/layout/popup";
@import "scss/layout/quick-add-to-cart";
@import "scss/layout/update-cart";
@import "scss/layout/404";

/*
	Example for media mixins:
	@include phone{
		//content goes here
	}

	Example for css3 mixins:
	@include border-radius(2px 3px 4px 5px);
	
*/
7
  • Next, We look at the gulpfile.js created before.

5.Add static block into sidebar left

1 For only one page specific.

1. Go to Admin site 
2. Content > Pages > [Your Page] > Edit > Design > Layout Update XML
3. Add to Layout Update XML the below code.
<referenceContainer name="sidebar.additional">
     <block class="Magento\Cms\Block\Block" name="[sidebar_left]">
        <arguments>
            <argument name="block_id" xsi:type="string">[sidebar_left]</argument>
        </arguments>
    </block>
</referenceContainer>

2 For all page /app/design/frontend///Magento_Cms/layout/cms_page_view.xml

. ________________________________________________________________________________________
β”œβ”€β”€ app
|	 └── design
|		   └── frontend
|			      └── [Vendor Theme]
|					 	 └── [Source Theme]
|								  └── Magento_Cms
|									   		└── layout
|											 	   └── cms_page_view.xml
. __________________________________________________________________________________________
<?xml version="1.0"?>
<!--
/**
 * Copyright Β© 2013-2017 Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="sidebar.additional">
            <block class="Magento\Cms\Block\Block" name="mycustomstaticblock">
                <arguments>
                    <argument name="block_id" xsi:type="string">static_block_id</argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

6.Add static block into a block

1. Select Block you want to add a other block into it.

2. Insert Widget > Choose block you want to insert. 
CODE LOOK LIKE THIS : 

{{widget type="Magento\Cms\Block\Widget\Block" template="widget/static_block/default.phtml" block_id="135" type_name="CMS Static Block"}}

7.Container and Block

1. Container : referenceContainer is call this container, this container will contain all child. After call that , The container will echo all child. If you want to add container or block into this. CODE BELOW

2. Block : Only ready that block, not convert child of block. This is difference between Block and Container. You want to Overwrite Block. Write referenceBlock to overwrite.
1. Check where is the container you want to reference. 

2. Often registration.php to see name of Folder

3. Create a Folder with name you found above

4. And then , create path the same with path of container you want to reference. With same name file.

5. Add code below
<?xml version="1.0"?>
<!--
/**
 * Copyright Β© 2018 Porto. All rights reserved.
 */
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="page.top">
            <container name="banner-top-container" htmlTag="div" htmlClass="banner-top" before="-">            
                <container name="banner-top-container-inside">
                    <block class="Magento\Cms\Block\Block" name="banner-top">
                        <arguments>
                            <argument name="block_id" xsi:type="string">category_banner_top</argument>
                        </arguments>
                    </block>
                </container>
            </container>
        </referenceContainer>
    </body>
</page>

Explain

<container name="banner-top-container" htmlTag="div" htmlClass="banner-top" before="-">  

1. before="-" 					: Insert container on head.
2. before="<container-name>" 	: Insert container on top of this container name.
3. WITH after is opposite.
1. Inspect to check container or block base on command 

getChildBlock

<referenceBlock name="parent">
    <Block name="children" class="..." template="..." />
</referenceBlock>

In block "parent" we can call child block by 

$block->getChildHtml('children'); 
   or
$block->getChildBlock('children');

8.Banner and Slider

1. Load or Copy extension : Banner Slider.

2. Create a banner and add banner to slider.

3. Add banner to page.

9.Multiple languages

. ________________________________________________________________________________________
β”œβ”€β”€ app
|	 └── design
|		   └── frontend
|			      └── [Vendor Theme]
|					 	 └── [Source Theme]
|									└── i18n
|										 └── nb_NO.csv 
. __________________________________________________________________________________________
Translate English to Norway languages

"Add to Cart","LEGG I HANDLEKURV"

10.Fix layout of theme

Example in Bridgestone
. ________________________________________________________________________________________
β”œβ”€β”€ app
|	 └── design
|		   └── frontend
|			      └── Smartwave
|					 	 β”œβ”€β”€ porto
|						 |	   └── pla pla pla
|						 |				 └── category_filter.phtml
|						 └── porto-child 
|							    └── pla pla pla 
|										  └── category_filter.phtml  
. __________________________________________________________________________________________
1. Create a path the same with folder of theme. 
porto : Parent theme.
porto-child : Theme overwrite.

2. Copy file from porto to porto-child 

11.Get image from Category Image

*NOTE : WRONG WAY

<?php
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$storeManager = $objectManager->get('\Magento\Store\Model\StoreManagerInterface');
$mediaUrl =$storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA);
$category = $objectManager->get('Magento\Framework\Registry')->registry('current_category'); //Get Current Category
?>
<?php if($category): ?>
<?php 
$subcats = $category->getChildrenCategories();
$_helper = $this->helper('Magento\Catalog\Helper\Output');
    if(count($subcats)>0){
?>
<div class="block-category-list">
    <div class="block-head">
        <p> <?= __('FINN DEKK') ?> </p>
    </div>
    <div class="block-title">
        <img src="<?= $mediaUrl ?>catalog/tmp/category/<?= strtolower(preg_replace('/[^A-Za-z0-9\-]/', '', str_replace(" ", "_", $category->getName())));?>.png"/>
        <strong><?php echo $category->getName() ?></strong>
    </div>
    <div class="block-content">
        <ol class="items">
        <?php
        foreach($subcats as $subcat){ 
        ?>
            <li class="item">
                <img src="<?= $mediaUrl ?>catalog/tmp/category/<?= strtolower(preg_replace('/[^A-Za-z0-9\-]/', '', str_replace(" ", "_", $subcat->getName())));?>.png"/>
                <a href="<?php echo $subcat->getUrl() ?>"><?php echo $subcat->getName() ?></a>
            </li>
        <?php
            }
        ?>
        </ol>
    </div>
    <script type="text/javascript">
    require([
        'jquery'
    ], function ($) {
        $("#layered-filter-block").before($(".block.block-category-list"));
    });
    </script>
</div>
<?php
    }
?>
<?php endif; ?>
GET MEDIA URL to combine with path image in category.

$storeManager = $objectManager->get('\Magento\Store\Model\StoreManagerInterface');
$mediaUrl =$storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA);
$mediaUrl ?>catalog/tmp/category/<?= strtolower(preg_replace('/[^A-Za-z0-9\-]/', '', str_replace(" ", "_", $category->getName())));

1. $mediaUrl : Above 

2. catalog/tmp/category : Folder contain image in admin categories image

3. strtolower : Transfer to lower words 

4. preg_replace : Remove special letters 

5. str_replace : replace any word you need. 

=> Purpose : Replace name of Category to a lower words without space between words. To specific image name. 

YOU WANT TO CHANGE IMAGE IN MENU LEFT SIDEBAR. 
1. Set the name of image with rule : <nameoficon>. 
2. Load it in specific category.
DONE.

RIGHT WAY

<?php
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$storeManager = $objectManager->get('\Magento\Store\Model\StoreManagerInterface');
$mediaUrl =$storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA);
$category = $objectManager->get('Magento\Framework\Registry')->registry('current_category'); //Get Current Category
?>
<?php if($category): ?>
<?php 
$subcats = $category->getChildrenCategories();
$_helper = $this->helper('Magento\Catalog\Helper\Output');
    if(count($subcats)>0){
?>
<div class="block-category-list">
    <div class="block-head">
        <p> <?= __('FINN DEKK') ?> </p>
    </div>
    <div class="block-title">
        <div class="container-icon-title">
            <img src="<?= $category->getImageUrl();?>"/>
        </div>
        <strong><?php echo $category->getName(); ?></strong>
    </div>
    <div class="block-content">
        <ol class="items">
        <?php
        foreach($subcats as $subcat){ 
            $_category = $objectManager->create('Magento\Catalog\Model\Category')->load($subcat->getId());
            
        ?>
            <li class="item">
                <div class="container-icon-content">
                    <img src="<?= $_category->getImageUrl();?>"/>
                </div>
                <a href="<?php echo $subcat->getUrl() ?>"><?php echo strtoupper($subcat->getName()) ?></a>
            </li>
        <?php
            }
        ?>
        </ol>
    </div>
    <script type="text/javascript">
    require([
        'jquery'
    ], function ($) {
        $("#layered-filter-block").before($(".block.block-category-list"));
    });
    </script>
</div>
<?php
    }
?>
<?php endif; ?>
<img src="<?= $category->getImageUrl();?>"/> 

Get image of Category 
<?php
        foreach($subcats as $subcat){ 
           ******** $_category = $objectManager->create('Magento\Catalog\Model\Category')->load($subcat->getId()); ********
        ?>
            <li class="item">
                <div class="container-icon-content">
                    <img src="<?= $_category->getImageUrl();?>"/>
                </div>
                <a href="<?php echo $subcat->getUrl() ?>"><?php echo strtoupper($subcat->getName()) ?></a>
            </li>
        <?php
            }
        ?>

GET IMAGE OF CHILD CATEGORY.

12.Navigation Attribute

Hiding Attribute in Navigation

- Store > Product > Choose Attribute > Storefront Properties > Use in Layered Navigation -> NO

Find Attribute

- Go to store > F12 > Check attribute =<"attribute-name">

- Copy attribute-name > Go to Admin site > Store > Product > Search Attribute with attribute-name

13.Add static block into phtml files

1. Create static block on admin (get Block ID EXAMPLE === block-id)

2. WAY 1 : insert into XML			

3. WAY 2 : create template files

WAY 1

layout/local.xml
=====================================================================
EXAMPLE : INSERT STATIC BLOCK INSIDE after_body_start
======================================================================
<reference name="after_body_start">
            <block type="cms/block" name="google_tag_block" before="-">
   				 <action method="setBlockId"><block_id>block-id</block_id></action>
			</block> 
</reference>

WAY 2

<reference name="after_body_start">
    <block type="core/template" before="-" template="page/html/google_code.phtml"/>
</reference>
page/html/google_code.phtml
=========================================================================================================
<?php echo $this->getLayout()->createBlock('cms/block')->setBlockId('block-id')->toHtml() ?>

WAY 3

1. Create extend layout file
2. Reference container contain Block you want to add Block
3. Add Block (static)
<block class="Magento\Cms\Block\Block" before="<block-name>"> 
	<arguments>
		<argument name="block-id" xsi:type = string>[id-block]</argument>
	</arguments>
</block>

14.Preference in di.xml

<config>
    <preference for = 'Magento\...\UrlInterface' 
                type = 'Magento\...\Url' />
</config>

# When having request to Magento\...\UrlInterface it will be inject into Magento\...\Url
// DEPENDENCE INJECTION

15.Virtual Type

<virtualType name="Netpower\...\className">
    <argument name="valu" type="object">Netpower\...\TEST</argument>
</virtualType>

--- Block Netpower\...\TEST having mission is pass data into valu. [1]

--- In block Netpower\...\className can get value of argument by : getValu(); [2]

[2] get data from [1]. We can call class Netpower\...\className and use valu as real Block class.

16.Onestep checkout

Copy extension OnePageCheckout from BLF or Lenspower from Lenspower.
[Need append more information]

17.Animation for add to cart

    app/code/Netpower/Lenspower/view/frontend/web/js/catalog-add-to-cart.js

18.Override JS magento 2

Check file requirejs-config.js of file need to override and copy Name or Path to your module in file requirejs-config.js

var config = {
    map: {
        '*': {
            'Magento_Checkout/js/view/summary/abstract-total':'Netpower_Lenspower/js/view/checkout/summary/abstract-total',
            configurableLens: 'Netpower_Lenspower/js/configurable',
            packageLens: 'Netpower_Lenspower/js/package',
            catalogAddToCart : 'Netpower_Lenspower/js/catalog-add-to-cart', 
            // catalogAddToCart is a name of path for catalog-add-to-cart.js in core module
        }
    }
};

19.Add script for magento 2

Example for Scroll header menu mobile LENSPOWER

1. Create file Magento_Theme/web/js/custom_header_script.js

2. Create file Magento_Theme/templates/html/custom_script.phtml

<script type="text/x-magento-init">
	{
        "*": {   //======================================== APPLY FOR ALL ELEMENT
           "Magento_Theme/js/custom_script": {}
        }.
        ".page-header" : { //======================================== USE FOR $.widget with this.element = .page-header DOM
            "Magento_Theme/js/custom_header_script" : {}
        }
    }
</script>

3. Write JS for custom_header_script.js NOTE : Using Widget.

define([
        "jquery",
        'mage/translate'
    ],
    function ($, $t) {

        'use strict';

        $.widget('mage.headerScroll', { //============================= Declare a widget
            _create: function () {
                var self = this.element;
                var startPos = $(".slider-container.slider-container-homepage").height() - 60;
                if ($(document).width() < 768) {
                    $(".page-header .header.content .logo").append("<a href='javascript:void(0)' id='stickyMenUSearchBut' class='sticky-menu-search-button'></a>");
                    $("#stickyMenUSearchBut").click(function() {
                        $(".page-header .header .block-search").slideToggle(300);
                    });
                }
                $(window).on('scroll', function() {
                    $('#stickyMenUSearchBut').hide();
                    if ($(window).scrollTop() >= startPos) {
                        $("body").addClass("has-sticky-menu");
                        $(".page-header .header .block-search").hide();
                        $('#stickyMenUSearchBut').show();
                    } else {
                        $('#stickyMenUSearchBut').hide();
                        $("body").removeClass("has-sticky-menu");
                        $(".page-header .header .block-search").show();
                    }
                });

            },
        });

        return $.mage.headerScroll //============================= Return widget was declared
    });

20.Product Detail

1. Price - Tax - Admin config

app/design/frontend/Smartwave/porto_child/Magento_Catalog/templates/product/price/amount/default.phtml
<?php
/**
 * Copyright Β© Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

// @codingStandardsIgnoreFile

?>

<?php /** @var \Magento\Framework\Pricing\Render\Amount $block */ ?>
<?php /** @var \Magento\Tax\Helper\Data $_taxHelper */ ?>
<?php $_taxHelper = $this->helper('Magento\Tax\Helper\Data'); ?>
<?php
$labelTax = "";

if ($_taxHelper->displayPriceIncludingTax()) {
    $labelTax = strtolower($block->escapeHtml(__('Incl. Tax')));
}

if ($_taxHelper->displayPriceExcludingTax()) {
    $labelTax = strtolower($block->escapeHtml(__('Excl. Tax')));
}

if ($_taxHelper->displayBothPrices()) {
    $labelTax = strtolower($block->escapeHtml(__('Incl. Tax')));
}
?>

<span class="price-container <?= /* @escapeNotVerified */ $block->getAdjustmentCssClasses() ?>"
    <?= $block->getSchema() ? ' itemprop="offers" itemscope itemtype="http://schema.org/Offer"' : '' ?>>
    <div class="adjustment-price">
        <?php if ($block->hasAdjustmentsHtml()): ?>
            <?= $block->getAdjustmentsHtml() ?>
        <?php endif; ?>
    </div>
    <div class="price">
        <?php if ($labelTax): ?>
            <span class="price-label"><?= /* @escapeNotVerified */ $labelTax ?></span>
        <?php endif; ?>
        <span <?php if ($block->getPriceId()): ?> id="<?= /* @escapeNotVerified */ $block->getPriceId() ?>"<?php endif;?>
            <?= ($block->getPriceDisplayLabel()) ? 'data-label="' . $block->getPriceDisplayLabel() . $block->getPriceDisplayInclExclTaxes() . '"' : '' ?>
            data-price-amount="<?= /* @escapeNotVerified */ $block->getDisplayValue() ?>"
            data-price-type="<?= /* @escapeNotVerified */ $block->getPriceType() ?>"
            class="price-wrapper <?= /* @escapeNotVerified */ $block->getPriceWrapperCss() ?>"
        ><?= /* @escapeNotVerified */ $block->formatCurrency($block->getDisplayValue(), (bool)$block->getIncludeContainer()) ?></span>
        <?php if ($block->getSchema()): ?>
            <meta itemprop="price" content="<?= /* @escapeNotVerified */ $block->getDisplayValue() ?>" />
            <meta itemprop="priceCurrency" content="<?= /* @escapeNotVerified */ $block->getDisplayCurrencyCode() ?>" />
        <?php endif; ?>
    </div>
</span>

21.KnockoutJS

1.Click event - with Jquery

/**
 * Copyright 2019 Netpower, Inc. All rights reserved.
 */

/*global define*/
define([
    'jquery',
    'underscore',
    'Magento_Checkout/js/view/shipping',
    'ko',
    'Magento_Checkout/js/model/quote',
    'Magento_Checkout/js/action/select-shipping-method',
    'Magento_Checkout/js/action/set-shipping-information',
    'Magento_Checkout/js/checkout-data',
    'Magento_Checkout/js/action/get-totals',
    'Magento_Checkout/js/model/address-converter',
    'Magento_Customer/js/model/customer',
    'Magento_Checkout/js/action/select-shipping-address',
    'Magento_Customer/js/model/address-list',
    'Netpower_OnePageCheckout/js/model/payment/is-loading',
    'Netpower_OnePageCheckout/js/action/checkout/select-shipping-method'
], function ($,
             _,
             Component,
             ko,
             quote,
             selectShippingMethodAction,
             setShippingInformationAction,
             checkoutData,
             getTotals,
             addressConverter,
             customer,
             selectShippingAddress,
             addressList,
             paymentIsLoading,
             onepageShippingMethod) {
    'use strict';
    var self;
    return Component.extend({
        defaults: {
            template: 'Netpower_OnePageCheckout/checkout/shipping-method'
        },
        isAddressFormVisible: ko.observable(addressList().length === 0),
        visible: ko.observable(true),
        shippingRateGroup: ko.observable(),
        shippingRate: ko.observable(),
        setupListener: function () {
            $('#onepage-checkout-shipping-method-additional-load').on('change', 'input', function () {
                setShippingInformationAction();
            });
        },

        initialize: function () {
            self = this;
            this._super();
        },

        /**
         * Set shipping information handler
         */
        setShippingInformation: function () {
            if (this.isAddressFormVisible()) {
                var shippingAddress,
                    addressData;
                shippingAddress = quote.shippingAddress();
                addressData = addressConverter.formAddressDataToQuoteAddress(
                    this.source.get('shippingAddress')
                );

                for (var field in addressData) {
                    if (addressData.hasOwnProperty(field) &&
                        shippingAddress.hasOwnProperty(field) &&
                        typeof addressData[field] !== 'function' &&
                        _.isEqual(shippingAddress[field], addressData[field])
                    ) {
                        shippingAddress[field] = addressData[field];
                    } else if (typeof addressData[field] !== 'function' && !_.isEqual(shippingAddress[field], addressData[field])) {
                        shippingAddress = addressData;
                        break;
                    }
                }

                if (customer.isLoggedIn()) {
                    shippingAddress.save_in_address_book = this.saveInAddressBook ? 1 : 0;
                }

                selectShippingAddress(shippingAddress);
                if (customer.isLoggedIn()) {
                    checkoutData.setNewCustomerShippingAddress(shippingAddress);
                }

            }

            if (quote.shippingMethod()) {
                paymentIsLoading.isLoading(true);
                return setShippingInformationAction().always(function () {
                    paymentIsLoading.isLoading(false);
                });
            } else {
                return $.Deferred();
            }
        },

        /**
         * @param {Object} shippingMethod
         * @return {Boolean}
         */
        selectShippingMethod: function (shippingMethod) {
            self.setShippingInformation();
            onepageShippingMethod(shippingMethod);
            return true;
        },
// HERE ====================================================================================
        setHeightForShippingMethod:  function() {
            var self = $(this);
            var setHeightElement = $('#checkout-step-shipping_method').find('.np-checkout-shipping-method').first();
            if($(setHeightElement).hasClass('clear-max-height')) {
                $(setHeightElement).removeClass('clear-max-height');
            }
            else {
                $(setHeightElement).addClass('clear-max-height');
            }
        }
    });
});

Using It

<div data-bind="click: setHeightForShippingMethod" class="read-more-information" id="js-read-more-information">
    <a>
        <span data-bind="i18n: 'More Shipping'"></span>
    </a>
</div>

22.Template on JS file

1. Button -,+ on checkout (BLF)

app/code/Netpower/OnePageCheckout/view/frontend/web/js/view/checkout/summary/item/details.js
/**
 * Copyright 2019 Netpower, Inc. All rights reserved.
 */

define(
    [
        'jquery',
        'uiComponent',
        'mage/storage',
        'Magento_Customer/js/customer-data',
        'Magento_Checkout/js/action/get-totals',
        'Magento_Checkout/js/model/totals',
        'Magento_Checkout/js/model/quote',
        'Netpower_OnePageCheckout/js/action/reload-shipping-method',
        'Magento_Checkout/js/action/get-payment-information',
        'Magento_Ui/js/modal/confirm',
        'Magento_Ui/js/modal/alert',
        'mage/translate',
        'Magento_Catalog/js/price-utils'
    ],
    function (
        $,
        Component,
        storage,
        customerData,
        getTotalsAction,
        totals,
        quote,
        reloadShippingMethod,
        getPaymentInformation,
        confirm,
        alertPopup,
        Translate,
        priceUtils
    ) {
        "use strict";
        return Component.extend({


            params: '',
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 
            defaults: {
                template: 'Netpower_OnePageCheckout/checkout/summary/item/details'
            },
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 
            getIndex: function(index) {
                return index + ' ' + $.mage.__(' pcs.');
            },

            getValue: function(quoteItem) {
                return quoteItem.name;
            },

            addQty: function (data) {
                this.updateQty(data.item_id, 'update', data.qty + 1);
            },

            minusQty: function (data) {
                this.updateQty(data.item_id, 'update', data.qty - 1);
            },

            updateNewQty: function (data) {
                this.updateQty(data.item_id, 'update', data.qty);
            },
            
            deleteItem: function (data) {
                var self = this;
                confirm({
                    content: $.mage.__('Do you want to remove the item from cart?'),
                    actions: {
                        confirm: function () {
                            self.updateQty(data.item_id, 'delete', '');
                        },
                        always: function (event) {
                            event.stopImmediatePropagation();
                        }
                    }
                });

            },

            showOverlay: function () {
                $('body').trigger('processStart');
            },

            hideOverlay: function () {
                $('body').trigger('processStop');
            },

            showPaymentOverlay: function () {
                $('#control_overlay_payment').show();
                $('#ajax-payment').show();
            },

            hidePaymentOverlay: function () {
                $('#control_overlay_payment').hide();
                $('#ajax-payment').hide();
            },

            updateTotal: function(point) {
                var listReward = {
                    '0': 'rewardpoint-earning',
                    '1': 'rewardpoint-spending',
                    '2': 'rewardpoint-use_point'
                };
                totals.isLoading(true);
                $.ajax({
                    url: rewardpointConfig.urlUpdateTotal,
                    type: 'POST',
                    data: {'reward_sales_rule': 'rate', 'reward_sales_point': point},
                    complete: function (data) {
                        var arrDataReward = $.map($.parseJSON(data.responseText), function (value, index) {
                            return [value];
                        });
                        $.dataReward = arrDataReward;
                        var deferred = $.Deferred();
                        getPaymentInformation(deferred);
                        $.when(deferred).done(function () {
                            $.each(listReward, function (key, val) {
                                $('tr.' + val).show();
                                $('tr.' + val + ' td.amount span').text($.dataReward[key]);
                            })
                            totals.isLoading(false);
                        });
                    },
                });
            },

            updateQty: function (itemId, type, qty) {
                var params = {
                    itemId: itemId,
                    qty: qty,
                    updateType: type
                };
                var self = this;
                this.showOverlay();
                storage.post(
                    'onestepcheckout/quote/update',
                    JSON.stringify(params),
                    false
                ).done(
                    function (result) {
                        var miniCart = $('[data-block="minicart"]');
                        miniCart.trigger('contentLoading');
                        customerData.reload('cart', true);
                        miniCart.trigger('contentUpdated');
                    }
                ).fail(
                    function (result) {

                    }
                ).always(
                    function (result) {
                        if (result.error) {
                            alertPopup({
                                content: Translate(result.error),
                                autoOpen: true,
                                clickableOverlay: true,
                                focus: "",
                                actions: {
                                    always: function(){

                                    }
                                }
                            });
                        }

                        if(result.cartEmpty || result.is_virtual){
                            window.location.reload();
                        }else{
                            if (result.rewardpointsEarning) {
                                $('tr.rewardpoint-earning td.amount span').text(result.rewardpointsEarning);
                            }
                            if (result.rewardpointsSpending) {
                                $('tr.rewardpoint-spending td.amount span').text(result.rewardpointsSpending);
                            }
                            if (result.rewardpointsUsePoint) {
                                $('tr.rewardpoint-use_point td.amount span').text(result.rewardpointsUsePoint);
                            }
                            if (result.affiliateDiscount) {
                                $('tr td.amount span').each(function () {
                                    if ($(this).data('th') == Translate('Affiliateplus Discount')) {
                                        if (result.affiliateDiscount) {
                                            $(this).text(priceUtils.formatPrice(result.affiliateDiscount, quote.getPriceFormat()));
                                            $(this).show();
                                        } else {
                                            $(this).hide();
                                        }

                                    }
                                })
                            }
                            if (result.getRulesJson && window.checkoutConfig.isCustomerLoggedIn) {
                                var rewardSliderRules = $.parseJSON(result.getRulesJson).rate;
                                var $range = $("#range_reward_point");
                                var rewardpointConfig = result;
                                rewardpointConfig.checkMaxpoint = parseInt(rewardpointConfig.checkMaxpoint);
                                if(rewardpointConfig.checkMaxpoint){
                                    self.updateTotal(rewardSliderRules.sliderOption.maxPoints);
                                    $('#reward_sales_point').val(rewardSliderRules.sliderOption.maxPoints);
                                }
                                var slider = $range.data("ionRangeSlider");
                                slider.update({
                                    grid:true,
                                    grid_num:((rewardSliderRules.sliderOption.maxPoints<4)?rewardSliderRules.sliderOption.maxPoints:4),
                                    min:rewardSliderRules.sliderOption.minPoints,
                                    max:rewardSliderRules.sliderOption.maxPoints,
                                    step:rewardSliderRules.sliderOption.pointStep,
                                    from:((rewardpointConfig.checkMaxpoint)?rewardSliderRules.sliderOption.maxPoints:rewardpointConfig.usePoint),
                                    onUpdate: function (data) {
                                        if(rewardSliderRules.sliderOption.maxPoints == data.from){
                                            $('#reward_max_points_used').attr('checked','checked');
                                        }else{
                                            $('#reward_max_points_used').removeAttr('checked');
                                        }
                                        $("#reward_sales_point").val(data.from);
                                        self.updateTotal(data.from);
                                    }
                                });
                            }
                            reloadShippingMethod();
                            getPaymentInformation().done(function () {
                                self.hideOverlay();
                            });
                        }

                    }
                );
            }
        });
    }
);

Template file

app/code/Netpower/OnePageCheckout/view/frontend/web/template/checkout/summary/item/details.html
<!--
/**
 * Copyright 2019 Netpower, Inc. All rights reserved.
 */
-->

<div class="before_details">
    <!-- ko foreach: getRegion('before_details') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
    <!-- /ko -->
</div>
<div class="product-item-details">
    <!-- ko foreach: getRegion('top_details') -->
    <!-- ko template: getTemplate() --><!-- /ko -->
    <!-- /ko -->

    <div class="product-item-inner">
        <div class="product-item-name" data-bind="text: $parent.name"></div>
    </div>

    <!-- ko foreach: getRegion('additional_details') -->
    <!-- ko template: getTemplate() --><!-- /ko -->
    <!-- /ko -->

    <!-- ko if: (JSON.parse($parent.options).length > 0)-->
    <div class="product options" data-bind="mageInit: {'collapsible':{'openedState': 'active'}}">
        <span data-role="title" class="toggle"><!-- ko i18n: 'View Details' --><!-- /ko --></span>
        <div data-role="content" class="content">
            <strong class="subtitle"><!-- ko i18n: 'Options Details' --><!-- /ko --></strong>
            <div class="item-options">
                <!--ko foreach: JSON.parse($parent.options)-->
                <dl>
                    <dt class="label" data-bind="text: label"></dt>
                    <!-- ko if: ($data.full_view)-->
                    <dd class="values" data-bind="html: full_view"></dd>
                    <!-- /ko -->
                    <!-- ko ifnot: ($data.full_view)-->
                    <dd class="values" data-bind="html: value"></dd>
                    <!-- /ko -->
                </dl>
                <!-- /ko -->
            </div>
        </div>
    </div>
    <!-- /ko -->

    <!-- ko foreach: getRegion('bottom_details') -->
    <!-- ko template: getTemplate() --><!-- /ko -->
    <!-- /ko -->

</div>

<div class="details-qty">
    <div class="product-item-head">
        <span data-bind="i18n: 'Number of packages'"></span>
    </div>
    <div class="box-qty">
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 
        <!--<select name="qty" data-bind="value: $parent.qty, event :{change: function(){updateNewQty($parent)}}, foreach: new Array(30)">-->
            <!--<option data-bind="text: $parent.getIndex($index()+1), value: $index()+1"></option>-->
        <!--</select>-->
        <div data-change-type="minus" class="osc-minus" data-bind="click: function(){minusQty($parent)}">-</div>
        <input class="qty qty-item-display" data-bind="value: $parent.qty, event :{change: function(){updateNewQty($parent)}}">
        <div data-change-type="add" class="osc-add" data-bind="click: function(){addQty($parent)}">+</div>
    </div>
</div>
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 
<div class="after_details">
    <!-- ko foreach: getRegion('after_details') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
    <!-- /ko -->
</div>

<div class="osc-delete" data-bind="click: function(){deleteItem($parent)}">
    <span data-bind="i18n: 'Delete'"></span>
</div>

23. Override mage js file

- Need override on theme (Not override on module)

- /<Vendor>/<THEME>...

24. Override widget js

1. Declare on require-js

2. create js file same path on require
EXAMPLE

define([
'jquery'
], function($){
  'use strict';
  return function () {
     $.widget('mage.validation', $.mage.validation, {
       _listenFormValidate: function() {
          this.element.on('invalid-form.validate', this.listenFormValidateHandler);
       }
     });
     return $.mage.validation;
   };
});

25. Get price to show on product list

<?php
/**
* Copyright Β© Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

// @codingStandardsIgnoreFile

?>

<?php
/** @var \Magento\Catalog\Pricing\Render\FinalPriceBox $block */

/** ex: \Magento\Catalog\Pricing\Price\RegularPrice */
/** @var \Magento\Framework\Pricing\Price\PriceInterface $priceModel */
$priceModel = $block->getPriceType('regular_price');
$productId = $block->getSaleableItem()->getId();
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();

//Load product by product id
$_product = $objectManager->create('Magento\Catalog\Model\Product')->load($productId);

/** ex: \Magento\Catalog\Pricing\Price\FinalPrice */
/** @var \Magento\Framework\Pricing\Price\PriceInterface $finalPriceModel */
$finalPriceModel = $block->getPriceType('final_price');
$idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : '';
$schema = ($block->getZone() == 'item_view') ? true : false;
==================== HERE ===============================================================
//var_dump($finalPriceModel->getAmount()->getValue());
//var_dump($priceModel->getAmount()->getValue());
//var_dump($this->helper('\Magento\Catalog\Helper\Data')->getTaxPrice($_product, $finalPriceModel->getAmount()->getValue()));
//var_dump($this->helper('\Magento\Catalog\Helper\Data')->getTaxPrice($_product, $priceModel->getAmount()->getValue()));
====================================================================================
?>
<?php if ($block->hasSpecialPrice()): ?>

   <span class="special-price">
       <?php /* @escapeNotVerified */ echo $block->renderAmount($finalPriceModel->getAmount(), [
           'display_label'     => __('Special Price'),
           'price_id'          => $block->getPriceId('product-price-' . $idSuffix),
           'price_type'        => 'finalPrice',
           'include_container' => true,
           'schema' => $schema
       ]); ?>
       <span class="old-price">
           <?php /* @escapeNotVerified */ echo $block->renderAmount($priceModel->getAmount(), [
               'display_label'     => __('Regular Price'),
               'price_id'          => $block->getPriceId('old-price-' . $idSuffix),
               'price_type'        => 'oldPrice',
               'include_container' => true,
               'skip_adjustments'  => true
           ]); ?>
       </span>
   </span>


<?php else: ?>
   <?php /* @escapeNotVerified */ echo $block->renderAmount($finalPriceModel->getAmount(), [
       'price_id'          => $block->getPriceId('product-price-' . $idSuffix),
       'price_type'        => 'finalPrice',
       'include_container' => true,
       'schema' => $schema
   ]); ?>
<?php endif; ?>

<?php if ($block->showMinimalPrice()): ?>
   <?php if ($block->getUseLinkForAsLowAs()):?>
       <a href="<?= /* @escapeNotVerified */ $block->getSaleableItem()->getProductUrl() ?>" class="minimal-price-link">
           <?= /* @escapeNotVerified */ $block->renderAmountMinimal() ?>
       </a>
   <?php else:?>
       <span class="minimal-price-link">
           <?= /* @escapeNotVerified */ $block->renderAmountMinimal() ?>
       </span>
   <?php endif?>
<?php endif; ?>

26. Show original price on product list of configurable product when apply price rule

Magento_ConfigurableProduct/templates/product/price/final_price.phtml 

<?php
/**
 * Copyright Β© Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

// @codingStandardsIgnoreFile

?>

<?php
/** @var \Magento\ConfigurableProduct\Pricing\Render\FinalPriceBox$block */

/** @var \Magento\Framework\Pricing\Price\PriceInterface $priceModel */
$priceModel = $block->getPriceType('regular_price');

/** @var \Magento\Framework\Pricing\Price\PriceInterface $finalPriceModel */
$finalPriceModel = $block->getPriceType('final_price');
$idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : '';
$schema = ($block->getZone() == 'item_view') ? true : false;
?>
<span class="normal-price">
    <?php
    $arguments = [
        'display_label' => __('As low as'),
        'price_id' => $block->getPriceId('product-price-' . $idSuffix),
        'price_type' => 'finalPrice',
        'include_container' => true,
        'schema' => $schema,
    ];
    /* @noEscape */ echo $block->renderAmount($finalPriceModel->getAmount(), $arguments);
    ?>
</span>

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 
<?php if ($block->hasSpecialPrice()): ?>
    <span class="old-price sly-old-price no-display">
        <?php /* @escapeNotVerified */ echo $block->renderAmount($priceModel->getAmount(), [
            'display_label'     => __('Regular Price'),
            'price_id'          => $block->getPriceId('old-price-' . $idSuffix),
            'price_type'        => 'oldPrice',
            'include_container' => true,
            'skip_adjustments'  => true
        ]); ?>
    </span>
<?php endif; ?>
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 

<?php if ($block->showMinimalPrice()): ?>
    <?php if ($block->getUseLinkForAsLowAs()):?>
        <a href="<?= /* @escapeNotVerified */ $block->getSaleableItem()->getProductUrl() ?>" class="minimal-price-link">
            <?= /* @escapeNotVerified */ $block->renderAmountMinimal() ?>
        </a>
    <?php else:?>
        <span class="minimal-price-link">
            <?= /* @escapeNotVerified */ $block->renderAmountMinimal() ?>
        </span>
    <?php endif?>
<?php endif; ?>

27. Show label sale price on product list of configurable product when apply price rule

<?php
/**
 * Copyright Β© Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

// @codingStandardsIgnoreFile

?>

<?php
$productId = $block->getSaleableItem()->getId();
/** @var \Magento\ConfigurableProduct\Pricing\Render\FinalPriceBox$block */

/** @var \Magento\Framework\Pricing\Price\PriceInterface $priceModel */
$priceModel = $block->getPriceType('regular_price');

/** @var \Magento\Framework\Pricing\Price\PriceInterface $finalPriceModel */
$finalPriceModel = $block->getPriceType('final_price');
$idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : '';
$schema = ($block->getZone() == 'item_view') ? true : false;
?>
<span class="normal-price">
    <?php
    $arguments = [
        'display_label' => __('As low as'),
        'price_id' => $block->getPriceId('product-price-' . $idSuffix),
        'price_type' => 'finalPrice',
        'include_container' => true,
        'schema' => $schema,
    ];
    /* @noEscape */ echo $block->renderAmount($finalPriceModel->getAmount(), $arguments);
    ?>
</span>

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 
<?php if ($block->hasSpecialPrice()): ?>
    <?php
       $finalPriceSales = $finalPriceModel->getAmount()->getValue();
       $originalPriceSales = $priceModel->getAmount()->getValue();
       $salePricesRule = (100 - round(($finalPriceSales/$originalPriceSales)*100));
       echo $product_labels = '<div class="product-labels configurable price-rule js-configurable-price-rule-label-'.$productId.'" ><div class="product-label sale-label">'.'-'.$salePricesRule.'%'.'</div></div>';

   ?>
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 
    <span class="old-price sly-old-price no-display">
        <?php /* @escapeNotVerified */ echo $block->renderAmount($priceModel->getAmount(), [
            'display_label'     => __('Regular Price'),
            'price_id'          => $block->getPriceId('old-price-' . $idSuffix),
            'price_type'        => 'oldPrice',
            'include_container' => true,
            'skip_adjustments'  => true
        ]); ?>
    </span>
<?php endif; ?>

<?php if ($block->showMinimalPrice()): ?>
    <?php if ($block->getUseLinkForAsLowAs()):?>
        <a href="<?= /* @escapeNotVerified */ $block->getSaleableItem()->getProductUrl() ?>" class="minimal-price-link">
            <?= /* @escapeNotVerified */ $block->renderAmountMinimal() ?>
        </a>
    <?php else:?>
        <span class="minimal-price-link">
            <?= /* @escapeNotVerified */ $block->renderAmountMinimal() ?>
        </span>
    <?php endif?>
<?php endif; ?>


<script type="text/javascript">
    require(['jquery'],
        function($) {
            var configurableProductSalePriceLabel = ".js-configurable-price-rule-label-" + "<?php echo $productId ?>";
            var $productItemDetail = $(configurableProductSalePriceLabel).parent().parent();
            var $productItemPhoto = $productItemDetail.siblings('.product-item-photo');
            var $productLabelContainer = $productItemPhoto.children('.product-labels');
            console.log($productLabelContainer.children('.product-label').hasClass('new-label'));
            if($productLabelContainer.children('.product-label').hasClass('new-label')) {
                $productLabelContainer.addClass("new-label-active");
            }
        })
</script>

28. Show label sale price on product detail AMASTY

INSTALL EXTENSION AMASTY PRODUCT LABEL

29. Add table field with add more field and multiple select on admin

Example on BLF for shipping methods

app/code/Netpower/Blf/etc/adminhtml/system.xml
<?xml version="1.0" ?>
<!--
/**
 * Copyright 2019 Netpower, Inc. All rights reserved.
 */
-->

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <tab id="netpower" sortOrder="0" translate="label">
            <label>Netpower</label>
        </tab>
        <section id="blf" showInDefault="1" showInStore="1" showInWebsite="1" sortOrder="1"
                 translate="label">
            <label>Blf</label>
            <resource>Netpower_Blf::config_netpower_settings</resource>
            <tab>netpower</tab>
            <group id="shipping" showInDefault="1" showInStore="1" showInWebsite="1" sortOrder="10" translate="label">
                <label>Shipping</label>
                <field id="shipping_methods_custom_text" translate="label" sortOrder="10" showInDefault="1" showInWebsite="1"
                       showInStore="1">
                    <label>Shipping method and custom text</label>
                    <frontend_model>Netpower\Blf\Block\Adminhtml\System\Config\ShippingMethodTextCustom</frontend_model>
                    <backend_model>Magento\Config\Model\Config\Backend\Serialized\ArraySerialized</backend_model>
                </field>
            </group>
        </section>
    </system>
</config>

app/code/Netpower/Blf/Block/Adminhtml/System/Config/ShippingMethodTextCustom.php
<?php
/**
 *  Copyright 2019 Netpower. All rights reserved.
 */

namespace Netpower\Blf\Block\Adminhtml\System\Config;

use Magento\Config\Block\System\Config\Form\Field\FieldArray\AbstractFieldArray;

/**
 * Class TopAttributes
 * @package Netpower\Lenspower\Block\Adminhtml\System\Config
 */
class ShippingMethodTextCustom extends AbstractFieldArray
{
    protected $_itemRenderer;
    protected $_itemRendererDefault;

    /**
     * @var bool
     */
    protected $_addAfter = TRUE;

    /**
     * @var
     */
    protected $_addButtonLabel;

    /**
     * Prepare to render the columns
     */
    protected function _prepareToRender()
    {
        $this->addColumn(
            'shipping_id',
            [
                'label' => __('Shipping methods'),
                'renderer' => $this->_getShippingMethodRenderer()
            ]
        );

        $this->addColumn(
            'attribute_label',
            ['label' => __('Description')]
        );

        $this->_addAfter = FALSE;
        $this->_addButtonLabel = __('Add');
    }

    /**\
     * @return template
     */
    protected function _getShippingMethodRenderer() {
        if (!$this->_itemRenderer) {
            $this->_itemRenderer = $this->getLayout()->createBlock(
                \Netpower\Blf\Block\Adminhtml\System\Config\Form\Field\shippingMethodsActive::class,
                '',
                [
                    'data' => ['is_render_to_js_template' => true]
                ]
            );
        }
        return $this->_itemRenderer;
    }

    /**\
     * @param \Magento\Framework\DataObject $row
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    protected function _prepareArrayRow(\Magento\Framework\DataObject $row)
    {
        $options = [];

        if ($row->getData('shipping_id')) {
            $options['option_' . $this->_getShippingMethodRenderer()->calcOptionHash($row->getData('shipping_id'))] = 'selected="selected"';
        }
        $row->setData('option_extra_attrs', $options);
    }
}

app/code/Netpower/Blf/Block/Adminhtml/System/Config/Form/Field/shippingMethodsActive.php
<?php
/**
 *  Copyright 2019 Netpower. All rights reserved.
 */

namespace Netpower\Blf\Block\Adminhtml\System\Config\Form\Field;

/**
 * Class Attributes
 * @package Netpower\Lenspower\Block\Adminhtml\System\Config\Form\Field
 */
class shippingMethodsActive extends \Magento\Framework\View\Element\Html\Select
{
    /**
     * @var \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory
     */
    protected $collectionFactory;

    /**
     * Attributes constructor.
     * @param \Magento\Framework\View\Element\Context $context
     * @param \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $collectionFactory
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\View\Element\Context $context,
        array $data = []
    )
    {
        parent::__construct(
            $context,
            $data
        );
    }

    /**
     * @return string
     */
    public function _toHtml()
    {
        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();

        $store = $objectManager->create('\Magento\Store\Model\StoreManagerInterface')->getStore();

        /*
         * Code to get list of active shipping methods
         */
        $activeCarriers = $objectManager->create('\Magento\Shipping\Model\Config')->getActiveCarriers($store);
        $shippingMethodsArray = array();
        foreach ($activeCarriers as $shippingCode => $shippingModel) {
//            $shippingTitle = $objectManager->create('\Magento\Framework\App\Config\ScopeConfigInterface')->getValue('carriers/' . $shippingCode . '/title');
            $shippingName = $objectManager->create('\Magento\Framework\App\Config\ScopeConfigInterface')->getValue('carriers/' . $shippingCode . '/name');
            $shippingMethodsArray[$shippingCode] = array(
                'label' => $shippingName,
                'value' => $shippingCode
            );
            $this->addOption($shippingCode,  $shippingName);
        }
        return parent::_toHtml();
    }

    /**
     * @param $value
     * @return mixed
     */
    public function setInputName($value)
    {
        return $this->setName($value);
    }
}

30. Add template into html file by knockoutjs

EXAMPLE OF BLF with Front-end 29. and Back-end 28

app/code/Netpower/OnePageCheckout/view/frontend/web/template/checkout/shipping-method.html
 <div class="custom-description-shipping-method">
      <!-- ko foreach: $parent.getRegion('custom-description-shipping-method') -->
      <!-- ko template: getTemplate() --><!-- /ko -->
      <!-- /ko -->
 </div>

app/code/Netpower/OnePageCheckout/view/frontend/layout/checkout_onepage_index.xml
<item name="shippingAddress" xsi:type="array">
   <item name="children" xsi:type="array">
   ... 
   <item name="custom-description-shipping-method" xsi:type="array">
      <item name="component" xsi:type="string">Netpower_OnePageCheckout/js/view/checkout/shipping-method-custom-description</item>
      <item name="displayArea" xsi:type="string">custom-description-shipping-method</item>
    </item>
</item>

component   : file script contain define template file html 
displayArea : Area to display template

app/code/Netpower/OnePageCheckout/view/frontend/web/js/view/checkout/shipping-method-custom-description.js
/**
 * Copyright 2019 Netpower, Inc. All rights reserved.
 */

/*global define*/
define([
    'jquery',
    'underscore',
    'uiComponent',
    'ko',

], function ($,
             _,
             Component,
             ko,
             ) {
    'use strict';
    var self;
    return Component.extend({
        defaults: {
            template: 'Netpower_OnePageCheckout/checkout/shipping/shipping-method-custom-description'
        },
        isAddressFormVisible: ko.observable(addressList().length === 0),
        visible: ko.observable(true),
        shippingRateGroup: ko.observable(),
        shippingRate: ko.observable(),

        initialize: function () {
            self = this;
            this._super();
        },

        getCustomDescription: function(shippingCode) {
            console.log(shippingCode);
            // var shippingCustom = window.checkoutConfig.shipping.shippingMethodsCustomDescription;
            // return shippingCustom[shippingCode];
        }
    });
});

app/code/Netpower/OnePageCheckout/view/frontend/web/template/checkout/shipping/shipping-method-custom-description.html
<div class="">
    <p data-bind="text: getCustomDescription(getMethod())"></p>
</div>

31. Create widget to get best seller


1.app/code/Netpower/Lenspower/etc/widget.xml

<?xml version="1.0" ?>
<!--
/**
 * Copyright 2019 Netpower, Inc. All rights reserved.
 */
-->
<widgets xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:helloworld:Magento_Widget:etc/widget.xsd">
    <widget class="Netpower\Lenspower\Block\Widget\MostOrder" id="np_most_order">
        <label translate="true">Bestseller Products List</label>
        <description translate="true">List of Best Selling Products</description>
        <parameters>
            <parameter name="productcount" xsi:type="text"  visible="true" sort_order="1" >
                <label translate="true">Product Count</label>
            </parameter>
        </parameters>
    </widget>
</widgets>

2.app/code/Netpower/Lenspower/Block/Widget/MostOrder.php

<?php

namespace Netpower\Lenspower\Block\Widget;

use Magento\Catalog\Api\CategoryRepositoryInterface;
use Magento\Catalog\Block\Product\Context;
use Magento\Catalog\Model\Layer\Resolver;
use Magento\Framework\Data\Helper\PostHelper;
use Magento\Framework\Url\Helper\Data;
use Magento\Sales\Model\ResourceModel\Report\Bestsellers\CollectionFactory as BestSellersCollectionFactory;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;

/**
 * Best Seller products widget
 */
class MostOrder extends \Magento\Catalog\Block\Product\ListProduct implements \Magento\Widget\Block\BlockInterface
{
    protected $_template = 'Netpower_Lenspower::catalog/product/view/mostOrder.phtml';

    /**
     * Default value for products count that will be shown
     */
    const DEFAULT_PRODUCTS_COUNT = 10;
    const DEFAULT_IMAGE_WIDTH = 150;
    const DEFAULT_IMAGE_HEIGHT = 150;
    /**
     * Products count
     *
     * @var int
     */
    protected $_productsCount;
    /**
     * @var \Magento\Framework\App\Http\Context
     */
    protected $httpContext;
    protected $_resourceFactory;
    /**
     * Catalog product visibility
     *
     * @var \Magento\Catalog\Model\Product\Visibility
     */
    protected $_catalogProductVisibility;

    /**
     * Product collection factory
     *
     * @var \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory
     */
    protected $_productCollectionFactory;

    /**
     * Image helper
     *
     * @var Magento\Catalog\Helper\Image
     */
    protected $_imageHelper;
    /**
     * @var \Magento\Checkout\Helper\Cart
     */
    protected $_cartHelper;

    /**
     * @var BestSellersCollectionFactory
     */
    protected $_bestSellersCollectionFactory;


    public function __construct(
        Context $context,
        PostHelper $postDataHelper,
        Resolver $layerResolver,
        CategoryRepositoryInterface $categoryRepository,
        Data $urlHelper,
        BestSellersCollectionFactory $bestSellersCollectionFactory,
        CollectionFactory $productCollectionFactory,
        array $data = []
    )
    {
        $this->_bestSellersCollectionFactory = $bestSellersCollectionFactory;
        $this->_productCollectionFactory = $productCollectionFactory;
        parent::__construct($context, $postDataHelper, $layerResolver, $categoryRepository, $urlHelper, $data);
    }

    /**
     * Image helper Object
     */
    public function imageHelperObj()
    {
        return $this->_imageHelper;
    }

    /**
     * get collection of best-seller products
     * @return mixed
     */
    public function getProductCollection()
    {
        $productIds = [];
        $bestSellers = $this->_bestSellersCollectionFactory->create()
            ->setPeriod('month');
        foreach ($bestSellers as $product) {
            $productIds[] = $product->getProductId();
        }
        $collection = $this->_productCollectionFactory->create()->addIdFilter($productIds);
        $collection->addMinimalPrice()
            ->addFinalPrice()
            ->addTaxPercents()
            ->addAttributeToSelect('*')
            ->addStoreFilter($this->getStoreId())->setPageSize($this->getProductsCount());
        return $collection;
    }

    /**
     * Get the configured limit of products
     * @return int
     */
    public function getProductLimit()
    {
        if ($this->getData('productcount') == '') {
            return DEFAULT_PRODUCTS_COUNT;
        }
        return $this->getData('productcount');
    }

    /**
     * Get the add to cart url
     * @return string
     */
    public function getAddToCartUrl($product, $additional = [])
    {
        return $this->_cartHelper->getAddUrl($product, $additional);
    }

    /**
     * Return HTML block with price
     *
     * @param \Magento\Catalog\Model\Product $product
     * @param string $priceType
     * @param string $renderZone
     * @param array $arguments
     * @return string
     * @SuppressWarnings(PHPMD.NPathComplexity)
     */
    public function getProductPriceHtml(
        \Magento\Catalog\Model\Product $product,
        $priceType = null,
        $renderZone = \Magento\Framework\Pricing\Render::ZONE_ITEM_LIST,
        array $arguments = []
    )
    {
        if (!isset($arguments['zone'])) {
            $arguments['zone'] = $renderZone;
        }
        $arguments['zone'] = isset($arguments['zone'])
            ? $arguments['zone']
            : $renderZone;
        $arguments['price_id'] = isset($arguments['price_id'])
            ? $arguments['price_id']
            : 'old-price-' . $product->getId() . '-' . $priceType;
        $arguments['include_container'] = isset($arguments['include_container'])
            ? $arguments['include_container']
            : true;
        $arguments['display_minimal_price'] = isset($arguments['display_minimal_price'])
            ? $arguments['display_minimal_price']
            : true;
        /** @var \Magento\Framework\Pricing\Render $priceRender */
        $priceRender = $this->getLayout()->getBlock('product.price.render.default');
        $price = '';
        if ($priceRender) {
            $price = $priceRender->render(
                \Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE,
                $product,
                $arguments
            );
        }
        return $price;
    }
}

3.app/code/Netpower/Lenspower/view/frontend/templates/catalog/product/view/mostOrder.phtml

<?php
/**
 * Copyright Β© 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
use Magento\Framework\App\Action\Action;

// @codingStandardsIgnoreFile

?>
<?php
/**
 * Product list template
 *
 * @var $block \Magento\Catalog\Block\Product\ListProduct
 */
?>
<?php
$_productCollection = $block->getProductCollection();
$_helper = $this->helper('Magento\Catalog\Helper\Output');
$_imagehelper = $this->helper('Magento\Catalog\Helper\Image');

// Daily deal Helper 
$dailydealhelper=$this->helper('Smartwave\Dailydeals\Helper\Data');

$_category_config = $this->helper('Smartwave\Porto\Helper\Data')->getConfig('porto_settings/category');
$_category_grid_config = $this->helper('Smartwave\Porto\Helper\Data')->getConfig('porto_settings/category_grid');
$_product_label_config = $this->helper('Smartwave\Porto\Helper\Data')->getConfig('porto_settings/product_label');
$move_actions = "";
$flex_grid = "";
$_lazyload = $this->helper('Smartwave\Porto\Helper\Data')->getConfig('porto_settings/optimization/lazyload');
?>
<?php $iterator = 1; ?>
<?php if (!$_productCollection->count()): ?>
    <div class="message info empty"><div><?php echo __('We can\'t find products matching the selection.') ?></div></div>
<?php else: ?>
    <?php echo $block->getToolbarHtml() ?>
    <?php echo $block->getAdditionalHtml() ?>
    <?php
    if ($block->getMode() == 'grid') {
        $viewMode = 'grid';
        $image = 'category_page_grid';
        $hover_image = 'category_page_grid-hover';
        $showDescription = false;
        $templateType = \Magento\Catalog\Block\Product\ReviewRendererInterface::SHORT_VIEW;
        $columns = 'columns'.$_category_grid_config['columns'];
        $move_actions = $_category_grid_config['move_actions'];
        if(isset($_category_grid_config['flex_grid']) && $_category_grid_config['flex_grid'])
            $flex_grid = "flex-grid";
    } else {
        $viewMode = 'list';
        $image = 'category_page_list';
        $hover_image = 'category_page_list-hover';
        $showDescription = true;
        $templateType = \Magento\Catalog\Block\Product\ReviewRendererInterface::FULL_VIEW;
        $columns = '';
    }
    $image_width = ($_category_config['ratio_width'])?$_category_config['ratio_width']:300;
    $image_height = ($_category_config['ratio_height'])?$_category_config['ratio_height']:300;
    if($_category_config['aspect_ratio'])
        $image_height = $image_width;
    ?>
    <div class="products wrapper <?php echo $viewMode; ?> <?php echo $columns; ?> <?php echo $flex_grid; ?> products-<?php echo $viewMode; ?>">
        <?php $iterator = 1; ?>
        <ol class="products list items product-items <?php if(isset($_category_config['qty_field']) && $_category_config['qty_field']):?>has-qty<?php endif;?>">
            <?php /** @var $_product \Magento\Catalog\Model\Product */ ?>
            <?php foreach ($_productCollection as $_product): ?>
                <?php echo($iterator++ == 1) ? '<li class="item product product-item">' : '</li><li class="item product product-item">' ?>
                <div class="product-item-info" data-container="product-grid">
                    <?php // Product Image ?>
                    <div class="product photo product-item-photo">
                        <a href="<?php echo $_product->getProductUrl() ?>" tabindex="-1">
                        <?php
                            if($_category_config['aspect_ratio'])
                                $productImage = $_imagehelper->init($_product, $image)->constrainOnly(FALSE)->keepAspectRatio(TRUE)->keepFrame(FALSE)->resize($image_width);
                            else
                                $productImage = $_imagehelper->init($_product, $image)->resize($image_width, $image_height);
                            $productImageUrl = $productImage->getUrl();
                        ?>
                            <img class="product-image-photo default_image <?php if(!$_lazyload): ?>porto-lazyload<?php endif;?>" <?php if(!$_lazyload): ?>data-<?php endif; ?>src="<?php echo $productImageUrl; ?>" width="<?php echo $image_width; ?>" height="<?php echo $image_height; ?>"/>
                        <?php if($_category_config['alternative_image']): ?>
                        <?php
                            if($_category_config['aspect_ratio'])
                                $productHoverImage = $_imagehelper->init($_product, $hover_image)->constrainOnly(FALSE)->keepAspectRatio(TRUE)->keepFrame(FALSE)->resize($image_width);
                            else
                                $productHoverImage = $_imagehelper->init($_product, $hover_image)->resize($image_width, $image_height);
                            $productHoverImageUrl = $productHoverImage->getUrl();
                        ?>
                            <?php if($productImageUrl != str_replace("/thumbnail/","/small_image/",$productHoverImageUrl)): ?>
                            <img class="product-image-photo hover_image" src="<?php echo $productHoverImageUrl; ?>"/>
                            <?php endif; ?>
                        <?php endif; ?>
                        </a>
                        <?php
                            $product_label = "";
                            if($_product_label_config['sale_label']) {
                                $orgprice = $_product->getPrice();
                                $specialprice = $_product->getSpecialPrice();
                                $specialfromdate = $_product->getSpecialFromDate();
                                $specialtodate = $_product->getSpecialToDate();
                                $today = time();
                                if(!$specialprice)
                                    $specialprice = $orgprice;
                                if($specialprice < $orgprice) {
                                    if((is_null($specialfromdate) && is_null($specialtodate)) || ($today >= strtotime($specialfromdate) && is_null($specialtodate)) || ($today <= strtotime($specialtodate) && is_null($specialfromdate)) || ($today >= strtotime($specialfromdate) && $today <= strtotime($specialtodate))){
                                        if($_product_label_config['sale_label_percent']) {
                                            $save_percent = 100-round(($specialprice/$orgprice)*100);
                                            $product_label .= '<div class="product-label sale-label">'.'-'.$save_percent.'%'.'</div>';
                                        } else {
                                            $product_label .= '<div class="product-label sale-label">'.$_product_label_config['sale_label_text'].'</div>';
                                        }
                                    }
                                }
                            }
                            if($_product_label_config['new_label']) {
                                $now = date("Y-m-d");
                                $newsFrom= substr($_product->getData('news_from_date'),0,10);
                                $newsTo=  substr($_product->getData('news_to_date'),0,10);
                                
                                if ($newsTo != '' || $newsFrom != ''){
                                    if (($newsTo != '' && $newsFrom != '' && $now>=$newsFrom && $now<=$newsTo) || ($newsTo == '' && $now >=$newsFrom) || ($newsFrom == '' && $now<=$newsTo)) {
                                        $product_label .= '<div class="product-label new-label">'.$_product_label_config['new_label_text'].'</div>';
                                    }
                                }
                            }
                            if($product_label)
                                echo '<div class="product-labels">'.$product_label.'</div>';
                        ?>
                        <!-- Dailydeal Product data -->
                        <?php if($dailydealhelper->isDealProduct($_product->getId())) : ?>
                        <input type="hidden" id="todate_<?php echo $iterator; ?>" value="<?php echo $dailydealhelper->getDailydealToDate($_product->getSku()); ?>" >
                        <input type="hidden" id="fromdate_<?php echo $iterator; ?>" value="<?php echo $dailydealhelper->getDailydealFromDate($_product->getSku()); ?>">
                        <div class="sw-dailydeal-wrapper" style="display:none;">
                            <div class="sw-dailydeal">
                                <p id="expired_<?php echo $iterator; ?>"></p> 
                                <div class="countdowncontainer_<?php echo $iterator; ?>" style="display:none;">
                                    <span class="dailydeal-label">
                                        <?php echo __('Ends In:'); ?>
                                    </span>
                                    <span class="number-wrapper">
                                        <div class="line"></div>
                                        <span class="number day"><p id="countdown_days_<?php echo $iterator; ?>"></p></span>
                                        <div class="caption"><?php echo __('Day(s), '); ?></div>
                                    </span>

                                    <span class="number-wrapper">
                                        <div class="line"></div>
                                        <span class="number hour"><p id="countdown_hours_<?php echo $iterator; ?>"></p></span>
                                        <div class="caption">:</div>
                                    </span>

                                    <span class="number-wrapper">
                                        <div class="line"></div>
                                        <span class="number min"><p id="countdown_minutes_<?php echo $iterator; ?>"></p></span>
                                        <div class="caption">:</div>
                                    </span>

                                    <span class="number-wrapper">
                                        <div class="line"></div>
                                        <span class="number sec"><p id="countdown_seconds_<?php echo $iterator; ?>"></p></span>
                                        <div class="caption"></div>
                                    </span>
                                </div>
                            </div>
                        </div>
                        <?php endif; ?> 
                       <!-- Dailydeal Product End -->
                        <?php if($_category_config['actions'] && $move_actions): ?>
                        <div class="product-item-inner">
                            <div class="product actions product-item-actions">
                                <div class="actions-primary">
                                    <?php if ($_product->isSaleable()): ?>
                                        <?php $postParams = $block->getAddToCartPostParams($_product); ?>
                                        <form data-role="tocart-form" action="<?php echo $postParams['action']; ?>" method="post">
                                            <input type="hidden" name="product" value="<?php echo $postParams['data']['product']; ?>">
                                            <input type="hidden" name="<?php echo Action::PARAM_NAME_URL_ENCODED; ?>" value="<?php echo $postParams['data'][Action::PARAM_NAME_URL_ENCODED]; ?>">
                                            <?php if(isset($_category_config['qty_field']) && $_category_config['qty_field']):?>
                                                <div class="qty-box">
                                                    <a href="javascript:void(0)" class="qtyminus"><i class="porto-icon-minus"></i></a>
                                                    <input type="text" name="qty" id="qty" maxlength="12" value="<?php /* @escapeNotVerified */ echo $block->getProductDefaultQty() * 1 ?>" title="<?php /* @escapeNotVerified */ echo __('Qty') ?>" class="input-text qty" data-validate="<?php echo $block->escapeHtml(json_encode($block->getQuantityValidators())) ?>"/>
                                                    <a href="javascript:void(0)" class="qtyplus"><i class="porto-icon-plus"></i></a>
                                                </div>
                                            <?php endif;?>
                                            <?php echo $block->getBlockHtml('formkey')?>
                                            <button type="submit"
                                                    title="<?php echo $block->escapeHtml(__('Add to Cart')); ?>"
                                                    class="action tocart primary">
                                                <span><?php echo __('Add to Cart') ?></span>
                                            </button>
                                        </form>
                                    <?php else: ?>
                                        <?php if ($_product->getIsSalable()): ?>
                                            <div class="stock available"><span><?php echo __('In stock') ?></span></div>
                                        <?php else: ?>
                                            <div class="stock unavailable"><span><?php echo __('Out of stock') ?></span></div>
                                        <?php endif; ?>
                                    <?php endif; ?>
                                </div>
                                <?php if ($block->getMode() == 'grid'): ?>
                                <?php if($_category_config['addtowishlist']): ?>
                                <?php if ($this->helper('Magento\Wishlist\Helper\Data')->isAllow()): ?>
                                    <a href="#"
                                       class="action towishlist actions-secondary"
                                       title="<?php echo $block->escapeHtml(__('Add to Wish List')); ?>"
                                       aria-label="<?php echo $block->escapeHtml(__('Add to Wish List')); ?>"
                                       data-post='<?php echo $block->getAddToWishlistParams($_product); ?>'
                                       data-action="add-to-wishlist"
                                       role="button">
                                        <span><?php echo __('Add to Wish List') ?></span>
                                    </a>
                                <?php endif; ?>
                                <?php endif; ?>
                                <?php endif; ?>
                                <?php if($_category_config['addtocompare']): ?>
                                <?php
                                $compareHelper = $this->helper('Magento\Catalog\Helper\Product\Compare');
                                ?>
                                <a href="#"
                                   class="action tocompare actions-secondary"
                                   title="<?php echo $block->escapeHtml(__('Add to Compare')); ?>"
                                   aria-label="<?php echo $block->escapeHtml(__('Add to Compare')); ?>"
                                   data-post='<?php echo $compareHelper->getPostDataParams($_product); ?>'
                                   role="button">
                                    <span><?php echo __('Add to Compare') ?></span>
                                </a>
                                <?php endif; ?>
                            </div>
                        </div>
                        <?php endif; ?>
                    </div>
                    <div class="product details product-item-details">
                        <?php
                            $_productNameStripped = $block->stripTags($_product->getName(), null, true);
                        ?>
                        <?php if(!$_category_grid_config['move_title']):?>
                        <strong class="product name product-item-name">
                            <a class="product-item-link"
                               href="<?php echo $_product->getProductUrl() ?>">
                                <?php echo $_helper->productAttribute($_product, $_product->getName(), 'name'); ?>
                            </a>
                        </strong>
                        <?php endif;?>
                        <?php if($_category_config['rating_star']): ?>
                        <?php
                            $review_html = $block->getReviewsSummaryHtml($_product, $templateType);
                        ?>
                        <?php if($review_html): ?>
                            <?php echo $review_html; ?>
                        <?php else: ?>
                        <div class="product-reviews-summary short">
                            <div class="rating-summary">
                                <span class="label"><span>Rating:</span></span>
                                <div class="rating-result" title="0%">
                                    <span style="width:0"><span>0%</span></span>
                                </div>
                            </div>
                        </div>
                        <?php endif; ?>
                        <?php endif; ?>
                        <?php if($_category_grid_config['move_title']):?>
                            <strong class="product name product-item-name">
                                <a class="product-item-link"
                                   href="<?php echo $_product->getProductUrl() ?>">
                                    <?php echo $_helper->productAttribute($_product, $_product->getName(), 'name'); ?>
                                </a>
                            </strong>
                        <?php endif;?>
                        <?php if ($showDescription):?>
                            <div class="product description product-item-description">
                                <?php echo $_helper->productAttribute($_product, $_product->getShortDescription(), 'short_description') ?>
                                <a href="<?php echo $_product->getProductUrl() ?>" title="<?php echo $_productNameStripped ?>"
                                   class="action more"><?php echo __('Learn More') ?></a>
                            </div>
                        <?php endif; ?>
                        <?php if($_category_config['product_price']): ?>
                        <?php echo $block->getProductPrice($_product) ?>
                        <?php endif; ?>
                        <?php echo $block->getProductDetailsHtml($_product); ?>
                        
                        <?php if($_category_config['actions'] && !$move_actions): ?>
                        <div class="product-item-inner">
                            <div class="product actions product-item-actions">
                                <?php if ($block->getMode() == 'grid'): ?>
                                <?php if($_category_config['addtowishlist']): ?>
                                <?php if ($this->helper('Magento\Wishlist\Helper\Data')->isAllow()): ?>
                                    <a href="#"
                                       class="action towishlist actions-secondary <?php if(isset($_category_config['qty_field']) && $_category_config['qty_field']):?>has-qty<?php endif;?>"
                                       title="<?php echo $block->escapeHtml(__('Add to Wish List')); ?>"
                                       aria-label="<?php echo $block->escapeHtml(__('Add to Wish List')); ?>"
                                       data-post='<?php echo $block->getAddToWishlistParams($_product); ?>'
                                       data-action="add-to-wishlist"
                                       role="button">
                                        <span><?php echo __('Add to Wish List') ?></span>
                                    </a>
                                <?php endif; ?>
                                <?php endif; ?>
                                <?php endif; ?>
                                <div class="actions-primary">
                                    <?php if ($_product->isSaleable()): ?>
                                        <?php $postParams = $block->getAddToCartPostParams($_product); ?>
                                        <form data-role="tocart-form" action="<?php echo $postParams['action']; ?>" method="post">
                                            <input type="hidden" name="product" value="<?php echo $postParams['data']['product']; ?>">
                                            <input type="hidden" name="<?php echo Action::PARAM_NAME_URL_ENCODED; ?>" value="<?php echo $postParams['data'][Action::PARAM_NAME_URL_ENCODED]; ?>">
                                            <?php if(isset($_category_config['qty_field']) && $_category_config['qty_field']):?>
                                            <div class="qty-box">
                                                <a href="javascript:void(0)" class="qtyminus"><i class="porto-icon-minus"></i></a>
                                                <input type="text" name="qty" id="qty" maxlength="12" value="<?php /* @escapeNotVerified */ echo $block->getProductDefaultQty() * 1 ?>" title="<?php /* @escapeNotVerified */ echo __('Qty') ?>" class="input-text qty" data-validate="<?php echo $block->escapeHtml(json_encode($block->getQuantityValidators())) ?>"/>
                                                <a href="javascript:void(0)" class="qtyplus"><i class="porto-icon-plus"></i></a>
                                            </div>
                                            <?php endif;?>
                                            <?php echo $block->getBlockHtml('formkey')?>
                                            <button type="submit"
                                                    title="<?php echo $block->escapeHtml(__('Add to Cart')); ?>"
                                                    class="action tocart primary">
                                                <span><?php echo __('Add to Cart') ?></span>
                                            </button>
                                        </form>
                                    <?php else: ?>
                                        <?php if ($_product->getIsSalable()): ?>
                                            <div class="stock available"><span><?php echo __('In stock') ?></span></div>
                                        <?php else: ?>
                                            <div class="stock unavailable"><span><?php echo __('Out of stock') ?></span></div>
                                        <?php endif; ?>
                                    <?php endif; ?>
                                </div>
                                <?php if ($block->getMode() != 'grid'): ?>
                                <?php if($_category_config['addtowishlist']): ?>
                                <?php if ($this->helper('Magento\Wishlist\Helper\Data')->isAllow()): ?>
                                    <a href="#"
                                       class="action towishlist actions-secondary <?php if(isset($_category_config['qty_field']) && $_category_config['qty_field']):?>has-qty<?php endif;?>"
                                       title="<?php echo $block->escapeHtml(__('Add to Wish List')); ?>"
                                       aria-label="<?php echo $block->escapeHtml(__('Add to Wish List')); ?>"
                                       data-post='<?php echo $block->getAddToWishlistParams($_product); ?>'
                                       data-action="add-to-wishlist"
                                       role="button">
                                        <span><?php echo __('Add to Wish List') ?></span>
                                    </a>
                                <?php endif; ?>
                                <?php endif; ?>
                                <?php endif; ?>
                                <?php if($_category_config['addtocompare']): ?>
                                <?php
                                $compareHelper = $this->helper('Magento\Catalog\Helper\Product\Compare');
                                ?>
                                <a href="#"
                                   class="action tocompare actions-secondary <?php if(isset($_category_config['qty_field']) && $_category_config['qty_field']):?>has-qty<?php endif;?>"
                                   title="<?php echo $block->escapeHtml(__('Add to Compare')); ?>"
                                   aria-label="<?php echo $block->escapeHtml(__('Add to Compare')); ?>"
                                   data-post='<?php echo $compareHelper->getPostDataParams($_product); ?>'
                                   role="button">
                                    <span><?php echo __('Add to Compare') ?></span>
                                </a>
                                <?php endif; ?>
                            </div>
                        </div>
                        <?php endif; ?>
                    </div>
                </div>
                <?php echo($iterator == count($_productCollection)+1) ? '</li>' : '' ?>
            <?php endforeach; ?>
        </ol>
    </div>
    <?php if(isset($_category_grid_config['infinite_scroller']) && $_category_grid_config['infinite_scroller']):?>
    <div class="infinite-loader"><div class="loading"><?php echo __("Loading ..."); ?></div><a href="javascript:void(0)" class="btn-load-more"><?php echo __("Load More ..."); ?></a></div>
    <?php endif;?>
    <?php echo $block->getToolbarHtml() ?>
    <?php if ($block->getMode() == 'grid'): ?>
        <script type="text/javascript">
            require([
                'jquery'        
            ], function ($) {
                $('.main .products.grid .product-items li.product-item:nth-child(2n)').addClass('nth-child-2n');
                $('.main .products.grid .product-items li.product-item:nth-child(2n+1)').addClass('nth-child-2np1');
                $('.main .products.grid .product-items li.product-item:nth-child(3n)').addClass('nth-child-3n');
                $('.main .products.grid .product-items li.product-item:nth-child(3n+1)').addClass('nth-child-3np1');
                $('.main .products.grid .product-items li.product-item:nth-child(4n)').addClass('nth-child-4n');
                $('.main .products.grid .product-items li.product-item:nth-child(4n+1)').addClass('nth-child-4np1');
                $('.main .products.grid .product-items li.product-item:nth-child(5n)').addClass('nth-child-5n');
                $('.main .products.grid .product-items li.product-item:nth-child(5n+1)').addClass('nth-child-5np1');
                $('.main .products.grid .product-items li.product-item:nth-child(6n)').addClass('nth-child-6n');
                $('.main .products.grid .product-items li.product-item:nth-child(6n+1)').addClass('nth-child-6np1');
                $('.main .products.grid .product-items li.product-item:nth-child(7n)').addClass('nth-child-7n');
                $('.main .products.grid .product-items li.product-item:nth-child(7n+1)').addClass('nth-child-7np1');
                $('.main .products.grid .product-items li.product-item:nth-child(8n)').addClass('nth-child-8n');
                $('.main .products.grid .product-items li.product-item:nth-child(8n+1)').addClass('nth-child-8np1');
            });
        </script>
    <?php endif; ?>
<?php endif; ?>
<script type="text/javascript">
require([
    'jquery'        
], function ($) {
// Timer for LEFT time for Dailydeal product
    var _second = 1000;
    var _minute = _second * 60;
    var _hour = _minute * 60;
    var _day = _hour * 24;
    var timer;
   
    function showRemaining(currentdate) 
    {
        var count;
        for (count = 2; count <= <?php echo $iterator; ?>; count++) 
        {
            // get Value of dailydeal product
            var cid='countdown_'+count;
            var daysid='countdown_days_'+count;
            var hoursid='countdown_hours_'+count;
            var minutesid='countdown_minutes_'+count;
            var secondsid='countdown_seconds_'+count;

            var startdateid='fromdate_'+count;
            var id='todate_'+count;

            var enddate = new Date($('#'+id).val());
            var dealstartdate=new Date($('#'+startdateid).val());

            // Get Current Date from magentodatetime
            var currentdate=new Date(currentdate);

            //Get Difference between Two dates
            var distance = enddate - currentdate;

            $('.sw-dailydeal-wrapper').show();

            if (distance < 0) {
               // clearInterval(timer);
                $('#expired_'+count).html("<span style='font-size:25px; color:#000;'>EXPIRED!<span>");

            } else if(dealstartdate > currentdate) {
               $('.countdowncontainer_'+count).hide();
               var msg="<span style='font-size:15px; color:#000;'> Coming Soon..<br>Deal Start at:<br>"+$('#'+startdateid).val()+"<span>";
               $('#expired_'+count).html(msg);
            } else {
                var days = Math.floor(distance / _day);
                var hours = Math.floor((distance % _day) / _hour);
                var minutes = Math.floor((distance % _hour) / _minute);
                var seconds = Math.floor((distance % _minute) / _second);

                if(hours < 10)
                    hours = "0" + hours;
                if(minutes < 10)
                    minutes = "0" + minutes;
                if(seconds < 10)
                    seconds = "0" + seconds;
                $('.countdowncontainer_'+count).show();
                $('#'+daysid).html(days);
                $('#'+hoursid).html(hours);
                $('#'+minutesid).html(minutes);
                $('#'+secondsid).html(seconds);
            }
        }
    }
    
    //Set date as magentodatetime 
    var date = new Date('<?php echo $dailydealhelper->getcurrentDate() ?>');
    
    var day   = date.getDate();
    var month = date.getMonth();
    var year  = date.getFullYear();
    var hours = date.getHours();
    var minutes = "0" + date.getMinutes();
    var seconds = "0" + date.getSeconds();

    var fulldate = year+'-'+(month+1)+'-'+day+' '+hours + ':' + minutes.substr(minutes.length-2) + ':' + seconds.substr(seconds.length-2);

    // Set Interval
    timer = setInterval(function() 
    {
        date.setSeconds(date.getSeconds() + 1);
        var month=date.getMonth();
        var currentdatetime=date.getFullYear()+"-"+(month+1)+"-"+date.getDate()+" "+date.getHours()+":"+date.getMinutes()+":"+date.getSeconds();
        showRemaining(currentdatetime);
    }, 1000); 
});   
</script>
<?php
    echo $block->getChildHtml('filter_toggle');
?>

4.Add widget on admin

Add widget by WYSIWYG > Choose name of widget was created

32. Change Copyright year static to dynamic year

app/design/frontend/Webbhuset/Holte/Magento_Theme/templates/html/copyright.phtml

<?php
/**
 * Copyright Β© Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
?>
<small class="copyright">
    <span><?= /* @escapeNotVerified */ preg_replace('/(^|\s)(\d{4})(\s|$)/m', " ".date('Y'). " ", $block->getCopyright()); ?></span>
</small>

33. Change font for magento 2

1. app/design/frontend/<your_vendor_name>/<your_theme_name>/web/css/source/_typography.less
copy from vendor/magento/theme-frontend-blank/web/css/source/_typography.less

2. app/design/frontend/<your_vendor_name>/<your_theme_name>/web/css/source/_variables.less
copy from vendor/magento/theme-frontend-luma/web/css/source/_variables.less

app/design/frontend/<your_vendor_name>/<your_theme_name>/web/css/source/_typography.less

// /**
//  * Copyright Β© Magento, Inc. All rights reserved.
//  * See COPYING.txt for license details.
//  */

//
//  Common
//  _____________________________________________

& when (@media-common = true) {
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 
GOOGLE FONT : <link href="https://fonts.googleapis.com/css?family=Manjari&display=swap" rel="stylesheet">
copy https://fonts.googleapis.com/css?family=Manjari and path to url to get code
paste code above to override code below.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 

    .lib-font-face(
        @family-name: @font-family-name__base,
        @font-path: '@{baseDir}fonts/opensans/light/opensans-300',
        @font-weight: 300,
        @font-style: normal
    );

    .lib-font-face(
        @family-name: @font-family-name__base,
        @font-path: '@{baseDir}fonts/opensans/regular/opensans-400',
        @font-weight: 400,
        @font-style: normal
    );

    .lib-font-face(
        @family-name: @font-family-name__base,
        @font-path: '@{baseDir}fonts/opensans/semibold/opensans-600',
        @font-weight: 600,
        @font-style: normal
    );

    .lib-font-face(
        @family-name: @font-family-name__base,
        @font-path: '@{baseDir}fonts/opensans/bold/opensans-700',
        @font-weight: 700,
        @font-style: normal
    );
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 
}

//
//  Desktop
//  _____________________________________________

.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
    h1 {
        .lib-css(font-size, @h1__font-size-desktop);
        .lib-css(margin-bottom, @h1__margin-bottom__desktop);
    }
}

//
//  Common
//  _____________________________________________

& when (@media-common = true) {
    .items {
        .lib-list-reset-styles();
    }
}

app/design/frontend/<your_vendor_name>/<your_theme_name>/web/css/source/_variables.less

// /**
//  * Copyright Β© Magento, Inc. All rights reserved.
//  * See COPYING.txt for license details.
//  */

//
//  Luma theme variables
//  _____________________________________________

//
//  Typography
//  ---------------------------------------------

//  Fonts
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 
GOOGLE FONT : font-family: 'Manjari', sans-serif;
fix same font-family of google
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 


@font-family-name__base: 'Manjari';
@font-family__base: @font-family-name__base, @font-family__sans-serif;
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 

//  Colors nesting
@page__background-color: @color-white;

//
//  Icons
//  ---------------------------------------------

@icon-success: '\e60e';
@icon-error: '\e61f';
@icon-edit: '\e601';
@icon-print: '\e624';
@icon-star-empty: '\e625';
@icon-download: '\e626';
@icon-private: '\e629';
@icon-present: '\e62a';
@icon-gift-registry: '\e62b';

@icon-calendar__font-size: 23px;

//
//  Sidebar
//  ---------------------------------------------

@sidebar__background-color: @color-white-smoke; // Used in cart sidebar, Checkout sidebar, Tier Prices, My account navigation, Rating block background

//
//  Sidebar blocks
//  ---------------------------------------------

@block-items__counter__color: @color-gray43;
php bin/magento setup:upgrade
php bin/magento cache:clean

34. Setup Grunt for magento 2

https://devdocs.magento.com/guides/v2.3/frontend-dev-guide/css-topics/css_debug.html

https://aureatelabs.com/magento-2/how-to-use-grunt-in-magento-2/

cp package.json.sample package.json &&
cp Gruntfile.js.sample Gruntfile.js &&
cp grunt-config.json.sample grunt-config.json &&
npm install &&
npm update

dev/tools/grunt/configs/local-themes.js



/**
 * Copyright Β© Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

'use strict';

/**
 * Define Themes
 *
 * area: area, one of (frontend|adminhtml|doc),
 * name: theme name in format Vendor/theme-name,
 * locale: locale,
 * files: [
 * 'css/styles-m',
 * 'css/styles-l'
 * ],
 * dsl: dynamic stylesheet language (less|sass)
 *
 */
module.exports = {
    grunt: {
    area: 'frontend',
        name: 'Hieu/Grunt',
        locale: 'en_US',
        files: [
        'css/hieu'
    ],
        dsl: 'less'
}
};

app/design/frontend/Hieu/Grunt/web/css/hieu.less

app/design/frontend/Hieu/Grunt/Magento_Theme/layout/default.xml

<?xml version="1.0"?>
<!--
/**
 * Copyright Β© Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<page layout="3columns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
        <css src="css/hieu.css" />
    </head>
</page>
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.

grunt clean && grunt exec && grunt less && grunt watch

SET UP LIVERELOAD

LINK INSTRUCTION

1. npm install -g livereload

2. install LiveReload browser extension Chrome

3. Create file livereload.js in pub/

LINK FILE

4. default.xml

<?xml version="1.0"?>
<!--
/**
 * Copyright Β© Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<page layout="3columns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
        <css src="css/hieu-one.css" />
        <script src="http://magento.local:35729/livereload.js" src_type="url"></script>
// url:port/livereload.js
    </head>
</page>

5. Check result : magento.local:35729/

It'll show :

tinylr "Welcome"

version "0.2.1"

6. Grunt watch and change file to see result


35. Get image path of theme

$block->getViewFileUrl('images/demo.jpg');

36. Translate generate for theme i18n

 php bin/magento i18n:collect-phrases --output="app/design/frontend/<Vendor>/<Theme>/i18n/en_US.csv" app/design/frontend/<Vendor>/<Theme>

37. Add custom link into header link

app/design/frontend///Magento_Theme/layout/default.xml

<referenceBlock name="header.links">
           <block class="Magento\Framework\View\Element\Html\Link" name="add-new-header-link" after="-">
               <arguments>
                   <argument name="label" xsi:type="string" translate="true">Contact Us</argument>
                   <argument name="path" xsi:type="string" translate="true">contact-us</argument>
               </arguments>
           </block>
        </referenceBlock>

38. LESS import media screen

@desktop: 1200px;
@tablet: 991px;
@phone: 767px;
@small-desktop-max: (@desktop - 1);
@small-desktop-min: (@tablet + 1);
@tablet-min: (@phone + 1);
@screen-desktop: ~"only screen and (min-width: @{desktop})";
@screen-small-desktop :  ~"only screen and (min-width: @{small-desktop-min}) and (max-width: @{small-desktop-max})";
@screen-tablet: ~"only screen and (min-width: @{tablet-min}) and (max-width: @{tablet})";
@screen-phone: ~"only screen and (max-width: @{phone})";


@media @screen-desktop {width: 100%}

Footer

⚠️ **GitHub.com Fallback** ⚠️