Skip to content
Development
Skill

/craftcms

Craft CMS 5 plugin and module development — extending Craft with PHP. Covers elements, element queries, services, models, records, controllers, migrations, queue jobs, console commands, field types, native fields, events, behaviors, Twig extensions, widgets, filesystems,

From plugin
craftcms-claude-skills
8013 skills6 agents
Install
$ npx -y skills add michtio/craftcms-claude-skills --skill craftcms --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/craftcms

Context preview

The summary Claude sees to decide when to auto-load this skill.

Craft CMS 5 plugin and module development — extending Craft with PHP. Covers elements, element queries, services, models, records, controllers, migrations, queue jobs, console commands, field types, native fields, events, behaviors, Twig extensions, widgets, filesystems,

SKILL.md

craftcms.SKILL.md
name: craftcms
description: "Craft CMS 5 plugin and module development — extending Craft with PHP. Covers elements, element queries, services, models, records, controllers, migrations, queue jobs, console commands, field types, native fields, events, behaviors, Twig extensions, widgets, filesystems, permissions, project config, GraphQL, testing, and debugging. Triggers on: beforePrepare()/afterSave()/defineSources()/defineTableAttributes()/attributeHtml(), MemoizableArray, BaseNativeField, EVENT_REGISTER_*/DEFINE_*/BEFORE_*/AFTER_*, CraftVariable, custom element or field type (normalizeValue/serializeValue/inputHtml), webhook, API endpoint, queue/batch job, CP section, dashboard widget, utility page, element action/exporter/condition, registerUserPermissions, requirePermission vs requireAdmin, kebab-case permission handles, allowAdminChanges, canView/canSave/canDelete, defineRules, elevated session, project-config/apply, drafts/revisions, element edit sidebar (EVENT_DEFINE_SIDEBAR_HTML) + toolbar buttons, metaFieldsHtml, VueAdminTable, GeneralConfig, getIsMultiSite/refreshSites stale after creating a site, deleteSite phantom sites, element query stops filtering by siteId, naive UTC datetime columns and strtotime drift, element-query ['like'] tuple matches nothing, configWarning config-file overrides. Always use when writing, editing, or reviewing Craft plugin/module PHP — even when no API is named. For plugin-specific work also load craft-plugins. Do NOT trigger for front-end Twig (craft-site) or content modeling (craft-content-modeling)."

Craft CMS 5 — Extending (Plugins & Modules)

Reference for extending Craft CMS 5 through plugins and modules. Covers everything from elements and services to controllers, migrations, fields, and events.

This skill is scoped to **extending** Craft — building plugins, modules, custom element types, field types, and backend integrations. For site/platform development (content modeling, sections, entry types, Twig templating, plugin selection), see the `craft-site` skill.

Companion Skills — Always Load Together

When this skill triggers, also load:

  • **`craft-php-guidelines`** — PHPDoc standards, section headers, naming conventions, class organization, ECS/PHPStan, verification checklist. Required for any PHP code.
  • **`ddev`** — All commands run through DDEV. Required for running ECS, PHPStan, scaffolding, and tests.
  • **`craft-garnish`** — When working on CP JavaScript, asset bundles, or interactive CP components. Covers Garnish's class system, UI widgets (Modal, HUD, DisclosureMenu, Select), drag system, and the Craft.* JS class pattern.
  • **`craft-pest`** — When writing, running, fixing, or reviewing tests. Covers the `markhuot/craft-pest-core` harness, database isolation (its rollback is opt-in and its env overrides are cwd-bound — both cause silent writes to the dev database), factories, HTTP/queue/DB assertions, and CI test jobs.
  • **`craft-cloud`** — When the project is hosted on Craft Cloud (detect via `craft-cloud.yaml` at the repo root or `craftcms/cloud` in `composer.json`). Required for plugin Cloud-compatibility constraints — `App::isEphemeral()` guards, asset-bundle CDN publishing, 15-minute queue-job cap, `csrfInput()` function over raw token output, and the `cloud/up` deploy lifecycle events.

Documentation

  • Extend guide: https://craftcms.com/docs/5.x/extend/
  • Class reference: https://docs.craftcms.com/api/v5/
  • Generator: https://craftcms.com/docs/5.x/extend/generator.html

Use `WebFetch` on specific doc pages when a reference file doesn't cover enough detail.

Common Pitfalls (Cross-Cutting)

  • Always use `addSelect()` in `beforePrepare()` — it's the Craft convention and safely additive when multiple extensions contribute columns.
  • Queue workers run in primary site context — use `->site('*')` for cross-site queries.
  • Including `id` in `getConfig()` — project config uses UIDs, never database IDs.
  • Business logic in models or controllers — services are where logic belongs.
  • Modules need manual template root, translation, and controllerNamespace registration — nothing is automatic.
  • `DateTimeHelper` in elements/queries, `Carbon` in services — never mix in the same class.
  • Hardcoding `/admin` in CP URLs — `cpTrigger` is configurable. Use `UrlHelper::cpUrl()` in PHP, `cpUrl()` in Twig.
  • Passing `$request->getBodyParams()` directly to `savePluginSettings()` on split-settings pages — only submitted keys persist, other settings are silently dropped. Load the full settings model first, update properties, then save.
  • **Naming a route or query param `token`** — it collides with Craft's reserved `tokenParam` and the request is rejected with a 400 before your controller runs. See `controllers.md` (Reserved request params).
  • Any non-underscore-prefixed template in a plugin's `templates/` dir is **directly routable in the CP**, bypassing your controller's `beforeAction()` gates. Underscore-prefix every template that isn't an intentional direct route. See `cp.md` (CP template routing bypasses controllers).

Reference Files

Read the relevant reference file(s) for your task. Multiple files often apply together.

**Task examples:**

  • "Build a custom element type" → read `elements.md` (Architecture section first) + `element-index.md` + `fields.md` + `migrations.md` + `cp.md`
  • "Build a hierarchical/tree element type" → read `elements.md` (Architecture: One Element Class with Native Structure)
  • "Add a webhook endpoint" → read `controllers.md` + `events.md`
  • "Create a queue job that syncs elements" → read `queue-jobs.md` + `elements.md` + `debugging.md`
  • "Add a settings page with form fields" → read `controllers.md` + `cp.md` + `architecture.md`
  • "Register a custom field type" → read `fields.md` + `events.md`
  • "Fix PHPStan errors" → read `quality.md`
  • "Add a dashboard widget" → read `cp-components.md` (Dashboard Widgets) + `events.md` (Widget Types section)
  • "Expose template variables for plugin users" → read `eve
Read more
Ships withcraftcms-claude-skills

Production-ready Claude Code skills, agents, and project templates for Craft CMS 5 development. Built and maintained by michtio.

Get the whole plugin

Other skills on craftcms-claude-skills.