Importing WooCommerce products into WordPress with custom fields and multiple product categories

If you are trying to import products into WooCommerce that have custom fields, you can try the Really Simple CSV Importer plugin and follow my instructions below.

Note that the Really Simple CSV Importer plugin v1.3 has not been updated for years, however it still works fine as of WordPress v5.8 for importing WooCommerce products.
In order to use it, you go to TOOLS then IMPORT and you will see it in the list import tools to choose from.

Some caveats with Really Simple CSV Importer plugin:
– The CSV file needs to be UTF-8.
– The header row of CSV file should NOT have double-quotes around each field.
– Each row in the CSV file (except the header row) should have double-quotes around each field.
– Each field in each row must use a comma as the seperator.
– To import to a custom field (meta field) called my_custom_field just use that exact name in the header row field name.
– To import to a hidden custom field called (hidden meta field) _my_custom_hidden_field you need to put an _underscore_ in front of the header row field name.
– It appears that post_id and post_name are required in the header row fields, but you can leave them blank and they will be automatically be generated.
– post_category generates a category under POSTS instead of PRODUCTS, so leave post_category blank.
– To import to a woocommerce specific custom field, you can use the following in the header row fields (these are just some of them):
  For REGULAR PRICE use: _regular_price
  For SALE PRICE use: _sale_price
  For the displayed PRICE use: _price
  For SKU use: _sku
  For STOCK MANAGEMENT (yes or no) use: _manage_stock
  For STOCK QUANTITY use: _stock
  For PRODUCT CATEGORY use (can only specify a single category): tax_product_cat
  For PRODUCT TYPE use (simple): tax_product_type
  For SHOP CATALOG or SEARCH visibility use (can specify one of exclude-from-search or exclude-from-catalog): tax_product_visibility

Here is a sample CSV file you can copy and paste:

post_id,post_name,post_title,post_content,post_author,post_date,post_tags,post_category,post_thumbnail,post_type,post_status,_sku,_regular_price,_price,_stock,_manage_stock,_visibility,tax_product_visibility,tax_product_type,tax_product_cat,_custom_field_hidden,custom_field_meta
"","my-first-product-url-slug","My first product name","description","","","","","https://mywordpresssite.com/wp-content/uploads/first-product-featured-image.jpg","product","publish","first-product-sku","50","50","3","yes","hidden","exclude-from-search","simple","my-product-category","hidden meta field","meta field"
"","my-second-product-url","My second product name","description","","","","","https://mywordpresssite.com/wp-content/uploads/second-product-featured-image.jpg","product","publish","second-product-sku","20","20","4","yes","hidden","exclude-from-catalog","simple","another-product-category","hidden meta field","meta field"

MODIFICATIONS TO CODE
I have created a couple modifications to the Really Simple CSV Importer code that will allow the following:
– Add multiple product categories seperated by the pipe | character: “my-product-cat|another-product-cat”
– Add both product visibility options seperated by the pipe | character: “exclude-from-catalog|exclude-from-search”
– Add a new header row option called “tax_search_exclude” which will allow you use the SEARCH EXCLUDE plugin: “yes”
NOTE: The exclude-from-search option will only hide products from the WooCommerce search but not from the WordPress search. In order to also hide products from the WordPress search, you need to use the SEARCH EXCLUDE plugin https://wordpress.org/plugins/search-exclude/

In order to make these modifications work, you need to modify the following file around line 289: class-rscsv_import_post_helper.php

Look for this code:

public function setObjectTerms($taxonomy, $terms)
{
$post = $this->getPost();

And replace with this code:

public function setObjectTerms($taxonomy, $terms)
{

//// MOD by jsherk //////////////////////////////////////////////////////////////////////////////////////

////////////// MULTIPLE terms for a TAXONOMY
// Check if taxonomy has more than one term (use | to specify multiple terms).
// For example import "tax_product_cat" as: "myCategory1|anotherCategory2" to add it to two categories.
// For example import "tax_product_visibility" as: "exclude-from-search|exclude-from-catalog" to hide from both shop catalog and search
$new_terms = array();
foreach ($terms as $term) {
$terms_split = false;
if (strpos($term, "|") == true ) {
$terms_split = true; // Yes the term contained multiple terms seperated by the pipe| character.
$split_terms = explode("|", $term);
foreach ($split_terms as $split_term ) {
// Add each split as a seperate term
$new_terms[] = $split_term;
}
}
if ($terms_split == false) {
// No the term did not contain multiple terms.
$new_terms[] = $term;
}
}
$terms = $new_terms; // Replace orignal terms with split up terms
//////////////

////////////// SEARCH EXCLUDE PLUGIN https://wordpress.org/plugins/search-exclude/
// If you use a plugin called SEARCH EXCLUDE then we need to create an OPTION instead of a TAXONOMY.
// In the csv file, use a csv header of "tax_search_exclude" and then set a value of either "yes" or "no". If the value is "yes" then we will add the option to the options table.
if ($taxonomy == "search_exclude") {
if (strtolower($terms[0]) == "yes") {
$server_path_array = explode("wp-content", __FILE__);
$server_path = $server_path_array[0];
$wp_load = $server_path.'wp-load.php';
require_once( $wp_load );
$wp_option = $server_path.'wp-includes/option.php';
require_once($wp_option);
$post = $this->getPost();
$new_option_id = intval($post->ID); // get the post_id
$search_exclude_options = get_option("sep_exclude"); // read the current values from the options table
if (empty($search_exclude_options)) {
// if the option is empty, then it does not exist and needs to be added
$new_search_exclude_option = array($new_option_id);
delete_option("sep_exclude"); // option may exist but be empty so we need to delete it first otherwise add_option will not update (add_option will only work if the option does not exist at all).
add_option("sep_exclude", $new_search_exclude_option, " ", "yes");
} else {
$search_exclude_options[] = $new_option_id;
update_option("sep_exclude", $search_exclude_options);
}
$search_exclude_options = get_option("sep_exclude"); // re-read the current values from the options table
}
}
//////////////

//// end MOD by jsherk //////////////////////////////////////////////////////////////////////////////////////

$post = $this->getPost();

Here is a sample CSV file with MODIFICATIONS you can copy and paste:

post_id,post_name,post_title,post_content,post_author,post_date,post_tags,post_category,post_thumbnail,post_type,post_status,_sku,_regular_price,_price,_stock,_manage_stock,_visibility,tax_search_exclude,tax_product_visibility,tax_product_type,tax_product_cat,_custom_field_hidden,custom_field_meta
"","my-first-product-url-slug","My first product name","description","","","","","https://mywordpresssite.com/wp-content/uploads/first-product-featured-image.jpg","product","publish","first-product-sku","50","50","3","yes","hidden","yes","exclude-from-search|exclude-from-catalog","simple","my-product-category|another-product-category","hidden meta field","meta field"
"","my-second-product-url","My second product name","description","","","","","https://mywordpresssite.com/wp-content/uploads/second-product-featured-image.jpg","product","publish","second-product-sku","20","20","4","yes","hidden","no","exclude-from-catalog","simple","another-product-category","hidden meta field","meta field"