Кастомні плагіни Sanity Studio: коли стандартних інструментів недостатньо
У реальному проєкті завжди не вистачає пари екшенів, окремого дашборду або кастомної мітки. Один із клієнтів — медіа-сайт із 50+ редакторами — витрачав щоденно 4 години на пошук дублікатів SEO-полів. Ми розробили кастомний дашборд, який за секунду підсвічує проблемні документи. Результат: час на аудит скоротився в 3 рази, ручні перевірки — на 70%. Економія бюджету на підтримку контенту — до $15,000 на рік при штаті з 10 редакторів, окупність протягом 2-3 місяців.
Ми розробляємо npm-пакети, які розширюють Studio новими інструментами, полями, діями та компонентами — під ключ, за 4-6 днів. Оцінимо ваш проєкт і запропонуємо оптимальне рішення. Зв'яжіться з нами для консультації.
Коли потрібен кастомний плагін?
Стандартна Sanity Studio не показує метрики контенту, не генерує slug автоматично і не попереджає про відсутність метаданих. Кастомний плагін вирішує ці завдання без встановлення десятка розрізнених розширень. Згідно з документацією Sanity з плагінів, плагіни — це npm-пакети, які додають у Studio нові можливості без зміни ядра. Наш досвід: 5+ років роботи з Sanity, понад 20 реалізованих плагінів для медіа, e-commerce та корпоративних порталів. Гарантуємо стабільність і сумісність з актуальною версією (3.x).
Як створити власний інструмент у Sanity Studio?
Плагін Sanity Studio — npm-пакет, що додає в Studio нові інструменти (tools), поля, документ-в'юхи, компоненти, дії. Плагін реєструється в sanity.config.ts через масив plugins. Офіційні плагіни (@sanity/vision, @sanity/media, @sanity/dashboard) побудовані за тією ж схемою. Але для специфічних завдань — наприклад, аналітики контенту або автоматичної генерації slug — доводиться писати свій.
definePlugin — основа
// src/index.ts
import { definePlugin } from 'sanity'
import { MyTool } from './components/MyTool'
import { additionalType } from './schema/additionalType'
import { publishWithSlugAction } from './actions/publishWithSlug'
import type { DocumentActionComponent } from 'sanity'
export interface MyPluginConfig {
apiEndpoint?: string
enableDashboard?: boolean
}
export const myPlugin = definePlugin<MyPluginConfig>((config = {}) => {
const { apiEndpoint = '/api', enableDashboard = true } = config
return {
name: 'my-plugin',
schema: {
types: [additionalType],
},
tools: enableDashboard
? [
{
name: 'my-dashboard',
title: 'Dashboard',
icon: () => '📊',
component: MyTool,
},
]
: [],
document: {
actions: (prev: DocumentActionComponent[], ctx: any) => {
if (ctx.schemaType === 'post') {
return [publishWithSlugAction, ...prev]
}
return prev
},
},
}
})
Які проблеми вирішують кастомні інструменти?
Стандартна Sanity Studio не показує, скільки постів містить дублікати SEO-полів. Ми створили дашборд, який за одне підключення виводить статистику: кількість опублікованих записів, чернеток і документів з відсутніми метаданими. Візуальний індикатор (зелений/червоний) допомагає редакторам одразу бачити проблемні картки.
Tool компонент (додатковий екран Studio)
// src/components/MyTool.tsx
import { useState, useEffect } from 'react'
import { useClient } from 'sanity'
export function MyTool() {
const client = useClient({ apiVersion: '2024-01-01' })
const [stats, setStats] = useState<any>(null)
const [loading, setLoading] = useState(true)
useEffect(() => {
async function fetchStats() {
const [posts, drafts] = await Promise.all([
client.fetch(`count(*[_type == "post" && !(_id in path("drafts.**"))])`),
client.fetch(`count(*[_type == "post" && _id in path("drafts.**"))])`),
])
const missingMeta = await client.fetch(`
*[_type == "post" && (!defined(seoTitle) || !defined(seoDescription))] {
_id, title, "slug": slug.current
}
`)
setStats({ posts, drafts, missingMeta })
setLoading(false)
}
fetchStats()
}, [client])
if (loading) return <div style={{ padding: 24 }}>Loading...</div>
return (
<div style={{ padding: 24 }}>
<h2>Content Dashboard</h2>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 16, marginBottom: 24 }}>
<StatCard label="Published posts" value={stats.posts} />
<StatCard label="Drafts" value={stats.drafts} />
<StatCard label="Missing SEO" value={stats.missingMeta.length} alert={stats.missingMeta.length > 0} />
</div>
{stats.missingMeta.length > 0 && (
<div>
<h3>Posts with missing SEO metadata</h3>
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
<thead>
<tr style={{ background: '#f5f5f5' }}>
<th style={{ padding: '8px', textAlign: 'left' }}>Title</th>
<th style={{ padding: '8px', textAlign: 'left' }}>Slug</th>
</tr>
</thead>
<tbody>
{stats.missingMeta.map((post: any) => (
<tr key={post._id} style={{ borderTop: '1px solid #eee' }}>
<td style={{ padding: '8px' }}>{post.title}</td>
<td style={{ padding: '8px' }}>/posts/{post.slug}</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
)
}
const StatCard = ({ label, value, alert }: { label: string; value: number; alert?: boolean }) => (
<div style={{
padding: 16,
border: `1px solid ${alert ? '#ff6b6b' : '#e0e0e0'}`,
borderRadius: 8,
background: alert ? '#fff5f5' : 'white',
}}>
<div style={{ fontSize: 32, fontWeight: 700, color: alert ? '#e53e3e' : 'inherit' }}>{value}</div>
<div style={{ fontSize: 13, color: '#666' }}>{label}</div>
</div>
)
Document Action (кастомна дія у формі)
// src/actions/publishWithSlug.ts
import { useDocumentOperation } from 'sanity'
import type { DocumentActionProps, DocumentActionComponent } from 'sanity'
export const publishWithSlugAction: DocumentActionComponent = (props: DocumentActionProps) => {
const { patch, publish } = useDocumentOperation(props.id, props.type)
const { draft } = props
return {
label: 'Publish',
icon: () => '🚀',
disabled: !draft || publish.disabled,
onHandle: async () => {
// Генерувати slug якщо відсутній
if (!draft?.slug?.current && draft?.title) {
const slug = (draft.title as string)
.toLowerCase()
.replace(/\s+/g, '-')
.replace(/[^\w-]/g, '')
patch.execute([{ set: { slug: { _type: 'slug', current: slug } } }])
// Зачекати застосування патча
await new Promise(r => setTimeout(r, 100))
}
publish.execute()
props.onComplete()
},
}
}
Крім actions, можна додавати Document Badge — мітку на картці документа, яка показує статус SEO-заповненості. Це візуально покращує UX редактора. У плагіні badge реєструється в document.badges за аналогією з actions. Кастомні документ-в'юхи дозволяють створювати окремі представлення для різних типів контенту.
| Тип плагіна | Що дає | Приклад завдання |
|---|---|---|
| Дашборд аналітики | Зведення по контенту з GROQ-запитами | Контроль дублікатів SEO |
| Кастомні actions | Додаткові кнопки у формі | Авто-генерація slug |
| Document badges | Візуальні мітки на картках | Індикатор заповненості метаданих |
| Інструменти | Новий розділ у навігації Studio | Модерація коментарів |
Чому кастомний плагін ефективніший за готове рішення?
Built-in інструменти Sanity надають мінімум. Наприклад, стандартний інспектор не рахує документи з пропущеними полями. Кастомний плагін робить це за секунду, використовуючи GROQ-запити та React-компоненти. Порівняння: готове розширення вирішує одне завдання, кастомний плагін закриває цілий клас проблем. На практиці це знижує вартість підтримки контенту в 2-3 рази і окупається за 2-3 місяці.
Публікація плагіна як npm-пакета
// package.json
{
"name": "sanity-plugin-content-dashboard",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"sanityExchangeUrl": "https://www.sanity.io/plugins/...",
"keywords": ["sanity", "sanity-plugin"],
"peerDependencies": {
"sanity": "^3.0.0",
"react": "^18.0.0"
},
"scripts": {
"build": "plugin-kit verify-package && pkg-utils build",
"watch": "pkg-utils watch"
}
}
Приклад оцінки складності плагіна
При оцінці ми враховуємо кількість інструментів, дій, badge та їхні взаємозв'язки. Простий дашборд з однією метрикою — 2-3 дні. Плагін з кастомними діями та badge — 4-6 днів. Складні інтеграції з зовнішніми API — до 10 днів. Точний термін називаємо після брифу.Процес роботи
- Аналітика — вивчаємо поточну схему та бізнес-процеси, складаємо специфікацію.
- Проектування — описуємо структуру плагіна, інтерфейси, взаємодію з API.
- Розробка — пишемо код, використовуємо TypeScript, React, Sanity SDK.
- Тестування — перевіряємо на вашому контенті, покриваємо кейси з помилками.
- Деплой — публікуємо в npm registry, підключаємо до вашого проєкту.
Що входить у роботу
- Вихідний код плагіна з коментарями.
- Документація з конфігурації та встановлення.
- Навчання команди (1 година онлайн).
- Підтримка 30 днів після здачі.
Терміни
Розробка плагіна з дашбордом, кастомними actions та badges — 4–6 днів. Для оцінки вашого проєкту зв'яжіться з нами: ми проаналізуємо завдання і запропонуємо варіанти.
| Компонент | Built-in | Custom plugin |
|---|---|---|
| Дашборд аналітики | Немає | Так, з будь-якою метрикою |
| SEO-перевірка | Немає | Так, з візуальною індикацією |
| Actions | Стандартні 4 | Будь-які, з доступом до groq-запитів |
| Badges | Немає | Так, кольорові мітки статусу |
Отримайте консультацію прямо зараз. Замовте кастомний плагін Sanity Studio — отримайте інструмент, який точно вирішує ваше завдання. Оцінимо проєкт протягом 1 робочого дня. Зв'яжіться з нами — розкажемо, як розширити можливості вашої студії.







