Receber por email
← Voltar para o catálogo

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 blocks (@author, @since, @throws chains, documenting exceptions), section headers (=========), class organization, naming

56estrelas
Atualizado há 4 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add michtio/craftcms-claude-skills

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/craft-php-guidelines/svg)](https://www.skillteca.com.br/skills/craft-php-guidelines)
#ai

Skills relacionadas

Ver todas de Desenvolvimento →

Alerta por categoria

Receba novas skills de Desenvolvimento toda segunda

1 email curto, só com as skills novas de Desenvolvimento. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

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

  • Official coding guidelines: https://craftcms.com/docs/5.x/extend/coding-guidelines.html
  • Class reference: https://docs.craftcms.com/api/v5/
  • Generator reference: https://craftcms.com/docs/5.x/extend/generator.html

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" suffix — ResaveElements, 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. (Craft core puts @author at the class level only; placing it on methods too is this project's house convention, not core style.)
  • Don't use string|null — use ?string (short nullable notation).
  • Forget parent::defineRules() and you lose all inherited validation.
  • Using [$this, '_validateFoo'] callable arrays or inline closures in defineRules() — Craft core uses string method names: [['attr'], 'validateAttr']. The validator method is public, no underscore — Yii invokes it by name.
  • 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.
  • Calling Craft-specific methods directly on Craft::$app (Craft::$app->getConfig()) — PHPStan can't resolve them because the static type is Yii's base union. Narrow with a typed local: /** @var \craft\web\Application $app */ $app = Craft::$app;. Don't use @phpstan-ignore-line.
  • Duplicating contract constants as private const across multiple classes with "keep in lockstep" comments — PHPStan can't detect drift. Declare public const on the owning service, reference as OwnerService::CONSTANT_NAME everywhere else.

Reference Files

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

| Task | Read | |------|------| | Writing PHPDocs, @author, @since, @throws, @var, @param, type references | references/phpdoc-standards.md | | Class structure, section headers, ordering, enums, control flow, comments, whitespace | references/class-organization.md | | Naming classes, methods, properties, files, services, events, migrations | references/naming-conventions.md | | CP Twig templates, form macros, translations, file headers, validation | references/templates-and-patterns.md | | ECS, PHPStan, scaffolding commands, commit messages | references/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. (Craft core itself uses dash separators — // ---- — with functional/domain labels like // Statuses or // Events. The ===== separators and visibility labels below are a deliberate house convention for consistency across this project's plugins, not core style.)
  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.
  • Prefer match over switch for value-mapping and returns. The official guideline is "don't use switch when a single if suffices"; switch remains acceptable where it reads more clearly (and is common in core).
  • 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

| Thing | Convention | Example | |-------|-----------|---------| | Services (resource) | Plural | Entries, Volumes, Users | | Services (utility) | Domain noun | Auth, Search, Gc | | Queue jobs | Action verb, no suffix | ResaveElements, UpdateSearchIndex | | Records | Same name as model | Namespace distinguishes | | Events | Three patterns | SectionEvent, RegisterUrlRulesEvent, DefineHtmlEvent | | Element actions | Action verb, no suffix | Delete, Duplicate, SetStatus | | Enums | PascalCase cases, string/int backed | PropagationMethod, 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 comp
Compartilhar X LinkedIn