{"id":"019f5204-76a8-42c5-a128-d1e501bc8c02","shortId":"cSwnhV","kind":"skill","title":"craftcms","tagline":"Craft CMS 5 plugin and module development — extending Craft with PHP. Covers the full extend surface: elements, element queries, services, models, records, project config, controllers, CP templates, migrations, queue jobs, console commands, field types, native fields, events, beh","description":"# Craft CMS 5 — Extending (Plugins & Modules)\n\nReference for extending Craft CMS 5 through plugins and modules. Covers everything from elements and services to controllers, migrations, fields, and events.\n\nThis 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.\n\n## Companion Skills — Always Load Together\n\nWhen this skill triggers, also load:\n\n- **`craft-php-guidelines`** — PHPDoc standards, section headers, naming conventions, class organization, ECS/PHPStan, verification checklist. Required for any PHP code.\n- **`ddev`** — All commands run through DDEV. Required for running ECS, PHPStan, scaffolding, and tests.\n- **`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.\n\n## Documentation\n\n- Extend guide: https://craftcms.com/docs/5.x/extend/\n- Class reference: https://docs.craftcms.com/api/v5/\n- Generator: https://craftcms.com/docs/5.x/extend/generator.html\n\nUse `WebFetch` on specific doc pages when a reference file doesn't cover enough detail.\n\n## Common Pitfalls (Cross-Cutting)\n\n- Always use `addSelect()` in `beforePrepare()` — it's the Craft convention and safely additive when multiple extensions contribute columns.\n- Queue workers run in primary site context — use `->site('*')` for cross-site queries.\n- Including `id` in `getConfig()` — project config uses UIDs, never database IDs.\n- Business logic in models or controllers — services are where logic belongs.\n- Modules need manual template root, translation, and controllerNamespace registration — nothing is automatic.\n- `DateTimeHelper` in elements/queries, `Carbon` in services — never mix in the same class.\n- Hardcoding `/admin` in CP URLs — `cpTrigger` is configurable. Use `UrlHelper::cpUrl()` in PHP, `cpUrl()` in Twig.\n- 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.\n\n## Reference Files\n\nRead the relevant reference file(s) for your task. Multiple files often apply together.\n\n**Task examples:**\n- \"Build a custom element type\" → read `elements.md` + `element-index.md` + `fields.md` + `migrations.md` + `cp.md`\n- \"Add a webhook endpoint\" → read `controllers.md` + `events.md`\n- \"Create a queue job that syncs elements\" → read `queue-jobs.md` + `elements.md` + `debugging.md`\n- \"Add a settings page with form fields\" → read `controllers.md` + `cp.md` + `architecture.md`\n- \"Register a custom field type\" → read `fields.md` + `events.md`\n- \"Fix PHPStan errors\" → read `quality.md`\n- \"Add a dashboard widget\" → read `cp.md` (Dashboard Widgets) + `events.md` (Widget Types section)\n- \"Expose template variables for plugin users\" → read `events.md` (Twig Extensions section)\n- \"Attach custom methods to entries\" → read `events.md` (Behaviors section)\n- \"Build a CP utility page\" → read `events.md` (Utilities section) + `cp.md`\n- \"Set up Vite for a plugin's CP assets\" → read `plugin-vite.md` + load `craft-garnish` skill\n- \"Add drag-to-reorder or interactive JS to a CP page\" → load `craft-garnish` skill\n- \"Write CP JavaScript for a custom field type\" → read `fields.md` + load `craft-garnish` skill\n- \"Build a headless Craft API\" → read `graphql.md` + load `craft-site` skill for `headless.md`\n- \"Configure preview for a Next.js front-end\" → load `craft-site` skill for `headless.md`\n- \"Set up Pest tests for a plugin\" → read `testing.md`\n- \"Write a test for a controller action\" → read `testing.md`\n- \"Configure Redis for caching and sessions\" → read `config-app.md`\n- \"Set up environment variables for production\" → read `config-bootstrap.md`\n- \"Find a GeneralConfig setting\" → read `config-general.md`\n- \"Read a config value in plugin code (App::env, parseEnv, GeneralConfig)\" → read `config-bootstrap.md` + `config-general.md`\n- \"Check if allowAdminChanges is enabled in plugin code\" → read `config-general.md` + `cp.md` (Read-Only Mode)\n- \"Resolve env vars in plugin settings ($MY_API_KEY)\" → read `config-bootstrap.md` (App::parseEnv)\n- \"Understand CRAFT_* env var conventions\" → read `config-bootstrap.md`\n- \"Configure mail transport / SMTP\" → read `config-app.md`\n- \"Set up custom URL routes\" → read `config-bootstrap.md`\n- \"Configure search to find short words\" → read `config-app.md`\n- \"Set up GraphQL tokens and schemas\" → read `graphql.md` + `config-general.md`\n- \"Set up caching for a high-traffic site\" → read `caching.md`\n- \"Register custom permissions for my plugin\" → read `permissions.md`\n- \"Check user permissions in templates\" → read `permissions.md`\n- \"Set up plugin editions / feature gating\" → read `architecture.md` (Plugin Editions section)\n- \"Upgrade a plugin from Craft 4 to 5\" → read `quality.md` (Rector section)\n- \"Set up CI for a Craft plugin\" → read `quality.md` (CI/CD Integration section)\n- \"Create sections or fields in a migration\" → read `migrations.md` (Content Migrations section)\n- \"Set up database read replicas\" → read `config-app.md` (Database Replicas section)\n- \"Register a module in app.php\" → read `config-app.md` (Module Registration section)\n- \"Create a custom validator\" → read `architecture.md` (Custom Validators section)\n- \"Create a custom filesystem type\" → read `events.md` (Filesystem Types section)\n- \"Build a custom condition rule for an element index\" → read `cp.md` (Condition Builders section)\n- \"Build a tri-state on/inherit/off control\" → read `cp.md` (CP UI Patterns — Tri-State Inheritance)\n- \"Add tabbed settings page to a plugin\" → read `cp.md` (Tabbed Settings Pages)\n- \"Show an 'overrides global' warning on a field\" → read `cp.md` (CP UI Patterns — Field Warning Parameter)\n- \"What CSS variables does Craft CP use?\" → read `cp.md` (CP UI Patterns — Craft CSS Custom Properties)\n- \"Set up pre-commit hooks for code quality\" → read `quality.md` (Pre-Commit Hooks section)\n- \"Restrict element access by user group\" → read `element-authorization.md` + `permissions.md`\n- \"Scope CP element index by permission\" → read `element-authorization.md` (Layer 3: Query Scoping)\n- \"Add authorization events to a custom element\" → read `element-authorization.md` + `elements.md`\n- \"Build defense-in-depth for a security plugin\" → read `element-authorization.md` (Defense Patterns)\n- \"Force-logout a user from all devices\" → read `sessions-and-auth.md` (Plugin Patterns)\n- \"Understand how Craft sessions work\" → read `sessions-and-auth.md`\n- \"Implement password reset required\" → read `sessions-and-auth.md` (passwordResetRequired Gap)\n- \"Add a column to the Users element index\" → read `element-index.md` (Extending Element Indexes via Events)\n- \"Add a bulk action to an element index\" → read `element-index.md` (Adding a custom bulk action)\n- \"Add a custom sidebar source to the element index\" → read `element-index.md` (Adding a sidebar source)\n- \"Build a custom field type\" → read `field-types-custom.md` + `fields.md`\n- \"Build a relation field type\" → read `field-types-custom.md` (Relation Fields)\n- \"Add a condition rule to the entry index\" → read `conditions.md` + `element-index.md`\n- \"Build a custom condition rule\" → read `conditions.md`\n- \"Send email from a plugin\" → read `email.md`\n- \"Register a custom system message\" → read `email.md` (Registering Custom System Messages)\n- \"Configure SMTP transport\" → read `config-app.md` + `email.md`\n- \"Deploy Craft CMS to production\" → read `deployment.md`\n- \"Set up CI/CD for a Craft project\" → read `deployment.md` (CI/CD Patterns)\n- \"Zero-downtime deploy\" → read `deployment.md` (Zero-Downtime)\n- \"Roll back a failed deploy\" → read `deployment.md` (Rollback Strategies)\n- \"Work with drafts and revisions\" → read `drafts-revisions.md`\n- \"Create a draft programmatically\" → read `drafts-revisions.md` (Creating Drafts)\n- \"Skip side effects for drafts in afterSave\" → read `drafts-revisions.md` (Plugin Considerations)\n- \"Add generated fields to a custom element\" → read `elements.md` (Generated Fields)\n- \"Customize how my element appears as a chip or card\" → read `element-index.md` (Element Display Modes)\n- \"Make plugin settings read-only when allowAdminChanges is off\" → read `cp.md` (Read-Only Mode)\n\n| Task | Read |\n|------|------|\n| Element core: lifecycle, queries, status, authorization, drafts, revisions, propagation, field layouts, events | `references/elements.md` |\n| Element index: sources, table/card attributes, sort, conditions, actions, exporters, sidebar, metadata, extending via events (columns, sources, bulk actions, condition rules, sort) | `references/element-index.md` |\n| Services, models, records, project config, MemoizableArray, events, API clients, custom validators | `references/architecture.md` |\n| Controllers: CP CRUD, webhooks, API endpoints, action routing, authorization | `references/controllers.md` |\n| CP templates, form macros, admin changes, VueAdminTable, asset bundles, CP layout, permissions. For CP JavaScript interactions, also load `craft-garnish` skill. | `references/cp.md` |\n| Database migrations, Install.php, foreign keys, indexes, idempotency, deployment | `references/migrations.md` |\n| Queue jobs, BaseJob, TTR, retry, progress, batch jobs, site context | `references/queue-jobs.md` |\n| Console commands, arguments, options, progress bars, output helpers, resave actions | `references/console-commands.md` |\n| Debugging, performance, query strategy, profiling, Xdebug, caching, logging | `references/debugging.md` |\n| PHPStan, ECS, code review checklist | `references/quality.md` |\n| Testing: Pest setup, element factories, HTTP/queue/DB assertions, mocking, multi-site, console, events | `references/testing.md` |\n| Field types, native fields, BaseNativeField, field layout elements, FieldLayoutBehavior | `references/fields.md` |\n| Events: registration, lifecycle, naming conventions, custom events, behaviors, Twig extensions, utilities, widgets, filesystems, discovering events | `references/events.md` |\n| GraphQL types, queries, mutations, directives, schema components, resolvers | `references/graphql.md` |\n| Plugin Vite: VitePluginService, CP asset bundles, HMR, TypeScript, Vue in CP | `references/plugin-vite.md` |\n| Headless & hybrid: headlessMode, GraphQL API, CORS, preview tokens, front-end frameworks | craft-site skill `references/headless.md` |\n| GeneralConfig (system, routing, security, users, sessions, search, assets, images) | `references/config-general.md` |\n| GeneralConfig (content, templates, performance, GC, localization, headless, GraphQL, accessibility, preview, dev, dangerous interactions) | `references/config-general-extended.md` |\n| App config: cache, session, queue, mutex, mailer/SMTP, search, logging, CORS, DB replicas, web/console split | `references/config-app.md` |\n| Config bootstrap: env vars, aliases, priority order, fluent API, custom.php, db.php, routes.php, htmlpurifier | `references/config-bootstrap.md` |\n| Caching: template cache tag, data cache, static caching (Blitz), CDN, layered strategy, invalidation | `references/caching.md` |\n| Permissions: built-in handles, user groups, custom registration, Twig/PHP checking, authorization events, strategies | `references/permissions.md` |\n| Element authorization: four-layer defense model, authorization events, can*() methods, EVENT_BEFORE_PREPARE query scoping, controller enforcement | `references/element-authorization.md` |\n| Sessions & auth internals: dual-layer session model, auth tokens, session invalidation, passwordResetRequired, elevated sessions, plugin patterns | `references/sessions-and-auth.md` |\n| Custom field types: build pattern, value lifecycle, settings, input HTML, validation, search, GraphQL, relation fields | `references/field-types-custom.md` |\n| Conditions framework: BaseCondition, ElementCondition, custom condition rules, registering rules, condition builder UI | `references/conditions.md` |\n| Email system: system messages, custom messages, programmatic sending, templates, events, testing | `references/email.md` |\n| Deployment: standard pipeline, project config deploy, zero-downtime, CI/CD, rollback, environment management | `references/deployment.md` |\n| Drafts & revisions: draft types, provisional drafts, autosave, applying, merge, revisions, plugin considerations | `references/drafts-revisions.md` |\n\n## Plugin vs Module Differences\n\nPlugins and modules share the same architecture patterns. The differences are in bootstrapping and registration:\n\n| Feature | Plugin | Module |\n|---------|--------|--------|\n| CP template root | Automatic (by handle) | Manual via `EVENT_REGISTER_CP_TEMPLATE_ROOTS` |\n| Site template root | Manual via event | Same — manual for both |\n| Translation category | Automatic (by handle) | Manual `PhpMessageSource` in `init()` |\n| Settings model | Built-in `createSettingsModel()` | Env vars, config files, or private plugin (`_` prefix) |\n| Install migration | `migrations/Install.php` | Content migrations only |\n| Console commands | Automatic `controllerNamespace` | Must set before `parent::init()`, must be bootstrapped |\n| CP nav section | `$hasCpSection = true` | `EVENT_REGISTER_CP_NAV_ITEMS` |\n| Project config | Settings auto-tracked | Manual `ProjectConfig::set()` only |\n| Namespace alias | Automatic via Composer | Must call `Craft::setAlias()` |\n\n### Module Template Root Registration\n\n```php\nuse craft\\events\\RegisterTemplateRootsEvent;\nuse craft\\web\\View;\n\nEvent::on(View::class, View::EVENT_REGISTER_CP_TEMPLATE_ROOTS,\n    function(RegisterTemplateRootsEvent $event) {\n        $event->roots['my-module'] = __DIR__ . '/templates';\n    }\n);\n```\n\n### Module Translation Registration\n\n```php\nCraft::$app->i18n->translations['my-module'] = [\n    'class' => \\craft\\i18n\\PhpMessageSource::class,\n    'sourceLanguage' => 'en',\n    'basePath' => __DIR__ . '/translations',\n    'allowOverrides' => true,\n];\n```\n\n### Module Console Command Registration\n\n```php\npublic function init()\n{\n    Craft::setAlias('@mymodule', __DIR__);\n\n    if (Craft::$app->getRequest()->getIsConsoleRequest()) {\n        $this->controllerNamespace = 'modules\\\\mymodule\\\\console\\\\controllers';\n    } else {\n        $this->controllerNamespace = 'modules\\\\mymodule\\\\controllers';\n    }\n\n    parent::init(); // MUST come after setting controllerNamespace\n}\n```\n\nThe module **must** be bootstrapped in `config/app.php` for console commands to be discoverable.","tags":["craftcms","claude","skills","michtio","agent-skills","claude-code","claude-code-plugin","claude-code-skills","claude-skills","content-modeling","craft-cms","craft-cms-5"],"capabilities":["skill","source-michtio","skill-craftcms","topic-agent-skills","topic-claude-code","topic-claude-code-plugin","topic-claude-code-skills","topic-claude-skills","topic-content-modeling","topic-craft-cms","topic-craft-cms-5","topic-craftcms","topic-ddev","topic-php","topic-twig"],"categories":["craftcms-claude-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/michtio/craftcms-claude-skills/craftcms","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add michtio/craftcms-claude-skills","source_repo":"https://github.com/michtio/craftcms-claude-skills","install_from":"skills.sh"}},"qualityScore":"0.469","qualityRationale":"deterministic score 0.47 from registry signals: · indexed on github topic:agent-skills · 39 github stars · SKILL.md body (14,628 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-01T18:56:49.059Z","embedding":null,"createdAt":"2026-04-18T22:19:37.015Z","updatedAt":"2026-05-01T18:56:49.059Z","lastSeenAt":"2026-05-01T18:56:49.059Z","tsv":"'/admin':296 '/api/v5/':192 '/docs/5.x/extend/':187 '/docs/5.x/extend/generator.html':196 '/templates':1671 '/translations':1692 '3':870 '4':692 '5':4,42,51,694 'access':854,1355 'action':546,941,952,1153,1163,1186,1242 'ad':948,964 'add':370,388,412,470,792,873,923,938,953,985,1089 'addit':229 'addselect':219 'admin':1194 'aftersav':1084 'alia':1631 'alias':1380 'allowadminchang':587,1122 'allowoverrid':1693 'also':113,1206 'alway':106,217 'api':506,607,1175,1184,1324,1384 'app':578,611,1361,1677,1709 'app.php':737 'appear':1104 'appli':355,1518 'architectur':1534 'architecture.md':398,683,748 'argument':1235 'assert':1265 'asset':157,462,1197,1312,1344 'attach':435 'attribut':1150 'auth':1439,1446 'author':874,1138,1188,1415,1420,1426 'auto':1624 'auto-track':1623 'automat':282,1549,1571,1600,1632 'autosav':1517 'back':1055 'backend':84 'bar':1238 'basecondit':1474 'basejob':1224 'basenativefield':1277 'basepath':1690 'batch':1228 'beforeprepar':221 'beh':39 'behavior':442,1290 'belong':270 'blitz':1398 'bootstrap':1377,1540,1609,1735 'build':75,359,444,502,762,776,883,968,976,996,1459 'builder':774,1482 'built':1406,1581 'built-in':1405,1580 'bulk':940,951,1162 'bundl':158,1198,1313 'busi':260 'cach':552,652,1250,1363,1390,1392,1395,1397 'caching.md':660 'call':1636 'carbon':286 'card':1109 'categori':1570 'cdn':1399 'chang':1195 'check':585,669,1414 'checklist':129,1257 'chip':1107 'ci':701 'ci/cd':708,1036,1043,1506 'class':125,166,180,188,294,1655,1683,1687 'client':1176 'cms':3,41,50,1029 'code':134,577,592,843,1255 'column':234,925,1160 'come':1727 'command':33,137,1234,1599,1697,1740 'commit':840,849 'common':212 'companion':104 'compon':162,1305 'compos':1634 'condit':765,773,987,999,1152,1164,1472,1477,1481 'conditions.md':994,1002 'config':25,254,573,1172,1362,1376,1501,1586,1621 'config-app.md':556,625,640,729,739,1025 'config-bootstrap.md':564,583,610,619,632 'config-general.md':570,584,594,649 'config/app.php':1737 'configur':302,516,549,620,633,1021 'consider':1088,1522 'consol':32,1233,1270,1598,1696,1716,1739 'content':89,720,1348,1595 'context':241,1231 'contribut':233 'control':26,63,265,545,782,1180,1435,1717,1723 'controllernamespac':278,1601,1713,1720,1730 'controllers.md':375,396 'convent':124,226,617,1287 'cor':1325,1370 'core':1134 'cover':13,56,163,209 'cp':27,155,161,298,446,461,480,488,785,814,825,829,862,1181,1190,1199,1203,1311,1318,1546,1556,1610,1617,1659 'cp.md':369,397,417,453,595,772,784,800,813,828,1126 'cptrigger':300 'cpurl':305,308 'craft':2,10,40,49,74,101,116,150,178,225,467,484,499,505,511,526,614,691,704,824,832,910,1028,1039,1209,1333,1637,1645,1649,1676,1684,1703,1708 'craft-garnish':149,466,483,498,1208 'craft-php-guidelin':115 'craft-sit':100,510,525,1332 'craftcm':1 'craftcms.com':186,195 'craftcms.com/docs/5.x/extend/':185 'craftcms.com/docs/5.x/extend/generator.html':194 'creat':377,711,743,752,1070,1076 'createsettingsmodel':1583 'cross':215,246 'cross-cut':214 'cross-sit':245 'crud':1182 'css':821,833 'custom':78,361,401,436,492,628,662,745,749,754,764,834,878,950,955,970,998,1012,1018,1094,1100,1177,1288,1411,1456,1476,1489 'custom.php':1385 'cut':216 'danger':1358 'dashboard':414,418 'data':1394 'databas':258,725,730,1213 'datetimehelp':283 'db':1371 'db.php':1386 'ddev':135,140 'debug':1244 'debugging.md':387 'defens':885,894,1424 'defense-in-depth':884 'deploy':1027,1048,1058,1220,1497,1502 'deployment.md':1033,1042,1050,1060 'depth':887 'detail':211 'dev':1357 'develop':8,88 'devic':903 'differ':1527,1537 'dir':1670,1691,1706 'direct':314,1303 'disclosuremenu':172 'discov':1296 'discover':1743 'display':1113 'doc':201 'docs.craftcms.com':191 'docs.craftcms.com/api/v5/':190 'document':182 'doesn':207 'downtim':1047,1053,1505 'draft':1065,1072,1077,1082,1139,1511,1513,1516 'drafts-revisions.md':1069,1075,1086 'drag':174,472 'drag-to-reord':471 'drop':330 'dual':1442 'dual-lay':1441 'ec':144,1254 'ecs/phpstan':127 'edit':679,685 'effect':1080 'element':18,19,59,79,362,383,769,853,863,879,929,934,944,960,1095,1103,1112,1133,1146,1262,1280,1419 'element-authorization.md':859,868,881,893 'element-index.md':366,932,947,963,995,1111 'elementcondit':1475 'elements.md':365,386,882,1097 'elements/queries':285 'elev':1451 'els':1718 'email':1004,1485 'email.md':1009,1016,1026 'en':1689 'enabl':589 'end':523,1330 'endpoint':373,1185 'enforc':1436 'enough':210 'entri':92,439,991 'env':579,601,615,1378,1584 'environ':559,1508 'error':409 'event':38,67,875,937,1144,1159,1174,1271,1283,1289,1297,1416,1427,1430,1494,1554,1564,1615,1646,1652,1657,1664,1665 'events.md':376,406,420,431,441,450,758 'everyth':57 'exampl':358 'export':1154 'expos':424 'extend':9,16,43,48,73,183,933,1157 'extens':232,433,1292 'factori':1263 'fail':1057 'featur':680,1543 'field':34,37,65,81,394,402,493,714,811,817,971,979,984,1091,1099,1142,1273,1276,1278,1457,1470 'field-types-custom.md':974,982 'fieldlayoutbehavior':1281 'fields.md':367,405,496,975 'file':206,342,347,353,1587 'filesystem':755,759,1295 'find':565,636 'first':336 'fix':407 'fluent':1383 'forc':897 'force-logout':896 'foreign':1216 'form':393,1192 'four':1422 'four-lay':1421 'framework':1331,1473 'front':522,1329 'front-end':521,1328 'full':15,333 'function':1662,1701 'gap':922 'garnish':151,164,468,485,500,1210 'gate':681 'gc':1351 'generalconfig':567,581,1337,1347 'generat':193,1090,1098 'getbodyparam':313 'getconfig':252 'getisconsolerequest':1711 'getrequest':1710 'global':807 'graphql':643,1299,1323,1354,1468 'graphql.md':508,648 'group':857,1410 'guid':184 'guidelin':118 'handl':1408,1551,1573 'hardcod':295 'hascpsect':1613 'header':122 'headless':504,1320,1353 'headless.md':515,530 'headlessmod':1322 'helper':1240 'high':656 'high-traff':655 'hmr':1314 'hook':841,850 'html':1465 'htmlpurifi':1388 'http/queue/db':1264 'hud':171 'hybrid':1321 'i18n':1678,1685 'id':250,259 'idempot':1219 'imag':1345 'implement':915 'includ':249 'index':770,864,930,935,945,961,992,1147,1218 'inherit':791 'init':1577,1606,1702,1725 'input':1464 'instal':1592 'install.php':1215 'integr':85,709 'interact':160,476,1205,1359 'intern':1440 'invalid':1402,1449 'item':1619 'javascript':156,489,1204 'job':31,380,1223,1229 'js':179,477 'key':324,608,1217 'layer':869,1400,1423,1443 'layout':1143,1200,1279 'lifecycl':1135,1285,1462 'load':107,114,331,465,482,497,509,524,1207 'local':1352 'log':1251,1369 'logic':261,269 'logout':898 'macro':1193 'mail':621 'mailer/smtp':1367 'make':1115 'manag':1509 'manual':273,1552,1562,1566,1574,1626 'memoizablearray':1173 'merg':1519 'messag':1014,1020,1488,1490 'metadata':1156 'method':437,1429 'migrat':29,64,717,721,1214,1593,1596 'migrations.md':368,719 'migrations/install.php':1594 'mix':290 'mock':1266 'modal':170 'mode':599,1114,1130 'model':22,90,263,335,1169,1425,1445,1579 'modul':7,45,55,77,271,735,740,1526,1530,1545,1639,1669,1672,1682,1695,1714,1721,1732 'multi':1268 'multi-sit':1267 'multipl':231,352 'must':1602,1607,1635,1726,1733 'mutat':1302 'mutex':1366 'my-modul':1667,1680 'mymodul':1705,1715,1722 'name':123,1286 'namespac':1630 'nativ':36,1275 'nav':1611,1618 'need':272 'never':257,289 'next.js':520 'noth':280 'often':354 'on/inherit/off':781 'option':1236 'order':1382 'organ':126 'output':1239 'overrid':806 'page':202,321,391,448,481,795,803 'paramet':819 'parent':1605,1724 'parseenv':580,612 'pass':311 'password':916 'passwordresetrequir':921,1450 'pattern':181,787,816,831,895,907,1044,1454,1460,1535 'perform':1245,1350 'permiss':663,671,866,1201,1404 'permissions.md':668,675,860 'persist':325 'pest':533,1260 'php':12,117,133,307,1643,1675,1699 'phpdoc':119 'phpmessagesourc':1575,1686 'phpstan':145,408,1253 'pipelin':1499 'pitfal':213 'plugin':5,44,53,76,96,428,459,537,576,591,604,666,678,684,689,705,798,891,906,1007,1087,1116,1308,1453,1521,1524,1528,1544,1590 'plugin-vite.md':464 'pre':839,848 'pre-commit':838,847 'prefix':1591 'prepar':1432 'preview':517,1326,1356 'primari':239 'prioriti':1381 'privat':1589 'product':562,1031 'profil':1248 'programmat':1073,1491 'progress':1227,1237 'project':24,253,1040,1171,1500,1620 'projectconfig':1627 'propag':1141 'properti':338,835 'provision':1515 'public':1700 'qualiti':844 'quality.md':411,696,707,846 'queri':20,248,871,1136,1246,1301,1433 'queue':30,235,379,1222,1365 'queue-jobs.md':385 'read':343,364,374,384,395,404,410,416,430,440,449,463,495,507,538,547,555,563,569,571,582,593,597,609,618,624,631,639,647,659,667,674,682,695,706,718,726,728,738,747,757,771,783,799,812,827,845,858,867,880,892,904,913,919,931,946,962,973,981,993,1001,1008,1015,1024,1032,1041,1049,1059,1068,1074,1085,1096,1110,1119,1125,1128,1132 'read-on':596,1118,1127 'record':23,1170 'rector':697 'redi':550 'refer':46,189,205,341,346 'references/architecture.md':1179 'references/caching.md':1403 'references/conditions.md':1484 'references/config-app.md':1375 'references/config-bootstrap.md':1389 'references/config-general-extended.md':1360 'references/config-general.md':1346 'references/console-commands.md':1243 'references/controllers.md':1189 'references/cp.md':1212 'references/debugging.md':1252 'references/deployment.md':1510 'references/drafts-revisions.md':1523 'references/element-authorization.md':1437 'references/element-index.md':1167 'references/elements.md':1145 'references/email.md':1496 'references/events.md':1298 'references/field-types-custom.md':1471 'references/fields.md':1282 'references/graphql.md':1307 'references/headless.md':1336 'references/migrations.md':1221 'references/permissions.md':1418 'references/plugin-vite.md':1319 'references/quality.md':1258 'references/queue-jobs.md':1232 'references/sessions-and-auth.md':1455 'references/testing.md':1272 'regist':399,661,733,1010,1017,1479,1555,1616,1658 'registertemplaterootsev':1647,1663 'registr':279,741,1284,1412,1542,1642,1674,1698 'relat':978,983,1469 'relev':345 'reorder':474 'replica':727,731,1372 'request':312 'requir':130,141,918 'resav':1241 'reset':917 'resolv':600,1306 'restrict':852 'retri':1226 'review':1256 'revis':1067,1140,1512,1520 'roll':1054 'rollback':1061,1507 'root':275,1548,1558,1561,1641,1661,1666 'rout':630,1187,1339 'routes.php':1387 'rule':766,988,1000,1165,1478,1480 'run':138,143,237 'safe':228 'save':340 'savepluginset':316 'scaffold':146 'schema':646,1304 'scope':71,861,872,1434 'search':634,1343,1368,1467 'section':91,121,423,434,443,452,686,698,710,712,722,732,742,751,761,775,851,1612 'secur':890,1340 'see':98 'select':97,173 'send':1003,1492 'servic':21,61,266,288,1168 'session':554,911,1342,1364,1438,1444,1448,1452 'sessions-and-auth.md':905,914,920 'set':320,327,334,390,454,531,557,568,605,626,641,650,676,699,723,794,802,836,1034,1117,1463,1578,1603,1622,1628,1729 'setalia':1638,1704 'setup':1261 'share':1531 'short':637 'show':804 'side':1079 'sidebar':956,966,1155 'silent':329 'site':102,240,243,247,512,527,658,1230,1269,1334,1559 'site/platform':87 'skill':69,103,105,111,469,486,501,513,528,1211,1335 'skill-craftcms' 'skip':1078 'smtp':623,1022 'sort':1151,1166 'sourc':957,967,1148,1161 'source-michtio' 'sourcelanguag':1688 'specif':200 'split':319,1374 'split-set':318 'standard':120,1498 'state':780,790 'static':1396 'status':1137 'strategi':1062,1247,1401,1417 'submit':323 'surfac':17 'sync':382 'system':167,175,1013,1019,1338,1486,1487 'tab':793,801 'table/card':1149 'tag':1393 'task':351,357,1131 'templat':28,95,274,425,673,1191,1349,1391,1493,1547,1557,1560,1640,1660 'test':148,534,542,1259,1495 'testing.md':539,548 'togeth':108,356 'token':644,1327,1447 'topic-agent-skills' 'topic-claude-code' 'topic-claude-code-plugin' 'topic-claude-code-skills' 'topic-claude-skills' 'topic-content-modeling' 'topic-craft-cms' 'topic-craft-cms-5' 'topic-craftcms' 'topic-ddev' 'topic-php' 'topic-twig' 'track':1625 'traffic':657 'translat':276,1569,1673,1679 'transport':622,1023 'tri':779,789 'tri-stat':778,788 'trigger':112 'true':1614,1694 'ttr':1225 'twig':94,310,432,1291 'twig/php':1413 'type':35,80,82,93,363,403,422,494,756,760,972,980,1274,1300,1458,1514 'typescript':1315 'ui':168,786,815,830,1483 'uid':256 'understand':613,908 'updat':337 'upgrad':687 'url':299,629 'urlhelp':304 'use':197,218,242,255,303,826,1644,1648 'user':429,670,856,900,928,1341,1409 'util':447,451,1293 'valid':746,750,1178,1466 'valu':574,1461 'var':602,616,1379,1585 'variabl':426,560,822 'verif':128 'via':936,1158,1553,1563,1633 'view':1651,1654,1656 'vite':456,1309 'vitepluginservic':1310 'vs':1525 'vue':1316 'vueadmint':1196 'warn':808,818 'web':1650 'web/console':1373 'webfetch':198 'webhook':372,1183 'widget':169,415,419,421,1294 'word':638 'work':153,912,1063 'worker':236 'write':487,540 'xdebug':1249 'zero':1046,1052,1504 'zero-downtim':1045,1051,1503","prices":[{"id":"22d6433a-454a-4630-bae5-a48eb7b45427","listingId":"019f5204-76a8-42c5-a128-d1e501bc8c02","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"michtio","category":"craftcms-claude-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T22:19:37.015Z"}],"sources":[{"listingId":"019f5204-76a8-42c5-a128-d1e501bc8c02","source":"github","sourceId":"michtio/craftcms-claude-skills/craftcms","sourceUrl":"https://github.com/michtio/craftcms-claude-skills/tree/main/skills/craftcms","isPrimary":false,"firstSeenAt":"2026-04-18T22:19:37.015Z","lastSeenAt":"2026-05-01T18:56:49.059Z"}],"details":{"listingId":"019f5204-76a8-42c5-a128-d1e501bc8c02","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"michtio","slug":"craftcms","github":{"repo":"michtio/craftcms-claude-skills","stars":39,"topics":["agent-skills","claude-code","claude-code-plugin","claude-code-skills","claude-skills","content-modeling","craft-cms","craft-cms-5","craftcms","ddev","php","twig"],"license":"mit","html_url":"https://github.com/michtio/craftcms-claude-skills","pushed_at":"2026-04-30T21:00:38Z","description":"Production-ready Claude Code skills, agents, and project templates for Craft CMS 5 development","skill_md_sha":"924dbe012af1fee823736569f16d894f580a603c","skill_md_path":"skills/craftcms/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/michtio/craftcms-claude-skills/tree/main/skills/craftcms"},"layout":"multi","source":"github","category":"craftcms-claude-skills","frontmatter":{"name":"craftcms","description":"Craft CMS 5 plugin and module development — extending Craft with PHP. Covers the full extend surface: elements, element queries, services, models, records, project config, controllers, CP templates, migrations, queue jobs, console commands, field types, native fields, events, behaviors, Twig extensions, utilities, widgets, filesystems, permissions, debugging, testing, GraphQL, and Craft configuration (config/app.php, config/general.php, Redis, SMTP, database replicas). Triggers on: beforePrepare(), afterSave(), defineSources(), defineTableAttributes(), attributeHtml(), MemoizableArray, getConfig(), handleChanged, $allowAnonymous, $enableCsrfValidation, BaseNativeField, EVENT_DEFINE_NATIVE_FIELDS, FieldLayoutBehavior, EVENT_REGISTER, EVENT_DEFINE, EVENT_BEFORE, EVENT_AFTER, CraftVariable, registerTwigExtension, DefineConsoleActionsEvent, PHPStan, Pest, plugin development, module development, custom element type, custom field type, webhook, API endpoint, queue job, batch processing, data sync, migration, CP section, control panel, Craft plugin, Craft module, extending Craft, element action, element exporter, element condition, dashboard widget, utility page, permissions, registerUserPermissions, requirePermission, GraphQL custom types, GraphQL custom mutations, GraphQL schema building, Rector, Craft 4 to 5, upgrade plugin, CI/CD, GitHub Actions, GitLab CI, custom validator, defineRules, EVENT_AUTHORIZE_VIEW, EVENT_AUTHORIZE_SAVE, canView, canSave, canDelete, element authorization, defense-in-depth, query scoping, EVENT_BEFORE_PREPARE, session invalidation, passwordResetRequired, elevated session, Table::SESSIONS, custom field type build, field type development, normalizeValue, serializeValue, inputHtml, BaseCondition, ElementCondition, condition rule, condition builder, system messages, composeFromKey, email sending, Mailer, deployment, zero-downtime deploy, atomic deploy, craft up, project-config/apply, allowAdminChanges, drafts, revisions, provisional draft, canCreateDrafts, applyDraft, getIsDraft, getIsRevision, App::env, App::parseEnv, CRAFT_CP_TRIGGER, CRAFT_DEV_MODE, CRAFT_ALLOW_ADMIN_CHANGES, GeneralConfig, config precedence, cpTrigger. Always use when writing, editing, or reviewing any Craft CMS plugin or module PHP code — even when the user asks about plugin architecture, Craft internals, or extending Craft without naming specific APIs. Do NOT trigger for front-end Twig templates, content modeling decisions, site-building without PHP, or consuming GraphQL/headless APIs from front-end frameworks (Next.js, Nuxt, Astro) — those belong in craft-site."},"skills_sh_url":"https://skills.sh/michtio/craftcms-claude-skills/craftcms"},"updatedAt":"2026-05-01T18:56:49.059Z"}}