:::: MENU ::::

Magento Tutorial | Magento Blog | Learn Magento 2

Are you a Magento 2 Developer? then you are at right place.

Cookies Consent Popup

Displaying Recently Viewed Products is a great way to improve user experience and boost conversions. Magento 2 provides a built‑in approach for this, but many developers still rely on older methods that are now deprecated. Let’s walk through the correct way to implement it.

Deprecated Approach

In older Magento versions, developers often used direct block creation in .phtml files:

<?php
echo $this->getLayout()
    ->createBlock("Magento\\Reports\\Block\\Product\\Widget\\Viewed")
    ->setDisplayType("recently.view.products")
    ->setProductsCount("5")
    ->setTemplate("widget/viewed/content/viewed_list.phtml")
    ->toHtml();
?>

This method is not recommended anymore because it doesn’t play well with Full Page Cache (FPC) and can cause performance issues.

Recommended Approach (KnockoutJS + Layout XML)

Magento now uses KnockoutJS and UI Components for Recently Viewed Products. To add the block via layout XML, use the Magento\Catalog\Block\Widget\RecentlyViewed class:

<block class="Magento\Catalog\Block\Widget\RecentlyViewed"
       name="recently_viewed"
       template="Magento_Catalog::product/widget/viewed/grid.phtml"
       after="-">
    <arguments>
        <argument name="uiComponent" xsi:type="string">widget_recently_viewed</argument>
        <argument name="page_size" xsi:type="number">4</argument>
    </arguments>
</block>

Advanced Configuration

You can customize the block further by specifying which attributes and buttons to display:

<block class="Magento\Catalog\Block\Widget\RecentlyViewed"
       name="recently_viewed"
       template="Magento_Catalog::product/widget/viewed/grid.phtml"
       after="-">
    <arguments>
        <argument name="uiComponent" xsi:type="string">widget_recently_viewed</argument>
        <argument name="page_size" xsi:type="number">4</argument>
        <argument name="show_attributes" xsi:type="string">name,image,price,learn_more</argument>
        <argument name="show_buttons" xsi:type="string">add_to_cart,add_to_compare,add_to_wishlist</argument>
    </arguments>
</block>

Important: Values for show_attributes and show_buttons must be comma‑delimited strings without spaces. Arrays or spaced values won’t work because of how the UI Component parses data before Knockout renders it.

Why This Approach?

  • Cache‑safe → Works properly with Full Page Cache.
  • Flexible → Easy to configure attributes and buttons.
  • Future‑proof → Uses Magento’s recommended KnockoutJS + UI Component approach.
  • No deprecated instructions → Avoids the old action XML instruction, which is now deprecated.

Conclusion

If you want to add Recently Viewed Products in Magento 2, always use the Magento\Catalog\Block\Widget\RecentlyViewed block via layout XML. It’s the most reliable, cache‑friendly, and customizable way to implement this feature.

Happy Coding!

Integrating Mailchimp with Magento 2 is one of the most effective ways to automate your marketing, grow your audience, and increase sales. With Mailchimp, you can send personalized campaigns, track customer behavior, and build stronger relationships with your shoppers. In this guide, we’ll cover everything from installation to testing, plus best practices to ensure your integration works smoothly.

Why Connect Mailchimp with Magento?

  • Automated Campaigns → Trigger emails based on customer actions (abandoned cart, new signup, repeat purchase).
  • Segmentation → Group customers by purchase history, location, or preferences for targeted marketing.
  • Analytics → Track open rates, conversions, and ROI directly from Mailchimp’s dashboard.
  • Scalability → As your store grows, Mailchimp can handle larger audiences and more complex workflows.

Step 1: Install the Mailchimp Extension

Magento does not ship with Mailchimp integration by default. You need to install the official Mailchimp extension or a trusted third‑party module.

composer require mailchimp/mc-magento2
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush

After installation, you’ll see a new configuration section in the Magento Admin under Stores → Configuration → Services → Mailchimp.

Step 2: Generate and Configure Your API Key

Log in to your Mailchimp account and generate an API key:

  1. Go to Profile → Extras → API Keys.
  2. Click Create A Key.
  3. Copy the generated key.

In Magento Admin:

  1. Navigate to Stores → Configuration → Services → Mailchimp.
  2. Paste your API key into the API Key field.
  3. Save the configuration.

Step 3: Sync Your Audience

Choose which Mailchimp audience (list) you want to sync with Magento customers. You can configure:

  • Customer Groups → e.g., Retail vs Wholesale.
  • Newsletter Subscribers → Sync only opted‑in users.
  • Order Data → Send purchase history for segmentation and product recommendations.

Step 4: Test the Integration

After saving, run a quick test to confirm data sync:

bin/magento mailchimp:sync

This command pushes customer and order data to Mailchimp. Check your Mailchimp dashboard to confirm records are appearing correctly.

Troubleshooting Common Issues

  • Invalid API Key → Ensure your key is active and copied correctly.
  • Sync Errors → Check Magento logs (var/log/system.log) for details.
  • Audience Not Updating → Verify that your Mailchimp audience is set up and selected in Magento config.
  • Performance Issues → Run sync during off‑peak hours to avoid slowing down checkout.

Best Practices for Mailchimp + Magento

  • Use Double Opt‑In → Ensures compliance with GDPR and builds a high‑quality subscriber list.
  • Segment Smartly → Create segments like “High‑value customers” or “Inactive users” for targeted campaigns.
  • Automate Abandoned Cart Emails → Recover lost sales by reminding customers of items left in their cart.
  • Track ROI → Use Mailchimp’s analytics to measure which campaigns drive the most revenue.

Conclusion

By connecting Mailchimp with Magento 2, you unlock powerful marketing automation tools that help you engage customers and drive sales. With the official extension and proper configuration, syncing data becomes seamless and reliable. Focus on building high‑quality campaigns, segmenting your audience, and tracking performance to get the most out of this integration.

Happy Integrating!

After upgrading Magento from 2.3.6 to 2.4.3‑p1, many developers encounter a frustrating issue: the admin login form simply reloads without showing any error message. This can be confusing, especially if you are not aware of the new security features introduced in Magento 2.4.

Root Cause of the Issue

Starting with Magento 2.4, Adobe introduced Two‑Factor Authentication (2FA) for all admin users. This means that logging in requires not only your username and password, but also a second authentication method (such as Google Authenticator, Duo, or other supported providers).

On some installations (especially local development environments like Windows), Magento does not clearly display the 2FA requirement. Instead, the login form reloads without explanation, leaving administrators locked out of the backend.

Quick Fix: Disable 2FA

If you are working in a local or development environment and don’t need 2FA, you can disable the module to regain access:

bin/magento module:disable Magento_TwoFactorAuth
bin/magento cache:flush

After running these commands, you should be able to log in to the admin panel normally.

Best Practice: Configure 2FA Properly

While disabling 2FA may be acceptable for local development, it is not recommended for production stores. Instead, configure 2FA correctly to protect your admin accounts:

  1. Log in to Magento Admin with your credentials.
  2. When prompted, select a 2FA provider (e.g., Google Authenticator).
  3. Scan the QR code with your authenticator app.
  4. Enter the generated code to complete login.

This ensures your store remains secure against unauthorized access.

Alternative Solutions

  • Whitelist IPs → If your team works from a fixed IP, you can configure IP whitelisting to reduce login friction.
  • Use Environment‑Specific Config → Disable 2FA only in development environments by setting it in app/etc/env.php.
  • Upgrade to Latest Magento → Later versions of Magento 2.4.x improved error messaging for 2FA, making it clearer why login fails.

Troubleshooting Tips

  • Check var/log/system.log and var/log/exception.log for hidden errors.
  • Ensure your PHP version matches Magento’s requirements (PHP 7.4 or 8.1 depending on patch level).
  • Clear browser cache and cookies if login loops persist.
  • Verify that all required modules are enabled after upgrade.

Security Considerations

Two‑Factor Authentication is a critical security feature. Disabling it permanently can expose your store to brute‑force attacks and unauthorized access. Always weigh convenience against security, and consider enabling 2FA in production environments.

Conclusion

If you encounter the “can’t login to admin panel” issue after upgrading to Magento 2.4.3‑p1, the cause is usually the new 2FA requirement. For development, you can disable the module to continue working. For production, configure 2FA properly to keep your store secure. Understanding this change will save you time and frustration during upgrades.

Happy Coding & Stay Secure!

Magento 2 uses RequireJS as its JavaScript module loader. RequireJS improves performance by loading scripts asynchronously and managing dependencies. To customize or extend Magento’s frontend behavior, developers often work with requirejs-config.js. In this article, we’ll explore shim, mixin, deps, and map configuration nodes, with practical examples and best practices.

Shim

The shim configuration is used when a JavaScript library does not support AMD (Asynchronous Module Definition). It tells RequireJS about dependencies and export values so the library loads correctly.

Example: Loading jquery.cookie only after jQuery:

var config = {
    paths: {
        'jquery.cookie': 'Vendor_Module/js/jquery.cookie.min'
    },
    shim: {
        'jquery.cookie': {
            deps: ['jquery']
        }
    }
};

Here, deps ensures jQuery is loaded before jquery.cookie. Without this, you may see “jQuery not defined” errors.

Mixin

The mixins configuration allows you to extend or override existing JavaScript modules without rewriting them completely. This is especially useful for customizing Magento core JS components.

Example: Extending Magento’s checkout shipping view:

var config = {
    config: {
        mixins: {
            'Magento_Checkout/js/view/shipping': {
                'Vendor_Module/js/shipping-mixin': true
            }
        }
    }
};

In this example, shipping-mixin.js adds or overrides methods in the original Magento_Checkout/js/view/shipping component. This approach is upgrade‑safe and avoids direct core modifications.

Deps

The deps configuration forces RequireJS to load specific modules immediately when the page loads. It’s useful for global scripts or initialization logic.

Example: Loading a custom script globally:

var config = {
    deps: [
        'Vendor_Module/js/global-script'
    ]
};

This ensures global-script.js runs as soon as RequireJS initializes, without waiting for other modules to call it.

Map

The map configuration allows you to remap module paths or override existing modules with custom ones. This is useful when you want to replace a core module with your own implementation.

Example: Override Magento’s default validation module:

var config = {
    map: {
        '*': {
            'Magento_Checkout/js/model/shipping-save-processor/default':
                'Vendor_Module/js/shipping-save-processor/custom'
        }
    }
};

Here, whenever Magento tries to load Magento_Checkout/js/model/shipping-save-processor/default, it will instead load your custom file.

Other Useful Nodes

  • paths → Defines shortcuts for module file paths.
  • config → Holds advanced configuration like mixins or text plugin settings.

Best Practices

  • Always use mixins instead of overriding core JS files directly.
  • Use shim only for non‑AMD libraries; prefer AMD‑compatible modules when possible.
  • Keep deps minimal to avoid unnecessary global scripts slowing down page load.
  • Use map for safe overrides, ensuring upgrade compatibility.
  • Organize your requirejs-config.js by scope (frontend, adminhtml) to avoid conflicts.

Conclusion

Understanding shim, mixin, deps, and map in Magento 2’s RequireJS configuration is essential for customizing frontend behavior safely and efficiently. By using these nodes correctly, you can extend Magento’s functionality, integrate third‑party libraries, and maintain upgrade‑safe code.

Happy Coding!

When working with Magento 2, you may encounter the error message:

bin/magento must be run as CLI

This typically happens when you try to access bin/magento through a browser or when the environment is misconfigured. Let’s explore why this error occurs and how to fix it.

Understanding the Error

The bin/magento script is designed to be executed from the command line interface (CLI), not from a web browser. Magento enforces this restriction to prevent unauthorized execution of system commands through HTTP requests.

Common scenarios where this error appears:

  • Trying to open http://yoursite.com/bin/magento in a browser.
  • Incorrect server configuration that routes requests to bin/magento.
  • Misuse of PHP execution commands in cron jobs or scripts.

Correct Way to Run bin/magento

Always run Magento CLI commands from your terminal or SSH session. Examples:

php bin/magento setup:upgrade
php bin/magento cache:flush
php bin/magento indexer:reindex

These commands must be executed from the Magento root directory.

Fixing the Error

  1. Do not access bin/magento via browser → It is not meant to be opened as a web page.
  2. Check server configuration → Ensure your web server does not expose the bin directory publicly.
  3. Run commands via CLI → Use SSH or terminal access to execute Magento commands.

Additional Troubleshooting

  • File Permissions → Ensure bin/magento has executable permissions:
    chmod +x bin/magento
  • PHP Path → Verify that PHP is installed and accessible:
    php -v
  • Correct Directory → Run commands from the Magento root folder, not from subdirectories.

Best Practices

  • Never expose the bin directory to the public web.
  • Use cron jobs for scheduled tasks instead of browser triggers.
  • Document CLI commands for your team to avoid confusion.
  • Always run CLI commands with the correct PHP version (e.g., PHP 7.4 or 8.1 depending on your Magento version).

Conclusion

The “bin/magento must be run as CLI” error is a reminder that Magento’s command‑line tools are designed for terminal use, not browser access. By running commands properly from the CLI and securing your server configuration, you can avoid this issue and keep your Magento environment safe and efficient.

Happy Coding!

When running Magento 2 on PHP 8.1 or later, you may encounter warnings related to str_replace() or similar string functions. These warnings usually appear because of deprecated usage patterns introduced in newer PHP versions. Let’s explore why this happens and how to fix it properly.

Understanding the Error

PHP 8.1 introduced stricter type checks and deprecated certain function usages. For example, calling str_replace() with null or invalid arguments can trigger warnings:

Deprecated: str_replace(): Passing null to parameter #3 ($subject) of type array|string is deprecated

This means that somewhere in your Magento code (or a custom module), str_replace() is being called with null instead of a valid string or array.

Common Causes in Magento

  • Custom modules passing null values to str_replace().
  • Third‑party extensions not updated for PHP 8.1 compatibility.
  • Core code using older patterns that are now flagged as deprecated.

How to Fix It

The fix is straightforward: ensure that the subject parameter is always a string or array, not null.

Before (deprecated):

$output = str_replace('foo', 'bar', $value);

If $value is null, this triggers a warning.

After (fixed):

$output = str_replace('foo', 'bar', $value ?? '');

Here, the null coalescing operator (??) ensures that $value defaults to an empty string if it is null.

Alternative Fixes

  • Type Casting → Cast the variable to string:
    $output = str_replace('foo', 'bar', (string)$value);
  • Validation → Check before calling:
    if ($value !== null) {
        $output = str_replace('foo', 'bar', $value);
    }

Best Practices for PHP 8.1+ Compatibility

  • Always validate input before passing to string functions.
  • Use ?? '' or type casting to avoid null warnings.
  • Update third‑party extensions to versions compatible with PHP 8.1.
  • Run bin/magento setup:upgrade and clear caches after applying fixes.
  • Enable display_errors in development to catch deprecations early.

Example in Magento Context

Suppose you have a helper method that manipulates product SKUs:

public function cleanSku($sku)
{
    return str_replace(' ', '-', $sku);
}

If $sku is null, this triggers a deprecation warning. Fix it like this:

public function cleanSku($sku)
{
    return str_replace(' ', '-', $sku ?? '');
}

This ensures compatibility with PHP 8.1+ and avoids unnecessary warnings.

Conclusion

The “str_replace() deprecated” warning in Magento 2 under PHP 8.1+ is caused by passing null values to string functions. The solution is to validate inputs or use null coalescing/type casting to ensure proper types. By applying these fixes across your custom modules and extensions, you can maintain a clean, warning‑free Magento environment.

Happy Coding & Stay Compatible!

Cron jobs are essential in Magento 2 for automating repetitive tasks such as reindexing, sending emails, generating reports, and cleaning logs. Sometimes, you may need to create a custom cron job for your own module to perform scheduled operations. In this guide, we’ll walk through the steps to set up a custom cron in Magento 2.

Step 1: Create cron.xml

Inside your custom module, create a etc/cron.xml file. This file defines the cron job and its schedule.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/cron.xsd">

    <group id="default">
        <job name="vendor_module_custom_cron"
             instance="Vendor\Module\Cron\Custom"
             method="execute">
            <schedule>*/5 * * * *</schedule>
        </job>
    </group>

</config>

Here, the cron job runs every 5 minutes (*/5 * * * *).

Step 2: Create Cron Class

Next, create the PHP class that will be executed by the cron job.

<?php
namespace Vendor\Module\Cron;

class Custom
{
    public function execute()
    {
        // Your custom logic here
        // Example: log a message
        file_put_contents(BP . '/var/log/custom_cron.log', "Cron executed at " . date('Y-m-d H:i:s') . "\n", FILE_APPEND);
    }
}

This class contains the execute() method, which Magento calls when the cron job runs.

Step 3: Enable and Test Cron

Ensure Magento’s cron is properly set up on your server. Run:

bin/magento cron:run

Check var/log/custom_cron.log to confirm your cron job executed successfully.

Step 4: Configure System Cron

Magento relies on the server’s cron daemon. Add the following to your server’s crontab:

* * * * * php /path/to/magento/bin/magento cron:run | grep -v "Ran jobs by schedule" >> /path/to/magento/var/log/magento.cron.log
* * * * * php /path/to/magento/update/cron.php >> /path/to/magento/var/log/update.cron.log
* * * * * php /path/to/magento/bin/magento setup:cron:run >> /path/to/magento/var/log/setup.cron.log

This ensures Magento’s cron system runs continuously.

Advanced Usage

  • Groups → You can define jobs under different groups (e.g., index, default).
  • Schedules → Use cron expressions to control frequency (e.g., 0 0 * * * for midnight daily).
  • Dependency Injection → Inject services into your cron class for database operations, API calls, etc.

Troubleshooting

  • Check var/log/magento.cron.log for errors.
  • Ensure your server’s cron daemon is running (service cron status).
  • Verify file permissions for var/log and bin/magento.
  • Run bin/magento setup:upgrade after adding new cron jobs.

Best Practices

  • Keep cron jobs lightweight; avoid long‑running tasks.
  • Use queues or background processes for heavy operations.
  • Log outputs for debugging and monitoring.
  • Test cron jobs in development before deploying to production.

Conclusion

Setting up a custom cron job in Magento 2 allows you to automate repetitive tasks and extend your module’s functionality. By defining cron.xml, creating a cron class, and configuring the system cron, you can ensure your jobs run reliably. Following best practices will keep your store efficient and maintainable.

Happy Coding & Automating!

Magento 2 is built on a powerful event-driven architecture. This means you can hook into specific events and perform custom actions before or after certain operations. One common requirement is to run logic before inserting data into the database, such as modifying product attributes, validating customer data, or logging changes.

Understanding Events in Magento 2

Magento dispatches events at key points in its workflow. Developers can listen to these events using observers. For example:

  • catalog_product_save_before → Triggered before a product is saved.
  • customer_save_before → Triggered before a customer record is saved.
  • sales_order_place_before → Triggered before an order is placed.

By listening to these events, you can run custom logic before Magento inserts or updates records.

Step 1: Define events.xml

Inside your module, create etc/events.xml to register the observer:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">

    <event name="catalog_product_save_before">
        <observer name="vendor_module_product_before_save"
                  instance="Vendor\Module\Observer\ProductBeforeSave" />
    </event>

</config>

This tells Magento to call your observer before a product is saved.

Step 2: Create the Observer Class

Now create the observer class in Vendor/Module/Observer/ProductBeforeSave.php:

<?php
namespace Vendor\Module\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;

class ProductBeforeSave implements ObserverInterface
{
    public function execute(Observer $observer)
    {
        $product = $observer->getEvent()->getProduct();

        // Example: Add prefix to product name before saving
        $name = $product->getName();
        $product->setName('[Custom] ' . $name);

        // Example: Log action
        file_put_contents(BP . '/var/log/product_before_save.log',
            "Product " . $product->getSku() . " modified before save at " . date('Y-m-d H:i:s') . "\n",
            FILE_APPEND
        );
    }
}

This observer modifies the product name and logs the action before Magento inserts/updates the product record.

Other Useful Events

  • customer_save_before → Validate or modify customer data before insert.
  • sales_order_place_before → Add custom logic before order placement.
  • checkout_cart_product_add_after → Run logic after a product is added to cart.

Best Practices

  • Keep observer logic lightweight; avoid heavy operations that slow down saves.
  • Use dependency injection for services instead of direct file_put_contents.
  • Log actions for debugging, but disable verbose logging in production.
  • Test observers in development before deploying to production.

Conclusion

Magento 2’s event/observer system makes it easy to perform actions before inserting or saving data. By registering events in events.xml and writing observer classes, you can customize Magento’s behavior in a clean, upgrade‑safe way. This approach is ideal for adding validations, modifying attributes, or logging changes before data is persisted.

Happy Coding & Customizing!

When working with Magento 2, many developers encounter a common issue: database backups missing tables. This usually happens when running Magento’s built‑in backup commands or when exporting the database manually. Missing tables can lead to broken restores, incomplete migrations, or errors during upgrades.

Understanding the Issue

Magento’s database is large and complex, with hundreds of tables and views. One of the most common problems after restoring a backup is the inventory_stock_1 view being missing. This view is part of Magento’s Multi‑Source Inventory (MSI) system and is required for product salability checks.

Step 1: Verify Missing View

Run the following command to check if inventory_stock_1 exists:

mysql -u username -p -e "SHOW FULL TABLES WHERE Table_type = 'VIEW';" magento_db

If inventory_stock_1 is missing, you’ll need to recreate it.

Step 2: Recreate inventory_stock_1 View

Use the following SQL query to recreate the missing view:

CREATE OR REPLACE VIEW `inventory_stock_1` AS
SELECT DISTINCT
    `legacy_stock_status`.`product_id` AS `product_id`,
    `legacy_stock_status`.`website_id` AS `website_id`,
    `legacy_stock_status`.`stock_id` AS `stock_id`,
    `legacy_stock_status`.`qty` AS `quantity`,
    `legacy_stock_status`.`stock_status` AS `is_salable`,
    `product`.`sku` AS `sku`
FROM
    `cataloginventory_stock_status` AS `legacy_stock_status`
JOIN
    `catalog_product_entity` AS `product`
ON
    `legacy_stock_status`.`product_id` = `product`.`entity_id`;

This query rebuilds the inventory_stock_1 view by joining cataloginventory_stock_status with catalog_product_entity, ensuring Magento can correctly calculate product salability.

Step 3: Flush Cache and Reindex

After recreating the view, run the following commands:

bin/magento cache:flush
bin/magento indexer:reindex

This ensures Magento recognizes the restored view and updates product stock data.

Troubleshooting Tips

  • Check var/log/system.log for errors after restoring backups.
  • Ensure your MySQL user has privileges to create views (CREATE VIEW).
  • If multiple inventory views are missing (inventory_stock_2, etc.), recreate them using similar queries.

Best Practices

  • Always use mysqldump with --routines --triggers to include views in backups.
  • Test restores regularly to confirm views are included.
  • Document custom fixes like this for your team.

Conclusion

The “database backup missing table/view” issue in Magento 2 is common, especially with MSI views like inventory_stock_1. By recreating the view with the correct SQL query and reindexing, you can restore functionality quickly. Following best practices for backups will help prevent this issue in the future.

Happy Coding & Safe Backups!

In Magento 2, updating product attributes can sometimes be tricky. By default, when you save a product, Magento attempts to update all attributes, which can cause performance issues. For example, saving a single product with all attributes may take 40–50 seconds. If you only need to update one attribute, there’s a faster and more efficient way.

Problem with Full Product Save

Using $product->save() or productRepository->save() updates the entire product object. This is resource‑intensive and unnecessary if you only want to change one attribute.

Example (not recommended):

$item->setWidth(10);
$item->save();

This approach saves the entire product, not just the width attribute.

Solution: Use updateAttributes()

Magento provides the updateAttributes() method in Magento\Catalog\Model\Product\Action to update specific attributes directly. This method is much faster and avoids saving the whole product.

Example Code

$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$productAction = $objectManager->get('Magento\Catalog\Model\Product\Action');

$productAction->updateAttributes(
    [$item->getId()],
    ['width' => 10],
    $storeId
);

Here’s what each parameter means:

  • $productIds → Array of product IDs to update.
  • $attrData → Key‑value pairs of attribute codes and values.
  • $storeId → Store view ID where the attribute should be updated.

Another Example

$this->action->updateAttributes(
    [$productObj->getId()],
    ['your_attribute_code' => 'your_value'],
    $storeId
);

Performance Benefits

  • Updates only the required attribute.
  • Reduces execution time significantly compared to full product save.
  • Prevents unnecessary reindexing of unrelated attributes.

Best Practices

  • Use updateAttributes() for bulk updates (e.g., changing prices or stock status for multiple products).
  • Always specify the correct storeId to avoid overwriting values in unintended store views.
  • Log changes for debugging and auditing purposes.
  • Test updates in a staging environment before applying to production.

Conclusion

Instead of saving the entire product object, use updateAttributes() to update only the required attribute. This method is faster, safer, and more efficient, especially when dealing with large catalogs. By following this approach, you can optimize your Magento 2 store’s performance and reduce unnecessary overhead.

Happy Coding & Optimizing!

Magento 2 introduced the Declarative Schema approach starting from version 2.3. This allows developers to define database structures (tables, columns, indexes, constraints) in XML files instead of writing install/upgrade scripts. One important part of this system is the db_schema_whitelist.json file, which helps Magento track and validate schema changes.

What is db_schema_whitelist.json?

The db_schema_whitelist.json file is automatically generated by Magento when you use the declarative schema. It contains a list of tables and columns that Magento recognizes as part of the schema. This file ensures that:

  • Magento knows which columns are safe to modify.
  • Schema changes are tracked consistently.
  • Developers avoid accidental drops or overwrites of important database structures.

When Do You Need It?

You need to generate db_schema_whitelist.json whenever:

  • You add new tables or columns via db_schema.xml.
  • You modify existing schema definitions.
  • You upgrade Magento and want to ensure schema consistency.

Step 1: Define Schema in db_schema.xml

Inside your module, create or update etc/db_schema.xml with your table definition:

<?xml version="1.0"?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">

    <table name="vendor_module_example" resource="default" engine="innodb">
        <column xsi:type="int" name="entity_id" nullable="false" identity="true" unsigned="true" comment="Entity ID"/>
        <column xsi:type="varchar" name="title" nullable="false" length="255" comment="Title"/>
        <constraint xsi:type="primary" referenceId="PRIMARY">
            <column name="entity_id"/>
        </constraint>
    </table>

</schema>

Step 2: Generate db_schema_whitelist.json

Run the following command from your Magento root directory:

bin/magento setup:db-declaration:generate-whitelist

This command scans your db_schema.xml and generates db_schema_whitelist.json in your module’s etc directory.

Step 3: Verify the File

The generated db_schema_whitelist.json will look something like this:

{
    "vendor_module_example": {
        "column": {
            "entity_id": true,
            "title": true
        }
    }
}

This confirms that Magento recognizes the columns and will not drop them during future upgrades.

Step 4: Commit to Version Control

Always commit db_schema_whitelist.json to your repository along with db_schema.xml. This ensures consistency across environments (local, staging, production).

Troubleshooting

  • If the file is not generated, check that your db_schema.xml is valid and follows the schema definition rules.
  • Run bin/magento setup:upgrade after generating the whitelist to apply changes.
  • Ensure your module is enabled (bin/magento module:enable Vendor_Module).

Best Practices

  • Always regenerate db_schema_whitelist.json after modifying db_schema.xml.
  • Do not edit db_schema_whitelist.json manually — let Magento generate it.
  • Use declarative schema for new modules instead of legacy install/upgrade scripts.
  • Test schema changes in a staging environment before deploying to production.

Conclusion

The db_schema_whitelist.json file is a critical part of Magento’s declarative schema system. It ensures safe and consistent database changes across environments. By defining your schema in db_schema.xml and generating the whitelist file, you can avoid common issues with missing tables or dropped columns during upgrades.

Happy Coding & Schema Managing!

Magento 2 provides multiple ways to interact with models and data. Two of the most common approaches are using Repositories and Factories. Understanding when to use each is important for writing clean, upgrade‑safe, and performant code.

What is a Repository?

A Repository is part of Magento’s Service Contracts. It is an implementation of an interface defined in the Api folder. Repositories act as a public API for modules, ensuring consistency and backward compatibility.

Key points:

  • Repositories are used for full loading of entities.
  • They provide methods like getById(), getList(), save(), and delete().
  • They hide implementation details (EAV, joins, etc.) and expose only the contract.

Example:

$productRepository = $objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class);
$product = $productRepository->getById($productId);

What is a Factory?

A Factory is used to create new instances of entities. Repositories do not provide methods to create new objects, so you need a factory when instantiating a fresh entity.

Key points:

  • Factories are generated automatically by Magento (e.g., ProductFactory).
  • They are used to create new objects that can later be saved via a repository.
  • Factories respect dependency injection and create the correct implementation.

Example:

$productFactory = $objectManager->get(\Magento\Catalog\Api\Data\ProductInterfaceFactory::class);
$product = $productFactory->create();
$product->setSku('test-sku');
$product->setName('Test Product');
$productRepository->save($product);

When to Use Repository vs Factory

Use Case Repository Factory
Load existing entity ✔️ getById(), getList() ❌ Not suitable
Create new entity ❌ Cannot create ✔️ Use create()
Save entity ✔️ save() ❌ Must pass to repository
Delete entity ✔️ delete() ❌ Not applicable

Collections vs Repositories

Repositories are the official way to interact with entities, but they can be limiting. For example, the SearchCriteria API allows filtering, but you cannot select specific EAV attributes or control joins. In such cases, developers often use Collection Factories for fine‑grained control.

Example:

$collection = $collectionFactory->create();
$collection->addAttributeToSelect(['name', 'sku']);
$collection->addFieldToFilter('status', 1);

Best Practices

  • Prefer repositories when they provide the functionality you need.
  • Use factories to create new entities, then save them via repositories.
  • Use collection factories only when repositories are too limited.
  • Avoid using $model->load() directly — it is not part of service contracts.
  • Always code against interfaces (ProductRepositoryInterface, ProductInterfaceFactory) for upgrade safety.

Conclusion

In Magento 2, repositories and factories serve different but complementary roles. Use repositories for loading, saving, and deleting entities, and factories for creating new ones. Collections can be used when you need fine‑grained control over queries. Following these practices ensures your code is clean, efficient, and aligned with Magento’s service contract architecture.

Happy Coding & Clean Architecture!

Try this code.

**system.xml**

    <field id="list_mode" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">

       <label>List Mode</label>        

       <source_model>Vendor\Module\Model\Config\Source\ListMode</source_model>

    </field>


**Vendor\Module\Model\Config\Source\ListMode.php**

  namespace Vendor\Module\Model\Config\Source;

    class ListMode implements \Magento\Framework\Data\OptionSourceInterface

    {

     public function toOptionArray()

     {

      return [

        ['value' => 'grid', 'label' => __('Grid Only')],

        ['value' => 'list', 'label' => __('List Only')],

        ['value' => 'grid-list', 'label' => __('Grid (default) / List')],

        ['value' => 'list-grid', 'label' => __('List (default) / Grid')]

      ];

     }

    }

            Try below code: 

           $obj = \Magento\Framework\App\ObjectManager::getInstance();    

            /** @var \Magento\Catalog\Model\Product $product */

            $productObject = $obj->get('Magento\Catalog\Model\Product');    

            $product = $productObject->loadByAttribute('sku', 'Test Test');    

            $linkDataAll = [];

            $skuLinks = "0012365,test1233,789456";

            $skuLinks = explode(",",$skuLinks);    

            foreach($skuLinks as $skuLink) {

                //check first that the product exist

                $linkedProduct = $productObject->loadByAttribute("sku",$skuLink);

                if($linkedProduct) {

                    /** @var  \Magento\Catalog\Api\Data\ProductLinkInterface $productLinks */

                    $productLinks = $obj->create('Magento\Catalog\Api\Data\ProductLinkInterface');

                    $linkData = $productLinks //Magento\Catalog\Api\Data\ProductLinkInterface

                        ->setSku($product->getSku())

                        ->setLinkedProductSku($skuLink)

                        ->setLinkType("related");

                    $linkDataAll[] = $linkData;

                }

            }

            if($linkDataAll) {

                print(count($linkDataAll)); //gives 3

                $product->setProductLinks($linkDataAll);

            }

            $product->save();

dont use **objectmanager** this code just for reference

Magento 2 introduced MSI (Multi‑Source Inventory) starting from version 2.3. This feature allows merchants to manage inventory across multiple sources (warehouses, stores, etc.). However, developers often need to programmatically fetch product inventory data, such as stock quantity and salable status, especially when building custom modules or integrations.

Problem Scenario

  • After enabling MSI, traditional methods like StockRegistryInterface may not return correct stock data.
  • Developers need to fetch salable quantity and is_salable status for products.
  • Custom modules or API integrations require accurate inventory values.

Solution: Use Magento MSI APIs

Magento provides new APIs and services to fetch inventory data under MSI. Below are examples:

1. Get Salable Quantity


use Magento\InventorySalesApi\Api\GetProductSalableQtyInterface;

class InventoryHelper
{
    protected $getProductSalableQty;

    public function __construct(
        GetProductSalableQtyInterface $getProductSalableQty
    ) {
        $this->getProductSalableQty = $getProductSalableQty;
    }

    public function getSalableQty($sku, $stockId = 1)
    {
        return $this->getProductSalableQty->execute($sku, $stockId);
    }
}

2. Check If Product is Salable


use Magento\InventorySalesApi\Api\IsProductSalableInterface;

class InventoryHelper
{
    protected $isProductSalable;

    public function __construct(
        IsProductSalableInterface $isProductSalable
    ) {
        $this->isProductSalable = $isProductSalable;
    }

    public function checkSalable($sku, $stockId = 1)
    {
        return $this->isProductSalable->execute($sku, $stockId);
    }
}

3. SQL View for Inventory Stock

Magento MSI creates database views like inventory_stock_1 to store inventory data. You can query directly:


SELECT product_id, sku, quantity, is_salable
FROM inventory_stock_1
WHERE sku = 'test-sku';

Practical Example

Suppose you want to display stock information on a custom product page. Using GetProductSalableQtyInterface, you can fetch the exact salable quantity for the SKU. Using IsProductSalableInterface, you can check if the product is available for purchase.

Best Practices

  • Always use MSI APIs instead of legacy StockRegistryInterface when MSI is enabled.
  • Use dependency injection to access MSI services.
  • Query inventory_stock_1 only for debugging, not in production code.
  • Test with multiple sources to ensure accurate results.

SEO & UX Benefits

  • Accurate stock data improves customer trust and reduces cart errors.
  • Helps SEO by ensuring products marked “In Stock” are truly available.
  • Improves conversion rates with reliable inventory visibility.

Troubleshooting

  • If MSI APIs return zero quantity, check if sources are assigned to the product.
  • Verify inventory_stock_1 view exists in the database.
  • Run php bin/magento indexer:reindex inventory after changes.
  • Check logs in var/log for MSI errors.

Conclusion

Magento 2 MSI changes how inventory data is managed. By using GetProductSalableQtyInterface and IsProductSalableInterface, developers can reliably fetch product stock information. This ensures accurate inventory display, better customer experience, and smoother integrations with external systems.

After upgrading Magento 2 to a newer version, many developers and store owners encounter indexing errors. These errors usually appear in the Admin Panel or when running CLI commands, and they can prevent catalog, price, or stock data from being updated correctly.

Common Error Messages


One or more indexers are invalid. Make sure your Magento cron job is running.

SQLSTATE[42S02]: Base table or view not found

Indexer process cannot be initialized.

Root Causes

  • Database schema changes after upgrade not applied correctly.
  • Missing or outdated indexer tables.
  • Cron jobs not running, leaving indexers invalid.
  • Custom modules conflicting with new Magento version.

Step-by-Step Fix

  1. Run Upgrade Command:
    
        php bin/magento setup:upgrade
        
  2. Recompile Code:
    
        php bin/magento setup:di:compile
        
  3. Reindex All:
    
        php bin/magento indexer:reindex
        
  4. Check Indexer Status:
    
        php bin/magento indexer:status
        
  5. Verify Cron Jobs:
    
        * * * * * php /path/to/magento/bin/magento cron:run | grep -v "Ran jobs by schedule" >> /path/to/magento/var/log/magento.cron.log
        

SQL Query Solution

If error in indexing after upgrade then run below SQL query in phpMyAdmin:


CREATE SQL SECURITY INVOKER VIEW `inventory_stock_1` AS 
SELECT DISTINCT 
    legacy_stock_status.product_id,
    legacy_stock_status.website_id,
    legacy_stock_status.stock_id,
    legacy_stock_status.qty quantity,
    legacy_stock_status.stock_status is_salable,
    product.sku
FROM `cataloginventory_stock_status` legacy_stock_status
INNER JOIN `catalog_product_entity` product 
    ON legacy_stock_status.product_id = product.entity_id;

After running the query, execute the following commands:

  • Reindex All:
    
        php bin/magento indexer:reindex
        

Practical Example

Suppose you upgraded from Magento 2.3.x to 2.4.x and see “One or more indexers are invalid.” Running the SQL query above recreates the missing inventory_stock_1 view, which resolves the indexing error. After clearing cache and recompiling, the indexers should show as Ready.

Best Practices

  • Always run setup:upgrade after upgrading Magento.
  • Reindex immediately after upgrade to refresh data tables.
  • Keep cron jobs active to avoid invalid indexers.
  • Document custom SQL fixes for future upgrades.

SEO & UX Benefits

  • Ensures product data is always fresh and accurate.
  • Improves customer experience with correct prices and stock levels.
  • Boosts SEO by keeping catalog data consistent.

Troubleshooting

  • If errors persist, check var/log/system.log and var/log/exception.log.
  • Verify database tables exist for all indexers.
  • Disable custom modules temporarily to isolate conflicts.
  • Run php bin/magento setup:db:status to confirm schema is up to date.

Conclusion

Indexing errors after upgrading Magento 2 are common but easily fixable. By running upgrade commands, applying the SQL query fix, and ensuring cron jobs are active, you can resolve these issues quickly. Keeping your store properly indexed ensures smooth performance, accurate product data, and a better shopping experience for customers.

When installing or running Magento 2.4.0, many developers encounter the error:


Could not validate a connection to Elasticsearch.
No alive nodes found in your cluster.

This error occurs because Magento 2.4.x requires Elasticsearch as the default catalog search engine. If Elasticsearch is not installed, not running, or misconfigured, Magento cannot connect and throws this error.

Root Cause

  • Elasticsearch service is not installed or not running.
  • Incorrect host or port configuration in Magento setup.
  • Firewall or permissions blocking the connection.
  • Version mismatch between Magento and Elasticsearch.

Step-by-Step Fix

  1. Install Elasticsearch: On Ubuntu/Debian:
    
        sudo apt update
        sudo apt install elasticsearch
        
    On CentOS/RHEL:
    
        sudo yum install elasticsearch
        
  2. Start and Enable Service:
    
        sudo systemctl start elasticsearch
        sudo systemctl enable elasticsearch
        
  3. Verify Elasticsearch is Running:
    
        curl -X GET "localhost:9200"
        
    You should see a JSON response with cluster information.
  4. Configure Magento to Use Elasticsearch: During installation, specify host and port:
    
        php bin/magento setup:install \
        --search-engine=elasticsearch7 \
        --elasticsearch-host=localhost \
        --elasticsearch-port=9200
        
  5. Check Magento Admin Settings: Go to Stores > Configuration > Catalog > Catalog Search and ensure Elasticsearch is selected with correct host and port.

Version Compatibility

  • Magento 2.4.0 supports Elasticsearch 7.x.
  • Ensure you install Elasticsearch 7.x or higher for compatibility.

Best Practices

  • Always run Elasticsearch as a service and enable auto‑start.
  • Use proper memory allocation for Elasticsearch (edit jvm.options).
  • Secure Elasticsearch if exposed to public networks.
  • Test connection with curl before running Magento setup.

Troubleshooting

  • If you still see “No alive nodes found,” check logs in /var/log/elasticsearch.
  • Ensure port 9200 is open and not blocked by firewall.
  • Restart both Elasticsearch and Apache/Nginx services after changes.
  • Check PHP memory limits if installation fails.

Conclusion

The “Could Not Validate a Connection to Elasticsearch” error in Magento 2.4.0 is caused by missing or misconfigured Elasticsearch. By installing Elasticsearch, starting the service, and configuring Magento correctly, you can resolve the issue and proceed with installation. Keeping Elasticsearch properly maintained ensures smooth catalog search and overall store performance.

When creating Shopping Cart Price Rules in Magento 2, you may encounter an issue where the Condition dropdown does not display product attributes. This can be frustrating when you want to create promotions based on SKU, category, or other product attributes.

Problem Scenario

  • You try to create a Cart Price Rule in Marketing > Cart Price Rules.
  • The condition dropdown only shows limited options like Price in cart, Quantity in cart, Row total, etc.
  • Product attributes such as SKU, Category, or custom attributes are missing.

Root Cause

By default, Magento only shows attributes in the Cart Price Rule condition dropdown if they are marked as usable for promotions. If this setting is disabled, the attribute will not appear in the list.

Step-by-Step Fix

  1. Go to Admin Panel: Navigate to Stores > Attributes > Product.
  2. Edit Attribute: Select the attribute you want to use in Cart Price Rules (e.g., SKU, Category, or a custom attribute).
  3. Enable Promo Usage: Under Frontend Properties, set Use for Promo Rule Conditions to Yes.
  4. Save Attribute: Click Save Attribute to apply changes.
  5. Reindex: Go to System > Index Management and reindex all data.
    
        php bin/magento indexer:reindex
        
  6. Clear Cache: Run:
    
        php bin/magento cache:flush
        

Verification

Now, when you go back to Marketing > Cart Price Rules and create a new rule, your attribute should appear in the condition dropdown list.

Practical Example

Suppose you want to create a rule: If there are 3 or more products with a specific SKU in the cart, apply a discount. After enabling Use for Promo Rule Conditions on the SKU attribute, you will be able to select SKU in the condition dropdown and configure the rule properly.

Best Practices

  • Always enable Use for Promo Rule Conditions for attributes you plan to use in promotions.
  • Keep attributes organized and documented for marketing teams.
  • Test rules in a staging environment before applying them to live.
  • Reindex and clear cache after making attribute changes.

SEO & UX Benefits

  • Allows you to create more targeted promotions based on product attributes.
  • Improves customer experience with personalized discounts.
  • Boosts conversion rates by offering relevant deals.

Troubleshooting

  • If attributes still don’t appear, double‑check that Use for Promo Rule Conditions is set to Yes.
  • Ensure you reindexed after saving the attribute.
  • Check for custom modules overriding Cart Price Rule logic.
  • Review var/log/system.log for errors if the dropdown is still incomplete.

Conclusion

The missing attributes in Magento 2 Cart Price Rule conditions are usually caused by disabled Use for Promo Rule Conditions settings. By enabling this option and reindexing, you can quickly fix the issue and create powerful, attribute‑based promotions that enhance both customer experience and sales.

In Magento 2, associated products are widely used in configurable products and bundled products. However, some store owners face an issue where associated products do not appear when custom options are added. This can be confusing and may look like a bug in Magento.

Understanding the Issue

  • When you add a required custom option to a product, Magento may fail to display associated products correctly.
  • This is due to a limitation in earlier Magento versions where required custom options conflicted with product association logic.
  • As a result, customers could not see or select associated products if a required custom option was present.

Magento Bug and Fix

This was a known bug in Magento 2 before version 2.2.4. The Magento team fixed the issue in Magento 2.2.4, so upgrading your store is the most reliable solution.

Workarounds for Older Versions

  1. Use Non‑Required Custom Options: If possible, set your custom option to non‑required so associated products can display.
  2. Upgrade Magento: Update to Magento 2.2.4 or later where the bug is fixed.
  3. Custom Module Override: Developers can override product option validation logic to allow associated products with required options.

Practical Example

Suppose you have a configurable product “T‑Shirt” with associated products for different sizes. If you add a required custom option like “Gift Wrap” or “Custom Text,” the associated size options may not appear. By making the custom option non‑required or upgrading Magento, the associated products will show correctly.

Best Practices

  • Always test associated products after adding custom options.
  • Keep Magento updated to avoid known bugs.
  • Use staging environments to test changes before applying them to live.
  • Document any custom overrides for future maintenance.

SEO & UX Benefits

  • Ensures customers can select product variations without confusion.
  • Improves conversion rates by reducing checkout errors.
  • Maintains a professional and reliable shopping experience.

Troubleshooting Checklist

  • Check if your Magento version is older than 2.2.4.
  • Verify if the custom option is marked as required.
  • Test with a non‑required option to confirm the issue.
  • Review logs in var/log for related errors.

Conclusion

The “Associated Product with Custom Option Not Showing” issue in Magento 2 is a known bug in earlier versions. The simplest fix is to upgrade to Magento 2.2.4 or later. For older versions, using non‑required custom options or applying a developer override can help. By resolving this issue, you ensure customers can view and select associated products smoothly, improving both user experience and sales.

Magento 2 store owners often face issues when trying to upload product images, category images, or placeholder images directly from the Admin Panel. This can be frustrating, especially when you need to quickly update your catalog visuals. In this guide, we’ll cover the common causes and step‑by‑step solutions to fix image upload problems in Magento 2.

Common Causes

  • File permissions: The pub/media or var directories don’t have proper write access.
  • PHP settings: Low upload_max_filesize or post_max_size values in php.ini.
  • Cache issues: Old cache entries prevent new images from being recognized.
  • Browser problems: Outdated cache or JavaScript conflicts in the admin panel.
  • Theme overrides: Custom themes may override image upload logic.

Step-by-Step Solutions

  1. Check Permissions: Ensure pub/media and var directories are writable.
    
        chmod -R 775 pub/media
        chmod -R 775 var
        
  2. Update PHP Settings: Increase limits in php.ini.
    
        upload_max_filesize = 20M
        post_max_size = 20M
        
  3. Clear Cache: Run:
    
        php bin/magento cache:flush
        
  4. Deploy Static Content: If using production mode:
    
        php bin/magento setup:static-content:deploy -f
        
  5. Check Browser: Clear browser cache or try another browser to rule out frontend conflicts.

Alternative Fix (Direct Upload)

If the admin panel upload fails, you can manually place your image in:


pub/media/catalog/product/yourimage.jpg

Magento will automatically use this file when you assign it to a product.

Best Practices

  • Use optimized images (compressed, proper dimensions) to improve performance.
  • Keep a consistent style across product and category images.
  • Always clear cache after uploading new images.
  • Test uploads in staging before applying changes to live.

SEO & UX Benefits

  • Improves user experience by ensuring products always display correctly.
  • Maintains a professional look for your store.
  • Helps search engines index products with proper visuals.

Troubleshooting

  • If the image doesn’t appear, check pub/media/catalog/product for the file.
  • Ensure your theme’s view.xml doesn’t override image dimensions.
  • Run php bin/magento cache:clean after changes.
  • Check server error logs for PHP or permission errors.

Conclusion

The “Unable to Upload Images from Magento 2 Admin Panel” issue is usually caused by permissions, PHP limits, or cache problems. By following the steps above, you can quickly fix the issue and ensure your store always displays product images correctly. This not only improves the customer experience but also boosts SEO and conversions.

Magento 2 uses Knockout.js heavily on checkout and other dynamic pages. This can cause timing issues when you try to run jQuery code: your script executes before the element is fully bound or rendered, resulting in errors or missing functionality.

To solve this, you can use a utility function that waits until the element is available in the DOM before executing your code.

Problem Scenario

  • Custom jQuery runs too early on checkout or cart pages.
  • Knockout.js binds elements asynchronously, so selectors return empty.
  • Scripts fail silently or cause console errors.

Solution: Wait for Element


function waitForElement(query, callback) {
    var checkExist = setInterval(function() {
        if (document.querySelector(query)) {
            clearInterval(checkExist);
            callback();
        }
    }, 100);
}

// Usage Example
waitForElement(".class", function() {
    alert("Element is loaded.. do stuff");
});

Explanation

  • query: CSS selector of the element you want to wait for.
  • setInterval: Checks every 100ms if the element exists.
  • clearInterval: Stops checking once the element is found.
  • callback(): Executes your custom code after the element is loaded.

Best Practices

  • Use specific selectors (e.g., #checkout-step-shipping) to avoid unnecessary checks.
  • Keep the callback lightweight to avoid performance issues.
  • Always test on multiple browsers and devices to confirm behavior.

Alternative: Using MutationObserver


function observeElement(query, callback) {
    var target = document.querySelector("body");
    var observer = new MutationObserver(function(mutations) {
        if (document.querySelector(query)) {
            callback();
            observer.disconnect();
        }
    });
    observer.observe(target, { childList: true, subtree: true });
}

// Usage Example
observeElement(".class", function() {
    console.log("Element loaded via MutationObserver");
});

Real Magento Example


// Wait for shipping method buttons on checkout
waitForElement("#shipping-method-buttons-container", function() {
    console.log("Shipping method buttons are ready");
    // Add your custom logic here
});

Troubleshooting

  • If your code never runs, double‑check the selector with browser DevTools.
  • Increase the interval time if the element takes longer to load.
  • Use MutationObserver for complex cases where elements are dynamically replaced.

Conclusion

Magento 2’s dynamic frontend can cause timing issues with jQuery. By using waitForElement or MutationObserver, you can ensure your script runs only after the element is available. This makes your customizations more reliable and prevents errors on checkout or other Knockout‑driven pages.

Logging is a critical part of Magento 2 development. It helps developers track issues, debug functionality, and monitor custom processes. While Magento provides system and exception logs by default, sometimes you need your own custom log file for module‑specific or business‑specific events.

Why Custom Logs?

  • Keep your module’s logs separate from Magento’s core logs
  • Quickly identify issues related to your custom functionality
  • Track specific events (e.g., product sync, API calls, payment gateway responses)
  • Provide an audit trail for business processes

Magento Version Specific Code

For Magento 2.4.2 and Before:


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

$logger->info('Custom message');
$logger->info(print_r($object->getData(), true));

For Magento 2.4.2 and After:


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

$logger->info('text message');
$logger->info(print_r($object->getData(), true));

For Magento 2.4.3:


$writer = new \Zend_Log_Writer_Stream(BP . '/var/log/custom.log');
$logger = new \Zend_Log();
$logger->addWriter($writer);

$logger->info('text message');
$logger->info(print_r($object->getData(), true));

Best Practices

  • Use meaningful log filenames (e.g., custom.log, sync.log, payment.log)
  • Apply log levels properly: info, debug, error
  • Rotate or clear logs regularly to avoid large files
  • Never log sensitive data like passwords or tokens

Step-by-Step Tutorial

  1. Create Logger: Instantiate the correct logger class based on your Magento version.
  2. Define Log File: Point to /var/log/custom.log or another meaningful filename.
  3. Write Messages: Use info(), debug(), or error() depending on the context.
  4. Test: Trigger your code and check the log file in var/log to confirm entries.

When to Use Custom Logs

  • Tracking API integrations (ERP, payment gateways, etc.)
  • Debugging custom module functionality
  • Monitoring cron jobs or scheduled tasks
  • Capturing business‑specific events for auditing

Troubleshooting

  • If your log file doesn’t appear, check file permissions for the var/log directory.
  • Ensure your code is actually executed (e.g., place a test $logger->info('Hello World');).
  • Clear cache after adding new code to make sure Magento picks up changes.

Conclusion

Depending on your Magento version, the logging classes differ slightly. By using the correct snippet above, you can generate custom logs safely and effectively. This ensures better visibility into your module’s behavior and makes debugging much easier. Custom logs are a simple but powerful tool to keep your Magento store stable and transparent.