
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
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:
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.
On the next screen, hit the next arrow until you reach the end of the file. You should see the new column popping up:
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:
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.