13

How can I assign 'New products' to 'NEW PRODUCTS category' programatically in magento 2.

8 Answers 8

18

You need to get category Ids and product Id to set data: impliment this :

$this->getCategoryLinkManagement()->assignProductToCategories(
                $product->getSku(),
                $product->getCategoryIds()
            );

also impliment this function :

private function getCategoryLinkManagement()
{
    if (null === $this->categoryLinkManagement) {
        $this->categoryLinkManagement = \Magento\Framework\App\ObjectManager::getInstance()
            ->get('Magento\Catalog\Api\CategoryLinkManagementInterface');
    }
    return $this->categoryLinkManagement;
}

rest dependency you should manage for : Magento\Catalog\Api\CategoryLinkManagementInterface

intialize :

protected $categoryLinkManagement;

Direct use of \Magento\Framework\App\ObjectManager::getInstance() is not valid as per magento so you can inject it in Constructor

This answer is for below magento 2.2 versions, so please take a note

7
  • I used this code in a block and tried to render that block in template file. When I tried this method I got "Uncaught Error: Call to a member function assignProductToCategories()" in the template file. Could you please help me to sort out this?
    – chinchu
    Commented Oct 17, 2016 at 9:58
  • Have you give dependency for "Magento\Catalog\Api\CategoryLinkManagementInterface" ? Commented Oct 17, 2016 at 12:40
  • Yes, I have added. I worked fine.
    – chinchu
    Commented Oct 18, 2016 at 8:48
  • Hi @RonakChauhan I tried your code but it doesnt seem like working . My products are not getting assigned to category..
    – Daniel_12
    Commented Oct 30, 2018 at 15:18
  • @Daniel_12 are you getting any error? Commented Oct 30, 2018 at 17:24
23

I think, this needs an updated answer which does not make use of the object manager. Also, there are some kinks involved which are not mentioned anywhere.

In your constructor, inject the CategoryLinkManagementInterface:

protected $categoryLinkManagement;

public function __construct(
    ...
    \Magento\Catalog\Api\CategoryLinkManagementInterface $categoryLinkManagementInterface,
    ...
) {
    $this->categoryLinkManagement = $categoryLinkManagementInterface;
    ...
}

Later in your code, assign categories the following way:

$product = $this->productRepository->getById(1337); // or any other way to get a product model/interface
$categoryIds = [
    42,
    606
];
$this->categoryLinkManagement->assignProductToCategories(
    $product->getSku(),
    $categoryIds
);

This will replace all previous category assignments. If you want to keep the existing category assignments, use something like this:

$categoryIds = array_unique(
    array_merge(
        $product->getCategoryIds(),
        $categoryIds
    )
);

Be aware: The link management defers the category assignment (for the product attribute) to the scheduled indexer. This means that if you make other changes to the product and save it after assignProductToCategories()

$product = $this->productRepository->save($product);

the category assignments will be gone as $product contains either null (if it was a newly created product) or only the previously assigned categories for its attribute. Also,

$product = $this->productRepository->getById($product->getId());

right after assignProductToCategories() will not help for the same reason mentioned above. Either assign categories at the latest possible point in time (when you do not save the product afterwards) or assign the attribute manually before saving again

$product->setCategoryIds($categoryIds);

If you opt to use the latter, you could probably fall back to only using setCategoryIds(). I have not tested either case (assignProductToCategories + setCategoryIds + save or setCategoryIds only + save) for performance impact, so I can not comment on that, but I think the whole circumstance was important to mention.

7
  • hi, @Drelling, Could not save product \"41859\" with position 0 to category 8 getting above error, Commented Nov 26, 2018 at 11:59
  • Hi @jafarpinjar, is that all you got in terms of error messages? I could think of a few reasons, why this occured: 1. You accidentally used $product->getId() instead of $product->getSku() 2. The product's URL key is not unique (although I think that the error message would be specific) 3. The product is already assigned to category with id 8 Commented Nov 27, 2018 at 12:07
  • 1. can we not use $product->getId()? 3. The product is already assigned to category with id 8 – T. if assigned can we not remove it? Commented Nov 27, 2018 at 12:18
  • 1. No, assignProductToCategories() explicitly needs the SKU, not the ID! If that was your error, try again with SKU instead. 3. Ah, I was somewhat wrong here. The error I was thinking of occurs when $categoryIds would contain the same category more than once. You actually need to include category id 8 to keep it in that category. If you don't, it will be removed. So that's how you can remove a product from a category. Commented Nov 27, 2018 at 12:53
  • The error I was thinking of occurs when $categoryIds would contain the same category more than once. Its not possible is it? because category id is unique, I am passing sku only to this method assignProductToCategories not the id Commented Nov 27, 2018 at 13:22
9

Assign Products To Category

 <?php
 $new_category_id = array('100','101');
 $sku = 'sku of product';

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

 $CategoryLinkRepository = $objectManager->get('\Magento\Catalog\Api\CategoryLinkManagementInterface');
 $CategoryLinkRepository->assignProductToCategories($sku, $new_category_id);

Remove Products From Category

 <?php
 $category_id = 101;
 $sku = 'sku of product';

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

 $CategoryLinkRepository = $objectManager->get('\Magento\Catalog\Model\CategoryLinkRepository');
 $CategoryLinkRepository->deleteByIds($category_id ,$sku);
6
  • getting this error, Could not save product with position 0 to category 8 Commented Nov 24, 2018 at 10:49
  • @jafarpinjar this error is related to other customization. If you check this code snippet with fresh Magento install, it will work well. Please check if any third party customization preventing this code from execution Commented Nov 26, 2018 at 3:57
  • hi @chirag dodia, no, I have used this code in custom file and running it by moving to root folder, no customization is used Commented Nov 26, 2018 at 6:00
  • @jafarpinjar try with fresh product and check is this something related to a particular product? Commented Nov 26, 2018 at 11:52
  • 1
    hi @chirag, i got this error, Could not save product \"41859\" with position 0 to category 8 Commented Nov 26, 2018 at 11:55
5

Even if the question was answered already, I'd like to add a faster way to assign a group of products to a category, as iterating $this->getCategoryLinkManagement()->assignProductToCategories() is quite slow

This alternative involves loading the category we want our group of products to be assigned to, so we need to inject Magento\Catalog\Model\CategoryFactory, we can set a group of products to the category using setPostedProducts() which takes an array of ['entity_id','position'] so a code example would be something like this:

use Magento\Catalog\Model\CategoryFactory;
...
protected $_category;
...
$this->_category = $categoryFactory;

    $parentsCollection = $this->_productCollection->create()
        ->addFieldToSelect('entity_id')
        ->addFieldToFilter('entity_id',['in' => $data['parent_ids']]);

    $parentsPosted = array_fill_keys(array_keys($parentsCollection->toArray(['entity_id'])), 0);

    if($catIds == 80 || $catIds == 82) {
        $category = $this->_category->create()->load($catIds);
        $category->setPostedProducts($parentsPosted);
        $category->save();
        echo "Products assigned to category: ".$catIds."\n";
    }

Hope this helps someone!

0
$objectManager = ObjectManager::getInstance();
$catalogProduct = $objectManager->create('Magento\Catalog\Model\Product');
$catalogProduct->setSku('sku-1');
$catalogProduct->setName('name');
$catalogProduct->setAttributeSetId(4);
$catalogProduct->setStatus(1); // Status on product enabled/ disabled 1/0
$catalogProduct->setVisibility(4);
$catalogProduct->setTypeId('simple'); // type of product (simple/virtual/downloadable/configurable)
$catalogProduct->setPrice(100);

$catalogProduct->setCategoryIds(['id']); // here you are

$catalogProduct->setStockData([
    'is_in_stock' => true,
    'qty'         => 10
]);

$catalogProduct->setStoreId(1); // $this->storeManagerInterface->getStore()->getId()
$catalogProduct->setWebsiteIds([1]); // $this->storeManagerInterface->getStore()->getWebsiteId()

$catalogProduct->save();
1
  • This is a very heavy request and executes very slowly as oppose to Link Manager
    – Timik
    Commented Aug 16, 2018 at 18:53
0

getCategoryIds() why we use CategoryIds()

1
  • Is this supposed to be a question or answer? Commented Sep 13, 2023 at 15:20
0

You can use position to assign product in category

namespace Vendor\Namespace\Controller\Adminhtml\Category;

use Magento\Framework\App\Filesystem\DirectoryList;

class Setpos extends \Magento\Backend\App\Action
{
    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Magento\Catalog\Model\ProductRepository $productRepository,
        \Magento\Catalog\Model\CategoryFactory $categoryFactory,
        \Magento\Framework\File\Csv $csvProcessor
    ) {
        $this->_productRepository = $productRepository;
        $this->_categoryFactory = $categoryFactory;
        $this->_csvProcessor = $csvProcessor;
        parent::__construct($context);
    }

    public function execute()
    {
        $cateId = 41;
        try {
            $file = 'dir1/dir2/filename.csv';
            if(isset($file) {
                $csvFields = $this->_csvProcessor->getData($file);
                $category = $this->_categoryFactory->create()->load($cateId);
                $products = $category->getProductsPosition();
                $count=0;
                foreach ($csvFields as $row => $csvField) 
                {
                    try
                    {
                        if (is_numeric(trim($csvField[1])))
                        {
                            $_products = $this->_productRepository->get(trim($csvField[0]));
                            $products[$_products->getId()] = trim($csvField[1]);  
                            $count++;                   
                        }
                    }catch (\Exception $e) {
                        echo $e->getMessage().'Get some erron in '.trim($csvField[0]);
                    }
                }
                $category->setPostedProducts($products);
                $category->save();
                if(!empty($errorSku))
                echo __('SKU '.implode(",",$errorSku).' .... were not updated. Please check if the sku exist.');   
                echo __($count.' Products have been successfully updated.');
            }
            else {
                echo __('CSV file not uploaded properly, please try again!');
            }
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }
}
0

Please try the code below to update the category of a product.

protected $categoryLinkManagement;

public function __construct(
    ............................................................................
    \Magento\Catalog\Api\CategoryLinkManagementInterface $categoryLinkManagement,
    ............................................................................
) {
    ............................................................................
    $this->categoryLinkManagement = $categoryLinkManagement;
    ............................................................................
}

............................................................................
............................................................................
............................................................................

public function updateCategoryId($productColl, $categoryId)
{
    $categoryId = 23;
    $categoryIds = array_unique(
        array_merge(
            $productColl->getCategoryIds(),
            [$categoryId]
        )
    );
    $this->categoryLinkManagement->assignProductToCategories($productColl->getSku(), $categoryIds);
}

Here, $productColl is the product object, and $categoryId contains the new category ID value.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.