8 min read

How to Import Products into WooCommerce from a Datafeed XML

Shashank Dubey
Content & Marketing, Wbcom Designs · Published Jul 23, 2024 · Updated Aug 21, 2026
How to Import Products into WooCommerce from a Datafeed XML

WooCommerce cannot import XML on its own. The built-in importer under Products → All Products → Import reads CSV files only, so a supplier or affiliate datafeed delivered as XML needs either a conversion step or an importer that understands XML natively. In practice that means one of three routes: convert the XML to CSV and use the core importer, use WP All Import with its WooCommerce add-on, or write a small script against the REST API.

This guide covers all three, explains how to map the usual datafeed fields to WooCommerce product fields, and shows how to keep the import running on a schedule so prices and stock stay current. It reflects WooCommerce 11.0 (August 2026) and WP All Import 4.x.

What a product datafeed usually looks like

Most supplier and affiliate feeds (Awin, CJ, Tradedoubler, dropshipping wholesalers) follow the same shape: a root element, one repeating element per product, and a flat set of children inside it. A typical record:

<products>
  <product>
    <id>AX-1042</id>
    <name>Merino Crew Sweater</name>
    <description><![CDATA[Mid-weight merino...]]></description>
    <price>79.00</price>
    <sale_price>59.00</sale_price>
    <currency>GBP</currency>
    <stock>14</stock>
    <category>Clothing &gt; Knitwear</category>
    <brand>Axel</brand>
    <image>https://cdn.example.com/ax-1042.jpg</image>
    <url>https://example.com/p/ax-1042</url>
  </product>
</products>

Before choosing a tool, open the feed and answer four questions: What is the repeating element (here product)? Which field is unique and stable across runs (here id)? Are variations nested inside the product or listed as separate records? And how big is the file? A 2 MB feed and a 400 MB feed call for different approaches.

Route 1: Convert XML to CSV and use the core importer

The free option. It suits one-off imports of a few hundred to a few thousand simple products where you do not need the feed to re-run automatically.

Converting the file

Any spreadsheet can open a flat XML file (Excel via Data → From XML, LibreOffice Calc via the XML Source dialog), and a short Python script gives you more control over column names:

import csv, xml.etree.ElementTree as ET

tree = ET.parse('feed.xml')
rows = []
for p in tree.getroot().findall('product'):
    rows.append({
        'SKU':           p.findtext('id'),
        'Name':          p.findtext('name'),
        'Description':   p.findtext('description'),
        'Regular price': p.findtext('price'),
        'Sale price':    p.findtext('sale_price'),
        'Stock':         p.findtext('stock'),
        'Categories':    p.findtext('category'),
        'Images':        p.findtext('image'),
        'Published':     '1',
        'Type':          'simple',
    })

with open('products.csv', 'w', newline='', encoding='utf-8') as f:
    w = csv.DictWriter(f, fieldnames=rows[0].keys())
    w.writeheader()
    w.writerows(rows)

Use the column names from the WooCommerce product CSV schema so the importer maps them automatically. Save as UTF-8. Categories use > for hierarchy (“Clothing > Knitwear”), multiple values are comma separated, and booleans are 1 or 0.

Running the import

  1. Go to Products → All Products and click Import.
  2. Choose the CSV. Tick Update existing products if you are refreshing a catalogue you imported before; WooCommerce then matches on ID or SKU and skips rows that do not match.
  3. On the Column mapping screen, confirm each column or set it to “Do not import”.
  4. Click Run the importer and leave the tab open.

The core importer downloads images from the URLs in the Images column into the Media Library, but only from direct links. URLs that redirect through a tracking script fail. It also has no scheduling, so when the supplier updates prices tomorrow you will be converting and uploading again by hand. That is the reason most stores outgrow this route.

Route 2: WP All Import with the WooCommerce add-on

This is what we use on client stores that take a recurring supplier feed. WP All Import reads XML directly, lets you map fields by dragging elements onto a form, and can fetch the file from a URL or FTP on a schedule. The free version on WordPress.org handles simple products; variable products, URL imports and scheduling need the Pro edition plus the WooCommerce add-on. In mid 2026 the full Import Pro package with all add-ons lists at $199 per year, with the base Pro plugin at $149 per year.

Step by step

  1. All Import → New Import. Choose “Download a file” and paste the feed URL (or use FTP/SFTP credentials), then pick “New Items” and “WooCommerce Products” as the post type.
  2. Review Import File. WP All Import auto-detects the repeating element. If it picks the wrong node, change it here. Use “Manage Filtering Options” to skip records, for example stock greater than 0 only.
  3. Drag and Drop. Map the title and description, then open the WooCommerce Add-On section and drag price into Regular Price, sale_price into Sale Price, id into SKU, and stock into Stock Qty with Manage Stock set to Yes. Map category in the Taxonomies section with “>” as the hierarchy separator. Put image into Images (download from URL).
  4. Unique identifier. Do not click Auto-detect here. Type {id[1]} (the supplier’s stable ID). This is what lets subsequent runs update rather than duplicate.
  5. Import Settings. Tick “Create new products”, “Update existing products”, and decide on “Delete products that are no longer present in your file”. For a supplier feed we usually tick delete but change the action to “set to draft” or “mark as out of stock” rather than trashing, so URLs with inbound links survive. Under Scheduling Options, set the run frequency (daily at 3 am is typical).
  6. Confirm & Run. Review the summary, run it once manually, and spot-check ten products before trusting the schedule.

Price markups and currency

Supplier feeds give you cost price, not sell price. WP All Import lets you run PHP on any field inline, so a 35 percent markup rounded to .99 is:

[round({price[1]} * 1.35) - 0.01]

Do the same for currency conversion if the feed is in a different currency from your store, and pin the rate in the import rather than fetching it live, so the price does not change every night.

Variable products from flat feeds

Feeds list sizes and colours as separate records with a shared parent reference. In the WooCommerce Add-On section choose Variable product, then “Variable products are grouped by a shared value” and point it at the parent field (often group_id or parent_sku). WP All Import builds the parent and children in one run. Check attribute names match existing global attributes or you will end up with duplicated “Size” and “size” attributes.

Route 3: A custom script against the REST API

When the feed is very large, updates several times a day, or needs business logic a mapping UI cannot express (per-brand markups, supplier priority when two feeds carry the same SKU), a script wins. Parse the XML with a streaming parser, then push batches to /wp-json/wc/v3/products/batch, which accepts up to 100 create, update or delete operations per request.

The outline in PHP, run via WP-CLI on the server so you can skip HTTP entirely:

$reader = new XMLReader();
$reader->open( '/path/to/feed.xml' );

while ( $reader->read() ) {
    if ( XMLReader::ELEMENT !== $reader->nodeType || 'product' !== $reader->name ) {
        continue;
    }
    $node = simplexml_load_string( $reader->readOuterXml() );
    $sku  = sanitize_text_field( (string) $node->id );
    $pid  = wc_get_product_id_by_sku( $sku );
    $prod = $pid ? wc_get_product( $pid ) : new WC_Product_Simple();

    $prod->set_sku( $sku );
    $prod->set_name( sanitize_text_field( (string) $node->name ) );
    $prod->set_regular_price( wc_format_decimal( (string) $node->price ) );
    $prod->set_manage_stock( true );
    $prod->set_stock_quantity( absint( (string) $node->stock ) );
    $prod->save();
}

Wrap it in a WP-CLI command, log every SKU that fails, and run it from cron. Using WC_Product objects rather than raw wp_insert_post() keeps lookup tables and caches consistent, which matters when the store later enables HPOS-style product lookups or Analytics.

Comparing the three routes

Core CSV importerWP All Import + Woo add-onCustom script
Reads XML directlyNoYesYes
Scheduled re-runsNoYes (Pro)Yes (cron)
Variable productsYes, two-pass CSVYes (Pro)Yes, you write it
CostFree$149 to $199 per yearDeveloper time
Best forOne-off loads under ~5,000 rowsRecurring supplier feedsLarge feeds, complex rules, multiple suppliers

Mapping decisions that save pain later

  • Unique key. Always the supplier’s ID in the SKU field. If you sell from several suppliers, prefix it (AX-1042) to avoid collisions.
  • Categories. Map feed categories to your own structure with a lookup table instead of importing the supplier’s taxonomy as-is, otherwise you inherit 400 categories you never wanted.
  • Images. Import them once and do not re-download on every run. In WP All Import untick “Update images” in the update settings after the first import; in a script, skip image handling when the product already has a thumbnail.
  • Stock. Decide whether “missing from feed” means out of stock or unchanged. For a full catalogue feed it means out of stock; for a delta feed it means unchanged.
  • Descriptions. Supplier descriptions are duplicated across every store carrying the feed. Import them, but plan to rewrite the ones on products that matter for search.

Troubleshooting

  • Import times out. Raise PHP max_execution_time and memory, or better, switch to WP All Import’s cron mode or a WP-CLI script, neither of which depends on a browser tab.
  • Duplicates on the second run. The unique identifier changed between runs (auto-detect built it from the title). Set it to the supplier ID and re-run with “Update existing”.
  • Images missing. The URLs redirect or require a referrer. Test one with curl; if it does not return an image directly, the importer cannot fetch it.
  • Prices import as 0. The feed uses commas as decimal separators. Convert the value (str_replace(',', '.'...)) before mapping.
  • Categories nested wrong. The hierarchy separator in the feed (>, / or |) does not match the one you told the importer.

FAQ

Can WooCommerce import XML natively?

No. The core importer and exporter handle CSV only. XML always needs conversion or a third-party importer.

How often should a supplier feed run?

As often as the supplier updates it and no more. Daily for prices and catalogue, hourly for stock if they publish a separate stock feed. Hitting a 300 MB feed every 15 minutes helps nobody.

Will imported products affect site speed?

The products themselves no, but 50,000 media uploads in one night can fill disk and slow backups. Offload images to object storage or import them lazily.

Is there a way to sell affiliate feed products without importing them?

Set the product type to External/Affiliate and map the feed’s url to the Product URL field. Shoppers click through to the merchant, and you never handle stock or orders.

Where to start

If this is a one-time load, convert to CSV and use the core importer this afternoon. If the feed will change, install WP All Import, map it once carefully, and schedule it. When the feed is enormous or your pricing rules are complicated, a scripted import is cheaper over a year than fighting a UI. Our WooCommerce development team builds those scripted imports regularly, and for marketplaces that sell supplier catalogues through multiple vendors our StoreMate WCFM theme pairs with WCFM’s own vendor import tools.

Shashank Dubey
Content & Marketing, Wbcom Designs

Shashank Dubey, a contributor of Wbcom Designs is a blogger and a digital marketer. He writes articles associated with different niches such as WordPress, SEO, Marketing, CMS, Web Design, and Development, and many more.

Related reading