Group documents by Autocomplete Tags in Structure Builder

By RD Pennell

The Autocomplete Tags plugin allows you to add an array of 'tag' strings to your document but grouping documents by those tags in your Desk Structure can present a challenge.

deskStructure.js

import S from '@sanity/desk-tool/structure-builder'
import postsByTag from './postsByTag'

export default () =>
  S.list()
    .title('Base')
    .items([
      postsByTag,
      ...S.documentTypeListItems()
    ])

postsByTag.js

import S from '@sanity/base/structure-builder'
import documentStore from 'part:@sanity/base/datastore/document'
import { map } from 'rxjs/operators'

// Get all an array of all tags defined on all 'post' type
const query = `*[_type == 'post' && count(tags) > 0].tags[]`

export default S.listItem()
  .title('Posts by Tag')
  .child(() =>
    // By using documentStore.listenQuery, our panes will automatically show any new documents or tags we create
    documentStore.listenQuery(query).pipe(
      map(tags => {

        //filter the array of tags to remove duplicate objects
        const uniqueTags = tags.filter((value, index) => {
          const _value = JSON.stringify(value)
          return index === tags.findIndex(obj => {
            return JSON.stringify(obj) === _value
          })
        })

        return S.list()
          .title('Posts By Tag')
          .items([
            ...uniqueTags.map(tag => { 
              return S.listItem()
              .title(tag[0].label)
              .child(
                S.documentList()
                  .title(tag[0].label)
                  .filter(`_type == 'post' && $tag in tags[].value`)
                  .params({ tag: tag[0].value })
              )}
            )
          ])}
       )
     )
   )

Dynamically grouping documents based off a reference is well documented in this handy guide, however, it requires you to be able to pass a document type to iterate over.

In order to group items by the tags created by the Autocomplete Tags plugin, we need to use some Javascript to fetch all of the tags that are defined for a given document type, remove any duplicate tags from the array, then render a list of all of the documents that contain a given tag. As a bonus, this setup will listen for any new tags you create or documents you publish and automatically update the Structure without requiring a manual refresh.

Looking at the source code of the plugin, all tags are tied to a document type, so you'll need to provide a type any time you use this. I've used my 'post' type in this example.

**Note: creating a new document from one of the child panes this generates will not preserve the context in the Desk Structure. All of the preceding panes will close.

Contributor

Other schemas by author