Skillquality 0.47

craft-php-guidelines

Craft CMS 5 PHP coding standards and conventions. ALWAYS load this skill when writing, editing, reviewing, or discussing any PHP file in a Craft CMS plugin or module — even for small edits. Also load when running ECS, PHPStan, or scaffolding with ddev craft make. Covers: PHPDoc b

Price
free
Protocol
skill
Verified
no

What it does

Craft CMS 5 PHP Guidelines

Complete PHP coding standards and conventions for Craft CMS 5 plugin and module development. These extend Craft's official coding guidelines with project-specific conventions.

Core principles: PHPDocs on everything — classes, methods, and properties — regardless of type hints. No declare(strict_types=1) in plugin source files (matching Craft core convention).

Companion Skills — Always Load Together

  • craftcms — Architecture patterns, element lifecycle, controllers, events, migrations. Required for any Craft plugin or module development.
  • ddev — All commands run through DDEV. Required for running ECS, PHPStan, scaffolding, and tests.

Documentation

When unsure about a convention, WebFetch the coding guidelines page for the authoritative answer.

Common Pitfalls

  • addSelect() is the convention in beforePrepare() — safely additive when multiple extensions contribute columns.
  • $_instances is not a Craft convention — private properties use underscore prefix but meaningful names like $_items, $_sections.
  • Records use the same class name as models (namespace distinguishes). Alias when importing both: use ...\records\MyEntity as MyEntityRecord;.
  • Queue jobs have no "Job" suffixResaveElements, not ResaveElementsJob.
  • declare(strict_types=1) is NOT used in plugin source files. Only in standalone config files like ecs.php.
  • @author goes on classes and methods only — never on properties.
  • Don't use string|null — use ?string (short nullable notation).
  • Forget parent::defineRules() and you lose all inherited validation.
  • DateTimeHelper in elements/queries, Carbon in services — never mix in the same class.
  • Missing @throws chains — document exceptions from called methods too, not just your own throws.
  • Using magic property access ($plugin->settings, $app->view) instead of explicit getters ($plugin->getSettings(), $app->getView()) — PHPStan can't resolve __get() calls, so magic access passes at runtime but fails static analysis. Always use explicit getters for Yii2 components and Craft plugin properties.

Reference Files

Read the relevant reference file(s) for your task:

TaskRead
Writing PHPDocs, @author, @since, @throws, @var, @param, type referencesreferences/phpdoc-standards.md
Class structure, section headers, ordering, enums, control flow, comments, whitespacereferences/class-organization.md
Naming classes, methods, properties, files, services, events, migrationsreferences/naming-conventions.md
CP Twig templates, form macros, translations, file headers, validationreferences/templates-and-patterns.md
ECS, PHPStan, scaffolding commands, commit messagesreferences/tooling.md

Critical Rules

  1. PHPDocs on everything: classes, methods, properties. No exceptions.
  2. @throws chains: document every exception including uncaught from called methods.
  3. @author and @since at the bottom of class/method docblocks, after a blank line.
  4. Section headers with // ========================================================================= on every class.
  5. declare(strict_types=1) is NOT used in plugin source files — Craft's internal type coercion depends on PHP's default weak typing mode.
  6. Private methods/properties prefixed with underscore: _registerCpUrlRules(), $_items.
  7. addSelect() convention in beforePrepare() — additive across extensions, prevents column conflicts.
  8. DateTimeHelper in elements/queries, Carbon in services — separate concerns prevent mixing date APIs in the same class.
  9. Always scaffold with ddev craft make <type> --with-docblocks, then customize.
  10. ddev composer check-cs and ddev composer phpstan must pass before every commit.

PHP Standards

  • Minimum PHP 8.2 (Craft CMS 5 requirement).
  • PSR-12 baseline with Craft modifications (trailing commas, constant visibility).
  • craftcms/ecs with SetList::CRAFT_CMS_4 preset (covers both Craft 4 and 5).
  • Short nullable notation: ?string not string|null.
  • Always specify void return types.
  • Typed properties everywhere. No untyped public properties.
  • Strict comparison always: $foo === null, in_array($x, $y, true).
  • Casts over functions: (int)$foo not intval($foo).

Section Header Order

// Traits
// Const Properties
// Static Properties
// Public Properties
// Protected Properties
// Private Properties
// Public Methods
// Protected Methods
// Private Methods

Only include sections that have content. Blank line after the separator, before the first item.

Control Flow

  • Happy path last. Handle error conditions first with early returns.
  • Avoid else — use early returns instead.
  • match over switch — always.
  • Always use curly brackets even for single statements.
  • Separate compound conditions into nested if statements for readability.
  • Named arguments when calling methods with 3+ parameters.

Date Handling

  • Elements and element queries: craft\helpers\DateTimeHelper.
  • Services (date arithmetic): Carbon\Carbon.
  • Never mix both in the same class.

Database Conventions

  • [[column]] quoting in Yii2 join conditions.
  • addSelect() in beforePrepare() — safely additive.
  • postDate and expiryDate in addSelect() and indexed on element tables.
  • Db::parseParam() for query parameters. Db::parseDateParam() for dates.
  • Foreign keys with explicit CASCADE / SET NULL behavior.

Naming Quick-Reference

ThingConventionExample
Services (resource)PluralEntries, Volumes, Users
Services (utility)Domain nounAuth, Search, Gc
Queue jobsAction verb, no suffixResaveElements, UpdateSearchIndex
RecordsSame name as modelNamespace distinguishes
EventsThree patternsSectionEvent, RegisterUrlRulesEvent, DefineHtmlEvent
Element actionsAction verb, no suffixDelete, Duplicate, SetStatus
EnumsPascalCase cases, string/int backedPropagationMethod, CmsEdition

For the complete naming reference including file structure conventions, read references/naming-conventions.md.

Verification Checklist

Before every commit:

  1. ddev composer check-cs passes
  2. ddev composer phpstan passes
  3. Tests green
  4. PHPDocs complete on all new/modified code
  5. @throws chains verified
  6. Section headers present and correct
  7. Imports alphabetical and grouped

Capabilities

skillsource-michtioskill-craft-php-guidelinestopic-agent-skillstopic-claude-codetopic-claude-code-plugintopic-claude-code-skillstopic-claude-skillstopic-content-modelingtopic-craft-cmstopic-craft-cms-5topic-craftcmstopic-ddevtopic-phptopic-twig

Install

Quality

0.47/ 1.00

deterministic score 0.47 from registry signals: · indexed on github topic:agent-skills · 39 github stars · SKILL.md body (6,785 chars)

Provenance

Indexed fromgithub
Enriched2026-05-01 18:56:48Z · deterministic:skill-github:v1 · v1
First seen2026-04-18
Last seen2026-05-01

Agent access