Goodbye product.published = false: Unpublishing in Shopify's GraphQL Admin API

Hey fellow store owners and developers!

If you've been dipping your toes into Shopify's GraphQL Admin API or are planning a full migration from the trusty old REST API, you've probably run into a few "wait, how do I do that now?" moments. One common head-scratcher that popped up in our community recently was around unpublishing products. Remember how straightforward it was with REST? Just set product.published = false, and poof, it was gone from your storefront.

But as one of our community members, lkates, pointed out, that familiar product.published field just isn't there in GraphQL. So, what's the new way to "unpublish" a product? Let's dive into what the experts in the thread shared and get you sorted.

The GraphQL Shift: It's All About 'Publications' Now

The biggest conceptual shift when moving to GraphQL for publishing/unpublishing is understanding 'publications'. Unlike the old binary "published or not published" status that applied broadly, GraphQL thinks in terms of specific sales channels. Your product isn't just "published"; it's published to your Online Store, or to your Buy Button channel, or to your Facebook Shop, etc.

This means that to unpublish something, you need to tell Shopify which publication (i.e., sales channel) you want to remove it from. This is where the publicationId comes into play.

Finding Your Publication IDs

Before you can unpublish anything, you need to know the IDs of the sales channels you want to affect. As tim_tairli wisely pointed out in the thread, there are a couple of ways to get these:

1. Querying All Available Publications

This is often the easiest way to see all your active sales channels and their corresponding IDs. You can run a simple GraphQL query:

query GetPublicationIDs {
  publications(first: 10) {
    nodes {
      id
      name
    }
  }
}

This query will return a list of your sales channels (like "Online Store") and their respective ids. Most stores will have "Online Store" at a minimum.

Here's a visual example shared in the discussion:

2. From a Specific Product's Data

If you're already querying a product, you can also find its publication IDs within the resourcePublicationsV2 field:

  • Product.resourcePublicationsV2.nodes.publication.id

The New Way to Unpublish: Using publishableUnpublish

Once you have the productId and the relevant publicationId, you're ready to unpublish. The key mutation here is publishableUnpublish. As Moeed clearly laid out, you can't just say "unpublish everywhere" in one go; you'll typically call this mutation for each specific publication you want to remove the product from.

Step-by-Step Unpublishing

  1. Get your productId: This is the global ID for the product you want to unpublish (e.g., gid://shopify/Product/108828309).
  2. Get your publicationId(s): Use the query above to find the ID for the sales channel you wish to unpublish from (e.g., gid://shopify/Publication/762454635 for your Online Store).
  3. Execute the mutation: Use the publishableUnpublish mutation like this:
mutation PublishableUnpublish($productId: ID!, $publicationId: ID!) {
  publishableUnpublish(id: $productId, input: { publicationId: $publicationId }) {
    publishable {
      publishedOnPublication(publicationId: $publicationId)
    }
    userErrors {
      field
      message
    }
  }
}

And your variables would look something like this:

{
  "productId": "gid://shopify/Product/108828309",
  "publicationId": "gid://shopify/Publication/762454635"
}

This mutation will remove the product from the specified sales channel. If you have multiple channels and want to unpublish from all of them, you'll need to loop through your publicationIds and call this mutation for each one.

A Crucial Distinction: Hiding vs. Archiving/Drafting

Moeed made a really important point that's worth reiterating. There's a difference between:

  • Hiding a product from sales channels (publishableUnpublish): This is what we've been discussing. The product still exists in your Shopify admin, its status (active, draft, archived) remains unchanged, but it's no longer visible or purchasable on the specified storefronts. This is the direct equivalent of the old REST API's product.published = false.
  • Changing a product's overall status (productUpdate with status: DRAFT or status: ARCHIVED): If you want to take a product offline entirely, making it a draft or archiving it, that's a different action. You'd use the productUpdate mutation and set its status field accordingly. This changes the product's lifecycle state within your admin, not just its visibility on channels.

So, if your goal is simply to make a product disappear from your storefronts while keeping it "active" in your admin for future use, publishableUnpublish is your go-to.

Migrating to GraphQL definitely requires a bit of a mindset shift, especially with how publishing and product states are managed. But once you understand the concept of publications and know which mutations to use, it becomes quite powerful and flexible. Thanks to the community, especially tim_tairli and Moeed, for shedding light on this crucial migration step. Happy coding!

Share:

Use cases

Explore use cases

Agencies, store owners, enterprise — find the migration path that fits.

Explore use cases