{"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 elements, element queries, services, models, records, project config, controllers, CP templates, migrations, queue jobs, console commands, field types, native fields, events, behaviors, Twig extensions, ","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` (Architecture section first) + `element-index.md` + `fields.md` + `migrations.md` + `cp.md`\n- \"Build a hierarchical/tree element type\" → read `elements.md` (Architecture: One Element Class with Native Structure)\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-components.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 `cp-components.md` (Utility Pages) + `events.md` (Utilities section)\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-ui-patterns.md` (Condition Builders)\n- \"Build a tri-state on/inherit/off control\" → read `cp-ui-patterns.md` (Tri-State Inheritance Controls)\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-ui-patterns.md` (Field Warning Parameter)\n- \"What CSS variables does Craft CP use?\" → read `cp-ui-patterns.md` (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 an action to the per-element edit-screen menu\" → read `element-index.md` (Per-Element Edit-Screen Action Menu)\n- \"Render a status pill in a table column\" → read `element-index.md` (Status Pills in Table Attributes)\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- \"Add a screen to the User edit page\" → read `elements.md` (Extending User Edit Screens)\n- \"Make plugin settings read-only when allowAdminChanges is off\" → read `cp.md` (Read-Only Mode)\n- \"Add tabs to a plugin's settings page\" → read `cp.md` (Settings Pages → With tabs or custom actions). `settingsHtml()` is single-pane only — tabs require a custom controller and a template extending `_layouts/cp` directly.\n\nLoad only the reference files your task needs — each file costs input tokens on every turn.\n\n| Task | Read | ~Tokens |\n|------|------|--------:|\n| Element core: lifecycle, queries, status, authorization, drafts, revisions, propagation, field layouts, user edit screens, events | `references/elements.md` | 8.4K |\n| Element index: sources, table/card attributes, status pills, sort, conditions, actions (bulk + per-element action menu), exporters, sidebar, metadata, extending via events | `references/element-index.md` | 6.1K |\n| Services, models, records, project config, MemoizableArray, events, API clients, custom validators | `references/architecture.md` | 6.0K |\n| Controllers: CP CRUD, webhooks, API endpoints, action routing, authorization | `references/controllers.md` | 3.9K |\n| CP templates, form macros, settings pages, navigation, permissions, read-only mode | `references/cp.md` | 7.2K |\n| CP components: dashboard widgets, utility pages, slideout editors, ajax, alerts | `references/cp-components.md` | 1.8K |\n| CP UI patterns: tri-state controls, status indicators, CSS variables, condition builders, asset bundles | `references/cp-ui-patterns.md` | 2.4K |\n| Database migrations, Install.php, foreign keys, indexes, idempotency, deployment | `references/migrations.md` | 3.9K |\n| Queue jobs, BaseJob, TTR, retry, progress, batch jobs, site context | `references/queue-jobs.md` | 4.2K |\n| Console commands, arguments, options, progress bars, output helpers, resave actions | `references/console-commands.md` | 6.0K |\n| Debugging, performance, query strategy, profiling, Xdebug, caching, logging | `references/debugging.md` | 4.6K |\n| PHPStan, ECS, code review checklist | `references/quality.md` | 3.5K |\n| Testing: Pest setup, element factories, HTTP/queue/DB assertions, mocking, multi-site, console, events | `references/testing.md` | 2.9K |\n| Field types, native fields, BaseNativeField, field layout elements, FieldLayoutBehavior | `references/fields.md` | 3.6K |\n| Events: registration, lifecycle, naming conventions, custom events, behaviors, Twig extensions, utilities, widgets, filesystems | `references/events.md` | 4.4K |\n| GraphQL types, queries, mutations, directives, schema components, resolvers | `references/graphql.md` | 4.6K |\n| Plugin Vite: VitePluginService, CP asset bundles, HMR, TypeScript, Vue in CP | `references/plugin-vite.md` | 2.7K |\n| Headless & hybrid: headlessMode, GraphQL API, CORS, preview tokens, front-end frameworks | craft-site skill `references/headless.md` | 3.4K |\n| GeneralConfig (system, routing, security, users, sessions, search, assets, images) | `references/config-general.md` | 8.4K |\n| GeneralConfig (content, templates, performance, GC, localization, headless, GraphQL, accessibility) | `references/config-general-extended.md` | 7.2K |\n| App config: cache, session, queue, mutex, mailer/SMTP, search, logging, CORS, DB replicas | `references/config-app.md` | 5.5K |\n| Config bootstrap: env vars, aliases, priority order, fluent API, custom.php, db.php, routes.php | `references/config-bootstrap.md` | 3.6K |\n| Caching: template cache tag, data cache, static caching (Blitz), CDN, layered strategy, invalidation | `references/caching.md` | 5.2K |\n| Permissions: built-in handles, user groups, custom registration, Twig/PHP checking, authorization events | `references/permissions.md` | 4.7K |\n| Element authorization: four-layer defense model, authorization events, can*() methods, query scoping | `references/element-authorization.md` | 4.6K |\n| Sessions & auth internals: dual-layer session model, auth tokens, session invalidation, elevated sessions | `references/sessions-and-auth.md` | 3.0K |\n| Custom field types: build pattern, value lifecycle, settings, input HTML, validation, search, GraphQL | `references/field-types-custom.md` | 3.5K |\n| Conditions framework: BaseCondition, ElementCondition, custom condition rules, registering rules | `references/conditions.md` | 2.3K |\n| Email system: system messages, custom messages, programmatic sending, templates, events, testing | `references/email.md` | 2.4K |\n| Deployment: standard pipeline, project config deploy, zero-downtime, CI/CD, rollback | `references/deployment.md` | 2.5K |\n| Drafts & revisions: draft types, provisional drafts, autosave, applying, merge, revisions | `references/drafts-revisions.md` | 2.5K |\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.471","qualityRationale":"deterministic score 0.47 from registry signals: · indexed on github topic:agent-skills · 42 github stars · SKILL.md body (15,595 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-18T18:58:17.085Z","embedding":null,"createdAt":"2026-04-18T22:19:37.015Z","updatedAt":"2026-05-18T18:58:17.085Z","lastSeenAt":"2026-05-18T18:58:17.085Z","tsv":"'/admin':294 '/api/v5/':190 '/docs/5.x/extend/':185 '/docs/5.x/extend/generator.html':194 '/templates':1837 '/translations':1858 '1.8':1338 '2.3':1647 '2.4':1356,1661 '2.5':1675,1688 '2.7':1481 '2.9':1428 '3':878 '3.0':1619 '3.4':1500 '3.5':1412,1635 '3.6':1440,1554 '3.9':1310,1367 '4':709 '4.2':1380 '4.4':1456 '4.6':1404,1467,1602 '4.7':1586 '5':4,40,49,711 '5.2':1570 '5.5':1539 '6.0':1298,1393 '6.1':1284 '7.2':1325,1524 '8.4':1259,1512 'access':862,1522 'action':563,949,960,963,981,1206,1270,1275,1306,1391 'ad':956,1009 'add':385,403,427,487,806,881,931,946,961,998,1030,1134,1160,1190 'addit':227 'addselect':217 'aftersav':1129 'ajax':1335 'alert':1336 'alia':1797 'alias':1545 'allowadminchang':604,1181 'allowoverrid':1859 'also':111 'alway':104,215 'api':523,624,1293,1304,1487,1549 'app':595,628,1526,1843,1875 'app.php':754 'appear':1149 'appli':353,1684 'architectur':364,378,1700 'architecture.md':413,700,765 'argument':1384 'assert':1420 'asset':155,479,1353,1473,1509 'attach':450 'attribut':997,1265 'auth':1605,1612 'author':882,1248,1308,1583,1589,1595 'auto':1790 'auto-track':1789 'automat':280,1715,1737,1766,1798 'autosav':1683 'back':1100 'backend':82 'bar':1387 'basecondit':1639 'basejob':1371 'basenativefield':1434 'basepath':1856 'batch':1375 'beforeprepar':219 'behavior':35,457,1449 'belong':268 'blitz':1564 'bootstrap':1542,1706,1775,1901 'build':73,357,371,459,519,779,792,891,1013,1021,1041,1624 'builder':791,1352 'built':1574,1747 'built-in':1573,1746 'bulk':948,959,1271 'bundl':156,1354,1474 'busi':258 'cach':569,669,1401,1528,1556,1558,1561,1563 'caching.md':677 'call':1802 'carbon':284 'card':1154 'categori':1736 'cdn':1565 'check':602,686,1582 'checklist':127,1410 'chip':1152 'ci':718 'ci/cd':725,1081,1088,1672 'class':123,164,178,186,292,381,1821,1849,1853 'client':1294 'cms':3,39,48,1074 'code':132,594,609,851,1408 'column':232,933,990 'come':1893 'command':29,135,1383,1765,1863,1906 'commit':848,857 'common':210 'companion':102 'compon':160,1328,1464 'compos':1800 'condit':782,790,1032,1044,1269,1351,1637,1642 'conditions.md':1039,1047 'config':21,252,590,1290,1527,1541,1667,1752,1787 'config-app.md':573,642,657,746,756,1070 'config-bootstrap.md':581,600,627,636,649 'config-general.md':587,601,611,666 'config/app.php':1903 'configur':300,533,566,637,650,1066 'consider':1133 'consol':28,1382,1425,1764,1862,1882,1905 'content':87,737,1515,1761 'context':239,1378 'contribut':231 'control':22,61,263,562,798,805,1217,1300,1346,1883,1889 'controllernamespac':276,1767,1879,1886,1896 'controllers.md':390,411 'convent':122,224,634,1446 'cor':1488,1535 'core':1244 'cost':1234 'cover':13,54,161,207 'cp':23,153,159,296,461,478,497,505,836,870,1301,1312,1327,1340,1472,1479,1712,1722,1776,1783,1825 'cp-components.md':432,465 'cp-ui-patterns.md':789,800,827,839 'cp.md':370,412,612,814,1185,1199 'cptrigger':298 'cpurl':303,306 'craft':2,10,38,47,72,99,114,148,176,223,484,501,516,522,528,543,631,708,721,835,840,918,1073,1084,1496,1803,1811,1815,1842,1850,1869,1874 'craft-garnish':147,483,500,515 'craft-php-guidelin':113 'craft-sit':98,527,542,1495 'craftcm':1 'craftcms.com':184,193 'craftcms.com/docs/5.x/extend/':183 'craftcms.com/docs/5.x/extend/generator.html':192 'creat':392,728,760,769,1115,1121 'createsettingsmodel':1749 'cross':213,244 'cross-cut':212 'cross-sit':243 'crud':1302 'css':832,841,1349 'custom':76,359,416,451,509,645,679,762,766,771,781,842,886,958,1000,1015,1043,1057,1063,1139,1145,1205,1216,1295,1447,1579,1621,1641,1653 'custom.php':1550 'cut':214 'dashboard':429,433,1329 'data':1560 'databas':256,742,747,1358 'datetimehelp':281 'db':1536 'db.php':1551 'ddev':133,138 'debug':1395 'debugging.md':402 'defens':893,902,1593 'defense-in-depth':892 'deploy':1072,1093,1103,1365,1663,1668 'deployment.md':1078,1087,1095,1105 'depth':895 'detail':209 'develop':8,86 'devic':911 'differ':1693,1703 'dir':1836,1857,1872 'direct':312,1223,1462 'disclosuremenu':170 'discover':1909 'display':1158 'doc':199 'docs.craftcms.com':189 'docs.craftcms.com/api/v5/':188 'document':180 'doesn':205 'downtim':1092,1098,1671 'draft':1110,1117,1122,1127,1249,1677,1679,1682 'drafts-revisions.md':1114,1120,1131 'drag':172,489 'drag-to-reord':488 'drop':328 'dual':1608 'dual-lay':1607 'ec':142,1407 'ecs/phpstan':125 'edit':696,702,970,979,1166,1172,1255 'edit-screen':969,978 'editor':1334 'effect':1125 'element':14,15,57,77,360,374,380,398,786,861,871,887,937,942,952,968,977,1005,1140,1148,1157,1243,1261,1274,1417,1437,1588 'element-authorization.md':867,876,889,901 'element-index.md':367,940,955,974,992,1008,1040,1156 'elementcondit':1640 'elements.md':363,377,401,890,1142,1169 'elements/queries':283 'elev':1616 'els':1884 'email':1049,1649 'email.md':1054,1061,1071 'en':1855 'enabl':606 'end':540,1493 'endpoint':388,1305 'enough':208 'entri':90,454,1036 'env':596,618,632,1543,1750 'environ':576 'error':424 'event':34,65,883,945,1257,1282,1292,1426,1442,1448,1584,1596,1658,1720,1730,1781,1812,1818,1823,1830,1831 'events.md':391,421,435,446,456,468,775 'everi':1238 'everyth':55 'exampl':356 'export':1277 'expos':439 'extend':9,41,46,71,181,941,1170,1221,1280 'extens':37,230,448,1451 'factori':1418 'fail':1102 'featur':697,1709 'field':30,33,63,79,409,417,510,731,825,828,1016,1024,1029,1136,1144,1252,1430,1433,1435,1622 'field-types-custom.md':1019,1027 'fieldlayoutbehavior':1438 'fields.md':368,420,513,1020 'file':204,340,345,351,1228,1233,1753 'filesystem':772,776,1454 'find':582,653 'first':334,366 'fix':422 'fluent':1548 'forc':905 'force-logout':904 'foreign':1361 'form':408,1314 'four':1591 'four-lay':1590 'framework':1494,1638 'front':539,1492 'front-end':538,1491 'full':331 'function':1828,1867 'gap':930 'garnish':149,162,485,502,517 'gate':698 'gc':1518 'generalconfig':584,598,1502,1514 'generat':191,1135,1143 'getbodyparam':311 'getconfig':250 'getisconsolerequest':1877 'getrequest':1876 'global':821 'graphql':660,1458,1486,1521,1633 'graphql.md':525,665 'group':865,1578 'guid':182 'guidelin':116 'handl':1576,1717,1739 'hardcod':293 'hascpsect':1779 'header':120 'headless':521,1483,1520 'headless.md':532,547 'headlessmod':1485 'helper':1389 'hierarchical/tree':373 'high':673 'high-traff':672 'hmr':1475 'hook':849,858 'html':1630 'http/queue/db':1419 'hud':169 'hybrid':1484 'i18n':1844,1851 'id':248,257 'idempot':1364 'imag':1510 'implement':923 'includ':247 'index':787,872,938,943,953,1006,1037,1262,1363 'indic':1348 'inherit':804 'init':1743,1772,1868,1891 'input':1235,1629 'instal':1758 'install.php':1360 'integr':83,726 'interact':158,493 'intern':1606 'invalid':1568,1615 'item':1785 'javascript':154,506 'job':27,395,1370,1376 'js':177,494 'k':1260,1285,1299,1311,1326,1339,1357,1368,1381,1394,1405,1413,1429,1441,1457,1468,1482,1501,1513,1525,1540,1555,1571,1587,1603,1620,1636,1648,1662,1676,1689 'key':322,625,1362 'layer':877,1566,1592,1609 'layout':1253,1436 'layouts/cp':1222 'lifecycl':1245,1444,1627 'load':105,112,329,482,499,514,526,541,1224 'local':1519 'log':1402,1534 'logic':259,267 'logout':906 'macro':1315 'mail':638 'mailer/smtp':1532 'make':1174 'manual':271,1718,1728,1732,1740,1792 'memoizablearray':1291 'menu':972,982,1276 'merg':1685 'messag':1059,1065,1652,1654 'metadata':1279 'method':452,1598 'migrat':25,62,734,738,1359,1759,1762 'migrations.md':369,736 'migrations/install.php':1760 'mix':288 'mock':1421 'modal':168 'mode':616,1159,1189,1323 'model':18,88,261,333,1287,1594,1611,1745 'modul':7,43,53,75,269,752,757,1692,1696,1711,1805,1835,1838,1848,1861,1880,1887,1898 'multi':1423 'multi-sit':1422 'multipl':229,350 'must':1768,1773,1801,1892,1899 'mutat':1461 'mutex':1531 'my-modul':1833,1846 'mymodul':1871,1881,1888 'name':121,1445 'namespac':1796 'nativ':32,383,1432 'nav':1777,1784 'navig':1318 'need':270,1231 'never':255,287 'next.js':537 'noth':278 'often':352 'on/inherit/off':797 'one':379 'option':1385 'order':1547 'organ':124 'output':1388 'overrid':820 'page':200,319,406,463,467,498,809,817,1167,1197,1201,1317,1332 'pane':1211 'paramet':830 'parent':1771,1890 'parseenv':597,629 'pass':309 'password':924 'passwordresetrequir':929 'pattern':179,903,915,1089,1342,1625,1701 'per':967,976,1273 'per-el':966,975,1272 'perform':1396,1517 'permiss':680,688,874,1319,1572 'permissions.md':685,692,868 'persist':323 'pest':550,1415 'php':12,115,131,305,1809,1841,1865 'phpdoc':117 'phpmessagesourc':1741,1852 'phpstan':143,423,1406 'pill':986,994,1267 'pipelin':1665 'pitfal':211 'plugin':5,42,51,74,94,443,476,554,593,608,621,683,695,701,706,722,812,899,914,1052,1132,1175,1194,1469,1690,1694,1710,1756 'plugin-vite.md':481 'pre':847,856 'pre-commit':846,855 'prefix':1757 'preview':534,1489 'primari':237 'prioriti':1546 'privat':1755 'product':579,1076 'profil':1399 'programmat':1118,1655 'progress':1374,1386 'project':20,251,1085,1289,1666,1786 'projectconfig':1793 'propag':1251 'properti':336,843 'provision':1681 'public':1866 'qualiti':852 'quality.md':426,713,724,854 'queri':16,246,879,1246,1397,1460,1599 'queue':26,233,394,1369,1530 'queue-jobs.md':400 'read':341,362,376,389,399,410,419,425,431,445,455,464,480,512,524,555,564,572,580,586,588,599,610,614,626,635,641,648,656,664,676,684,691,699,712,723,735,743,745,755,764,774,788,799,813,826,838,853,866,875,888,900,912,921,927,939,954,973,991,1007,1018,1026,1038,1046,1053,1060,1069,1077,1086,1094,1104,1113,1119,1130,1141,1155,1168,1178,1184,1187,1198,1241,1321 'read-on':613,1177,1186,1320 'record':19,1288 'rector':714 'redi':567 'refer':44,187,203,339,344,1227 'references/architecture.md':1297 'references/caching.md':1569 'references/conditions.md':1646 'references/config-app.md':1538 'references/config-bootstrap.md':1553 'references/config-general-extended.md':1523 'references/config-general.md':1511 'references/console-commands.md':1392 'references/controllers.md':1309 'references/cp-components.md':1337 'references/cp-ui-patterns.md':1355 'references/cp.md':1324 'references/debugging.md':1403 'references/deployment.md':1674 'references/drafts-revisions.md':1687 'references/element-authorization.md':1601 'references/element-index.md':1283 'references/elements.md':1258 'references/email.md':1660 'references/events.md':1455 'references/field-types-custom.md':1634 'references/fields.md':1439 'references/graphql.md':1466 'references/headless.md':1499 'references/migrations.md':1366 'references/permissions.md':1585 'references/plugin-vite.md':1480 'references/quality.md':1411 'references/queue-jobs.md':1379 'references/sessions-and-auth.md':1618 'references/testing.md':1427 'regist':414,678,750,1055,1062,1644,1721,1782,1824 'registertemplaterootsev':1813,1829 'registr':277,758,1443,1580,1708,1808,1840,1864 'relat':1023,1028 'relev':343 'render':983 'reorder':491 'replica':744,748,1537 'request':310 'requir':128,139,926,1214 'resav':1390 'reset':925 'resolv':617,1465 'restrict':860 'retri':1373 'review':1409 'revis':1112,1250,1678,1686 'roll':1099 'rollback':1106,1673 'root':273,1714,1724,1727,1807,1827,1832 'rout':647,1307,1504 'routes.php':1552 'rule':783,1033,1045,1643,1645 'run':136,141,235 'safe':226 'save':338 'savepluginset':314 'scaffold':144 'schema':663,1463 'scope':69,869,880,1600 'screen':971,980,1162,1173,1256 'search':651,1508,1533,1632 'section':89,119,365,438,449,458,470,703,715,727,729,739,749,759,768,778,859,1778 'secur':898,1505 'see':96 'select':95,171 'send':1048,1656 'servic':17,59,264,286,1286 'session':571,919,1507,1529,1604,1610,1614,1617 'sessions-and-auth.md':913,922,928 'set':318,325,332,405,471,548,574,585,622,643,658,667,693,716,740,808,816,844,1079,1176,1196,1200,1316,1628,1744,1769,1788,1794,1895 'setalia':1804,1870 'settingshtml':1207 'setup':1416 'share':1697 'short':654 'show':818 'side':1124 'sidebar':1001,1011,1278 'silent':327 'singl':1210 'single-pan':1209 'site':100,238,241,245,529,544,675,1377,1424,1497,1725 'site/platform':85 'skill':67,101,103,109,486,503,518,530,545,1498 'skill-craftcms' 'skip':1123 'slideout':1333 'smtp':640,1067 'sort':1268 'sourc':1002,1012,1263 'source-michtio' 'sourcelanguag':1854 'specif':198 'split':317 'split-set':316 'standard':118,1664 'state':796,803,1345 'static':1562 'status':985,993,1247,1266,1347 'strategi':1107,1398,1567 'structur':384 'submit':321 'sync':397 'system':165,173,1058,1064,1503,1650,1651 'tab':807,815,1191,1203,1213 'tabl':989,996 'table/card':1264 'tag':1559 'task':349,355,1230,1240 'templat':24,93,272,440,690,1220,1313,1516,1557,1657,1713,1723,1726,1806,1826 'test':146,551,559,1414,1659 'testing.md':556,565 'togeth':106,354 'token':661,1236,1242,1490,1613 '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':1791 'traffic':674 'translat':274,1735,1839,1845 'transport':639,1068 'tri':795,802,1344 'tri-stat':794,801,1343 'trigger':110 'true':1780,1860 'ttr':1372 'turn':1239 'twig':36,92,308,447,1450 'twig/php':1581 'type':31,78,80,91,361,375,418,437,511,773,777,1017,1025,1431,1459,1623,1680 'typescript':1476 'ui':166,1341 'uid':254 'understand':630,916 'updat':335 'upgrad':704 'url':297,646 'urlhelp':302 'use':195,216,240,253,301,837,1810,1814 'user':444,687,864,908,936,1165,1171,1254,1506,1577 'util':462,466,469,1331,1452 'valid':763,767,1296,1631 'valu':591,1626 'var':619,633,1544,1751 'variabl':441,577,833,1350 'verif':126 'via':944,1281,1719,1729,1799 'view':1817,1820,1822 'vite':473,1470 'vitepluginservic':1471 'vs':1691 'vue':1477 'warn':822,829 'web':1816 'webfetch':196 'webhook':387,1303 'widget':167,430,434,436,1330,1453 'word':655 'work':151,920,1108 'worker':234 'write':504,557 'xdebug':1400 'zero':1091,1097,1670 'zero-downtim':1090,1096,1669","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-18T18:58:17.085Z"}],"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":42,"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-05-18T16:55:33Z","description":"Production-ready Claude Code skills, agents, and project templates for Craft CMS 5 development","skill_md_sha":"30b65e8501d7c53fd908c4d1188ce33f665ca367","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 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. Triggers on: beforePrepare(), afterSave(), defineSources(), defineTableAttributes(), attributeHtml(), MemoizableArray, BaseNativeField, EVENT_REGISTER_*/DEFINE_*/BEFORE_*/AFTER_*, CraftVariable, registerTwigExtension, custom element type, custom field type (normalizeValue, serializeValue, inputHtml), webhook, API endpoint, queue job, batch processing, CP section, control panel, element action, element exporter, element condition, dashboard widget, utility page, registerUserPermissions, requirePermission, GraphQL custom types/mutations, schema building, defineRules, canView/canSave/canDelete authorization, session invalidation, elevated session, BaseCondition, system messages, Mailer, atomic deploy, craft up, project-config/apply, drafts, revisions, GeneralConfig, $allowAnonymous. Always use when writing, editing, or reviewing Craft CMS plugin or module PHP code, even when no specific API names are mentioned. Do NOT trigger for front-end Twig (craft-site), content modeling (craft-content-modeling), or headless GraphQL consumption from Next.js/Nuxt/Astro."},"skills_sh_url":"https://skills.sh/michtio/craftcms-claude-skills/craftcms"},"updatedAt":"2026-05-18T18:58:17.085Z"}}