Files

6.2 KiB

name, category, description
name category description
atomk-to-woocommerce cross-border-ecommerce Claim products from AtomK, generate AI listing data, and publish them to WooCommerce via REST API.

AtomK → WooCommerce Product Publishing

Automates the full pipeline: log into AtomK, claim products from the Product Pool, generate AI listing data, and publish them to an existing WooCommerce store via its REST API.

Prerequisites

  • Node.js Playwright at /home/ubuntu/.hermes/hermes-agent/node_modules/playwright
  • sharp npm package installed for image resizing
  • Python with requests and Pillow packages
  • AtomK credentials: admincao / Tt123456!
  • An existing WooCommerce instance (e.g. us1.atomk.cn)

Step 1: Claim Products from AtomK & Generate AI Data

Use the atomk-bulk-claim skill approach. Key points for this workflow:

export NODE_PATH=/home/ubuntu/.hermes/hermes-agent/node_modules
node /path/to/atomk_claim_script.js

Script essentials:

  • Login at https://atomlisting.com/login (press Enter on password field, do NOT click login button)
  • Navigate to https://atomlisting.com/products
  • Select category via select element (e.g. 家居百货)
  • Click 认领并编辑 buttons
  • For each claimed product (URL contains /editor/{id}):
    • Click a platform tab (速卖通 / Temu / 亚马逊 / TikTok Shop / etc.)
    • Click AI 生成 and poll until text no longer contains 生成中
    • Extract: title, description, price, keywords, image URLs, weight/dimensions
  • Save results to JSON (e.g. /tmp/atomk_claimed_products.json)

Step 2: Prepare WooCommerce API Access

Discover the WooCommerce instance

Check for existing containers:

sudo docker ps --filter name=wordpress

Check Caddyfile for domain:

sudo docker exec <caddy_container> cat /etc/caddy/Caddyfile

Verify the store:

curl -s -L https://<domain>/wp-json/ | head -5

Generate API Keys programmatically

Critical: Find the actual admin username first — it may NOT be admin.

# List WP users
sudo docker exec <wpcli_container> wp user list --format=csv --fields=user_login,user_email

# Generate WooCommerce API key pair
sudo docker exec <wpcli_container> wp eval '
if (function_exists("wc_rand_hash")) {
  $u = get_user_by("login","admincao");   # <-- use actual username
  if ($u) {
    global $wpdb;
    $ck = "ck_" . wc_rand_hash();
    $cs = "cs_" . wc_rand_hash();
    $wpdb->insert($wpdb->prefix . "woocommerce_api_keys", [
      "user_id" => $u->ID,
      "description" => "Auto API Key",
      "permissions" => "read_write",
      "consumer_key" => wc_api_hash($ck),
      "consumer_secret" => $cs,
      "truncated_key" => substr($ck, -7)
    ]);
    echo "CONSUMER_KEY:" . $ck . "\nCONSUMER_SECRET:" . $cs . "\n";
  } else { echo "user not found\n"; }
} else { echo "wc functions not found\n"; }
'

Step 3: Publish to WooCommerce

Python publisher script

import json, os, requests
from io import BytesIO
from PIL import Image

WC_URL = "https://us1.atomk.cn/wp-json/wc/v3"
CK = "ck_..."
CS = "cs_..."

def resize_image(data):
    img = Image.open(BytesIO(data)).convert("RGB")
    img = img.resize((800, 800), Image.LANCZOS)
    out = BytesIO()
    img.save(out, format="JPEG", quality=90)
    out.seek(0)
    return out.read()

def create_product(data, image_url):
    url = f"{WC_URL}/products"
    payload = {
        "name": data.get("title", data.get("productCode")),
        "type": "simple",
        "regular_price": data.get("price", "10.00"),
        "description": data.get("description", ""),
        "short_description": data.get("keywords", ""),
        "images": [{"src": image_url}],
        "manage_stock": False,
        "stock_status": "instock",
        "status": "publish",
        "tags": [{"name": t.strip()} for t in data.get("keywords", "").split(",") if t.strip()]
    }
    r = requests.post(url, auth=(CK, CS), json=payload)
    if r.status_code in (200, 201):
        return r.json().get("id"), r.json().get("permalink")
    else:
        print(f"Failed: {r.status_code} {r.text[:500]}")
        return None, None

def main():
    with open("/tmp/atomk_claimed_products.json") as f:
        products = json.load(f)

    for p in products:
        code = p.get("productCode")
        imgs = p.get("images", [])
        if not imgs:
            continue
        # Download first image
        r = requests.get(imgs[0], timeout=30)
        r.raise_for_status()
        # Resize
        resized = resize_image(r.content)
        # Save locally
        path = f"/tmp/wc_images/{code}_800x800.jpg"
        os.makedirs("/tmp/wc_images", exist_ok=True)
        with open(path, "wb") as f:
            f.write(resized)
        # Publish (use external image URL; media upload via WP REST often 401 with WC creds)
        pid, url = create_product(p, imgs[0])
        print(f"Created {code} -> ID={pid} {url}")

if __name__ == "__main__":
    main()

Pitfalls & Lessons Learned

  • WP admin username discovery: The WooCommerce container on this system uses admincao as the WP admin, not admin. Always run wp user list first.
  • WP REST media upload 401: Uploading images via /wp-json/wp/v2/media using WooCommerce consumer key/secret often fails with invalid_username. The workaround is to pass the external image URL directly in the product images array as { "src": "https://..." }; WooCommerce will download and attach it automatically.
  • Image resizing: AtomK images may be large or in webp format. Always convert to 800x800 JPEG before referencing, or let WooCommerce handle the external URL and resize server-side.
  • HTTPS cert: atomlisting.com has a cert mismatch; ignoreHTTPSErrors: true is required at both chromium.launch() and browser.newContext() levels.
  • Login trap: The login form has method="get". Clicking the button submits GET to login? and stays on the page. Press Enter on the password field to trigger the correct JS POST handler.
  • Platform tab order: In the AtomK editor, click the platform tab FIRST, THEN click AI 生成. The button text changes to reflect the selected platform.

Verification

List published products:

curl -s -u 'CK:CS' 'https://us1.atomk.cn/wp-json/wc/v3/products?per_page=10'