6

I'm using Magento 1.9.x and trying to change default position number of products.

Ex, when we assign product to category via product page i need to set it to 999 position

enter image description here

I changed default position field value of catalog_category_product table

enter image description here

But nothing changed.

i changed magento\app\code\core\Mage\Catalog\Model\Resource\Category.php

/**
         * Add products to category
         */
        if (!empty($insert)) {
            $data = array();
            foreach ($insert as $productId => $position) {
                $data[] = array(
                    'category_id' => (int)$id,
                    'product_id'  => (int)$productId,
                    'position'    =>  (int)$position ? (int)$position : 999
                );
            }
            //(int)$position
            $adapter->insertMultiple($this->_categoryProductTable, $data);
        }

but it only effect when adding products to category via category page.

anyone know a solution for this please, Thank You

  • I've updated my answer with an example module, which only sets the position for new categories added when a product has been saved (or all categories if it's a new product). This doesn't include category save events but a similar principal can be followed – eddhall Sep 12 '18 at 11:49
0

Navigate here,

app\code\core\Mage\Catalog\Model\Resource

Open Product.php, find function name _saveCategories

You will find the d following array within that file.

$data[] = array(
    'category_id' => (int)$categoryId,
    'product_id'  => (int)$object->getId(),
    'position'    => 1  
);

Replace $data array with following one.

$data[] = array(
    'category_id' => (int)$categoryId,
    'product_id'  => (int)$object->getId(),
    'position'    => 999
);

Additional Note: Go here, app\code\core\Mage\Catalog\Model\Resource, Open Category.php Find _saveCategoryProducts() method name, and looking for the following code.

This will work from category pages in add assign mode.

/**
* Add products to category
*/
if (!empty($insert)) {
    $data = array();
    foreach ($insert as $productId => $position) {
        $position = 999; //Added this line
        $data[] = array(
            'category_id' => (int)$id,
            'product_id'  => (int)$productId,
            'position'    => (int)$position
        );
    }
    $adapter->insertMultiple($this->_categoryProductTable, $data);
}

This will work from category pages in update assign mode.

/**
* Update product positions in category
*/
if (!empty($update)) {
    foreach ($update as $productId => $position) {
        $position = 999; //Added this line
        $where = array(
            'category_id = ?'=> (int)$id,
            'product_id = ?' => (int)$productId
        );
        $bind  = array('position' => (int)$position);
        $adapter->update($this->_categoryProductTable, $bind, $where);
    }
}
  • It is forbidden to update the Magento core files ! – PЯINCƏ Sep 9 '18 at 7:04
  • @sandip can i know the megento version above you used, i checked on my magento 1.9 version but cannot find that kind of functions – Suneth Kalhara Sep 10 '18 at 8:03
  • @SunethKalhara Magento version is 1.9.3 – sandip Sep 10 '18 at 9:03
  • 1
    Do NOT do this, never ever edit the core files, at the very least, copy the file into the local codepool (copy app/code/core/Mage/Catalog/Model/Resource/Product.php to app/code/local/Mage/Catalog/Model/Resource/Product.php), or better, create a custom module and rewrite that particular class – eddhall Sep 10 '18 at 14:54
  • 1
    this worked fine, thank you for the answer – Suneth Kalhara Oct 12 '18 at 16:03
3
+25

You need to create a new module.. Its working fine. I tested it.

Let's call it Product_Position.

app/etc/modules/Product_Position.xml - the declaration file

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <Product_Position>
            <active>true</active>
            <codePool>local</codePool>
        </Product_Position>
    </modules>
</config>

app/code/local/Product/Position/etc/config.xml - the configuration file

<?xml version="1.0"?>
<config>
    <modules>
        <Product_Position>
            <version>0.1.0</version>
        </Product_Position>
    </modules>
    <global>
        <models>
            <position>
                <class>Product_Position_Model</class>
            </position>
        </models>       
    </global>
    <adminhtml>
        <events>
            <catalog_product_save_after><!-- observe the event -->
                <observers>
                    <product_position>
                        <type>singleton</type>
                        <class>Product_Position_Model_Observer</class>
                        <method>setPosition</method>
                    </product_position>
                </observers>
            </catalog_product_save_after>
        </events>
    </adminhtml>
</config>

app/code/local/Product/Position/Model/Observer.php - the observe class

<?php

class Product_Position_Model_Observer extends Mage_Core_Model_Abstract
{
    public function setPosition($observer) {
        $product = $observer->getEvent()->getProduct();
        $id = $product->getId();
        $resource = Mage::getSingleton('core/resource'); //get an instance of the core resource
        $connection = $resource->getConnection('core_write');
        $tableName = $resource->getTableName('catalog/category_product');
        $sql = "UPDATE {$tableName} SET `position` = 999 WHERE `product_id` = {$id}"; //set the position for the product in all the categories.
        $connection->query($sql);
    } 
}
  • 1
    This will set every position to 999 whenever the product is saved, which wasn't what was asked, also it's very bad practice to run direct SQL queries – eddhall Sep 11 '18 at 13:19
  • @eddhall , You can customize code for add required position in observer. Also if you see code in question then you can see "999" written is static. You are Welcome. :) – Chirag Rajput Sep 11 '18 at 13:25
  • 2
    OP asked for a product to be set to 999 when a product is assigned to a category, the module you have written changes the position of a product in every category to 999 whenever it has been saved, regardless of whether the product is new in that category or not - it is wrong – eddhall Sep 11 '18 at 15:46
  • @eddhall , so you are welcome to make changes in Answer for help in more specified way in prospect of question. – Chirag Rajput Sep 12 '18 at 4:30
  • I have done so, my answer now contains a full and tested module to do what the original question asked, without using direct SQL queries – eddhall Sep 12 '18 at 11:48
1

The best way to do it would be to:

  1. Create a custom module
  2. Create an observer on the catalog_product_save_before event, using it to set a flag in the registry (something like Mage::register('new_product_for_positioning', 'yes'); if the product is new, or saving the products before-save category IDs to the registry to compare after
  3. Create an observer on the catalog_product_save_after event, fetching the products category ids if the product is new, or comparing the after-save category IDs to the before save ones (that you saved in the registry)
  4. Iterate through each category ID, and change the product's position in there.

Edit: Module code:

app/etc/modules/Product_Position.xml

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <Product_Position>
            <active>true</active>
            <codePool>local</codePool>
        </Product_Position>
    </modules>
</config>

app/code/local/Product/Position/etc/config.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Product_Position>
            <version>0.1.0</version>
        </Product_Position>
    </modules>
    <global>
        <models>
            <position>
                <class>Product_Position_Model</class>
            </position>
        </models>       
    </global>
    <adminhtml>
        <events>
            <!-- set flags for new product or new categories -->
            <catalog_product_save_before>
                <observers>
                    <product_position_before>
                        <type>singleton</type>
                        <class>product_position/observer</class>
                        <method>setFlags</method>
                    </product_position_before>
                </observers>
            </catalog_product_save_before>

            <!-- use previously set flags to change product position -->
            <catalog_product_save_after>
                <observers>
                    <product_position_before>
                        <type>singleton</type>
                        <class>product_position/observer</class>
                        <method>setPosition</method>
                    </product_position_before>
                </observers>
            </catalog_product_save_after>
        </events>
    </adminhtml>
</config>

app/code/local/Product/Position/Model/Observer.php

<?php

class Product_Position_Model_Observer
{
    /**
     * Check before a product save, if it is new, or record pre-save cateogory IDs if it is not
     * 
     * @param Varien_Event_Observer $observer
     *
     * @throws Mage_Core_Exception
     */
    public function setFlags (Varien_Event_Observer $observer) {
        $product = $observer->getProduct();
        if($product->getId()===null){
            Mage::register('new_product_for_positioning', 'yes');
        }else{
            $product = Mage::getModel('catalog/product')->load($product->getId());
            $categoryIds = $product->getCategoryIds();
            Mage::register('categories_before_update'.$product->getId(), $categoryIds);
        }
    }

    /**
     * If a product is new, update position for all categorys
     * If a product is not new, compare pre-save category IDs to post save ones, and update positioning for new ids
     * 
     * @param Varien_Event_Observer $observer
     *
     * @return $this
     */
    public function setPosition(Varien_Event_Observer $observer) {
        $product = $observer->getProduct();

        $categoryIds = $product->getCategoryIds();

        if (Mage::registry('new_product_for_positioning') == 'yes') {
            Mage::unregister('new_product_for_positioning');

            if (count($categoryIds) > 0) {
                foreach ($categoryIds as $categoryId) {
                    $this->_updateProductPosition($categoryId, $product->getId());
                }
            }

            return $this; //Don't need to do any more after this
        }

        $categoriesBeforeSave = Mage::registry('categories_before_update' . $product->getId());
        if (is_array($categoryIds) && count($categoryIds) > 0) {
            Mage::unregister('categories_before_update' . $product->getId());

            $categoriesForUpdate = array_diff($categoryIds, $categoriesBeforeSave);

            if (is_array($categoriesForUpdate) && count($categoriesForUpdate) > 0) {
                foreach ($categoryIds as $categoryId) {
                    $this->_updateProductPosition($categoryId, $product->getId());
                }
            }
        }

    }

    /**
     * Get category, get category positions, update for specific product
     * 
     * @param $categoryId
     * @param $productId
     *
     * @throws Exception
     */
    protected function _updateProductPosition($categoryId, $productId) {
        /** @var Mage_Catalog_Model_Category $category */
        $category = Mage::getModel('catalog/category')->load($categoryId);

        if (!$category->getId()) { //do nothing as category somehow doesn't exist
            return;
        }

        //$newPosition = $category->getProductCollection()->getFirstItem()->getData('position') + 1;
        //use the above to place product last in category, or the below to set to 999
        $newPosition = 999;

        $positions = Mage::getResourceModel('catalog/category')->getProductsPosition($category);

        if (is_array_key($productId, $positions)) {
            $positions[$productId] = $newPosition;
        }

        $category->setData('products_position', $positions);

        $category->save();
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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