# Integrate SocialCutter with WordPress and WooCommerce
> Upload the master to WordPress over REST, generate every size with SocialCutter and set the right output as featured image. WooCommerce variant and PHP snippet.
- URL: https://socialcutter.theboomer.dev/en/guides/wordpress/
- Idioma: en
- Familia: cms
- Actualizado: 2026-09-24
- Palabras clave: WordPress, WooCommerce, REST API, Application Passwords, featured image, media library, PHP
## Why a single master image

The flow is: **you upload one master, SocialCutter returns one output per destination, and WordPress receives the right one in each slot**. The default `cover` fit mode is a **centred crop**: it scales the image and trims the excess evenly on both sides.

| Slot in WordPress | SocialCutter destination | Size |
|---|---|---|
| Post featured image | `linkedin` `post` | 1200x627 (1.91:1) |
| Image inside the content | `facebook` `post` | 1200x630 (1.91:1) |
| Social card for the post | `twitter` `post` | 1200x675 (16:9) |
| Theme header banner | `twitter` `header` | 1500x500 (3:1) |
| WooCommerce product (main) | `instagram` `post` | 1080x1080 (1:1) |
| Second product image | `instagram` `story` | 1080x1920 (9:16) |

## Before you start

- WordPress 5.6 or newer with HTTPS enabled (Application Passwords arrived in 5.6).
- A SocialCutter key created in the dashboard under **Profile → API keys**. It starts with `sc_` and is shown only once.
- For WooCommerce, REST API keys generated in **WooCommerce → Settings → Advanced → REST API**.

```bash
export WP_URL="https://your-blog.com"
export WP_USER="username"
export WP_APP_PASSWORD="abcd efgh ijkl mnop qrst uvwx"
export SC_KEY="sc_your_key"
```

## 1. Create an Application Password

In wp-admin go to **Users → Profile → Application Passwords**, give it a name such as `SocialCutter media bot` and copy the value: it is shown once.

It travels over **HTTP Basic Auth** (RFC 7617) on HTTPS; with `curl`, `--user` builds the base64 header for you:

```bash
curl -s --user "$WP_USER:$WP_APP_PASSWORD" "$WP_URL/wp-json/wp/v2/users/me" | jq '{id, name}'
```

Reference: https://developer.wordpress.org/advanced-administration/security/application-passwords/

## 2. Process the master with SocialCutter

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

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

The body is `source` plus `destinations`, and the response carries `image_id` with one URL per destination. For a local file use `POST /api/v1/images/process/upload` (multipart, 5 MB max).

## 3. Upload the output to the media library

The media endpoint takes the file **in the request body** as binary data, plus a `Content-Disposition` header with the filename:

```bash
curl -s -o cover.jpg "$(jq -r '.outputs[0].url' sc.json)"

curl -s -X POST "$WP_URL/wp-json/wp/v2/media" \
  --user "$WP_USER:$WP_APP_PASSWORD" \
  -H "Content-Disposition: attachment; filename=cover-1200x627.jpg" \
  -H "Content-Type: image/jpeg" \
  --data-binary "@cover.jpg" > media.json

jq '{id, source_url, media_type}' media.json
```

The response carries the attachment `id` and its `source_url`. `alt_text` goes in the same request or a later `POST` to `/wp-json/wp/v2/media/{id}`. Reference: https://developer.wordpress.org/rest-api/reference/media/

While uploading the attachment you can also link it to the post through the media item's own `post` field, defined as *The ID for the associated post of the attachment*. It makes the library show the related post without touching the post itself.

## 4. Set the featured image and the in-content image

The featured image is set by **identifier**, through the `featured_media` field, which the REST API reference defines as *The ID of the featured media for the post*. That field is accepted both when **creating** the post (`POST /wp-json/wp/v2/posts`) and when **updating** it (`POST /wp-json/wp/v2/posts/{id}`).

When creating the post, the attachment goes in the same request:

```bash
MEDIA_ID=$(jq -r '.id' media.json)

curl -s -X POST "$WP_URL/wp-json/wp/v2/posts" \
  --user "$WP_USER:$WP_APP_PASSWORD" \
  -H "Content-Type: application/json" \
  -d "{
    \"title\": \"Sample post\",
    \"status\": \"draft\",
    \"featured_media\": $MEDIA_ID
  }" | jq '{id, status, featured_media}'
```

If the post already exists, update it with the same field:

```bash
curl -s -X POST "$WP_URL/wp-json/wp/v2/posts/42" \
  --user "$WP_USER:$WP_APP_PASSWORD" \
  -H "Content-Type: application/json" \
  -d "{\"featured_media\": $MEDIA_ID}" | jq '{id, featured_media, link}'
```

What travels in `featured_media` is the **attachment ID**, never a URL. To verify the result without downloading the whole post, request only that field with the global `_fields` parameter:

```bash
curl -s --user "$WP_USER:$WP_APP_PASSWORD" \
  "$WP_URL/wp-json/wp/v2/posts/42?_fields=id,featured_media" | jq
```

Inside the content, use the attachment `source_url` in a plain `img` tag so the theme keeps control of its classes and `srcset`:

```html
<figure>
  <img src="https://your-blog.com/wp-content/uploads/2026/09/cover-1200x627.jpg"
       alt="Real description of the image" width="1200" height="627">
</figure>
```

Reference: https://developer.wordpress.org/rest-api/reference/posts/

## 5. Regenerate WordPress intermediate sizes

WordPress does not keep a single copy of each image: when you upload an attachment it generates several **intermediate sizes** (`thumbnail`, `medium`, `medium_large`, `large` and whatever the theme registers with `add_image_size`). Two details of `add_image_size( $name, $width, $height, $crop )` matter here:

- The names `thumb`, `thumbnail`, `medium`, `medium_large`, `large` and `post-thumbnail` are reserved.
- With `$crop = true` the crop is a **hard, centred crop**: the default position is `center` (or `array( 'left', 'top' )` to move it).

The catch: sizes are generated **when the file is uploaded**. If the theme changes its dimensions later, already-uploaded images keep the old crops and the theme starts asking for files that do not exist. The three typical cases are: a new size was added, you changed the dimensions of an existing one under **Settings → Media**, or you switched to a theme that uses featured images at a different size.

To find out what is missing, request the attachment in edit context. The media schema exposes the `missing_image_sizes` field (*List of the missing image sizes of the attachment*) and the size tree in `media_details`:

```bash
curl -s --user "$WP_USER:$WP_APP_PASSWORD" \
  "$WP_URL/wp-json/wp/v2/media/$MEDIA_ID?context=edit" \
  | jq '{id, missing_image_sizes, sizes: (.media_details.sizes | keys)}'
```

### With WP-CLI

`wp media regenerate` regenerates the thumbnails of one or more attachments:

```bash
# A single attachment
wp media regenerate 123

# A range of IDs
seq 1000 2000 | xargs wp media regenerate

# Only attachments that are missing sizes
wp media regenerate --only-missing

# A single size, without confirmation
wp media regenerate --image_size=large --yes

# The whole library
wp media regenerate --yes
```

Other options on the command: `--skip-delete` (keeps old files) and `--delete-unknown` (deletes files for sizes that are no longer registered). Reference: https://developer.wordpress.org/cli/commands/media/regenerate/

### With the Regenerate Thumbnails plugin

If you have no terminal access to the server, the **Regenerate Thumbnails** plugin does the same from the dashboard, under **Tools → Regenerate Thumbnails**, and also from the media list and each attachment's edit screen. It can additionally delete old, unused thumbnail files to free server space. The plugin page warns that it has not been tested with the last three major WordPress releases, and its own author recommends WP-CLI because it is faster since it skips the HTTP overhead. Reference: https://wordpress.org/plugins/regenerate-thumbnails/

### Where SocialCutter fits

Both methods above crop from the file that is already in the library. SocialCutter does it **before**: it produces the file already at the destination's proportion (`instagram` `post` at 1080x1080, `linkedin` `post` at 1200x627) and that file enters the library with the correct proportion. The `cover` crop, the default mode, is a **centred crop**, the same idea as the hard crop in `add_image_size`.

That means the intermediate size the theme requests is generated from an original that already has the right proportion, so WordPress's crop starts from a correct source instead of an image with a different ratio. And if the theme changes its dimensions later you still need `wp media regenerate`: the benefit is that your network crops are regenerated with SocialCutter and uploaded again, independent of whatever crop the theme made.

## 6. WooCommerce variant: the product gallery

WooCommerce exposes its own REST API under `/wp-json/wc/v3/`. A product has an `images` field that is a list: the first entry is the main image and the rest form the gallery. Each entry accepts `id` (an existing media attachment) or `src` (a URL WooCommerce downloads).

Upload the attachment to the WordPress media endpoint first and reference it by `id`, so the file is not duplicated:

```bash
GALLERY_ID=$(jq -r '.id' media.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\": [{\"id\": $GALLERY_ID, \"alt\": \"T-shirt, front view\"}]}" | jq '.id, .images'
```

It authenticates with the `ck_` and `cs_` keys over Basic Auth on HTTPS. Docs: https://developer.woocommerce.com/docs/apis/rest-api/v3/products/ — field names can change between releases, so check your version.

## 7. PHP snippet with wp_remote_post

`wp_remote_post` is WordPress's standard helper for external APIs. Paste this into a child theme's `functions.php` or ship it as a small plugin.

```php
<?php
/**
 * Plugin Name: SocialCutter Media
 * Description: Processes a master with SocialCutter and sets it as the featured image.
 * Version: 1.0.0
 */

function sc_process_master( int $post_id, string $master_url ): int|WP_Error {
    $key = defined( 'SOCIALCUTTER_API_KEY' ) ? SOCIALCUTTER_API_KEY : '';
    if ( '' === $key ) {
        return new WP_Error( 'sc_no_key', 'SOCIALCUTTER_API_KEY is missing' );
    }

    $response = wp_remote_post( 'https://api.socialcutter.theboomer.dev/api/v1/images/process', array(
        'timeout' => 30,
        'headers' => array( 'X-API-Key' => $key, 'Content-Type' => 'application/json' ),
        'body'    => wp_json_encode( array(
            'source'       => array( 'type' => 'url', 'value' => $master_url ),
            'destinations' => array( array( 'platform' => 'linkedin', 'format' => 'post' ) ),
        ) ),
    ) );

    if ( is_wp_error( $response ) ) {
        return $response;
    }

    $data = json_decode( wp_remote_retrieve_body( $response ), true );
    $url  = $data['outputs'][0]['url'] ?? '';

    require_once ABSPATH . 'wp-admin/includes/media.php';
    require_once ABSPATH . 'wp-admin/includes/file.php';
    require_once ABSPATH . 'wp-admin/includes/image.php';

    $attachment_id = media_sideload_image( $url, $post_id, null, 'id' );
    if ( is_wp_error( $attachment_id ) ) {
        return $attachment_id;
    }

    set_post_thumbnail( $post_id, $attachment_id );

    return (int) $attachment_id;
}
```

`media_sideload_image` downloads the URL into the library and returns the attachment ID when the fourth argument is `'id'`; `set_post_thumbnail` makes it the featured image. Keep the key in `wp-config.php` with `define( 'SOCIALCUTTER_API_KEY', 'sc_...' );`, never inside the theme.

## 8. No code: Zapier, Make and n8n

An automation tool does the same with nodes: a trigger, an HTTP node calling `/api/v1/images/process` and a WordPress or WooCommerce node that uploads the media and assigns it. The full flow is in the [n8n automation guide](/en/guides/n8n/); Zapier and Make follow the same pattern.

## Cost

- **1 use per destination** (platform and format) per request; duplicates are not charged twice.
- Failed processings are refunded.
- Every plan includes API and MCP: Free 3 uses/day, Basic 10, Pro 30, Agency 100.

## Common errors

| Symptom | Cause | Fix |
|---|---|---|
| `401` from WordPress | Mistyped application password, or a site without HTTPS | Regenerate the password and check TLS |
| `401` from SocialCutter | Missing, malformed or revoked key | Send `X-API-Key` with an active `sc_` key |
| `413` from SocialCutter | The master is over 5 MB | Shrink the image before uploading it |
| The featured image does not change | A URL was sent in `featured_media` | Send the attachment **ID**, not the URL |
| `400` creating the post | The `featured_media` ID does not exist or points at a deleted attachment | Check the `id` with `GET /wp-json/wp/v2/media/{id}` |
| The theme asks for a thumbnail that does not exist | The theme registered that size after the image was uploaded | Regenerate with `wp media regenerate --only-missing` or the Regenerate Thumbnails plugin |

## Next steps

- Shopify: [Integrate SocialCutter with the Shopify Admin API](/en/guides/shopify/)
- ERPNext: [Normalize catalogue images in ERPNext](/en/guides/erpnext/)
- MCP: [Use SocialCutter from your LLM or editor with MCP](/en/guides/mcp/)
- Terminal: [Process images with the API from the terminal (curl)](/en/guides/curl/)
- Automation: [Automate image resizing with n8n](/en/guides/n8n/)