Logging in Magento 2.4+

As we all know that after the release of the Magento 2.4.3 version, the Laminas-log module is removed. Thus, the previous method by using the following will not work

quick ways to debug

    $writer = new \Laminas\Log\Writer\Stream(BP . '/var/log/custom.log');
    $logger = new \Laminas\Log\Logger();
    $logger->addWriter($writer);

So after 2.4.3+

  try {
        $writer = new \Zend_Log_Writer_Stream(BP . '/var/log/custom.log');
    } catch (\Zend_Log_Exception $e) {
        // throw exception
    }
    $logger = new \Zend_Log();
    $logger->addWriter($writer);
    $logger->info('Debuggging on!');

How to Add Date Picker in Custom Form

In this post , we are going to see how we can add date picker in custom form at Backend or Frontend.

<div class="admin__field">
      <label for="delivery_date" class="admin__field-label"><?= $block->escapeHtml(__('Shipment Delivery Date')) ?></label>
         <div class="admin__field-control">
           <input name="delivery_date" type="text" class="input-text" id="delivery_date" />
       </div>
 </div>
<script>
    require([
        'jquery',
        'mage/calendar'
    ], function () {
        jQuery('#delivery_date').datepicker({
            dateFormat: 'dd/mm/yy',
            changeMonth: false,
            changeYear: false
        });
    });
</script>

We have to add HTML block and javascript code in same phtml to make date picker work. Let us know if you are facing any issue about the same.

Happy Coding 😀

How to add banner on the category sidebar in Magento 2

Have you ever required to add some offers and promotions banner on your website ? I guess answer is ‘Yes’.

Here we have described how can you easily add a banner to the category sidebar even you do not have knowledge of coding because it is really easy to do with Magento 2 admin.

To add a banner in the sidebar follow the below steps.

  1. Create Bock

First, you need to create a bock and add a banner image. You can design it with HTML code if you want.

To add Block go to ‘Admin->Content->Blocks->Add New

create block
  1. Create Widget

Once you create a block, just go to the widget and add a block to the ‘category page sidebar’.

To add widget go to ‘Admin->Content->Widgets->Add new

Check the below screenshot to know the information to be feeling up in Widget.

Create Widget – 1
Create Widget – 2

  1. Flush Cache

Once you finish all the above steps just go to ‘Admin->System->Cache Management’ and flush the cache.

Happy coding 🙂

How to change price dynamically on product page in Magento2

In this blog post, we are going to code how to dynamically change the price on product page for magento 2.

To add JS code on the product page, we have created layout file and added js file in content reference container.

<page layout="1column" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <referenceContainer name="content">
        <block class="Magento\Framework\View\Element\Template"
               name="pricechange" as="pricechange" template="Codedecorator_Learn::product/js.phtml"/>
    </referenceContainer>
</page>

After creating layout file, lets create template file which will have our js code

require(["jquery","Magento_Catalog/js/price-utils"], function(jQuery,priceUtils) {
    var productPrice = parseFloat(jQuery('span.price-final_price > span[data-price-type="finalPrice"]').attr('data-price-amount'));
    var finalPrice=100;
    formatedPrice = priceUtils.formatPrice(parseInt(finalPrice));
    jQuery('span.price-final_price > span.price-wrapper > span.price').text(formatedPrice);
    var finalPrice=productPrice+(pricePerText*textObjects)+(pricePerImage*imageObjects);
    formatedPrice = priceUtils.formatPrice(parseInt(finalPrice));
    jQuery('span.price-final_price > span.price-wrapper > span.price').text(formatedPrice);
}); // Required

After creating both the files, just flush the cache using following command.

php bin/magento cache:flush

I hope this post will help and give the solution for any of your problem.

happy coding 😀

How to rewrite widget function with mixins Magento 2

In this post, we will understand how to use Mixins in Magento 2.

What is Mixin?

Mixins are a language concept that allows a programmer to inject some code into a class

A mixin is a class containing methods that can be used by other classes without a need to inherit from it.

Wikipedia

If we want to perform an extra action or extend a Javascript functionality without completely overwriting it, in this case mixin comes in picture. Let’s start with an example

var config = {
    config: {
        mixins: {
            'Magento_Catalog/js/catalog-add-to-cart': {
                'Codedecorator_Learn/js/cd-catalog-add-to-cart-mixin': true
            }
        }
    }
};

After creating above file, we need to create cd-catalog-add-to-cart-mixin.js file where we will extend the functionality of the submitForm function.

define([
], function () {
    'use strict';
    return function (widget) {
        $.widget('mage.catalogAddToCart', widget, {
            /**
             * Handler for the form 'submit' event
             *
             * @param {jQuery} form
             */
            submitForm: function (form) {
                this.ajaxSubmit(form); // original code
                this.doSomethingAfterSubmit(); // add every thing you want
            },
            /**
             * Do something
             */
            doSomethingAfterSubmit: function () {
                // Do stuff
            },
        });
        return $.mage.catalogAddToCart;
    }
});

Try to add product into cart and see your change is coming in or not. If not then try to flush cache or deploy the content.

Happy coding guys 😀

How to Enable Error Log in Magento2.4

Errors are the part of developer coding journey and they also improve us as developer.

A good developer always read the error carefully and find the solution for the same so let’s see how we can see error log in Magento.

Where you can find the error log

The log files are located in the <magento-root>/var/log/ folder.

By default, Magento2 writes to the debug log (<magento-root>/var/log/debug.log) when it is in default or develop mode, but not when it is in production mode.

Enable error log

Use the bin/magento setup:config:set --enable-debug-logging=true && bin/magento c:f command to change the default value.

Disable error log

Use the bin/magento setup:config:set --enable-debug-logging=false && bin/magento c:f command to change the default value

Before Magento 2.3.1 enable error log

Use the bin/magento config:set dev/debug/debug_logging 1 && bin/magento c:f command to change the default value

Happy debugging 😀

How To Additional Options In Cart Item – Magento2

If you want to show any additional information in cart item then following code will help you out.

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="checkout_cart_product_add_after">
        <observer name="set_additional_options"
        instance="Codedecorator\Learn\Observer\SetAdditionalOptions"/>
    </event>
</config>
namespace Codedecorator\Learn\Observer;

use Magento\Framework\Event\Observer as EventObserver;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Serialize\SerializerInterface;

class SetAdditionalOptions implements ObserverInterface
{
    protected $request;
    private $serializer;

    public function __construct(
        RequestInterface $request,
        SerializerInterface $serializer
    )
    {
        $this->request = $request;
        $this->serializer = $serializer;
    }

    public function execute(EventObserver $observer)
    {
        $item = $observer->getQuoteItem();
        $post = $this->request->getPost();
		
        $additionalOptions = array();
        if ($additionalOption = $item->getOptionByCode('additional_options')) {
            $additionalOptions = $this->serializer->unserialize($additionalOption->getValue());
        }
        // check your custom condition
        if(isset($post['height'])){
			$price = 100;
            $additionalOptions[] = [
                'label' => 'Height',
                'value' => $post['height']
            ];
        }
         // Without any condition add option
         $additionalOptions[] = [
                'label' => 'CD',
                'value' => 'CD OPTION'
            ];

        if (count($additionalOptions) > 0) {
            $item->addOption(array(
                'product_id' => $item->getProductId(),
                'code' => 'additional_options',
                'value' => $this->serializer->serialize($additionalOptions)
            ));
        }
    }
}

Options will be shown on frontend side but wont show in admin order.

To set Additional in Order as well then go with following steps.

Append following code in events.xml that we have created

 <event name="sales_model_service_quote_submit_before">
        <observer name="order_add" instance="Codedecorator\Learn\Observer\SetAdditionalOptionsToOrder" />
 </event>
<?php

namespace Codedecorator\Learn\Observer;

use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Serialize\SerializerInterface;

class SetAdditionalOptionsToOrder implements ObserverInterface
{
    private $serializer;

    public function __construct(
        SerializerInterface $serializer
    )
    {
        $this->serializer = $serializer;
    }

    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        try{

            $quote = $observer->getQuote();
            $order = $observer->getOrder();

            foreach ($quote->getAllVisibleItems() as $quoteItem) {
              $quoteItems[$quoteItem->getId()] = $quoteItem;
            }

            foreach ($order->getAllVisibleItems() as $orderItem) {

                $quoteItemId = $orderItem->getQuoteItemId();
                $quoteItem = $quoteItems[$quoteItemId];
                $additionalOptions = $quoteItem->getOptionByCode('additional_options');

                if(!is_null($additionalOptions)) {
                    $options = $orderItem->getProductOptions();
                    $options['additional_options'] = $this->serializer->unserialize($additionalOptions->getValue());
                    $orderItem->setProductOptions($options);
                }
            }
            return $this;

        }catch (\Exception $e) {
            
             // catch error if any
        
        }
      
    }
}

Happy coding 🙂

System configuration in admin Magento2

System configuration mainly used as module configuration where the admin will set some configuration for specific modules like enable/disable the module. Get some input or selection of options like that we have a variety of field to be created in the configuration.

Where you will find it?
You will be able to find the module configuration in Magento 2 admin -> Stores(Menu) -> Configuration

All the system configuration will have three parts:

  1. Tab (It is left side the system configuration page. Which contains multiple sections of multiple modules)
  2. The section will contain the groups of configuration for the specific module
  3. Each group will contain fields for the configuration

Few basic attributes are used in all the elements of system configuration are:

  1. Id: unique ID of the element
  2. Translate: To tell Magento to translate the label of the element according to the language of the admin
  3. sortOrder: Position of the element.
  4. showInDefault: Do you want to show this element when an admin hasn’t selected any scope. (Global)
  5. showInWebsite: Do you want to show this element when admin select website (Website)
  6. showInStore: Do you want to show this element when admin select store view (Store View)

Above mentioned 3,4,5 point mainly useful when we want to allow admin customer to configure the module based on the scope.

SCOPE in configuration.

Store: It is configuration limited to the store view, which is often used to display
a store in multiple languages.
Website: Configuration is limited to the website.
Global: It applies to the entire installation.

For example enable/disable of module if we can showInDefault=1 , ShowIndWebsite=1 and ShowInStore=1 then will show this field in all scope. If make Show InDefault=0, ShowInWebsite and ShowInStore=1 then it will show field in default or global scope admin have to change the scope.

<system> 
     <tab id="codedecorator" translate="label" sortOrder="10">
       <label>Codedecorator</label> <!--Tab Name-->
     </tab>
     <section id="one" translate="label" sortOrder="130" showInDefault="1" showInWebsite="1" showInStore="1">
       <class>one-section</class> <!--  Class name to section -->
       <label>Hello World</label> <!--Label Of this section -->
       <tab>codedecorator</tab> <!-- It will tell which tab is linked with this section so it should match with tab id and also can be used to group multiple section -->
       <resource>Codedecorator_Learn::codedecorator_config</resource> <!--  It used in ACL -->
       <group id="general" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
                <label>License Configuration</label>
                <!-- Field element has type attribute which decide the type of field. -->
                <field id="serial_key" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Serial Key</label>
                    <backend_model>Codedecorator\Learn\Model\Config\Backend\Lookup</backend_model>
                    <validate>required-entry</validate>
                    <comment>Take serial key from Codedecorator</comment> <!--Give a comment to field -->
                </field>
                <field id="enable" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Module Enable</label>
                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                </field>
       </group>
    </section>
</system>

Source Model: Source is model to provide data to field like select and multiple select.
Backend Model: Backend model is mainly useful when want to take some action before saving the configuration. Like to check serial key correct or not before saving the configuration if wrong provides a message that is not correct.

Happy coding guys!

How to delete image or file in Magento2

When we are working on image or file upload functionality from frontend of Magento, we also allowing customer to upload another or update the image so that time we also have to delete previously upload the image or file as we can left those uploaded image or file left on server.

Following code will help you with that logic.

<?php
namespace Codedecorator\Learn\Controller\Index;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\Filesystem\Driver\File;
use Magento\Framework\Filesystem;
use Magento\Framework\App\Filesystem\DirectoryList;

class Delete extends Action
{

    protected $_filesystem;
    protected $_file;

    public function __construct(
        Context $context,
        Filesystem $_filesystem,
        File $file
    )
    {
        parent::__construct($context);
        $this->_filesystem = $_filesystem;
        $this->_file = $file;
    }

    public function execute()
    {
        ........
        $fileName = "file or image name";// replace this with some codes to get the $fileName
        $mediaRootDir = $this->_filesystem->getDirectoryRead(DirectoryList::MEDIA)->getAbsolutePath();
        if ($this->_file->isExists($mediaRootDir . $fileName)) {
            $this->_file->deleteFile($mediaRootDir . $fileName);
        }
       ......
    }
}

Let’s us know if you need any issue or any query.

Happy coding guys!

How to create a new table using Declarative Schema( db_schema.xml) in Magento2

We all know about PHP script like InstallSchema.php (old way to create new table) to create new table but magento has introduced Declarative schema to create or maintain the tables using declarative schema xml.

Advantage of this db_schema.xml is to avoid the unnecessary version checking for create new columns or delete column for each table change. Let’s create one table

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
   <table name="codedecorator_learn" resource="default" engine="innodb" comment="Codedecorator Learn">
      <column xsi:type="int" name="id" padding="10" unsigned="false" nullable="false" identity="true" comment="ID" />
      <column xsi:type="varchar" name="name" nullable="false" length="25" comment="Name" />
      <column xsi:type="varchar" name="email" nullable="false" length="25" comment="Email" />
      <column xsi:type="varchar" name="description" nullable="false" length="255" comment="Description" />
      <column name="created_at" nullable="false" xsi:type="datetime" default="CURRENT_TIMESTAMP" on_update="false"/>
      <column name="updated_at" nullable="true" xsi:type="datetime" default="CURRENT_TIMESTAMP" on_update="true"/>
      <constraint xsi:type="primary" referenceId="PRIMARY">
         <column name="id" />
      </constraint>
   </table>
</schema>

After creating db_schema.xml, we need to run following command to tell magento that we have created new table and also for backward compatibility with php script.

It will not directly delete any column or table if you dont have entry in whitelist because there might be upgrade schema available for the same so that it is important to generate whitelist.

php bin/magento setup:db-declaration:generate-whitelist --module-name=Codedecorator_Learn

Note: When you disable any module with db schema and you run setup upgrade command then it will delete the module table directly if you want to avoid that situation.

Please ran command using setup:upgrade --safe-mode=1 in order to create a database backup and then eventually setup:upgrade --data-restore=1 if you enable the module back and wish to restore from that backup.

Happy coding guys!