Кастомні плагіни 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 робочого дня. Зв'яжіться з нами — розкажемо, як розширити можливості вашої студії.







