Skip to content

Overview

The Magento_Catalog module is the foundational product and category management system in Adobe Commerce and Magento Open Source. It provides the core data structures, business logic, and APIs for managing products, categories, product attributes, and pricing across the entire platform.

This module serves as the backbone for merchandising operations, providing extensible service contracts that enable third-party integrations, custom business logic, and omnichannel commerce experiences.

Module Version

2.4.7+ compatible

Namespace

Magento\Catalog

Area

Global

Key Features

1. Product Management

The module supports six product types out of the box:

  • Simple Products: Single SKU with no variations
  • Configurable Products: Parent product with child variations based on configurable attributes
  • Grouped Products: Collection of simple products sold as a set
  • Bundle Products: Customizable products with multiple options
  • Virtual Products: Non-shippable products (services, memberships)
  • Downloadable Products: Digital goods (requires Magento_Downloadable)

Product Type Constants

\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE
\Magento\Catalog\Model\Product\Type::TYPE_VIRTUAL
\Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE
\Magento\GroupedProduct\Model\Product\Type\Grouped::TYPE_CODE
\Magento\Bundle\Model\Product\Type::TYPE_CODE
\Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE

2. Category Hierarchy

Manages multi-level category trees with:

  • Unlimited nested depth
  • Multiple category assignment per product
  • Anchor category logic for layered navigation
  • URL rewrites and canonical URLs
  • Category landing pages with CMS content

Note

Categories use a nested set model (MPTT - Modified Preorder Tree Traversal) for efficient tree queries.

3. Entity-Attribute-Value (EAV) System

Products and categories use EAV storage:

  • Dynamic attribute creation without schema changes
  • Attribute sets and attribute groups for organizing attributes
  • Multiple attribute types: text, textarea, date, boolean, select, multiselect, price, media_image
  • Scoped attributes (global, website, store view)
  • Attribute frontend models for custom rendering

4. Pricing Framework

Comprehensive pricing with:

  • Base price, special price, tier pricing, group pricing
  • Catalog price rules (promotional pricing)
  • Tax calculation integration
  • Multi-currency support
  • Customer group-specific pricing

Quick Start

1

Loading a Product

<?php
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Framework\Exception\NoSuchEntityException;

class MyClass
{
    public function __construct(
        private readonly ProductRepositoryInterface $productRepository
    ) {}

    public function loadProduct(string $sku): ?\Magento\Catalog\Api\Data\ProductInterface
    {
        try {
            return $this->productRepository->get($sku, false, null, true);
        } catch (NoSuchEntityException $e) {
            return null;
        }
    }
}
2

Creating a Simple Product

<?php
use Magento\Catalog\Api\Data\ProductInterfaceFactory;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Model\Product\Attribute\Source\Status;
use Magento\Catalog\Model\Product\Type;
use Magento\Catalog\Model\Product\Visibility;

class ProductCreator
{
    public function __construct(
        private readonly ProductInterfaceFactory $productFactory,
        private readonly ProductRepositoryInterface $productRepository
    ) {}

    public function createSimpleProduct(): void
    {
        $product = $this->productFactory->create();
        $product->setSku('SIMPLE-001')
            ->setName('Sample Simple Product')
            ->setAttributeSetId(4) // Default attribute set
            ->setStatus(Status::STATUS_ENABLED)
            ->setVisibility(Visibility::VISIBILITY_BOTH)
            ->setTypeId(Type::TYPE_SIMPLE)
            ->setPrice(29.99)
            ->setWeight(1.5)
            ->setStockData([
                'use_config_manage_stock' => 1,
                'qty' => 100,
                'is_in_stock' => 1
            ])
            ->setWebsiteIds([1]);

        $this->productRepository->save($product);
    }
}
3

Working with Product Attributes

<?php
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;

class AttributeHandler
{
    public function __construct(
        private readonly ProductRepositoryInterface $productRepository,
        private readonly ProductAttributeRepositoryInterface $attributeRepository
    ) {}

    public function setCustomAttribute(string $sku, string $attributeCode, mixed $value): void
    {
        $product = $this->productRepository->get($sku);
        $product->setCustomAttribute($attributeCode, $value);
        $this->productRepository->save($product);
    }

    public function getAttributeMetadata(string $attributeCode): array
    {
        $attribute = $this->attributeRepository->get($attributeCode);

        return [
            'label' => $attribute->getDefaultFrontendLabel(),
            'type' => $attribute->getFrontendInput(),
            'required' => $attribute->getIsRequired(),
            'searchable' => $attribute->getIsSearchable(),
            'filterable' => $attribute->getIsFilterable(),
            'scope' => $attribute->getScope()
        ];
    }
}

Module Structure

Magento/Catalog/
├── Api/                         # Service contracts (interfaces)
│   ├── Data/                   # Data transfer objects
│   ├── ProductRepositoryInterface.php
│   ├── CategoryRepositoryInterface.php
│   └── ProductAttributeRepositoryInterface.php
├── Block/                      # View blocks for frontend and admin
├── Console/                    # CLI commands
├── Controller/                 # Frontend controllers (product view, category view)
├── Cron/                       # Scheduled tasks
├── Helper/                     # Helper classes (legacy, prefer services)
├── Model/                      # Business logic and data models
│   ├── Product/               # Product-specific models
│   ├── Category/              # Category-specific models
│   ├── ResourceModel/         # Database operations
│   └── Product.php            # Main product model
├── Observer/                   # Event observers
├── Plugin/                     # Plugins (interceptors)
├── Pricing/                    # Pricing framework
├── Setup/                      # Installation and upgrade scripts
├── Ui/                        # Admin UI components
├── view/                      # Templates, layouts, web assets
│   ├── adminhtml/
│   ├── frontend/
│   └── base/
└── etc/
    ├── module.xml             # Module declaration
    ├── di.xml                 # Dependency injection
    ├── events.xml             # Event observers
    ├── webapi.xml             # REST/SOAP API routes
    └── catalog_attributes.xml # System product attributes

Key Dependencies

Required Modules

Magento_Store

Multi-store, website, store view scoping

Magento_Eav

Entity-Attribute-Value system

Magento_Customer

Customer groups for pricing

Magento_Backend

Admin panel infrastructure

Magento_Indexer

Data indexing framework

Magento_UrlRewrite

SEO-friendly URLs

Common Integration Points

  • Magento_CatalogInventory / Magento_InventoryApi: Stock management
  • Magento_CatalogRule: Promotional pricing rules
  • Magento_CatalogSearch: Search integration layer
  • Magento_Quote: Shopping cart integration
  • Magento_Sales: Order creation and processing

Configuration

System Configuration Path

Admin: Stores > Configuration > Catalog

Key settings:

  • catalog/frontend/*: Frontend display options
  • catalog/placeholder/*: Placeholder images
  • catalog/seo/*: SEO settings (product URL suffix, category URL suffix)
  • catalog/price/*: Price display settings

Programmatic Access

<?php
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Store\Model\ScopeInterface;

class ConfigReader
{
    public function __construct(
        private readonly ScopeConfigInterface $scopeConfig
    ) {}

    public function isProductUrlSuffixEnabled(int $storeId): string
    {
        return $this->scopeConfig->getValue(
            'catalog/seo/product_url_suffix',
            ScopeInterface::SCOPE_STORE,
            $storeId
        );
    }
}

Indexers

The Catalog module manages several critical indexers:

Indexer Description
catalog_product_category Product-to-category assignments
catalog_product_attribute EAV attribute values for flat tables
catalog_product_price Calculated final prices including rules
catalog_category_product Category-to-product assignments (reverse)
catalog_product_flat Denormalized product data (if enabled)

Reindex Commands

# Reindex all catalog indexers
bin/magento indexer:reindex catalog_product_category catalog_product_attribute catalog_product_price

# Check indexer status
bin/magento indexer:status

CLI Commands

# Clean up unused product attributes
bin/magento catalog:product:attributes:cleanup

# Resize product images (regenerate cached image sizes)
bin/magento catalog:images:resize

# Reindex catalog URL rewrites
bin/magento indexer:reindex catalog_url_rewrite

Note

Magento Open Source does not include CLI commands for direct CSV import, listing attributes, removing unused images, or regenerating URL rewrites. Use the Admin Panel Import/Export UI or a third-party extension for these operations.

REST API Examples

Get Product by SKU

GET /rest/V1/products/{sku}
Authorization: Bearer {token}

Create Product

POST /rest/V1/products
Content-Type: application/json
Authorization: Bearer {token}
{
  "product": {
    "sku": "TEST-SKU-001",
    "name": "Test Product",
    "attribute_set_id": 4,
    "price": 99.99,
    "status": 1,
    "visibility": 4,
    "type_id": "simple",
    "weight": 1,
    "extension_attributes": {
      "stock_item": {
        "qty": 100,
        "is_in_stock": true
      }
    }
  }
}

GraphQL: Query Product

{
  products(filter: { sku: { eq: "24-MB01" } }) {
    items {
      id
      sku
      name
      price_range {
        minimum_price {
          final_price {
            value
            currency
          }
        }
      }
      categories {
        id
        name
        url_path
      }
    }
  }
}

Testing

Unit Test Example

<?php
namespace Vendor\Module\Test\Unit\Model;

use PHPUnit\Framework\TestCase;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Api\Data\ProductInterface;

class ProductServiceTest extends TestCase
{
    private ProductRepositoryInterface $productRepository;
    private ProductService $productService;

    protected function setUp(): void
    {
        $this->productRepository = $this->createMock(ProductRepositoryInterface::class);
        $this->productService = new ProductService($this->productRepository);
    }

    public function testGetProductBySku(): void
    {
        $sku = 'TEST-SKU';
        $product = $this->createMock(ProductInterface::class);

        $this->productRepository->expects($this->once())
            ->method('get')
            ->with($sku)
            ->willReturn($product);

        $result = $this->productService->getProductBySku($sku);
        $this->assertInstanceOf(ProductInterface::class, $result);
    }
}

Integration Test Example

<?php
namespace Vendor\Module\Test\Integration\Model;

use Magento\TestFramework\Helper\Bootstrap;
use Magento\Catalog\Api\ProductRepositoryInterface;
use PHPUnit\Framework\TestCase;

class ProductRepositoryTest extends TestCase
{
    private ProductRepositoryInterface $productRepository;

    protected function setUp(): void
    {
        $objectManager = Bootstrap::getObjectManager();
        $this->productRepository = $objectManager->get(ProductRepositoryInterface::class);
    }

    /**
     * @magentoDataFixture Magento/Catalog/_files/product_simple.php
     */
    public function testGetProductBySku(): void
    {
        $product = $this->productRepository->get('simple');
        $this->assertEquals('simple', $product->getSku());
        $this->assertEquals('Simple Product', $product->getName());
    }
}

Performance Considerations

Optimization Tips

  • Use repositories, not direct model loading (repositories leverage cache layers)
  • Enable flat catalog for large catalogs (improves frontend performance significantly)
  • Optimize attribute loading: Only load needed attributes using addAttributeToSelect()
  • Use full page cache for product and category pages
  • Index in schedule mode for production environments
  • Optimize images: Use proper image sizes and formats (WebP when possible)

Common Pitfalls

  • Loading products in loops (N+1 query problem)
  • Bypassing service contracts and using models directly
  • Not respecting store scope when loading products
  • Forgetting to reindex after bulk operations
  • Using deprecated helper methods instead of service contracts
  • Direct database manipulation instead of using repositories