Install
$ agentstack add skill-ddtcorex-dev-skills-hub-magento2-dev-core ✓ 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
Magento 2 Developer Core
This skill provides the foundational patterns all Magento 2 developers must follow. It covers architectural decisions, security, and best practices that apply to every part of a Magento project.
Related Skills
This is the foundation the other Magento 2 skills build on: magento2-frontend-dev and magento2-hyva-dev cover the two mutually exclusive theme stacks (check the theme's theme.xml parent to see which one the project actually uses — Luma vs Hyvä), magento2-backend-dev covers APIs/CLI/cron, and magento2-linter, magento2-security-scan, magento2-performance-audit verify the patterns below. In a Govard environment, pair this with govard-magento for the container/CLI side.
Core Architectural Standards
Dependency Injection (DI)
DO: Use Constructor Injection for all dependencies.
class MyService
{
public function __construct(
private readonly ProductRepositoryInterface $productRepository,
private readonly LoggerInterface $logger
) {}
public function getProduct(int $id): ?ProductInterface
{
return $this->productRepository->get($id);
}
}
NEVER: Use ObjectManager::getInstance() (Service Locator anti-pattern).
// WRONG - Never do this
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$product = $objectManager->create(Product::class);
// CORRECT
public function __construct(ProductFactory $productFactory) {
$this->productFactory = $productFactory;
}
Service Contracts
Always prefer interfaces in Api/ folders over concrete classes:
// WRONG
public function __construct(Product $product) { }
// CORRECT
public function __construct(ProductInterface $product) { }
Repositories
Always use repositories for data operations. Never call load(), save(), or delete() directly on models.
// WRONG
$product = $this->productFactory->create();
$product->load($id);
// CORRECT
$product = $this->productRepository->getById($id);
// WRONG
$this->productFactory->create()->save($product);
// CORRECT
$this->productRepository->save($product);
Plugins (Interceptors)
Prefer before and after plugins over around plugins:
| Plugin Type | Use Case | |-------------|----------| | before | Modify arguments before method execution | | after | Modify return value after method execution | | around | Avoid unless necessary - blocks original method execution |
// Prefer this pattern
public function beforeExecute(
SaveProduct $subject,
ProductInterface $product
): array {
// Validate or modify $product before save
return [$product];
}
// Instead of around plugins that wrap the entire method
Plugins only intercept public methods, must be stateless, and should not target a module's own classes or data objects. Register them in di.xml with an explicit sortOrder when order matters. Observer order is not guaranteed by contrast — if the sequence matters, use a plugin instead of an observer.
Declarative Schema
Use db_schema.xml for all database changes. Never modify database directly:
Coding Standards
PHPCS (Magento2 Ruleset)
| Rule | Example | |------|---------| | Class naming | PascalCase - ProductRepository | | Method naming | camelCase - getProductById() | | Property naming | snake_case - $product_id, $_cacheIdPrefix | | Visibility | Always explicit - public, protected, or private | | Indentation | 4 spaces (no tabs) | | Line endings | LF (Unix) |
PHPStan Requirements
Always run PHPStan at level 6+ using bitexpert/phpstan-magento for Magento's magic classes.
# In a Govard environment
govard sh -c "vendor/bin/phpstan analyse app/code -c phpstan.neon"
Strict Typing
Always include at the top of new PHP files:
request->getParam('id');
XSS Prevention
Always escape output in templates:
// HTML content
escapeHtml($userInput) ?>
// HTML attributes
escapeHtmlAttr($id) ?>">
// JavaScript strings
var name = 'escapeJs($productName) ?>';
// URLs
escapeUrl($url) ?>">
// CSS values
escapeCss($color) ?>">
The Magento2.Security.XssTemplate PHPCS sniff treats any method whose name contains html (e.g. getLabelHtml()) as already safe — do not wrap it in escapeHtml() again, that double-escapes the output.
CSRF Protection
Include form key in all forms:
escapeUrl($block->getSubmitUrl()) ?>" method="post">
getBlockHtml('formkey') ?>
Discouraged Functions
Use Magento wrappers instead of native PHP:
| Native PHP | Use Instead | |------------|-------------| | serialize/unserialize | SerializerInterface | | json_encode/decode | \Magento\Framework\Serialize\Serializer\Json | | curl_* | Magento\Framework\HTTP\ClientInterface | | date(), time() | \Magento\Framework\Stdlib\DateTime\DateTime | | md5(), sha1() | EncryptorInterface |
Verification Workflow
Run these checks before completing any backend task:
# 1. PHPCS Linting
vendor/bin/phpcs --standard=Magento2 app/code/Vendor/Module
# 2. PHPStan Analysis
vendor/bin/phpstan analyse app/code/Vendor/Module -c phpstan.neon
# 3. DI Compilation
bin/magento setup:di:compile
# 4. Flush cache
bin/magento cache:flush
Usage Patterns
Creating a Module
- Create registration file:
app/code/Vendor/Module/registration.php - Create
etc/module.xmlwith correct sequence - Define
etc/di.xmlfor preferences and plugins - Use
db_schema.xmlfor database schema - Run
bin/magento module:enable Vendor_Module
CLI Commands
// etc/di.xml
Vendor\Module\Console\Command\SyncCommand
Cron Jobs
0 2 * * *
Configuration File Reference
Quick lookup for what each etc/ XML file controls:
| File | Purpose | |------|---------| | di.xml | Dependency injection: preferences, plugins, virtual types | | events.xml | Observer registration | | crontab.xml / cron_groups.xml | Cron jobs / cron group tuning | | acl.xml | Admin permission tree | | routes.xml | Frontend/adminhtml controller routing | | webapi.xml | REST route declarations | | system.xml | Admin configuration fields | | config.xml | Default config values | | indexer.xml + mview.xml | Indexer declaration + its change tracker (enables schedule mode) | | extension_attributes.xml | Extend a core entity without a preference | | view.xml | Theme image/gallery sizing, layout config | | queue.xml / communication.xml | Message queue publishers, consumers, topics | | widget.xml | CMS widget declaration | | email_templates.xml | Transactional email template registration |
Rule of thumb: stale data is an indexer problem (check indexer:status); stale output is a cache problem (cache:clean/cache:flush). Diagnose in that order rather than assuming a cache bug.
Anti-Pattern Severity (for code review)
| Anti-pattern | Severity | Why | |---|---|---| | ObjectManager::getInstance() outside factories/proxies/bootstrap | Critical | Breaks testability, hides dependencies, escapes DI interception | | ` on a core class | High | Replaces the class entirely, blocks other extensions, upgrade-fragile | | Plugin on Sales\Model\Order, Quote, Checkout, Payment, Customer\Model\Session | High | High-traffic core classes — re-verify after every Magento upgrade | | Raw SQL outside a ResourceModel | Medium | Bypasses events, plugins, indexers, caching | | Copy-pasted theme template override | Medium | Silently breaks when Magento changes the original on upgrade — prefer layout XML/view models | | Extending Action, AbstractModel, Template` base classes | Low | Prefer result interfaces, repositories, view models |
Testing Conventions
- Unit tests (
Test/Unit/): typed mocks only, neverObjectManager::getInstance(), never test private methods via reflection — if a private method needs its own test, it belongs in its own class. - Integration tests (
Test/Integration/): useBootstrap::getObjectManager(), load data with@magentoDataFixturefixture files rather than creating entities inline, and annotate with@magentoDbIsolationso tests don't leak state between each other. - Functional tests: MFTF (Magento Functional Testing Framework) for full user-journey coverage.
References
For detailed patterns, see:
references/coding-standards.md- Extended PHPCS/PHPStan guidereferences/architecture-patterns.md- Service contracts, repositories, pluginsreferences/security-best-practices.md- Security checklist and patterns
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: ddtcorex
- Source: ddtcorex/dev-skills-hub
- 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.