0

I try to import custom options and translate the titles and row titles during the import. I am not able to translate the row title though. Here is my code:

<?php

error_reporting(E_ALL);
ini_set('display_errors', '1');

require_once 'app/Mage.php';

Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);


$data = array(
    array(
        'sku' => '123456',
        '_type' => 'simple',
        '_attribute_set' => 'Default',
        '_product_websites' => 'base',
        'name' => 'Test Product',
        'price' => 10,
        'description' => 'description',
        'short_description' => 'short_description',
        'status' => 1,
        'visibility' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH,
        'tax_class_id' => 1,
        'is_in_stock' => 1
    ),
    array(
        '_custom_option_sku'         => 'MY_SKU',
        '_custom_option_sort_order'  => 10,
        '_custom_option_title'       => 'My EN title',
        '_custom_option_type'        => Mage_Catalog_Model_Product_Option::OPTION_TYPE_CHECKBOX,
        '_custom_option_is_required' => false,
        '_custom_option_row_title'   => 'My EN row title',
        '_custom_option_row_price'   => 0,
        '_custom_option_row_sku'     => 'MY_SKU',
        '_custom_option_row_sort'    => 10
    ),
    array(
        '_custom_option_store'       => 'de',
        '_custom_option_title'       => 'My DE title',
        '_custom_option_row_title'   => 'My DE row title'
    )
);

$import = Mage::getModel('fastsimpleimport/import');
try {
    $import->processProductImport($data);
} catch (Exception $e) {
    print_r($import->getErrorMessages());
}

This works fine for the default view:

Custom Option Default Store

But it only translate the title in the DE store:

enter image description here

It does not translate the row title. How can I translate the row title during the import? If this is not possible (that is what I think), how can the import be extended, so that translations of _custom_option_row_titles can be imported?

1 Answer 1

0

Okay, we came up with a solution by altering Mage_ImportExport_Model_Import_Entity_Product::_saveCustomOptions. Here is a full extension, which solves the issue in Magento 1.9.2.4 and works together with AvS_FastSimpleImport:

app/etc/modules/StackExchange_CustomOptionImport.xml:

<?xml version="1.0"?>
<config>
    <modules>
        <StackExchange_CustomOptionImport>
            <active>true</active>
            <codePool>local</codePool>
            <depends>
                <Mage_Core/>
                <Mage_ImportExport/>
            </depends>
        </StackExchange_CustomOptionImport>
    </modules>
</config>

app/code/local/StackExchange/CustomOptionImport/etc/config.xml:

<?xml version="1.0"?>
<config>
    <modules>
        <StackExchange_CustomOptionImport>
            <version>1.0.0</version>
        </StackExchange_CustomOptionImport>
    </modules>
    <global>
        <models>
            <stackexchange_customoptionimport>
                <class>StackExchange_CustomOptionImport_Model</class>
            </stackexchange_customoptionimport>
            <fastsimpleimport>
                <rewrite>
                    <import_entity_product>StackExchange_CustomOptionImport_Model_Import_Entity_Product</import_entity_product>
                </rewrite>
            </fastsimpleimport>
            <importexport>
                <rewrite>
                    <import_entity_product>StackExchange_CustomOptionImport_Model_Import_Entity_Product</import_entity_product>
                </rewrite>
            </importexport>
        </models>
    </global>
</config>

app/code/local/StackExchange/CustomOptionImport/Model/Import/Entity/Product.php:

<?php

if (Mage::helper('core')->isModuleEnabled('AvS_FastSimpleImport')) {
    class StackExchange_CustomOptionImport_Model_Import_Entity_Product_Abstract extends AvS_FastSimpleImport_Model_Import_Entity_Product {}
} else {
    class StackExchange_CustomOptionImport_Model_Import_Entity_Product_Abstract extends Mage_ImportExport_Model_Import_Entity_Product {}
}

class StackExchange_CustomOptionImport_Model_Import_Entity_Product extends StackExchange_CustomOptionImport_Model_Import_Entity_Product_Abstract
{

    protected function _saveCustomOptions()
    {
        /** @var $coreResource Mage_Core_Model_Resource */
        $coreResource   = Mage::getSingleton('core/resource');
        $productTable   = $coreResource->getTableName('catalog/product');
        $optionTable    = $coreResource->getTableName('catalog/product_option');
        $priceTable     = $coreResource->getTableName('catalog/product_option_price');
        $titleTable     = $coreResource->getTableName('catalog/product_option_title');
        $typePriceTable = $coreResource->getTableName('catalog/product_option_type_price');
        $typeTitleTable = $coreResource->getTableName('catalog/product_option_type_title');
        $typeValueTable = $coreResource->getTableName('catalog/product_option_type_value');
        $nextOptionId   = Mage::getResourceHelper('importexport')->getNextAutoincrement($optionTable);
        $nextValueId    = Mage::getResourceHelper('importexport')->getNextAutoincrement($typeValueTable);
        $priceIsGlobal  = Mage::helper('catalog')->isPriceGlobal();
        $type           = null;
        $typeSpecific   = array(
            'date'      => array('price', 'sku'),
            'date_time' => array('price', 'sku'),
            'time'      => array('price', 'sku'),
            'field'     => array('price', 'sku', 'max_characters'),
            'area'      => array('price', 'sku', 'max_characters'),
            //'file'      => array('price', 'sku', 'file_extension', 'image_size_x', 'image_size_y'),
            'drop_down' => true,
            'radio'     => true,
            'checkbox'  => true,
            'multiple'  => true
        );

        $alreadyUsedProductIds = array();
        while ($bunch = $this->_dataSourceModel->getNextBunch()) {
            $customOptions = array(
                'product_id'    => array(),
                $optionTable    => array(),
                $priceTable     => array(),
                $titleTable     => array(),
                $typePriceTable => array(),
                $typeTitleTable => array(),
                $typeValueTable => array()
            );

            foreach ($bunch as $rowNum => $rowData) {
                $this->_filterRowData($rowData);
                if (!$this->isRowAllowedToImport($rowData, $rowNum)) {
                    continue;
                }
                if (self::SCOPE_DEFAULT == $this->getRowScope($rowData)) {
                    $productId = $this->_newSku[$rowData[self::COL_SKU]]['entity_id'];
                } elseif (!isset($productId)) {
                    continue;
                }
                if (!empty($rowData['_custom_option_store'])) {
                    if (!isset($this->_storeCodeToId[$rowData['_custom_option_store']])) {
                        continue;
                    }
                    $storeId = $this->_storeCodeToId[$rowData['_custom_option_store']];
                } else {
                    $storeId = Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID;
                }
                if (!empty($rowData['_custom_option_type'])) { // get CO type if its specified
                    if (!isset($typeSpecific[$rowData['_custom_option_type']])) {
                        $type = null;
                        continue;
                    }
                    $type = $rowData['_custom_option_type'];
                    $rowIsMain = true;
                } else {
                    if (null === $type) {
                        continue;
                    }
                    $rowIsMain = false;
                }
                if (!isset($customOptions['product_id'][$productId])) { // for update product entity table
                    $customOptions['product_id'][$productId] = array(
                        'entity_id'        => $productId,
                        'has_options'      => 0,
                        'required_options' => 0,
                        'updated_at'       => now()
                    );
                }
                if ($rowIsMain) {
                    $solidParams = array(
                        'option_id'      => $nextOptionId,
                        'sku'            => '',
                        'max_characters' => 0,
                        'file_extension' => null,
                        'image_size_x'   => 0,
                        'image_size_y'   => 0,
                        'product_id'     => $productId,
                        'type'           => $type,
                        'is_require'     => empty($rowData['_custom_option_is_required']) ? 0 : 1,
                        'sort_order'     => empty($rowData['_custom_option_sort_order'])
                            ? 0 : abs($rowData['_custom_option_sort_order'])
                    );

                    if (true !== $typeSpecific[$type]) { // simple option may have optional params
                        $priceTableRow = array(
                            'option_id'  => $nextOptionId,
                            'store_id'   => Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID,
                            'price'      => 0,
                            'price_type' => 'fixed'
                        );

                        foreach ($typeSpecific[$type] as $paramSuffix) {
                            if (isset($rowData['_custom_option_' . $paramSuffix])) {
                                $data = $rowData['_custom_option_' . $paramSuffix];

                                if (array_key_exists($paramSuffix, $solidParams)) {
                                    $solidParams[$paramSuffix] = $data;
                                } elseif ('price' == $paramSuffix) {
                                    if ('%' == substr($data, -1)) {
                                        $priceTableRow['price_type'] = 'percent';
                                    }
                                    $priceTableRow['price'] = (float) rtrim($data, '%');
                                }
                            }
                        }
                        $customOptions[$priceTable][] = $priceTableRow;
                    }
                    $customOptions[$optionTable][] = $solidParams;
                    $customOptions['product_id'][$productId]['has_options'] = 1;

                    if (!empty($rowData['_custom_option_is_required'])) {
                        $customOptions['product_id'][$productId]['required_options'] = 1;
                    }
                    $prevOptionId = $nextOptionId++; // increment option id, but preserve value for $typeValueTable
                }
                if ($typeSpecific[$type] === true && !empty($rowData['_custom_option_row_title'])
                    && empty($rowData['_custom_option_store'])) {
                    // complex CO option row
                    $customOptions[$typeValueTable][$prevOptionId][] = array(
                        'option_type_id' => $nextValueId,
                        'sort_order'     => empty($rowData['_custom_option_row_sort'])
                            ? 0 : abs($rowData['_custom_option_row_sort']),
                        'sku'            => !empty($rowData['_custom_option_row_sku'])
                            ? $rowData['_custom_option_row_sku'] : ''
                    );
                    if (!isset($customOptions[$typeTitleTable][$nextValueId][0])) { // ensure default title is set
                        $customOptions[$typeTitleTable][$nextValueId][0] = $rowData['_custom_option_row_title'];
                    }
                    $customOptions[$typeTitleTable][$nextValueId][$storeId] = $rowData['_custom_option_row_title'];

                    if (!empty($rowData['_custom_option_row_price'])) {
                        $typePriceRow = array(
                            'price'      => (float) rtrim($rowData['_custom_option_row_price'], '%'),
                            'price_type' => 'fixed'
                        );
                        if ('%' == substr($rowData['_custom_option_row_price'], -1)) {
                            $typePriceRow['price_type'] = 'percent';
                        }
                        if ($priceIsGlobal) {
                            $customOptions[$typePriceTable][$nextValueId][0] = $typePriceRow;
                        } else {
                            // ensure default price is set
                            if (!isset($customOptions[$typePriceTable][$nextValueId][0])) {
                                $customOptions[$typePriceTable][$nextValueId][0] = $typePriceRow;
                            }
                            $customOptions[$typePriceTable][$nextValueId][$storeId] = $typePriceRow;
                        }
                    }
                    $prevValueId = $nextValueId++;
                }
                // also save the row title for specific stores - see http://magento.stackexchange.com/q/123855/142
                if ($typeSpecific[$type] === true && !empty($rowData['_custom_option_row_title'])
                    && !empty($rowData['_custom_option_store'])) {
                    $customOptions[$typeTitleTable][$prevValueId][$storeId] = $rowData['_custom_option_row_title'];
                }
                if (!empty($rowData['_custom_option_title'])) {
                    if (!isset($customOptions[$titleTable][$prevOptionId][0])) { // ensure default title is set
                        $customOptions[$titleTable][$prevOptionId][0] = $rowData['_custom_option_title'];
                    }
                    $customOptions[$titleTable][$prevOptionId][$storeId] = $rowData['_custom_option_title'];
                }
            }
            $productIds = array_keys($customOptions['product_id']);
            $productIds = array_diff($productIds, $alreadyUsedProductIds);
            if ($this->getBehavior() != Mage_ImportExport_Model_Import::BEHAVIOR_APPEND
                && !empty($productIds)
            ) { // remove old data?
                $this->_connection->delete(
                    $optionTable,
                    $this->_connection->quoteInto('product_id IN (?)', $productIds)
                );
            }
            // if complex options does not contain values - ignore them
            foreach ($customOptions[$optionTable] as $key => $optionData) {
                if ($typeSpecific[$optionData['type']] === true
                    && !isset($customOptions[$typeValueTable][$optionData['option_id']])
                ) {
                    unset($customOptions[$optionTable][$key], $customOptions[$titleTable][$optionData['option_id']]);
                }
            }

            if ($customOptions[$optionTable]) {
                $this->_connection->insertMultiple($optionTable, $customOptions[$optionTable]);
            }
            $titleRows = array();

            foreach ($customOptions[$titleTable] as $optionId => $storeInfo) {
                foreach ($storeInfo as $storeId => $title) {
                    $titleRows[] = array('option_id' => $optionId, 'store_id' => $storeId, 'title' => $title);
                }
            }
            if ($titleRows) {
                $this->_connection->insertOnDuplicate($titleTable, $titleRows, array('title'));
            }
            if ($customOptions[$priceTable]) {
                $this->_connection->insertOnDuplicate(
                    $priceTable,
                    $customOptions[$priceTable],
                    array('price', 'price_type')
                );
            }
            $typeValueRows = array();

            foreach ($customOptions[$typeValueTable] as $optionId => $optionInfo) {
                foreach ($optionInfo as $row) {
                    $row['option_id'] = $optionId;
                    $typeValueRows[]  = $row;
                }
            }
            if ($typeValueRows) {
                $this->_connection->insertMultiple($typeValueTable, $typeValueRows);
            }
            $optionTypePriceRows = array();
            $optionTypeTitleRows = array();

            foreach ($customOptions[$typePriceTable] as $optionTypeId => $storesData) {
                foreach ($storesData as $storeId => $row) {
                    $row['option_type_id'] = $optionTypeId;
                    $row['store_id']       = $storeId;
                    $optionTypePriceRows[] = $row;
                }
            }
            foreach ($customOptions[$typeTitleTable] as $optionTypeId => $storesData) {
                foreach ($storesData as $storeId => $title) {
                    $optionTypeTitleRows[] = array(
                        'option_type_id' => $optionTypeId,
                        'store_id'       => $storeId,
                        'title'          => $title
                    );
                }
            }
            if ($optionTypePriceRows) {
                $this->_connection->insertOnDuplicate(
                    $typePriceTable,
                    $optionTypePriceRows,
                    array('price', 'price_type')
                );
            }
            if ($optionTypeTitleRows) {
                $this->_connection->insertOnDuplicate($typeTitleTable, $optionTypeTitleRows, array('title'));
            }

            if ($productIds) { // update product entity table to show that product has options
                $customOptionsProducts = $customOptions['product_id'];

                foreach ($customOptionsProducts as $key => $value) {
                    if (!in_array($key, $productIds)) {
                        unset($customOptionsProducts[$key]);
                    }
                }
                $this->_connection->insertOnDuplicate(
                    $productTable,
                    $customOptionsProducts,
                    array('has_options', 'required_options', 'updated_at')
                );
            }

            $alreadyUsedProductIds = array_merge($alreadyUsedProductIds, $productIds);
        }
        return $this;
    }

}

You can compare the class with the default one in order to see what is changed. But there are only two changes:

  1. The $prevValueId is stored:

    $prevValueId = $nextValueId++;
    
  2. The store-specific row-title is saved:

    if ($typeSpecific[$type] === true && !empty($rowData['_custom_option_row_title'])
        && !empty($rowData['_custom_option_store'])) {
        $customOptions[$typeTitleTable][$prevValueId][$storeId] = $rowData['_custom_option_row_title'];
    }
    
1
  • This issue may be fixed in Magento 1.9.3.x.
    – Simon
    Dec 28, 2016 at 11:09

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.