Skip to main content
SocialCutter

CMS and websites

Attach catalogue images to WooCommerce with SocialCutter

Upload the master to the media library or pass a public URL, generate the catalogue sizes with SocialCutter and attach them to a product over REST.

  • WooCommerce
  • WordPress
  • media library
  • REST API
  • Application Passwords
  • product gallery
  • PHP

Why pre-generate the catalogue sizes

A product page shows up in the grid, in search, in the cart and in ads, and each slot has its own ratio.

The flow is: one master goes in, SocialCutter returns every size, and WooCommerce gets the right one in each slot. The cover crop, the default mode, is centred: it scales and splits the excess evenly on both sides. Frame the master with some room around the edges.

Where it goes in the storeSocialCutter destinationSize
Main product imageinstagram post1080x1080 (1:1)
Variant or second portrait imageinstagram story1080x1920 (9:16)
Category bannerfacebook post1200x630 (1.91:1)
Store headertwitter header1500x500 (3:1)
Ad or marketplace listingfacebook story1080x1920 (9:16)

Sizes come from GET /api/v1/platforms, which is public.

WooCommerce already generates its own sizes

When an attachment is uploaded, WordPress and WooCommerce generate their thumbnails: grid, product page, cart. The widths live in Appearance → Customize → WooCommerce → Product Images and the cropping in Settings → Media: rules from the CMS, not from you.

Pre-generating with SocialCutter pays off when:

  • You need an exact size the CMS does not produce (1080x1920, 1500x500): the theme would crop to its own ratio.
  • You do not want to depend on regeneration: a theme change leaves thumbnails out of date.
  • You work in batches, with POST /api/v1/images/batch, preparing hundreds of products before touching the store.
  • The same master feeds external channels (marketplace, ads) with other formats.

For a square thumbnail in the grid, the CMS sizes are plenty.

Before you start

  • WordPress 5.6 or newer over HTTPS, for Application Passwords.
  • A SocialCutter sc_ key from Profile → API keys in the dashboard.
  • ck_ and cs_ keys from WooCommerce → Settings → Advanced → REST API.
export WP_URL="https://your-store.com"
export WP_USER="username"
export WP_APP_PASSWORD="abcd efgh ijkl mnop qrst uvwx"
export WC_CK="ck_..."
export WC_CS="cs_..."
export SC_KEY="sc_your_key"

1. The master: upload it to the media library or pass its URL

Media library route. The endpoint takes the file in the request body, with Content-Disposition for the name:

curl -s -X POST "$WP_URL/wp-json/wp/v2/media" \
  --user "$WP_USER:$WP_APP_PASSWORD" \
  -H "Content-Disposition: attachment; filename=master.jpg" \
  -H "Content-Type: image/jpeg" \
  --data-binary "@master.jpg" | jq -r '.id, .source_url'

They are created in Users → Profile → Application Passwords and travel over HTTP Basic: https://developer.wordpress.org/rest-api/reference/media/

Public URL route. If the master is already on a CDN, pass its URL as source.value and push only the outputs you will use.

2. Generate the sizes with SocialCutter

curl -s -X POST "https://api.socialcutter.theboomer.dev/api/v1/images/process" \
  -H "X-API-Key: $SC_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: product-99-catalogue" \
  -d '{
    "source": { "type": "url", "value": "https://your-cdn.com/master.jpg" },
    "destinations": [
      { "platform": "instagram", "format": "post" },
      { "platform": "instagram", "format": "story" }
    ]
  }' > sc.json

jq '.image_id, (.outputs[] | {url, platform, format, width, height})' sc.json

Every output is a public URL. Idempotency-Key makes retries safe. For a local file use POST /api/v1/images/process/upload (multipart, 5 MB maximum).

3. Attach the images to the product

The images field is a list: the first image is the main one and the rest form the gallery. Each entry accepts id (media library attachment) or src (a URL WooCommerce downloads), plus alt and position.

SQUARE=$(jq -r '.outputs[0].url' sc.json)
PORTRAIT=$(jq -r '.outputs[1].url' sc.json)

curl -s -X PUT "$WP_URL/wp-json/wc/v3/products/99" \
  --user "$WC_CK:$WC_CS" \
  -H "Content-Type: application/json" \
  -d "{
    \"images\": [
      { \"src\": \"$SQUARE\", \"alt\": \"T-shirt, front view\", \"position\": 0 },
      { \"src\": \"$PORTRAIT\", \"alt\": \"T-shirt, fabric detail\", \"position\": 1 }
    ]
  }" | jq '{id, images: [.images[] | {id, src, position}]}'

Swap src for id if the file is already in the media library so it is not duplicated. Docs: https://developer.woocommerce.com/docs/apis/rest-api/v3/products/ — fields change between releases: check the ones in your version.

4. PHP snippet with wp_remote_post

wp_remote_post is the standard WordPress function for calling external APIs and it accepts a method argument, which it forwards to wp_remote_request. That same call does the PUT to WooCommerce:

<?php
/**
 * Plugin Name: SocialCutter Catalogue
 * Description: Generates catalogue sizes and attaches them to a WooCommerce product.
 */

function sc_catalogue_sizes( int $product_id, string $master_url ): array {
    $response = wp_remote_post( 'https://api.socialcutter.theboomer.dev/api/v1/images/process', array(
        'timeout' => 30,
        'headers' => array(
            'X-API-Key'       => SOCIALCUTTER_API_KEY,
            'Content-Type'    => 'application/json',
            'Idempotency-Key' => 'product-' . $product_id,
        ),
        'body' => wp_json_encode( array(
            'source'       => array( 'type' => 'url', 'value' => $master_url ),
            'destinations' => array(
                array( 'platform' => 'instagram', 'format' => 'post' ),
                array( 'platform' => 'instagram', 'format' => 'story' ),
            ),
        ) ),
    ) );

    if ( is_wp_error( $response ) ) {
        return array( 'error' => $response->get_error_message() );
    }

    $outputs = json_decode( wp_remote_retrieve_body( $response ), true )['outputs'] ?? array();
    if ( ! $outputs ) {
        return array( 'error' => 'The API returned no outputs' );
    }

    $images = array();
    foreach ( $outputs as $output ) {
        $images[] = array( 'src' => $output['url'], 'alt' => get_the_title( $product_id ) );
    }

    $request = wp_remote_post(
        rest_url( 'wc/v3/products/' . $product_id ),
        array(
            'method'  => 'PUT', // wp_remote_post forwards 'method' to wp_remote_request.
            'timeout' => 30,
            'headers' => array(
                'Authorization' => 'Basic ' . base64_encode( WC_CK . ':' . WC_CS ),
                'Content-Type'  => 'application/json',
            ),
            'body'    => wp_json_encode( array( 'images' => $images ) ),
        )
    );

    return json_decode( wp_remote_retrieve_body( $request ), true )['images'] ?? array();
}

Define SOCIALCUTTER_API_KEY, WC_CK and WC_CS in wp-config.php, never in the theme. To attach from the media library, media_sideload_image( $url, $product_id, null, 'id' ) returns the attachment id.

5. No code: CSV importer and automators

The WooCommerce importer accepts an Images column with comma-separated URLs: it downloads them on import and builds the gallery in that order. Generate the sizes, build the CSV and use Products → Import. Reference: https://woocommerce.com/document/product-csv-import-suite-column-header-reference/

With n8n, Zapier or Make the pattern is one HTTP request step to /api/v1/images/process and another that updates the product: n8n automation guide.

Cost

  • 1 use per destination (platform and format) per request; repeated ones are not charged twice.
  • Failed processings are refunded.
  • Plans include API and MCP: Free 3 uses/day, Basic 10, Pro 30, Agency 100.

Common errors

SymptomCauseFix
401 from the media libraryApplication Password mistyped or site without HTTPSRegenerate the application password and check TLS
401 from /wc/v3/ck_/cs_ keys revoked or pasted wrongRecheck WooCommerce → Settings → Advanced → REST API
400 saying “image is invalid”src is not a public URL or not an imageCheck the URL points at a SocialCutter output
The main image is not the one you wantedOrder of the images listReorder with position; the first entry wins

Next steps

Frequently asked questions

Should I upload the master to WordPress or pass its URL?

Either works. If the master is already in the media library, send its source_url as source.value. If it lives on a CDN, pass the public URL and upload only the outputs you will actually use.

Does WooCommerce not generate its own sizes already?

It does, and for the catalogue grid and the product page they are usually enough. Pre-generate with SocialCutter when you need an exact size the CMS does not produce, when you do not want to depend on thumbnail regeneration, or when you process the catalogue in batches.

Does the images field expect an id or a URL?

Both. With id you reference an attachment already in the media library and the file is not duplicated; with src you pass a public URL and WooCommerce downloads it. The first entry in the list is the main image and the rest form the gallery.

Why is my 4:5 image cropped?

Because SocialCutter's destination catalogue does not include 4:5. The square option is 1:1 (1080x1080) and portrait is 9:16 (1080x1920). If you need exactly 4:5, crop outside SocialCutter.

What does it cost to prepare one product's images?

1 use per destination, meaning per platform and format pair. Instagram post and Instagram story from the same master spend 2 uses; repeated destinations in one request are not charged twice.