npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

sanity-plugin-search-listing

v1.0.7

Published

A small Sanity Studio SEO search listing field.

Readme

sanity-plugin-search-listing

A small Sanity Studio plugin for editing how a document appears in search results.

It registers a single seo object type with four fields:

  • image - the social sharing image
  • title - the page title shown in search results
  • description - the meta description shown in search results
  • url - an optional URL handle override

The plugin also adds a compact search listing preview above the editable fields. Editors can see the current title, description, URL, image, and common fallbacks without leaving the document form.

When a document does not have an SEO URL, document slug, or storefront slug yet, the URL handle field shows a visual fallback slugified from the document title. This does not save a slug value; it only previews the URL an automatic slug function could create later.

Why this design

Most projects need the same SEO fields on pages, products, posts, collections, and global settings. This plugin keeps that shape reusable without turning SEO into a large framework.

vs. copying an SEO object into every schema

  • One shared seo type instead of repeating fields across documents.
  • One preview UI everywhere the type is used.
  • One place to adjust character counts, fallbacks, and image presentation.

vs. a highly configurable SEO plugin

  • Only one plugin option: siteName.
  • No project-specific routes, document types, or frontend assumptions.
  • The stored value stays plain Sanity data that your frontend can query however it wants.

Installation

npm install sanity-plugin-search-listing

Usage

Add the plugin to sanity.config.ts:

import {defineConfig} from 'sanity'
import {searchListing} from 'sanity-plugin-search-listing'

export default defineConfig({
  // ...
  plugins: [
    searchListing({
      siteName: 'Your Site Name',
    }),
  ],
})

Use the seo type anywhere in your schema:

import {defineField, defineType} from 'sanity'

export const page = defineType({
  name: 'page',
  title: 'Page',
  type: 'document',
  fields: [
    defineField({
      name: 'seo',
      title: 'Search engine listing',
      type: 'seo',
      options: {
        pathPrefix: '/',
      },
    }),
  ],
})

Set options.pathPrefix on each schema field when a document type needs a route prefix in the preview:

defineField({
  name: 'seo',
  title: 'Search engine listing',
  type: 'seo',
  group: 'seo',
  options: {
    pathPrefix: '/products/',
  },
})

Common storefront patterns:

// page
options: {
  pathPrefix: '/'
}

// product
options: {
  pathPrefix: '/products/'
}

// collection
options: {
  pathPrefix: '/collections/'
}

Stored Value

A saved search listing value looks like this:

type SearchListingValue = {
  _type?: 'seo'
  image?: unknown
  title?: string | null
  description?: string | null
  url?: {
    _type?: 'slug'
    current?: string | null
  } | null
}

The plugin does not generate frontend metadata for you. It gives editors a consistent object, then lets your GROQ projection and frontend decide how that object becomes <title>, meta tags, Open Graph tags, and canonical URLs.

Querying Search Listings

Project the fields your frontend needs:

*[_type == "page" && slug.current == $slug][0] {
  title,
  slug,
  seo {
    image,
    title,
    description,
    url
  }
}

Then resolve fallbacks in your app:

type Page = {
  title?: string | null
  slug?: {current?: string | null} | null
  seo?: SearchListingValue | null
}

function resolveMetadata(page: Page) {
  return {
    title: page.seo?.title || page.title,
    description: page.seo?.description,
    slug: page.seo?.url?.current || page.slug?.current,
    image: page.seo?.image,
  }
}

The Studio preview uses similar fallbacks for common fields like title, description, body, and Shopify-style store data. Your frontend can keep those rules, simplify them, or replace them completely.