We sacrifice by not doing any other technology, so that you get the best of Magento.

We sacrifice by not doing any other technology, so that you get the best of Magento.

    How to add custom product sorter in magento 2?

    This article is a solution If you want to add new custom sorter or filter options such as below:

    New product,
    Name, Instock,
    Price Low to high,
    Price High to Low.

    Create a custom module and follow the below step.

    1. Create file di.xml on app/code/Magemonkeys/Sorting/etc

    <?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">    
        <type name="MagentoCatalogModelConfig">
            <plugin name="Magemonkeys_Sorting::addCustomSortOptions" type="MagemonkeysSortingPluginModelConfig" />
        </type>
        <type name="MagentoCatalogBlockProductProductListToolbar">
            <plugin name="Magemonkeys_Sorting::implementCustomSortOptions" type="MagemonkeysSortingPluginProductProductListToolbar" />
        </type>
    </config>

    2. Create file Config.php on app/code/Magemonkeys/Sorting/Plugin

    <?php
    namespace MagemonkeysSortingPluginModel;
    
    class Config
    {    
        public function afterGetAttributeUsedForSortByArray(MagentoCatalogModelConfig $catalogConfig, $options)
        {
            //Remove default sorting options
            unset($options['position']);
            unset($options['name']);
            unset($options['price']);
    
            //New sorting options
            $options['newest'] = __('New product');        
            $options['is_salable'] = __('Stock');
            $options['name'] = __('Name');        
            $options['price_desc'] = __('Price High to Low');
            $options['price_asc'] = __('Price Low to High');
    
            return $options;
        }
    }

    3. Create file Toolbar.php on app/code/Magemonkeys/Sorting/Product/ProductList

    <?php
    namespace MagemonkeysSortingPluginProductProductList;
    
    class Toolbar
    {    
        public function aroundSetCollection(
            MagentoCatalogBlockProductProductListToolbar $toolbar,
            Closure $proceed,
            $collection
        ) {
            $this->_collection = $collection;
            $currentOrder = $toolbar->getCurrentOrder();
            $currentDirection = $toolbar->getCurrentDirection();
            $result = $proceed($collection);
    
            if ($currentOrder) {
                switch ($currentOrder) {
    
                case 'newest':
                    if ($currentDirection == 'desc') {
                        $this->_collection->getSelect()->order('e.created_at ASC');
                    } elseif ($currentDirection == 'asc') {
                        $this->_collection->getSelect()->order('e.created_at DESC');
                    }
                break;
    
                case 'is_salable': 
                    if ($currentDirection == 'desc') {
                        $this->_collection->getSelect()->order('qty ASC');
                    } elseif ($currentDirection == 'asc') {
                        $this->_collection->getSelect()->order('qty DESC');
                    }               
                              
                break;            
    
                case 'name':
                    if ($currentDirection == 'desc') {
                        $this->_collection->getSelect()->order('name ASC');
                    } elseif ($currentDirection == 'asc') {
                        $this->_collection->getSelect()->order('name DESC');
                    }
                break;
    
                case 'price_desc':            
                    if ($currentDirection == 'desc') {
                        $this->_collection->getSelect()->order('price ASC');
                    } elseif ($currentDirection == 'asc') {
                        $this->_collection->getSelect()->order('price DESC');
                    }
                break;
    
                case 'price_asc':
                    if ($currentDirection == 'desc') {
                        $this->_collection->getSelect()->order('price DESC');
                    } elseif ($currentDirection == 'asc') {
                        $this->_collection->getSelect()->order('price ASC');
                    }
                break;            
    
                default:        
                    $this->_collection
                        ->setOrder($currentOrder, $currentDirection);
                break;
    
                }
            }        
            //var_dump($currentDirection);
            return $result;
        }
    }

     

    Solve : Call to a member function setUseContainer() on boolean in customer wishlist page

    If you face this type of fatal error on customer wishlish page.

    Fatal error: Uncaught Error: Call to a member function setUseContainer() on boolean in /var/www/vhosts/test.com/vendor/magento/module-wishlist/Block/Customer/Wishlist.php:127 Stack trace: #0 /var/www/vhosts/test.com/vendor/magento/framework/View/Element/AbstractBlock.php(286): MagentoWishlistBlockCustomerWishlist->_prepareLayout() #1 /var/www/vhosts/test.com/vendor/magento/framework/View/Layout/Generator/Block.php(149): MagentoFrameworkViewElementAbstractBlock->setLayout(Object(MagentoFrameworkViewLayoutInterceptor)) #2 /var/www/vhosts/test.com/vendor/magento/framework/View/Layout/GeneratorPool.php(81): MagentoFrameworkViewLayoutGeneratorBlock->process(Object(MagentoFrameworkViewLayoutReaderContext), Object(MagentoFrameworkViewLayoutGeneratorContext)) #3 /var/www/vhosts/test.com/vendor/magento/framework/View/Layout.php(352): MagentoFrameworkViewLayoutGeneratorPool->process(Object(Mag in /var/www/vhosts/test.com/vendor/magento/module-wishlist/Block/Customer/Wishlist.php on line 127

    Then, follow below instruction to solve it.

    Override wishlist_index_index.xml file in your theme and paste below code

    .
    .
    .
        <block class="MagentoWishlistBlockCustomerWishlist" name="customer.wishlist" template="view.phtml" cacheable="false">
            <block class="MagentoThemeBlockHtmlPager" name="wishlist_item_pager"/>
    .
    .
    .

    in app/design/frontend/Magestore/theme/Magento_Wishlist/layout/wishlist_index_index.xml

    After processing above steps, run below commands

    - php bin/magento setup:upgrade
    - php bin/magento setup:di:compile
    - php bin/magento cache:clean

    That’s it. Now, you can check your customer wishlist page. Your wishlist page error should be resolved.

    PayPlug and PayPal problem while checkout in Magento 2.3.3 and above version

    Checkout this article if you face an error like below.


    [2020-09-23 21:55:18] main.CRITICAL: Report ID: webapi-5f6bc446bb808; Message: Property "DisableTmpl" does not have accessor method "getDisableTmpl" in class "MagentoQuoteApiDataPaymentInterface". {"exception":"[object] (Exception(code: 0): Report ID: webapi-5f6bc446bb808; Message: Property "DisableTmpl" does not have accessor method "getDisableTmpl" in class "Magento\Quote\Api\Data\PaymentInterface". at /home/solivrfrpa/www/vendor/magento/framework/Webapi/ErrorProcessor.php:208, LogicException(code: 0): Property "DisableTmpl" does not have accessor method "getDisableTmpl" in class "Magento\Quote\Api\Data\PaymentInterface". at /home/solivrfrpa/www/vendor/magento/framework/Reflection/NameFinder.php:100)"} []

    Follow below step-by-step guide to solve the issue.

    Step 1 : Go to this path /vendor/magento/module-checkout/view/frontend/web/js/action/select-payment-method.js

    Step 2 : Overwrite this select-payment-method.js in your theme  /app/design/frontend/[VendorName]/[theme]/Magento_Checkout/web/js/action/select-payment-method.js

    Step 3 : Comment below mention code in line no.15 approx.

    /*
    if (paymentMethod) {
        paymentMethod.__disableTmpl = {
            title: true
        };
    }
    */

    Step 4 : After that run below mentioned commands

    - php bin/magento setup:upgrade
    - php bin/magento setup:di:compile
    - php bin/magento cache:clean

    That’s it…

    Now, you can check your payment method while placing the order on checkout page. Your payment method related issue should have resolved.

    Magento 2: add new custom product attribute in product tabs

    If you want to add a new custom attribute in product tabs, then you you need to add the below code:

    <referenceBlock name="product.info.details"> 
     <block class="MagentoCatalogBlockProductView" name="product.info.keyfeature" as="keyfeature" template="Magento_Catalog::product/view/attribute.phtml" group="detailed_info">
     <arguments>
     <argument name="at_call" xsi:type="string">getKeyFeatures</argument>
     <argument name="at_code" xsi:type="string">key_features</argument>
     <argument name="css_class" xsi:type="string">keyfeature</argument>
     <argument name="title" translate="true" xsi:type="string">Key Features</argument>
     <argument name="sort_order" xsi:type="string">20</argument>
     </arguments>
     </block>
     </referenceBlock>

    in your theme/Magento_Catalog/layout/catalog_product_view.xml file between the body tag.

    Here I have set “key_features” product attribute in product tabs.

    Magento 2 remove error Property “DisableTmpl” does not have accessor method “getDisableTmpl” on checkout page

    Overwrite file from

    vendor/magento/module-checkout/view/frontend/web/js/action/select-payment-method.js

    to your theme –

    app/design/frontend/yourtheme/themename/Magento_Checkout/web/js/action/select-payment-method.js

    define([
        '../model/quote'
    ], function (quote) {
        'use strict';
    
        return function (paymentMethod) {
            if (paymentMethod) {
                paymentMethod.__disableTmpl = {
                    title: true
                };
            }
            quote.paymentMethod(paymentMethod);
        };
    });

    Please comment the below lines

    /*if (paymentMethod) {
        paymentMethod.__disableTmpl = {
            title: true
        };
    }*/

    Then  execute the upgrade & deploy the command.

    How to check current area in Magento 2? Frontend or Backend?

    Here, we have described how to check whether the current area is frontend or backend

    Well, you can check it with object manager

    $objectManager = MagentoFrameworkAppObjectManager::getInstance();
    $areastate =  $objectManager->get('MagentoFrameworkAppState');
    echo $areastate->getAreaCode();

    so it will show you that the current area is frontend or adminhtml

    Magento 2 add button in configuration setting with controller action

    In Magento there are so many default field types available for configuration settings field, but no type is provided for the button,

    To add button in configuration setting, we have to process via custom frontend model.

    First we have to put button setting in existing module system.xml or create new module by adding the below code:

    [Vendor Name][Module Name]etcadminhtmlsystem.xml

    <?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <tab id="tab_id" translate="label" sortOrder="1000">
            <label>Your Tab Title</label>
        </tab>
        <section id="yoursection_id" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
            <label>Section Label</label>
            <tab>tab_id</tab>
            <resource>[your resource name]</resource>
            <group id="scheduler_export_product" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
                <label>Export Products Scheduler Options</label>
                <field id="export_all_product" translate="label comment" type="button" sortOrder="10" showInDefault="1" showInWebsite="0" showInStore="0">
                    <label>Export All Products</label>
                    <frontend_model>[Vendor Name][Module Name]BlockSystemConfigExportproduct</frontend_model>
                    <comment><![CDATA[Your Field Comment Here]]></comment>
                </field>
            </group>
        </section>
    </system>
    </config>

    Then you have to create frontend model file & add the below code:

    [Vendor Name][Module Name]BlockSystemConfigExportproduct.php

    <?php
    namespace [Vendor Name][Module Name]BlockSystemConfig;
    
    /**
     * Class Exportproduct
     * @package [Vendor Name][Module Name]BlockSystemConfig
     */
    class Exportproduct extends MagentoConfigBlockSystemConfigFormField
    {
        protected $_template = '[Vendor Name]_[Module Name]::system/config/exportproduct.phtml';
    
        public function __construct(
            MagentoBackendBlockTemplateContext $context,
            array $data = []
        ) {
            parent::__construct($context, $data);
        }
    
        public function render(MagentoFrameworkDataFormElementAbstractElement $element)
        {
            $element->unsScope()->unsCanUseWebsiteValue()->unsCanUseDefaultValue();
            return parent::render($element);
        }
    
        protected function _getElementHtml(MagentoFrameworkDataFormElementAbstractElement $element)
        {
            return $this->_toHtml();
        }
    
        public function getAjaxUrl()
        {
            return $this->getUrl('loyalty/export/allproducts'); //Put your controller action URL here
        }
    
        public function getButtonHtml()
        {
            $button = $this->getLayout()->createBlock(
                'MagentoBackendBlockWidgetButton'
                )->setData(
                [
                    'id' => 'exportbtn',
                    'label' => __('Export All Products'),
                ]
            );
            return $button->toHtml();
        }
    }

    Now you have to create button related template file & add the below code:

    [Vendor Name][Module Name]viewadminhtmltemplatessystemconfigexportproduct.phtml

    <?php
    /**
     * @var [Vendor Name][Module Name]BlockSystemConfigExportproduct $block
     */
    ?>
    <script>
        require([
            'jquery',
            'prototype',
        ], function ($) {
            function exportAllProducts() {
                params = {};
                new Ajax.Request('<?php echo $block->getAjaxUrl() ?>', {
                    loaderArea: true,
                    asynchronous: true,
                    parameters: params,
                    onSuccess: function (transport) {
                        var response = JSON.parse(transport.responseText);
                        $('#messages .message-success span.message-text').text('Your Controller Action Success Message Here');
                        $('#messages .message-success').show();
                        $('#messages .message-success').delay(8000).fadeOut();
                    },
                    onFailure: function() {               
                        $('#messages .message-error span.message-text').text('Your Controller Action Failure Message Here');
                        $('#messages .message-error').show();
                        $('#messages .message-error').delay(8000).fadeOut();
                        return false;
                    }
                });
            }
            $('#exportbtn').click(function () {
                exportAllProducts();
            });
        });
    </script>
    
    <div id="messages" >
        <div class="messages">
            <div class="message message-success success" style="display: none;">
                <div data-ui-id="messages-message-success">
                    <span class="message-text"></span>
                </div>
            </div>
            <div class="message message-error error" style="display: none;">
                <div data-ui-id="messages-message-error">
                    <span class="message-text"></span>
                </div>
            </div>
        </div>
    </div>
    <?php echo $block->getButtonHtml() ?>

    In the end, you have to create your controller action file with your logic & return Json response as per your requirement.

    After doing all the above steps run php bin/magento cache:flush command and verify that whether your admin configuration settings display button in your section as shown below or not.

     

    PDF Invoice showing wrong date in Magento 2.3.5

    When PDF Incvoice show wrong date in Magento 2.3.5 then follow below steps.

    Step 1 : Go to this path /vendor/magento/framework/Stdlib/DateTime/Timezone.php

    Step 2 : Go to line no. 196 (approx).

    Step 3 : Comment this below function.

    public function scopeDate($scope = null, $date = null, $includeTime = false)
    {
        ...
        ...
    }

    Step 4 : Place this below mention function after above commented function.

    public function scopeDate($scope = null, $date = null, $includeTime = false)
    {
        $timezone = new DateTimeZone(
            $this->_scopeConfig->getValue($this->getDefaultTimezonePath(), $this->_scopeType, $scope)
        );
        switch (true) {
            case (empty($date)):
                $date = new DateTime('now', $timezone);
                break;
            case ($date instanceof DateTime):
            case ($date instanceof DateTimeImmutable):
                $date = $date->setTimezone($timezone);
                break;
            default:
                $date = new DateTime(is_numeric($date) ? '@' . $date : $date);
                $date->setTimezone($timezone);
                break;
        }
    
        if (!$includeTime) {
            $date->setTime(0, 0, 0);
        }
    
        return $date;
    }

    Step 5 : After that run below mentioned commands

    - php bin/magento setup:upgrade
    - php bin/magento cache:clean

    That’s it.

    After performing above steps, you can check the PDF Invoice. You will find the appropriate date in your PDF Invoices.

    Magento 2 print barcode with unique code in invoice pdf

    There are so many third party libraries or extensions that are available for generating/tracking barcodes.

    Today I’m going to share with you that how we can easily add unique barcodes in our pdf using Magento default Zend library.

    First, you have to create [Vendor Name]/[Module Name]/etc/di.xml in your existing module or create a new module and add the below code:

    <?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
        <type name="MagentoSalesModelOrderPdfInvoice">
            <plugin name="barcodes_pdf_invoice" type="[Vendor Name][Module Name]PluginInvoice" sortOrder="10" />
        </type>
    </config>

    Then you have to create a plugin file [Vendor Name][Module Name]PluginInvoice.php and add the below code:

    <?php
    
    namespace [Vendor Name][Module Name]Plugin;
    
    use MagentoFrameworkAppConfigScopeConfigInterface;
    
    class Invoice
    {
         /**
         * Configuration barcode enable XML path
         */
        const XML_PATH_BARCODES_ENABLED = 'barcodes/general/eb_barcodes_active';
        /**
         * @var ScopeConfigInterface
         */
        private $scopeConfig;
        
        public function __construct(
            ScopeConfigInterface $scopeConfig
        ) {
            $this->scopeConfig = $scopeConfig;
        }
        
        public function beforeInsertDocumentNumber($subject, $page, $text)
        {
            if ($this->scopeConfig->isSetFlag(self::XML_PATH_BARCODES_ENABLED)) { //Here you will check your custom condition like enable/disable
                $docHeader = $subject->getDocHeaderCoordinates();
                $image = $this->generateBarcode($text);
                $page->drawImage($image, $docHeader[2] - 150, $docHeader[1] + 5, $docHeader[2] + 8, $docHeader[1] +50); //You will adjust barcode image place or height/width as per your requirement
            }
        }
    
        protected function generateBarcode($text)
        {
            $config = new Zend_Config([
                'barcode' => 'code128',
                'barcodeParams' => [
                    'text' => $this->extractInvoiceNumber($text),
                    'drawText' => true
                ],
                'renderer' => 'image',
                'rendererParams' => ['imageType' => 'png']
            ]);
            $barcodeResource = ZendBarcodeBarcode::factory($config)->draw();
            ob_start();
            imagepng($barcodeResource);
            $barcodeImage = ob_get_clean();
            $image = new Zend_Pdf_Resource_Image_Png('data:image/png;base64,' . base64_encode($barcodeImage));
            return $image;
        }
    
        protected function extractInvoiceNumber($text)
        {
            $array_of_words = explode("#", $text);
            return $array_of_words[1];
        }
    }
    

    After creating both files run php bin/magento cache:flush and see any invoice pdf barcodes are printed as below.

    Magento 2: How to remove default Magento Open Sans fonts?

    “opensans” font is the default font adopted by Magento.

    So if you need to remove default preloaded “opensans” fonts then you can follow the below instructions.

    1. You need to add the below code in between <head> tag on your theme/Magento_Theme/layout/default.xml

    <head>
     <remove src="fonts/opensans/light/opensans-300.woff2"/>
     <remove src="fonts/opensans/regular/opensans-400.woff2"/>
     <remove src="fonts/opensans/semibold/opensans-600.woff2"/>
     <remove src="fonts/opensans/bold/opensans-700.woff2"/>
     </head>

    Note: I have tested it in Magento Version: 2.3.5