Skip to main content

WordPress/WooCommerce Product Import Guide

Version: 1.0 Last Updated: 2025-01-10 Author: Claude Code Strategic Planner

πŸ“‹ Table of Contents

  1. Pre-Import Checklist
  2. Import Methods Overview
  3. Method A: WP All Import Plugin
  4. Method B: WooCommerce REST API
  5. Method C: Native CSV Import
  6. Post-Import Actions
  7. Troubleshooting
  8. Reference Files

1. Pre-Import Checklist

βœ… Backup Database

CRITICAL: Always backup before importing!
# Via WP-CLI
wp db export --path=/path/to/wordpress backup_$(date +%Y%m%d_%H%M%S).sql

# Via phpMyAdmin
1. Log in to phpMyAdmin
2. Select your WordPress database
3. Click "Export" tab
4. Choose "Quick" export method
5. Click "Go"

# Via cPanel
1. Backup β†’ Backup Wizard
2. Select "MySQL Database"
3. Download backup

βœ… Check Product Categories

Ensure categories exist before importing:
# List existing categories
wp term list category --format=table --path=/path/to/wordpress

# Create missing categories
wp term create category "TΓͺn-Danh-Mα»₯c" --description="MΓ΄ tαΊ£" --slug="slug" --path=/path/to/wordpress
Required Categories for This Project:
  • Meso
  • Filler
  • CΔƒng Chỉ
  • [Other categories from your data]

βœ… Verify Image URLs

Check if image URLs are accessible:
# Test a sample URL
curl -I https://example.com/image.jpg

# Bulk check (requires jq)
cat products.json | jq -r '.[].image' | while read url; do
  curl -s -o /dev/null -w "%{http_code} $url\n" "$url"
done

βœ… Test with 1-2 Products First

ALWAYS test with a small batch before full import:
# Extract first 2 products for testing
jq '.[:2]' docs/new_products_to_add.json > test_import.json

2. Import Methods Overview

MethodDifficultySpeedReliabilityBest For
WP All Import⭐⭐ EasyπŸš€ Fastβœ… Very HighLarge imports, complex data
REST API⭐⭐⭐ MediumπŸš€πŸš€ Very Fastβœ… HighDevelopers, automation
Native CSV⭐ Easy🐒 Slow⚠️ MediumSimple imports, small batches
Recommendation: Use WP All Import for this project due to complex pricing structures.

3.1 Installation

# Download WP All Import
wget https://downloads.wordpress.org/plugin/wp-all-import.3.6.6.zip

# Install via WP-CLI
wp plugin install wp-all-import --activate --path=/path/to/wordpress

# Install WooCommerce Add-On
wp plugin install wp-all-import-woocommerce --activate --path=/path/to/wordpress
Or via WordPress Admin:
  1. Plugins β†’ Add New
  2. Search β€œWP All Import”
  3. Install & Activate
  4. Install β€œWP All Import - WooCommerce Add-On”

3.2 Step-by-Step Import

Step 1: Prepare JSON File

Convert your JSON to WP All Import compatible format:
# Convert new_products_to_add.json
cat > /tmp/import_prepare.js << 'EOF'
const data = require('/Users/tannguyen/Documents/fullstack/triseo.drmanhlinhmd.com/docs/new_products_to_add.json');

// WP All Import format
const wpFormat = data.map(product => ({
  post_title: product.name,
  post_content: product.description || '',
  post_excerpt: product.short_description || product.name,
  post_status: 'publish',
  post_type: 'product',

  // WooCommerce fields
  meta: {
    _sku: product.sku || product.slug,
    _regular_price: product.price,
    _sale_price: product.sale_price || '',
    _price: product.sale_price || product.price,
    _stock: product.stock || 0,
    _manage_stock: product.manage_stock ? 'yes' : 'no',
    _backorders: product.backorders || 'no',
    _sold_individually: product.sold_individually ? 'yes' : 'no',
    _weight: product.weight || '',
    _length: product.length || '',
    _width: product.width || '',
    _height: product.height || '',
    _product_url: product.external_url || '',
    _button_text: product.external_button_text || 'Buy Now',
    _downloadable: product.downloadable ? 'yes' : 'no',
    _virtual: product.virtual ? 'yes' : 'no',
    _product_image_gallery: product.gallery_images.join(','),
  },

  // Categories
  categories: product.categories.map(cat => ({
    name: cat
  })),

  // Images
  images: [product.image],

  // Attributes
  attributes: product.attributes || []
}));

console.log(JSON.stringify(wpFormat, null, 2));
EOF

node /tmp/import_prepare.js > /tmp/wp_import.json

Step 2: Start Import

  1. Navigate to: All Import β†’ New Import
  2. [SCREENSHOT: Select β€œUpload a file”]
  3. Choose: wp_import.json
  4. Click β€œUpload file and continue”

Step 3: Configure Import

[SCREENSHOT: Drag & Drop template builder] Post Title:
  • Drag {name} to Title field
Content:
  • Drag {description} to Content field
  • Drag {short_description} to Excerpt field
Images:
  • Drag {image} to Images field
  • Enable β€œDownload images externally”
  • Enable β€œUse as featured image”

Step 4: WooCommerce Fields

Click β€œConfigure WooCommerce Settings” [SCREENSHOT: WooCommerce field mapping]
WP All Import FieldSource FieldNotes
SKU{sku}Must be unique
Regular Price{price}Required
Sale Price{sale_price}Optional
Stock{stock}Default: 0
Manage Stock{manage_stock}yes/no
Backorders{backorders}no/notify/yes

Step 5: Categories

[SCREENSHOT: Category mapping]
  • Drag {categories} to Product Categories
  • Select: β€œMatch by name”
  • Enable: β€œCreate categories if they don’t exist”

Step 6: Import Options

[SCREENSHOT: Import settings]
β˜‘ Create new products
☐ Update existing products (matched by SKU)
☐ Auto-detect existing products
☐ Delete products that are no longer in the file
Processing Mode:
  • Choose: β€œProcess in background” (recommended for >100 products)

Step 7: Run Import

Click β€œContinue & Run Import” [SCREENSHOT: Progress bar]
  • Monitor progress in real-time
  • Receive email when complete

3.3 Advanced Features

Automatic Scheduling

// Schedule auto-import every hour
add_filter('wp_all_import_cron_schedules', function($schedules) {
    $schedules['hourly'] = [
        'interval' => 3600,
        'display' => 'Once Hourly'
    ];
    return $schedules;
});

Custom Field Mapping

// Add custom logic during import
add_action('pmxi_saved_post', function($post_id) {
    // Update product after import
    $product = wc_get_product($post_id);

    // Add custom meta
    update_post_meta($post_id, '_import_date', current_time('mysql'));

    // Set default attributes
    $product->set_default_attributes([
        'color' => 'red'
    ]);
    $product->save();
});

4. Method B: WooCommerce REST API

4.1 Setup Authentication

# Generate API keys via WordPress CLI
wp user api-key create 1 --description="Product Import" --permissions=read_write --path=/path/to/wordpress
Or via Admin:
  1. WooCommerce β†’ Settings β†’ Advanced β†’ REST API
  2. Click β€œAdd Key”
  3. Description: β€œProduct Import”
  4. Permissions: Read/Write
  5. Click β€œGenerate API Key”
  6. COPY Consumer Key & Secret (you won’t see them again!)

4.2 Prepare Import Script

Create /tmp/import_products.js:
const WooCommerceAPI = require('woocommerce-api');
const fs = require('fs');

// Configuration
const WooCommerce = new WooCommerceAPI({
  url: 'https://yoursite.com',
  consumerKey: 'YOUR_CONSUMER_KEY',
  consumerSecret: 'YOUR_CONSUMER_SECRET',
  wpAPI: true,
  version: 'wc/v3'
});

// Load products
const products = JSON.parse(
  fs.readFileSync('/Users/tannguyen/Documents/fullstack/triseo.drmanhlinhmd.com/docs/new_products_to_add.json')
);

// Transform to WooCommerce format
const transformProduct = (product) => ({
  name: product.name,
  slug: product.slug,
  type: product.type || 'simple',
  status: 'publish',
  description: product.description || '',
  short_description: product.short_description || product.name,
  sku: product.sku || product.slug,
  regular_price: product.price.toString(),
  sale_price: product.sale_price ? product.sale_price.toString() : '',
  manage_stock: product.manage_stock || false,
  stock_quantity: product.stock || 0,
  categories: product.categories.map(cat => ({ name: cat })),
  images: [
    {
      src: product.image,
      name: product.name
    }
  ],
  attributes: product.attributes || [],
  meta_data: [
    {
      key: '_external_url',
      value: product.external_url || ''
    },
    {
      key: '_external_button_text',
      value: product.external_button_text || 'Buy Now'
    }
  ]
});

// Import function
async function importProducts() {
  const results = {
    success: [],
    failed: []
  };

  for (const product of products) {
    try {
      const response = await WooCommerce.postAsync('products', transformProduct(product));
      const result = JSON.parse(response.toJSON().body);

      console.log(`βœ… Imported: ${product.name}`);
      results.success.push({
        name: product.name,
        id: result.id,
        sku: result.sku
      });

      // Rate limiting: wait 500ms between requests
      await new Promise(resolve => setTimeout(resolve, 500));

    } catch (error) {
      console.error(`❌ Failed: ${product.name}`);
      console.error(error.message);
      results.failed.push({
        name: product.name,
        error: error.message
      });
    }
  }

  // Save results
  fs.writeFileSync('/tmp/import_results.json', JSON.stringify(results, null, 2));
  console.log('\nπŸ“Š Import Summary:');
  console.log(`βœ… Success: ${results.success.length}`);
  console.log(`❌ Failed: ${results.failed.length}`);
}

// Run import
importProducts();

4.3 Run Import Script

# Install dependencies
npm install woocommerce-api

# Run import
node /tmp/import_products.js

# Check results
cat /tmp/import_results.json

4.4 Update Existing Products

// Check if product exists by SKU
async function checkProductExists(sku) {
  const response = await WooCommerce.getAsync(`products?sku=${sku}`);
  const products = JSON.parse(response.toJSON().body);
  return products.length > 0 ? products[0].id : null;
}

// Update or create
async function upsertProduct(product) {
  const existingId = await checkProductExists(product.sku);
  const data = transformProduct(product);

  if (existingId) {
    console.log(`πŸ”„ Updating: ${product.name}`);
    await WooCommerce.putAsync(`products/${existingId}`, data);
  } else {
    console.log(`βž• Creating: ${product.name}`);
    await WooCommerce.postAsync('products', data);
  }
}

4.5 Batch Import (WooCommerce 3.0+)

// Batch import (100 products at a time)
async function batchImport(products) {
  const batchSize = 100;
  const batches = Math.ceil(products.length / batchSize);

  for (let i = 0; i < batches; i++) {
    const batch = products.slice(i * batchSize, (i + 1) * batchSize);

    console.log(`\nπŸ“¦ Processing batch ${i + 1}/${batches}`);

    const response = await WooCommerce.postAsync('products/batch', {
      create: batch.map(transformProduct)
    });

    console.log(`βœ… Batch ${i + 1} complete`);
  }
}

5. Method C: Native CSV Import via WooCommerce

5.1 Prepare CSV Template

Create /tmp/products_import.csv:
ID,Type,SKU,Name,Published,Featured,Visibility in catalog,Short description,Description,Tax status,Tax class,In stock?,Stock,Backorders,Sold individually?,Weight (kg),Length (cm),Width (cm),Height (cm),Allow customer reviews?,Purchase note,Sale price,Regular price,Categories,Tags,Images,Attribute 1 name,Attribute 1 value,Attribute 1 visible,Attribute 1 global,Attribute 2 name,Attribute 2 value,Attribute 2 visible,Attribute 2 global,Download 1 name,Download 1 URL,Download 1 limit,Meta: _external_url,Meta: _external_button_text
,simple,BRUNO-001,Bruno Vassari Product 1,1,0,visible,"Short desc here","Full description here",taxable,,1,0,no,0,,,,1,,,990000,1200000,"meso,filler","https://example.com/image.jpg",Color,Red,1,1,Size,Large,1,1,,,,https://external.com/buy,Buy Now

5.2 Convert JSON to CSV

Create /tmp/json_to_csv.py:
#!/usr/bin/env python3
import json
import csv

# Load JSON
with open('/Users/tannguyen/Documents/fullstack/triseo.drmanhlinhmd.com/docs/new_products_to_add.json') as f:
    products = json.load(f)

# CSV headers
headers = [
    'ID', 'Type', 'SKU', 'Name', 'Published', 'Featured',
    'Visibility in catalog', 'Short description', 'Description',
    'Tax status', 'Tax class', 'In stock?', 'Stock', 'Backorders',
    'Sold individually?', 'Weight (kg)', 'Length (cm)', 'Width (cm)',
    'Height (cm)', 'Allow customer reviews?', 'Purchase note',
    'Sale price', 'Regular price', 'Categories', 'Tags', 'Images',
    'Attribute 1 name', 'Attribute 1 value', 'Attribute 1 visible',
    'Attribute 1 global', 'Meta: _external_url', 'Meta: _external_button_text'
]

# Convert to CSV
with open('/tmp/products_import.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.DictWriter(f, fieldnames=headers)
    writer.writeheader()

    for p in products:
        row = {
            'ID': '',
            'Type': p.get('type', 'simple'),
            'SKU': p.get('sku', p.get('slug', '')),
            'Name': p.get('name', ''),
            'Published': 1,
            'Featured': 0,
            'Visibility in catalog': 'visible',
            'Short description': p.get('short_description', ''),
            'Description': p.get('description', ''),
            'Tax status': 'taxable',
            'Tax class': '',
            'In stock?': 1 if p.get('stock', 0) > 0 else 0,
            'Stock': p.get('stock', 0),
            'Backorders': p.get('backorders', 'no'),
            'Sold individually?': 'yes' if p.get('sold_individually') else 'no',
            'Weight (kg)': p.get('weight', ''),
            'Length (cm)': p.get('length', ''),
            'Width (cm)': p.get('width', ''),
            'Height (cm)': p.get('height', ''),
            'Allow customer reviews?': 1,
            'Purchase note': '',
            'Sale price': p.get('sale_price', ''),
            'Regular price': p.get('price', ''),
            'Categories': ','.join(p.get('categories', [])),
            'Tags': '',
            'Images': p.get('image', ''),
            'Attribute 1 name': '',
            'Attribute 1 value': '',
            'Attribute 1 visible': 1,
            'Attribute 1 global': 1,
            'Meta: _external_url': p.get('external_url', ''),
            'Meta: _external_button_text': p.get('external_button_text', 'Buy Now')
        }
        writer.writerow(row)

print(f'βœ… Converted {len(products)} products to CSV')
Run conversion:
python3 /tmp/json_to_csv.py

5.3 Import via WooCommerce

  1. Navigate to: WooCommerce β†’ Products β†’ Import
  2. [SCREENSHOT: CSV upload screen]
  3. Choose products_import.csv
  4. Click β€œUpload file and continue”

5.4 Map CSV Columns

[SCREENSHOT: Column mapping screen] Required Mappings:
  • Name β†’ Name
  • SKU β†’ SKU
  • Regular price β†’ Regular price
  • Categories β†’ Categories
  • Images β†’ Images

5.5 Run Import

Click β€œRun Import” [SCREENSHOT: Import progress]

6. Post-Import Actions

6.1 Verify Prices

# Check all imported prices
wp post list --post_type=product --format=table --fields=ID,post_title --path=/path/to/wordpress | \
while read line; do
  id=$(echo $line | awk '{print $1}')
  regular=$(wp post meta get $id _regular_price --path=/path/to/wordpress)
  sale=$(wp post meta get $id _sale_price --path=/path/to/wordpress)
  echo "$id | $regular | $sale"
done

6.2 Check Sale Prices

# Find products with sale price > regular price
wp wc product list --fields=id,name,regular_price,sale_price --path=/path/to/wordpress | \
awk -F, '{if ($4 > $3) print $0}'

6.3 Test Product Pages

# Generate list of URLs to test
wp post list --post_type=product --format=ids --path=/path/to/wordpress | \
while read id; do
  slug=$(wp post get $id --field=permalink --path=/path/to/wordpress)
  echo "$slug"
done > /tmp/product_urls.txt

# Test with curl
cat /tmp/product_urls.txt | while read url; do
  status=$(curl -s -o /dev/null -w "%{http_code}" "$url")
  echo "$status - $url"
done

6.4 Update Inventory

# Set inventory management
wp post list --post_type=product --format=ids --path=/path/to/wordpress | \
while read id; do
  wp post meta update $id _manage_stock 'yes' --path=/path/to/wordpress
  wp post meta update $id _stock '100' --path=/path/to/wordpress
done

6.5 Regenerate Thumbnails

# Regenerate all product images
wp media regenerate --yes --path=/path/to/wordpress

6.6 Clear Cache

# Clear object cache
wp cache flush --path=/path/to/wordpress

# Clear CDN cache (if using)
# Example for Cloudflare via API
curl -X DELETE "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
  -H "Authorization: Bearer API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"purge_everything":true}'

7. Troubleshooting

7.1 Common Issues

Issue: Images Not Importing

Symptoms:
  • Products imported but no images
  • Broken image icons
Solutions:
  1. Check image URL accessibility:
curl -I https://example.com/image.jpg
# Should return 200 OK
  1. Enable β€œDownload images externally”:
    • WP All Import: Images section β†’ Enable β€œDownload externally hosted images”
  2. Check file permissions:
# Fix upload directory permissions
chmod 755 /path/to/wordpress/wp-content/uploads
chown www-data:www-data /path/to/wordpress/wp-content/uploads
  1. Increase memory limits:
// Add to wp-config.php
define('WP_MEMORY_LIMIT', '512M');

Issue: Duplicate SKUs

Symptoms:
  • Import fails with β€œSKU already exists”
  • Products not updating
Solutions:
  1. Find duplicates:
SELECT meta_value, COUNT(*) as count
FROM wp_postmeta
WHERE meta_key = '_sku'
AND meta_value != ''
GROUP BY meta_value
HAVING count > 1;
  1. Remove duplicates:
DELETE p1 FROM wp_posts p1
INNER JOIN wp_posts p2
WHERE p1.ID > p2.ID
AND p1.post_type = 'product'
AND p1.post_title = p2.post_title;
  1. Update import strategy:
    • Enable β€œUpdate existing products”
    • Match by: SKU

Issue: Categories Not Mapping

Symptoms:
  • Products import but no categories
  • All products in β€œUncategorized”
Solutions:
  1. Check category slugs:
wp term list category --format=table --path=/path/to/wordpress
  1. Create missing categories:
# From CSV
while IFS=, read -r name slug; do
  wp term create category "$name" --slug="$slug" --path=/path/to/wordpress
done < categories.csv
  1. Verify mapping:
    • WP All Import: Categories β†’ Match by β€œname” (not slug)
    • Enable β€œCreate categories if they don’t exist”

Issue: Import Timeout

Symptoms:
  • Import stops after 30-60 seconds
  • Only some products imported
Solutions:
  1. Increase PHP limits:
// In wp-config.php
@ini_set('max_execution_time', '300');
@ini_set('upload_max_filesize', '50M');
@ini_set('post_max_size', '50M');

// In .htaccess
php_value max_execution_time 300
php_value upload_max_filesize 50M
php_value post_max_size 50M
  1. Use background processing:
    • WP All Import: Enable β€œProcess in background”
    • Set lower batch size: 50 products per batch
  2. Split large files:
# Split JSON into 100-product chunks
split -l 100 products.json chunk_

Issue: Special Characters Not Displaying

Symptoms:
  • Vietnamese characters show as question marks
  • Accented letters broken
Solutions:
  1. Check database charset:
SHOW VARIABLES LIKE 'character_set%';
-- Should be: utf8mb4
  1. Convert to UTF-8:
# Convert CSV to UTF-8
iconv -f ISO-8859-1 -t UTF-8 products.csv > products_utf8.csv
  1. Set charset in wp-config.php:
define('DB_CHARSET', 'utf8mb4');
define('DB_COLLATE', 'utf8mb4_unicode_ci');

7.2 Error Codes Reference

Error CodeMeaningSolution
woocommerce_rest_product_invalid_skuSKU already existsUse unique SKU or update existing
woocommerce_rest_invalid_imageInvalid image URLCheck URL returns 200 OK
woocommerce_rest_invalid_categoryCategory doesn’t existCreate category first
woocommerce_rest_product_missing_pricePrice requiredAdd regular_price
500 Internal Server ErrorServer errorCheck PHP error logs

7.3 Enable Debug Mode

// In wp-config.php
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);

// Check logs
tail -f /path/to/wordpress/wp-content/debug.log

8. Reference Files

8.1 Data Sources

New Products to Add:
/Users/tannguyen/Documents/fullstack/triseo.drmanhlinhmd.com/docs/new_products_to_add.json
Bruno Vassari Products:
/Users/tannguyen/Documents/fullstack/triseo.drmanhlinhmd.com/docs/bruno_vassari_wp_products.json

8.2 File Formats

Expected JSON Structure

[
  {
    "name": "Product Name",
    "slug": "product-slug",
    "sku": "PROD-001",
    "type": "simple",
    "description": "Full product description",
    "short_description": "Short excerpt",
    "price": "1000000",
    "sale_price": "990000",
    "manage_stock": true,
    "stock": 50,
    "categories": ["Category 1", "Category 2"],
    "image": "https://example.com/image.jpg",
    "images": [
      "https://example.com/image1.jpg",
      "https://example.com/image2.jpg"
    ],
    "attributes": [
      {
        "name": "Color",
        "value": "Red",
        "visible": true,
        "variation": false
      }
    ]
  }
]

8.3 Quick Reference Commands

# List all products
wp wc product list --fields=id,name,sku,price,stock --path=/path/to/wordpress

# Get product by SKU
wp wc product get --sku=BRUNO-001 --path=/path/to/wordpress

# Delete all products (DANGER!)
wp wc product delete $(wp wc product list --format=ids --path=/path/to/wordpress) --force

# Export products to CSV
wp wc product export --path=/path/to/wordpress > products_export.csv

# Count products
wp wc product list --format=count --path=/path/to/wordpress

9. Best Practices

βœ… DO:

  • Always backup before importing
  • Test with 2-5 products first
  • Use unique SKUs
  • Optimize images before import (max 1500px, under 500KB)
  • Clean data before import (remove special chars, trim spaces)
  • Use background processing for >100 products
  • Monitor server resources during import
  • Keep import logs for troubleshooting

❌ DON’T:

  • Import thousands of products without testing
  • Use spaces or special chars in SKUs
  • Skip category creation
  • Ignore error messages
  • Import during peak traffic hours
  • Forget to clear cache after import
  • Assume everything worked without verification

10. Support Resources

Documentation: Tools: Community:
  • WordPress.org Forums
  • WooCommerce Slack Community
  • Stack Overflow (tag: woocommerce)

Appendix A: Import Workflow Checklist

Before Import:

  • Backup database
  • Backup uploads folder
  • Verify image URLs accessible
  • Create all categories
  • Test with 1-2 products
  • Review JSON structure
  • Clean data (remove duplicates, fix SKUs)

During Import:

  • Monitor progress
  • Check for errors
  • Verify server resources
  • Watch error logs

After Import:

  • Verify product count
  • Check sample products
  • Test prices (regular & sale)
  • Verify categories
  • Test product pages
  • Check images load
  • Update inventory
  • Clear cache
  • Test checkout
  • Revoke API keys (if used)

End of Guide For questions or issues, refer to troubleshooting section or consult WordPress/WooCommerce documentation.