Our Partner & Developer boards on the community are moving to a brand new home: the .dev community forums! While you can still access past discussions here, for all your future app and storefront building questions, head over to the new forums.

Is there a way for me to overwrite existing media when updating a product via GraphQL api?

Is there a way for me to overwrite existing media when updating a product via GraphQL api?

PriLopes
Shopify Partner
13 0 16

I'm starting a new integration using graphql api and I need to run frequent media updates, but when I use the `media` input field it only appends the new content instead of overwriting the previous one. But in my case I need to actually replace the old ones with new ones.

 

If I have to delete the old ones before updating then it is 2 extra api calls (one to get old media ids and another one to delete it) but we have the rate limits so I would like to avoid calls like this whenever it is posible.

Replies 12 (12)

PriLopes
Shopify Partner
13 0 16

In the end I just want to make it work like old `images` 

tggdev
Shopify Partner
1 0 4

I'm interesting in a solution for this as well.

 

I need to do bulk image updates constantly to keep them in sync with correct images, but to first have to download all images, save IDs, then do anther call to delete them is very inefficient and is not going to work for thousands of products.

There isn't even an option to run a productDeleteMedia mutation in a bulk operation.

Zakaria
Shopify Partner
15 0 6

I also would be interested in a solution or in not deprecating the `images` field on the product and `imageSrc` on the product variants. The `images` field behaviour is ideal for syncing engines, since it allows to always override the existing images.

Beehive Apps Founder - Currently building Bundle Bee, the best quantity breaks, free gifts and bundles app.

Axel29
Shopify Partner
3 0 4

As far as I know, there's no simple way to manage product medias anymore since the version 2023-07.

As mentioned, the "images" field was perfect as it would allow not only to replace every images with the new ones, but it also allowed us to manage the sort order.

 

Now, the only solution I see is:

 

1. Store the medias in the app's database

2. On every sync, detect any creation, update or deletion for each media

3. Call the productDeleteMedia mutation to delete all medias (if need to have a specific sort order, or else only add the deleted medias in the variables)

4. Call the productCreateMedia mutation to recreate every media.

 

But this is really not optimal as it makes 3 API calls (productUpdate + productDeleteMedia + productCreateMedia) instead of only one (productUpdate), we need to store the medias in the app's database and detect any change etc.

 

Shopify really needs to improve this new "media" variable to at least manage the creation, update and deletion of medias, and add a sortOrder field too!

den232
Shopify Partner
220 8 56

productUpdateMedia might do it for you ... you do need the (old) mediaIds to replace ... jb

Axel29
Shopify Partner
3 0 4

That's the thing, we need to call separate APIs to do a single action: update a product with its medias at once, like we did before with the "images" field.

den232
Shopify Partner
220 8 56

Ayup, You are totally right.  But both mutations can be in one API call.   Cheers jb

Axel29
Shopify Partner
3 0 4

Except when doing bulk operations, or am I missing something?

den232
Shopify Partner
220 8 56

Not sure about bulk operations, but in one-by-one operations, there is another gotcha:

 

The mediaIds must be available for the productUpdateMedia mutation, but these ids will change when you replace the media

 

So ... you have to get new mediaIds (as you say) for every change.  

 

The catch is that it will take another API call entirely to store these new mediaIds, whether in the app's database or in a metafield of the product itself.

 

Do I have it right?  I can't see any route to avoiding multiple API interactions:

 

A path with 3 API steps:

1. get old mediaIds from database,

2. update media and get new mediaIds, 

3. store new mediaIds in database for next time

 

A path with 2 API steps:

1. Query product to get old mediaIds

2. productUpdateMedia using those mediaIds (do not record them)

 

phrtaylor
Shopify Partner
2 0 0

I am new to Shopfy and trying to update Media. 

For some reason, I can't even get the old media ids.

I wish we had a 'replaceMedia' method  

den232
Shopify Partner
220 8 56

Hi Taylor,

There is no replaceMedia method of which I am aware.  I get the old media ids, create new ones, delete the old ones (by id).  To get the mediaIds, I use this query:

 

  const query = `query Query_Initial_State (
        $ancestorFullId: ID!,
      ) {
      product (id: $ancestorFullId) {
        media (first: 20) { nodes { ... on MediaImage { id } } }
      }
    }
  `
  const variables = {
    ancestorFullId: "gid://shopify/Product/1234567890",
  };
 
Best of luck!  jb
 
phrtaylor
Shopify Partner
2 0 0

I have made many attempts to retrieve the media, but I always get an empty result.
Note: I can see the products have existing media in the back end.

Note: I can also retrieve the product its self, just not the media.

This is my first interaction with graphql and the shopify API, so I am starting from zero.

I started by generating an app template with the CLI and now am modifying it to do bulk product updates.

Thanks for your help.
```

  const fetchShopifyProductMedia = async (productId: string) => {
    // const response = await admin.graphql(
    //   `#graphql
    //   query {
    //     product(id: "${productId}") {
    //       title
    //       media(first: 5) {
    //         edges {
    //           node {
    //             ...fieldsForMediaTypes
    //           }
    //         }
    //       }
    //     }
    //   }

    //   fragment fieldsForMediaTypes on Media {
    //     alt
    //     status
    //     MediaImage {
    //       id
    //       image {
    //         altText
    //         originalSrc
    //       }
    //     }
    //   }`,
    // );

    // const response = await admin.graphql(
    //   `#graphql
    //   query {
    //     product(id: "${productId}") {
    //       images (first:10) {
    //         edges {
    //           node {
    //             id
    //             url
    //           }
    //         }
    //       }
    //       media(first: 10) {
    //         edges {
    //           node {
    //             id
    //             ... on MediaImage {
    //               id
    //               image {
    //                 id
    //                 url
    //               }
    //               mediaContentType
    //               originalSource {
    //                 fileSize
    //               }
    //             }
    //           }
    //         }
    //       }
    //     }
    //    }`,
    // );

    const response = await admin.graphql(
      `#graphql
      query Query_Initial_State (
      $ancestorFullId: ID!,
    ) {
        product (id: $ancestorFullId) {
          media (first: 20) { nodes { ... on MediaImage { id } } }
        }
      }
    `,
      {
        variables: {
          ancestorFullId: productId,
        },
      },
    );
    return await response.json();
  };

  const fetchShopifyProductMedia = async (productId: string) => {
    // const response = await admin.graphql(
    //   `#graphql
    //   query {
    //     product(id: "${productId}") {
    //       title
    //       media(first: 5) {
    //         edges {
    //           node {
    //             ...fieldsForMediaTypes
    //           }
    //         }
    //       }
    //     }
    //   }
    //   fragment fieldsForMediaTypes on Media {
    //     alt
    //     status
    //     MediaImage {
    //       id
    //       image {
    //         altText
    //         originalSrc
    //       }
    //     }
    //   }`,
    // );

    // const response = await admin.graphql(
    //   `#graphql
    //   query {
    //     product(id: "${productId}") {
    //       images (first:10) {
    //         edges {
    //           node {
    //             id
    //             url
    //           }
    //         }
    //       }
    //       media(first: 10) {
    //         edges {
    //           node {
    //             id
    //             ... on MediaImage {
    //               id
    //               image {
    //                 id
    //                 url
    //               }
    //               mediaContentType
    //               originalSource {
    //                 fileSize
    //               }
    //             }
    //           }
    //         }
    //       }
    //     }
    //    }`,
    // );

    const response = await admin.graphql(
      `#graphql
      query Query_Initial_State (
      $ancestorFullId: ID!,
    ) {
        product (id: $ancestorFullId) {
          media (first: 20) { nodes { ... on MediaImage { id } } }
        }
      }
    `,
      {
        variables: {
          ancestorFullId: productId,
        },
      },
    );
    return await response.json();
  };
```