MathieuAuclair
MathieuAuclair

Reputation: 1327

How to delete all products matching a collection - Shopify

I have this retarded amount of product in a collection on Shopify (over 50k products) and I would need to delete them all, is there a way I can automate that? All I can find on the internet is to use the "bulk edit tool" which is the most useless thing I've ever seen as it can only grab 50 products at a time.

I've tried automating a script to update the rows with the CSV export file, but it takes over 6 hours for 20K products to import. Plus, since there are hashtags in the title and handle, it apparently doesn't overwrite the products for some reason. So I just can't use the archive anymore...

Has anyone ran into this issue and found a solution?

Thank you!

Upvotes: 0

Views: 803

Answers (1)

drip
drip

Reputation: 12943

When it comes to this kinds of tasks I usually write myself a quick dev console script that will do the job for me instead of relying on an app.

Here is a script that you can use in the dev console of your shopify admin page (just copy /paste):

let productsArray = [];

// Recursive function that will grab all products from a collection
const requestCollection = (collectionId, url = `https://${window.location.host}/admin/api/2020-10/collections/${collectionId}/products.json?limit=250`) => {
    fetch(url).then(async res  => {
        const link = res.headers.get('link');
        const data = await res.json();
        productsArray = [...productsArray, ...data.products];

        if(link && link.match(/<([^\s]+)>;\srel="next"/)){
            const nextLink = link.match(/<([^\s]+)>;\srel="next"/)[1];
            requestCollection(collectionId, nextLink)
        } else {
            initDelete(productsArray)
        }
    })
}

// Get CSRF token or the request will require password
const getCSRFToken = () => fetch('/admin/settings/files',{
    headers: {
        "x-requested-with": "XMLHttpRequest",
        "x-shopify-web": 1,
        "x-xhr-referer": `https://${window.location.host}/admin/settings/files`
    }
}).then(res => res.text()).then(res => {
    const parser = new DOMParser();
    const doc = parser.parseFromString(res, 'text/html');
    return doc.querySelector('meta[name="csrf-token"]').getAttribute('content')
})

// The function that will start the deleting process
const initDelete = async (products) => {
    const csrfToken = await getCSRFToken();
    products.forEach(item => {
        fetch(`https://${window.location.host}/admin/api/2020-10/products/${item.id}.json`, {
            method: "delete",
            credentials: 'include',
            headers: {
                "x-csrf-token": csrfToken,
                "x-requested-with": "XMLHttpRequest",
                "x-shopify-web": 1,
                "x-xhr-referer": `https://${window.location.host}/admin/settings/files`
            }
        })
    })
}

And you start it by using requestCollection(ADD_YOUR_COLLECTION_ID_HERE).

To clarify the script, there are 3 main functions:

  • requestCollection - this handles the product grabbing from the collection. It's a recursive function since we can't grab more than 250 products at the same time.
  • getCSRFToken - this grabs the CSRF token since most of the post/update/delete request requires it or they will fail (I grab it from the files page)
  • initDelete - this function start the delete process where we stack all the request one of the other without waiting, you may want to await each request, but even if you crash your browser I think it will be still faster to repeat the process rather then wait for each request to finish.

If you plan to use this script please TEST IT BEFORE USING IT. Create a collection with a few products and run against that, in case there are issues. I've tested it on my side and it's working but it's a code I wrote in 10 minutes after midnight, there can be issues there.

Have in mind that this script will delete ALL products in the collection you specify in the requestCollection(1231254125) method.

PS: All of this can be done using a Private App as well with the products scope set to read/write, using a back-end language of your choice. The main difference will be that you won't need the CSRF token and most of the headers that I set above. But I like quick solutions that doesn't require you to pull out the big guns.

Upvotes: 1

Related Questions