disable the publish button for a subset of users while still allowing them to edit the content?

2 replies
Last updated: Sep 17, 2020
I am trying to disable the publish button for a subset of users while still allowing them to edit the content... Is this possible in sanity? Looking at the docs it seems like user permissions are based only on read/write for specific schema types defined in the group definition. Ultimately, I believe I am looking for a way to guard against certain users groups on the documentAction level... Any ideas on how to accomplish?
AI Update

Yes, this is absolutely possible! You can customize document actions to disable the publish button for specific user groups while keeping edit permissions intact. Here's how:

The Solution: Filter Document Actions Based on User Roles

You'll need to customize the document actions resolver in your Studio configuration. The key is accessing the currentUser from the context that's passed to your resolver function.

Here's a practical example:

// In your sanity.config.ts or sanity.config.js
import {defineConfig} from 'sanity'
import {PublishAction} from 'sanity'

export default defineConfig({
  // ... other config
  document: {
    actions: (prev, context) => {
      const {currentUser, schemaType} = context
      
      // Check if user has a specific role (adjust to match your role names)
      const isRestrictedUser = currentUser?.roles?.some(
        role => role.name === 'editor' || role.name === 'contributor'
      )
      
      // If restricted user, filter out the PublishAction
      if (isRestrictedUser) {
        return prev.filter(action => action !== PublishAction)
      }
      
      return prev
    }
  }
})

How This Works

The actions function receives two parameters:

  • prev - the default array of document actions
  • context - an object containing currentUser, schemaType, and other metadata

The currentUser object includes the user's roles, which you can check against your role definitions. You can then filter the actions array to remove PublishAction for specific users.

More Granular Control

You can make this even more sophisticated by combining user roles with document types:

actions: (prev, context) => {
  const {currentUser, schemaType} = context
  const isEditor = currentUser?.roles?.some(role => role.name === 'editor')
  
  // Only restrict publish on certain document types
  if (isEditor && ['article', 'page'].includes(schemaType)) {
    return prev.filter(action => action !== PublishAction)
  }
  
  return prev
}

Important Notes

You're correct that the core role-based permissions system in Sanity focuses on read/write access at the dataset and document type level. However, document actions operate at the Studio UI layer, giving you this additional control point.

Keep in mind: This approach hides the publish button in the Studio UI, but users with write permissions can still technically publish via the API if they have the appropriate dataset permissions. For true enforcement, you'd need to combine this with proper role configuration at the project level to ensure restricted users don't have publish permissions on the dataset itself.

The document actions customization is perfect for creating editorial workflows where some users can draft and edit content, while others (like admins or publishers) handle the actual publishing step.

Hi Sarah, you could set up a custom document action to limit publication to just the administrators on your team, for example:
// documentActions.js

import userStore from 'part:@sanity/base/user';
import { useDocumentOperation } from '@sanity/react-hooks';

const AdminPublish = (props) => {
  const { patch, publish } = useDocumentOperation(this.props.id, this.props.type)
  let buttonDisabled = true;
  const next = ({ user }) => {
    buttonDisabled = user.role !== 'administrator';
  }
  
  userStore.currentUser.subscribe({
    next,
    error: error => console.error(`Failed to get current user: ${error}`),
  })
  
  return {
    label: 'Admin-Publish',
    disabled: buttonDisabled,
    onHandle: () => {
      // Set publishedAt to current date and time
      patch.execute([{ set: { publishedAt: new Date().toISOString() } }])
      // Perform the publish
      publish.execute()
      // Signal that the action is completed
      this.props.onComplete()
      router.navigate('/')
    }
  }
}
export default withRouterHOC(AdminPublish)

// resolveDocumentActions.js

import defaultResolve, { PublishAction } from 'part:@sanity/base/document-actions'

import { AdminPublish } from './documentActions'

export default function resolveDocumentActions(props) {
  return defaultResolve(props)
  .map(Action =>
    Action === PublishAction ? AdminPublish : Action
  )
}

// sanity.json 
// ...

"parts": [ 
  //... 
  { 
    "implements": "part:@sanity/base/document-actions/resolver", 
    "path": "resolveDocumentActions.js" 
  } 
]
More info:
https://www.sanity.io/docs/document-actions
Awesome, thank you so much! This looks great, I will give it a try!

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?