# PayloadCMS Skill for QwenClaw ## Overview This skill provides **PayloadCMS expertise** to QwenClaw, enabling it to build, configure, and extend Payload CMS projects. Payload is an open-source, fullstack Next.js framework that gives you instant backend superpowers. **Source:** https://github.com/payloadcms/payload --- ## What is PayloadCMS? **Payload** is a Next.js native CMS that can be installed directly in your existing `/app` folder. It provides: - Full TypeScript backend and admin panel instantly - Server components to extend Payload UI - Direct database queries in server components (no REST/GraphQL needed) - Automatic TypeScript types for your data ### Key Features - **Next.js Native** - Runs inside your `/app` folder - **TypeScript First** - Automatic type generation - **Authentication** - Built-in auth out of the box - **Versions & Drafts** - Content versioning support - **Localization** - Multi-language content - **Block-Based Layout** - Visual page builder - **Customizable Admin** - React-based admin panel - **Lexical Editor** - Modern rich text editor - **Access Control** - Granular permissions - **Hooks** - Document and field-level hooks - **High Performance** - Optimized API - **Security** - HTTP-only cookies, CSRF protection --- ## Installation ### Create New Project ```bash # Basic installation pnpx create-payload-app@latest # With website template (recommended) pnpx create-payload-app@latest -t website # From example npx create-payload-app --example example_name ``` ### Project Structure ``` my-payload-app/ ├── app/ │ ├── (payload)/ │ │ ├── admin/ │ │ ├── api/ │ │ └── layout.tsx │ └── (frontend)/ │ ├── page.tsx │ └── layout.tsx ├── collections/ │ ├── Users.ts │ └── Posts.ts ├── payload.config.ts ├── payload-types.ts └── package.json ``` --- ## Collections & Schemas ### Basic Collection ```typescript // collections/Posts.ts import type { CollectionConfig } from 'payload'; export const Posts: CollectionConfig = { slug: 'posts', admin: { useAsTitle: 'title', }, access: { read: () => true, }, fields: [ { name: 'title', type: 'text', required: true, }, { name: 'content', type: 'richText', required: true, }, { name: 'publishedAt', type: 'date', admin: { date: { pickerAppearance: 'dayAndTime', }, }, }, { name: 'status', type: 'select', options: [ { label: 'Draft', value: 'draft' }, { label: 'Published', value: 'published' }, ], defaultValue: 'draft', }, ], }; ``` ### Collection with Relationships ```typescript // collections/Authors.ts export const Authors: CollectionConfig = { slug: 'authors', admin: { useAsTitle: 'name', }, fields: [ { name: 'name', type: 'text', required: true, }, { name: 'email', type: 'email', required: true, }, { name: 'avatar', type: 'upload', relationTo: 'media', }, ], }; // In Posts collection { name: 'author', type: 'relationship', relationTo: 'authors', } ``` ### Blocks Field (Page Builder) ```typescript { name: 'layout', type: 'blocks', blocks: [ { slug: 'hero', fields: [ { name: 'title', type: 'text', }, { name: 'subtitle', type: 'text', }, { name: 'backgroundImage', type: 'upload', relationTo: 'media', }, ], }, { slug: 'content', fields: [ { name: 'content', type: 'richText', }, ], }, { slug: 'cta', fields: [ { name: 'title', type: 'text', }, { name: 'buttonText', type: 'text', }, { name: 'buttonUrl', type: 'text', }, ], }, ], } ``` --- ## Access Control ### Field-Level Access ```typescript { name: 'isFeatured', type: 'checkbox', access: { read: () => true, update: ({ req }) => req.user?.role === 'admin', }, } ``` ### Collection Access ```typescript access: { read: () => true, create: ({ req }) => req.user?.role === 'admin', update: ({ req }) => req.user?.role === 'admin', delete: ({ req }) => req.user?.role === 'admin', } ``` --- ## Hooks ### Before Change Hook ```typescript { name: 'slug', type: 'text', hooks: { beforeChange: [ ({ value, data }) => { if (!value && data.title) { return data.title .toLowerCase() .replace(/[^a-z0-9]+/g, '-') .replace(/(^-|-$)/g, ''); } return value; }, ], }, } ``` ### After Change Hook ```typescript hooks: { afterChange: [ async ({ doc, req, operation }) => { if (operation === 'create') { // Send welcome email await sendWelcomeEmail(doc.email); } return doc; }, ], } ``` --- ## Localization ```typescript const config: Config = { localization: { locales: [ { code: 'en', label: 'English' }, { code: 'es', label: 'Spanish' }, { code: 'fr', label: 'French' }, ], defaultLocale: 'en', }, // ... }; ``` --- ## Using Payload in Server Components ### Query Collection ```typescript import { getPayload } from 'payload'; import config from '@payload-config'; export default async function PostsPage() { const payload = await getPayload({ config }); const posts = await payload.find({ collection: 'posts', where: { status: { equals: 'published' }, }, sort: '-publishedAt', limit: 10, }); return (
{posts.docs.map(post => (

{post.title}

{post.content}

))}
); } ``` ### Query by ID ```typescript const post = await payload.findByID({ collection: 'posts', id: postId, depth: 2, // Populate relationships }); ``` --- ## VPS Landing Page with PayloadCMS ### Collections for VPS Site ```typescript // collections/VpsPlans.ts export const VpsPlans: CollectionConfig = { slug: 'vps-plans', admin: { useAsTitle: 'name', }, access: { read: () => true, }, fields: [ { name: 'name', type: 'text', required: true, }, { name: 'price', type: 'number', required: true, }, { name: 'billingPeriod', type: 'select', options: ['monthly', 'yearly'], defaultValue: 'monthly', }, { name: 'vcpuCores', type: 'number', required: true, }, { name: 'ram', type: 'number', label: 'RAM (GB)', required: true, }, { name: 'storage', type: 'number', label: 'Storage (GB)', required: true, }, { name: 'bandwidth', type: 'text', label: 'Bandwidth', required: true, }, { name: 'features', type: 'array', fields: [ { name: 'feature', type: 'text', }, ], }, { name: 'isPopular', type: 'checkbox', defaultValue: false, }, { name: 'ctaText', type: 'text', defaultValue: 'Get Started', }, ], }; // collections/Features.ts export const Features: CollectionConfig = { slug: 'features', admin: { useAsTitle: 'title', }, access: { read: () => true, }, fields: [ { name: 'title', type: 'text', required: true, }, { name: 'description', type: 'richText', required: true, }, { name: 'icon', type: 'text', label: 'Icon Name (Bootstrap Icons)', }, { name: 'order', type: 'number', admin: { position: 'sidebar', }, }, ], }; // collections/Testimonials.ts export const Testimonials: CollectionConfig = { slug: 'testimonials', admin: { useAsTitle: 'authorName', }, access: { read: () => true, }, fields: [ { name: 'authorName', type: 'text', required: true, }, { name: 'authorTitle', type: 'text', }, { name: 'company', type: 'text', }, { name: 'quote', type: 'richText', required: true, }, { name: 'avatar', type: 'upload', relationTo: 'media', }, { name: 'rating', type: 'number', min: 1, max: 5, }, ], }; ``` ### Frontend Page Component ```typescript // app/(frontend)/page.tsx import { getPayload } from 'payload'; import config from '@payload-config'; import VpsPricing from './components/VpsPricing'; import FeaturesGrid from './components/FeaturesGrid'; export default async function HomePage() { const payload = await getPayload({ config }); const plans = await payload.find({ collection: 'vps-plans', sort: 'price', }); const features = await payload.find({ collection: 'features', sort: 'order', }); return (
); } ``` ### Pricing Component ```typescript // app/(frontend)/components/VpsPricing.tsx import type { VpsPlan } from '@payload-types'; interface VpsPricingProps { plans: VpsPlan[]; } export default function VpsPricing({ plans }: VpsPricingProps) { return (

Simple, Transparent Pricing

No hidden fees. Pay only for what you use.

{plans.map((plan) => (
{plan.isPopular && ( Most Popular )}

{plan.name}

${plan.price} /{plan.billingPeriod}
  • {plan.vcpuCores} vCPU Cores
  • {plan.ram} GB RAM
  • {plan.storage} GB NVMe Storage
  • {plan.bandwidth} Bandwidth
  • {plan.features?.map((feature, idx) => (
  • {feature.feature}
  • ))}
))}
); } ``` --- ## Payload Config Example ```typescript // payload.config.ts import { buildConfig } from 'payload'; import { lexicalEditor } from '@payloadcms/richtext-lexical'; import { mongooseAdapter } from '@payloadcms/db-mongodb'; import { nodemailerAdapter } from '@payloadcms/email-nodemailer'; import path from 'path'; import { fileURLToPath } from 'url'; import { Users } from './collections/Users'; import { VpsPlans } from './collections/VpsPlans'; import { Features } from './collections/Features'; import { Media } from './collections/Media'; const filename = fileURLToPath(import.meta.url); const dirname = path.dirname(filename); export default buildConfig({ admin: { user: Users.slug, importMap: { baseDir: path.resolve(dirname), }, }, collections: [ Users, VpsPlans, Features, Media, ], editor: lexicalEditor(), db: mongooseAdapter({ url: process.env.DATABASE_URI || '', }), email: nodemailerAdapter({ defaultFromAddress: 'noreply@example.com', defaultFromName: 'CloudVPS', }), typescript: { outputFile: path.resolve(dirname, 'payload-types.ts'), }, }); ``` --- ## Usage in QwenClaw ### Basic Payload Project Creation ``` Use the payloadcms-cms skill to create a new PayloadCMS project for a VPS hosting landing page with: - VPS plans collection (name, price, specs, features) - Features collection (title, description, icon) - Testimonials collection - Media library for images ``` ### Query Payload Data ``` Use payloadcms-cms to query all VPS plans sorted by price and display them in a pricing table ``` ### Create Collection ``` Use payloadcms-cms skill to create a new collection for data centers with: - name (text) - location (text) - region (select: US, EU, Asia) - features (array: DDoS protection, NVMe, 10Gbps) - latitude/longitude for map ``` --- ## Best Practices ### 1. Type Safety ```typescript // Always import generated types import type { Post, User } from '@payload-types'; ``` ### 2. Depth for Relationships ```typescript // Use depth to populate relationships const post = await payload.findByID({ collection: 'posts', id: postId, depth: 2, }); ``` ### 3. Access Control ```typescript // Always define access control access: { read: () => true, create: ({ req }) => !!req.user, update: ({ req }) => !!req.user, } ``` ### 4. Validation ```typescript // Add validation to fields { name: 'email', type: 'email', required: true, validate: (value) => { if (value && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) { return 'Invalid email format'; } return true; }, } ``` --- ## Resources ### Official - **Website**: https://payloadcms.com/ - **GitHub**: https://github.com/payloadcms/payload - **Documentation**: https://payloadcms.com/docs - **Examples**: https://github.com/payloadcms/payload/tree/main/examples ### Templates - **Website**: `pnpx create-payload-app@latest -t website` - **E-commerce**: `pnpx create-payload-app@latest -t ecommerce` - **Blank**: `pnpx create-payload-app@latest -t blank` --- ## Skill Metadata ```yaml name: payloadcms-cms version: 1.0.0 category: development description: PayloadCMS project creation, configuration, and development author: PayloadCMS Team (https://github.com/payloadcms) license: MIT tags: - cms - nextjs - typescript - react - backend - admin-panel ``` --- **Skill ready for QwenClaw integration!** 🚀