Adding new fields to the PrestaShop CSV Importer

The CSV import PrestaShop natively comes with becomes useless if we have added custom fields to our objects. Let’s see how to overcome the limit, and enable extra fields in the CSV Importer as well.

Adding an extra field to PrestaShop objects

Before doing anything with CSVs or the importer, we need a field to fill with your data. If you don’t know how to add one, here is a tutorial on How to extend PrestaShop Objects, and add new fields to them.
In this example, we will use that extrafield one added in the tutorial.
As a side note, it’s not strictly necessary to add the extra field to the product object, as we will see, but it’s essential to have a database column we can use.

Two approaches

Given that the Product class override is not strictly necessary, we can proceed in two ways, depending on our needs: the first, is to complete the previous tutorial, and add the field to the Product Object; the second is to stop after adding the database column, and override an extra method of the AdminImportController, to manually update the new field. We will cover both to see how they work.

The AdminImportController override

Let’s start playing with the real file. First of all, create a new file in override/controllers/admin, and name it AdminImportController.php

Open it up, and add some standard override code within PHP tags

class AdminImportController extends AdminImportControllerCore
{

}

Next, we want to tell the Importer we have an extra field for products. To do this, we have to override the whole construct method, since it’s the one defining available fields for all entities. It’s too long to copy it here, to make sure you grab yours from the original Controller, and drop it into the override.

class AdminImportController extends AdminImportControllerCore
{
        $this->bootstrap = true;
        $this->entities = array(
            $this->l('Categories'),
            $this->l('Products'),
            $this->l('Combinations'),
            $this->l('Customers'),
            $this->l('Addresses'),
            $this->l('Manufacturers'),
            $this->l('Suppliers'),
            $this->l('Alias'),
        );
        // more code here

        $this->separator = ($separator = Tools::substr(strval(trim(Tools::getValue('separator'))), 0, 1)) ? $separator :  ';';
        $this->multiple_value_separator = ($separator = Tools::substr(strval(trim(Tools::getValue('multiple_value_separator'))), 0, 1)) ? $separator :  ',';
        AdminController::__construct();
}

Make absolutely sure you change the very last call to AdminController::__construct(); to avoid losing any modification to the product properties.

Now that the override is in place, we must let it know about our field. Locate the following snippet:

            case $this->entities[$this->l('Products')]:
                self::$validators['image'] = array(
                    'AdminImportController',
                    'split'
                );

You will notice it’s followed by an array defining available fields:

               $this->available_fields = array(
                    'no' => array('label' => $this->l('Ignore this column')),
                    'id' => array('label' => $this->l('ID')),
                    'active' => array('label' => $this->l('Active (0/1)')),
                    'name' => array('label' => $this->l('Name')),
                    'category' => array('label' => $this->l('Categories (x,y,z...)')),
                    'price_tex' => array('label' => $this->l('Price tax excluded')),
                    'price_tin' => array('label' => $this->l('Price tax included')),
                    'id_tax_rules_group' => array('label' => $this->l('Tax rules ID')),
                    'wholesale_price' => array('label' => $this->l('Wholesale price')),
                    'on_sale' => array('label' => $this->l('On sale (0/1)')),
                    'reduction_price' => array('label' => $this->l('Discount amount')),
                    'reduction_percent' => array('label' => $this->l('Discount percent')),
                    'reduction_from' => array('label' => $this->l('Discount from (yyyy-mm-dd)')),
                    'reduction_to' => array('label' => $this->l('Discount to (yyyy-mm-dd)')),
                    'reference' => array('label' => $this->l('Reference #')),
                    'supplier_reference' => array('label' => $this->l('Supplier reference #')),
                    'supplier' => array('label' => $this->l('Supplier')),
                    'manufacturer' => array('label' => $this->l('Manufacturer')),
                    'ean13' => array('label' => $this->l('EAN13')),
                    'upc' => array('label' => $this->l('UPC')),
                    'ecotax' => array('label' => $this->l('Ecotax')),
                    'width' => array('label' => $this->l('Width')),
                    'height' => array('label' => $this->l('Height')),
                    'depth' => array('label' => $this->l('Depth')),
                    'weight' => array('label' => $this->l('Weight')),
                    'quantity' => array('label' => $this->l('Quantity')),
                    'minimal_quantity' => array('label' => $this->l('Minimal quantity')),
                    'visibility' => array('label' => $this->l('Visibility')),
                    'additional_shipping_cost' => array('label' => $this->l('Additional shipping cost')),
                    'unity' => array('label' => $this->l('Unit for the unit price')),
                    'unit_price' => array('label' => $this->l('Unit price')),
                    'description_short' => array('label' => $this->l('Short description')),
                    'description' => array('label' => $this->l('Description')),
                    'tags' => array('label' => $this->l('Tags (x,y,z...)')),
                    'meta_title' => array('label' => $this->l('Meta title')),
                    'meta_keywords' => array('label' => $this->l('Meta keywords')),
                    'meta_description' => array('label' => $this->l('Meta description')),
                    'link_rewrite' => array('label' => $this->l('URL rewritten')),
                    'available_now' => array('label' => $this->l('Text when in stock')),
                    'available_later' => array('label' => $this->l('Text when backorder allowed')),
                    'available_for_order' => array('label' => $this->l('Available for order (0 = No, 1 = Yes)')),
                    'available_date' => array('label' => $this->l('Product availability date')),
                    'date_add' => array('label' => $this->l('Product creation date')),
                    'show_price' => array('label' => $this->l('Show price (0 = No, 1 = Yes)')),
                    'image' => array('label' => $this->l('Image URLs (x,y,z...)')),
                    'delete_existing_images' => array(
                        'label' => $this->l('Delete existing images (0 = No, 1 = Yes)')
                    ),
                    'features' => array('label' => $this->l('Feature (Name:Value:Position:Customized)')),
                    'online_only' => array('label' => $this->l('Available online only (0 = No, 1 = Yes)')),
                    'condition' => array('label' => $this->l('Condition')),
                    'customizable' => array('label' => $this->l('Customizable (0 = No, 1 = Yes)')),
                    'uploadable_files' => array('label' => $this->l('Uploadable files (0 = No, 1 = Yes)')),
                    'text_fields' => array('label' => $this->l('Text fields (0 = No, 1 = Yes)')),
                    'out_of_stock' => array('label' => $this->l('Action when out of stock')),
                    'shop' => array(
                        'label' => $this->l('ID / Name of shop'),
                        'help' => $this->l('Ignore this field if you don\'t use the Multistore tool. If you leave this field empty, the default shop will be used.'),
                    ),
                    'advanced_stock_management' => array(
                        'label' => $this->l('Advanced Stock Management'),
                        'help' => $this->l('Enable Advanced Stock Management on product (0 = No, 1 = Yes).')
                    ),
                    'depends_on_stock' => array(
                        'label' => $this->l('Depends on stock'),
                        'help' => $this->l('0 = Use quantity set in product, 1 = Use quantity from warehouse.')
                    ),
                    'warehouse' => array(
                        'label' => $this->l('Warehouse'),
                        'help' => $this->l('ID of the warehouse to set as storage.')
                    )
                );

This represents all of the fields, or columns, that you can map to every column of your csv file. At this point, it’s enough to append our element to the array:

                    'depends_on_stock' => array(
                        'label' => $this->l('Depends on stock'),
                        'help' => $this->l('0 = Use quantity set in product, 1 = Use quantity from warehouse.')
                    ),
                    'warehouse' => array(
                        'label' => $this->l('Warehouse'),
                        'help' => $this->l('ID of the warehouse to set as storage.')
                    ),
                    'extrafield' => array(
                        'label' => $this->l('Extrafield'),
                        'help' => $this->l('Something')
                    )
                );

Save, then reach the cache folder and delete class_index.php, so that the override file is loaded.

If you added the Product class override, you can skip to Testing The Import

Otherwise, there is a little snippet you need to add. Unfortunately, in order to do it we have to override the whole ProductImport() method. Therefore, copy and paste yours into the override file we created; then, reach the very end of it, where it reads:

        $this->closeCsvFile($handle);
        Module::processDeferedFuncCall();
        Module::processDeferedClearCache();
        Tag::updateTagCount();

Right before, add the following statement

Db::getInstance()->update('product', array('extrafield' => $info['extrafield']), 'id_product = ' . (int)$product->id);

This will manually update the field, in case it was not part of the product object.

Testing The Import

Before proceeding: Make sure you do not have a product with the same ID of the sample one, or it will be overridden.

We are ready for a test run. Download the product csv sample from Advanced Parameters > CSV Import

PrestaShop Sample CSV File Download

Open up the file in any text editor, get rid of all lines apart from the heading and first product. Then, add a new heading after “Warehouse”, and a value for it on the next line:

Adding an extra field value to the csv for PrestaShop

Adding an extra field to the csv for PrestaShop

Save the file. Now load it up in the importer. Make sure you select Products as entity, and leave all other settings as default. Hit Next.

PrestaShop CSV Import Settings

On the next screen, hit the next arrow until you reach the end of the file. You should see the new column popping up:

PrestaShop CSV Import Settings for Columns

Now proceed and simply hit import to complete the process. You will probably get an error because of the broken image url, but the new field should be added to the database:

PrestaShop Database Updated PrestaShop Database via CSV via CSV

We are done! Now you can display the extra field the way you like, whether it is with a module or following the previously linked tutorial.

Additional Resources on CSV Import in PrestaShop

You like the tuts and want to say "thank you"? Well, you can always feel free to donate:

  • John Nash

    Please, send me source file. A don’t undestend where they ara
    klionash@gmail.com

  • Hanny

    Hey Nemo – great writeup (as usual); if I have products that I want to
    have customized – what is the process to put that in the CSV?

    I’ve tried using the format: “Line 1″|1, “Line 2″|1 – but that’s not working.

    What would be the best way to do that?

    • NemoPS

      If you want to use the pipe as separator, you must set it as such before importing (there is a field set to semicolon for it)

You like the tuts and want to say "thank you"? Well, you can always feel free to donate: