Agent skill

framer-core-workflow-a

Execute Framer primary workflow: Core Workflow A. Use when implementing primary use case, building main features, or core integration tasks. Trigger with phrases like "framer main workflow", "primary task with framer".

Stars 1,803
Forks 241

Install this agent skill to your Project

npx add-skill https://github.com/jeremylongshore/claude-code-plugins-plus-skills/tree/main/plugins/saas-packs/framer-pack/skills/framer-core-workflow-a

SKILL.md

Framer CMS Plugin — Managed Collections

Overview

Build a Framer plugin that syncs external data into CMS Managed Collections. Managed Collections are plugin-controlled — your plugin creates the schema and populates items. This is the primary integration pattern for connecting Framer to external CMSes, databases, or APIs.

Prerequisites

  • Completed framer-install-auth setup
  • Plugin dev server running
  • Understanding of Framer CMS concepts

Instructions

Step 1: Create a Managed Collection

tsx
// src/App.tsx — CMS sync plugin
import { framer } from 'framer-plugin';
import { useState } from 'react';

framer.showUI({ width: 340, height: 400, title: 'Content Sync' });

export function App() {
  const [status, setStatus] = useState('');

  const syncCollection = async () => {
    setStatus('Fetching data...');
    const response = await fetch('https://jsonplaceholder.typicode.com/posts');
    const posts = await response.json();

    setStatus('Creating collection...');
    const collection = await framer.createManagedCollection({
      name: 'Blog Posts',
      fields: [
        { id: 'title', name: 'Title', type: 'string' },
        { id: 'body', name: 'Body', type: 'formattedText' },
        { id: 'author', name: 'Author', type: 'string' },
        { id: 'slug', name: 'Slug', type: 'slug', userEditable: false },
      ],
    });

    setStatus(`Syncing ${posts.length} items...`);
    const items = posts.slice(0, 20).map((post: any) => ({
      fieldData: {
        title: post.title,
        body: `<p>${post.body}</p>`,
        author: `User ${post.userId}`,
        slug: post.title.toLowerCase().replace(/[^a-z0-9]+/g, '-').slice(0, 50),
      },
    }));

    await collection.setItems(items);
    setStatus(`Synced ${items.length} posts`);
    framer.notify(`Synced ${items.length} blog posts`);
  };

  return (
    <div style={{ padding: 16 }}>
      <h3>Blog Post Sync</h3>
      <button onClick={syncCollection} style={{ width: '100%', padding: 8 }}>Sync Now</button>
      {status && <p style={{ marginTop: 8, fontSize: 13, color: '#666' }}>{status}</p>}
    </div>
  );
}

Step 2: Handle CMS Field Types

typescript
// Framer CMS field types reference
const fields = [
  { id: 'title', name: 'Title', type: 'string' as const },
  { id: 'content', name: 'Content', type: 'formattedText' as const },
  { id: 'price', name: 'Price', type: 'number' as const },
  { id: 'featured', name: 'Featured', type: 'boolean' as const },
  { id: 'publishDate', name: 'Published', type: 'date' as const },
  { id: 'heroImage', name: 'Hero', type: 'image' as const },
  { id: 'category', name: 'Category', type: 'enum' as const, cases: [
    { id: 'tech', name: 'Technology' },
    { id: 'design', name: 'Design' },
  ]},
  { id: 'slug', name: 'Slug', type: 'slug' as const, userEditable: false },
];

Step 3: Incremental Sync with Change Detection

typescript
async function incrementalSync(collection: ManagedCollection, newData: any[]) {
  const existing = await collection.getItems();
  const existingMap = new Map(existing.map(i => [i.fieldData.slug, i]));
  const toUpsert = newData.map(item => {
    const match = existingMap.get(item.slug);
    return match ? { ...item, id: match.id } : item;
  });
  await collection.setItems(toUpsert);
}

Step 4: Unmanaged Collection Access

typescript
// Read from user-created CMS collections (not plugin-managed)
const collections = await framer.getCollections();
for (const col of collections) {
  if (col.type === 'unmanaged') {
    const items = await col.getItems();
    console.log(`${col.name}: ${items.length} items`);
  }
}

Output

  • Managed CMS collection with typed fields
  • External data synced into Framer CMS
  • Incremental sync support
  • Image auto-upload from URLs

Error Handling

Error Cause Solution
Collection exists Duplicate name Use getManagedCollection() first
Invalid field type Wrong type string Use: string, formattedText, number, boolean, date, image, enum, slug
Image upload failed URL not public Ensure images are publicly accessible
setItems timeout Too many items Batch into chunks of 100

Resources

Next Steps

For code components and overrides, see framer-core-workflow-b.

Expand your agent's capabilities with these related and highly-rated skills.

Didn't find tool you were looking for?

Be as detailed as possible for better results