Install
$ agentstack add skill-chrisrowe-craftcms-claude-skills-craftcms ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
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.
For PHP coding standards and conventions, see the separate craft-php-guidelines skill.
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 web_fetch on specific doc pages when a reference file doesn't cover enough detail.
Common Pitfalls (Cross-Cutting)
- Always use
addSelect()inbeforePrepare()— 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
idingetConfig()— 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.
DateTimeHelperin elements/queries,Carbonin services — never mix in the same class.
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+element-index.md+fields.md+migrations.md - "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
events.md(Widget Types section) - "Expose template variables for plugin users" → read
events.md(Twig Extensions section) - "Attach custom methods to entries" → read
events.md(Behaviors section) - "Build a CP utility page" → read
events.md(Utilities section) +cp.md
| Task | Read | |------|------| | Element core: lifecycle, queries, status, authorization, drafts, revisions, propagation, field layouts, events | references/elements.md | | Element index: sources, table/card attributes, sort, conditions, actions, exporters, sidebar, metadata | references/element-index.md | | Services, models, records, project config, MemoizableArray, events, API clients, custom validators | references/architecture.md | | Controllers: CP CRUD, webhooks, API endpoints, action routing, authorization | references/controllers.md | | CP templates, form macros, admin changes, VueAdminTable, asset bundles, CP layout, permissions | references/cp.md | | Database migrations, Install.php, foreign keys, indexes, idempotency, deployment | references/migrations.md | | Queue jobs, BaseJob, TTR, retry, progress, batch jobs, site context | references/queue-jobs.md | | Console commands, arguments, options, progress bars, output helpers, resave actions | references/console-commands.md | | Debugging, performance, query strategy, profiling, Xdebug, caching, logging | references/debugging.md | | PHPStan, Pest testing, code review checklist | references/quality.md | | Field types, native fields, BaseNativeField, field layout elements, FieldLayoutBehavior | references/fields.md | | Events: registration, lifecycle, naming conventions, custom events, behaviors, Twig extensions, utilities, widgets, filesystems, discovering events | references/events.md | | GraphQL types, queries, mutations, directives, schema components, resolvers | references/graphql.md |
Plugin vs Module Differences
Plugins and modules share the same architecture patterns. The differences are in bootstrapping and registration:
| Feature | Plugin | Module | |---------|--------|--------| | CP template root | Automatic (by handle) | Manual via EVENT_REGISTER_CP_TEMPLATE_ROOTS | | Site template root | Manual via event | Same — manual for both | | Translation category | Automatic (by handle) | Manual PhpMessageSource in init() | | Settings model | Built-in createSettingsModel() | Env vars, config files, or private plugin (_ prefix) | | Install migration | migrations/Install.php | Content migrations only | | Console commands | Automatic controllerNamespace | Must set before parent::init(), must be bootstrapped | | CP nav section | $hasCpSection = true | EVENT_REGISTER_CP_NAV_ITEMS | | Project config | Settings auto-tracked | Manual ProjectConfig::set() only | | Namespace alias | Automatic via Composer | Must call Craft::setAlias() |
Module Template Root Registration
use craft\events\RegisterTemplateRootsEvent;
use craft\web\View;
Event::on(View::class, View::EVENT_REGISTER_CP_TEMPLATE_ROOTS,
function(RegisterTemplateRootsEvent $event) {
$event->roots['my-module'] = __DIR__ . '/templates';
}
);
Module Translation Registration
Craft::$app->i18n->translations['my-module'] = [
'class' => \craft\i18n\PhpMessageSource::class,
'sourceLanguage' => 'en',
'basePath' => __DIR__ . '/translations',
'allowOverrides' => true,
];
Module Console Command Registration
public function init()
{
Craft::setAlias('@mymodule', __DIR__);
if (Craft::$app->getRequest()->getIsConsoleRequest()) {
$this->controllerNamespace = 'modules\\mymodule\\console\\controllers';
} else {
$this->controllerNamespace = 'modules\\mymodule\\controllers';
}
parent::init(); // MUST come after setting controllerNamespace
}
The module must be bootstrapped in config/app.php for console commands to be discoverable.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: chrisrowe
- Source: chrisrowe/craftcms-claude-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.