Add Extensions and Themes
Understanding extension installation, read-only filesystem limitations, PHP version matching, proper coding patterns, and module enablement.
Adding Extensions & Themes
How to Install Extensions and Themes
Installation Workflow Overview
Step 1: Checkout New Branch
Check out a new branch from:
- Starter: From
masterbranch - Pro: From
integrationbranch
# Starter
git checkout master
git pull origin master
git checkout -b add-extension-name
# Pro
git checkout integration
git pull origin integration
git checkout -b add-extension-name
Step 2: Install Extension (Two Methods)
Method 1: Composer (Preferred)
composer require vendor/module-name
- Recommended approach
- Better dependency management
- Easier updates
- Proper version control
Method 2: Drop Files
app/code/Vendor/Module/
- Manual file placement
- Less common
- Harder to maintain
- Use only if necessary
Composer Installation (Preferred Method)
Using Composer for Extensions
Standard Composer Installation
composer require vendor/module-name:^1.0
Installing from Private VCS Repository
VCS Repository Configuration
You can install from a git repository (like GitLab) using VCS repository configuration in composer.json:
{
"repositories": [
{
"type": "vcs",
"url": "https://gitlab.com/vendor/module-name.git"
}
]
}
Then install:
composer require vendor/module-name:dev-master
Repository Types Supported
- VCS: Git, GitHub, GitLab, Bitbucket
- Package: Custom package repositories
- Composer: Packagist or private Composer repos
- Path: Local filesystem paths
Critical: PHP Version Matching
IMPERATIVE Requirement
PHP Version Must Match!
It is IMPERATIVE to run composer install or composer update in an environment that matches the PHP version of the deployed site.
Why This Matters:
- Composer dependencies are established in
composer.lock composer installruns before build hooks- Tries to install dependencies from
composer.lock - Version mismatch causes installation failures
- May result in incompatible packages or missing dependencies
Example Problem
Scenario:
- Developer runs
composer updateon PHP 8.1 - Cloud environment uses PHP 8.2
- composer.lock contains PHP 8.1-specific dependencies
- Deployment fails because dependencies don't match PHP 8.2
Solution:
Always run Composer commands on an environment with the same PHP version as your Cloud environment!
Check PHP Version
# Local environment
php -v
# Cloud environment (SSH)
php -v
# Verify they match before running composer commands!
Read-Only Filesystem Limitations
Understanding Read-Only Generated Directory
Critical Limitation
In Cloud environments, the generated/ directory is read-only after deployment.
What This Means:
- Modules cannot write to
generated/at runtime - All code generation must happen during build phase
- Writing to
generated/when read-only causes fatal error - Site breaks if module tries to write at runtime
The ObjectManager Problem
Bad Code Pattern
If a module uses ObjectManager outside of the constructor, there is a reasonable chance files will be written to generated/ directory.
Example of BAD Code:
// ❌ BAD - ObjectManager used outside constructor
class BadExample
{
public function execute()
{
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$product = $objectManager->create('Magento\Catalog\Model\Product');
// This may try to write to generated/ directory!
}
}
Why This Fails:
- ObjectManager may generate factory/interceptor classes
- Tries to write to
generated/directory generated/is read-only in Cloud- Results in fatal error and site crash
Correct Approach
GOOD Code Pattern
// ✅ GOOD - Dependency injection
class GoodExample
{
protected $productFactory;
public function __construct(
\Magento\Catalog\Model\ProductFactory $productFactory
) {
$this->productFactory = $productFactory;
}
public function execute()
{
$product = $this->productFactory->create();
// Safe! Factory already generated during build
}
}
- Uses dependency injection (constructor)
- Factories generated during build phase
- No runtime writes to
generated/ - Works perfectly in Cloud environment
Module Quality and Marketplace Extensions
Extension Quality Considerations
Marketplace Extensions
Marketplace extensions are usually good. They've been vetted by Adobe and follow best practices.
- Properly coded using dependency injection
- Don't use ObjectManager outside constructors
- Compatible with read-only filesystem
- Tested for Cloud compatibility
Third-Party Extensions (Non-Marketplace)
Be cautious with extensions from unknown sources:
- May use ObjectManager incorrectly
- May not follow Magento best practices
- May write to filesystem at runtime
- May break in Cloud environment
- Always test thoroughly in integration!
Enabling Modules
Module Activation Process
Step 1: Enable the Module
bin/magento module:enable Vendor_ModuleName
What This Does:
- Updates
app/etc/config.php - Sets module status to
1(enabled) - Makes module active in Magento
Step 2: Review Changes to config.php
git diff app/etc/config.php
You should see:
'Vendor_ModuleName' => 1,
Step 3: Commit and Push
git add app/etc/config.php composer.json composer.lock
git commit -m "Add Vendor_ModuleName extension"
git push origin add-extension-name
Important: config.php Must Be in Git
Because app/etc/config.php (where modules are enabled) should be saved in git, you simply need to run bin/magento module:enable and then commit and push.
Installing Themes
Theme Installation Process
Theme Installation is Basically Identical to Extensions
The process is the same, with one difference:
Location Difference
| Type | Composer Location | Manual Location |
|---|---|---|
| Extension | vendor/vendor-name/module-name/ | app/code/Vendor/Module/ |
| Theme | vendor/vendor-name/theme-name/ | app/design/[AREA]/Vendor/theme-name/ |
Manual Theme Installation Path
Theme Directory Structure:
app/design/frontend/Vendor/theme-name/- Frontend themesapp/design/adminhtml/Vendor/theme-name/- Admin themes
Composer Theme Installation
composer require vendor/theme-name
Enable Theme
- Install theme (Composer or manual)
- Navigate to Content → Design → Configuration
- Select store view
- Click Edit
- Select theme from dropdown
- Click Save Configuration
- Flush cache:
bin/magento cache:flush - Deploy static content (or wait for build)
Complete Installation Workflow
Step-by-Step: Installing an Extension
| Step | Command/Action | Notes |
|---|---|---|
| 1 | git checkout -b add-extension |
From master (Starter) or integration (Pro) |
| 2 | composer require vendor/module |
Ensure PHP version matches Cloud |
| 3 | bin/magento module:enable Vendor_Module |
Updates app/etc/config.php |
| 4 | git status |
Verify config.php, composer.json, composer.lock changed |
| 5 | git add -A |
Stage all changes |
| 6 | git commit -m "Add extension" |
Commit to branch |
| 7 | git push origin add-extension |
Push to Cloud, triggers deployment |
| 8 | Monitor deployment logs | Watch for errors during build/deploy |
| 9 | Test in integration environment | Verify extension works correctly |
| 10 | Merge to staging, then production | After successful testing |
ObjectManager Anti-Pattern
Why You Should Never Use ObjectManager
Side Note on ObjectManager
I am confident that you know not to use ObjectManager in your code (except in the 0.01% of use cases).
It's a BAD Idea Because:
- Code smell: Indicates poor code design
- Hidden dependencies: Not visible in constructor
- Runtime errors: May break in Cloud (read-only generated/)
- Testing difficulty: Hard to mock and test
- Performance impact: Slower than dependency injection
- Maintenance nightmare: Hard to track dependencies
The Embarrassment Factor:
Save yourself the embarrassment of having someone else come in to find you added code smells to your code, or merchants upset asking why their site breaks when going to production!
The 0.01% Valid Use Cases
ObjectManager is acceptable ONLY in:
- Test classes
- Setup/upgrade scripts (deprecated pattern)
- Factory classes (generated code)
- Extremely rare edge cases in framework code
Best Practices
Extension Installation Best Practices
Do's
- Use Composer: Preferred method for dependency management
- Match PHP versions: Critical for composer.lock compatibility
- Test in integration: Always test before staging/production
- Check Marketplace: Prefer vetted Marketplace extensions
- Review code: Inspect third-party code for quality
- Enable modules properly: Use bin/magento module:enable
- Commit config.php: Essential for deployment
- Use dependency injection: Proper Magento pattern
- Document extensions: Keep track of what's installed
Don'ts
- Don't use ObjectManager: Except in 0.01% of cases
- Don't skip PHP version check: Causes deployment failures
- Don't install untested extensions in production: Always test first
- Don't write to generated/ at runtime: Read-only filesystem
- Don't forget to enable modules: Won't work without module:enable
- Don't commit vendor/ directory: Only composer.lock needed
- Don't use poorly coded extensions: Check quality first
Troubleshooting
Common Issues and Solutions
Issue 1: Fatal Error - Can't Write to generated/
Error Message:
Fatal error: Uncaught exception writing to generated/ directory
Cause:
Extension uses ObjectManager outside constructor or writes to filesystem at runtime.
Solution:
- Identify problematic extension
- Review extension code for ObjectManager usage
- Contact vendor for Cloud-compatible version
- Consider alternative extension
- Fix code if custom extension (use dependency injection)
Issue 2: Composer Install Fails During Deployment
Cause:
composer.lock created with different PHP version than Cloud environment.
Solution:
- Check Cloud PHP version:
php -v(SSH) - Match local PHP version to Cloud
- Delete
composer.lock - Run
composer updatewith matching PHP version - Commit new
composer.lock - Push and redeploy
Issue 3: Module Not Showing Up
Possible Causes:
- Module not enabled in config.php
- config.php not committed to git
- Cache not cleared
- Module registration missing
Solution:
- Run
bin/magento module:enable Vendor_Module - Verify module in config.php:
grep Vendor_Module app/etc/config.php - Commit config.php to git
- Clear cache:
bin/magento cache:flush - Check module registration.php exists
Exam Tips
Key Points to Remember
- Checkout from: master (Starter) or integration (Pro)
- Installation methods: Composer (preferred) or drop in app/code
- VCS repositories: Can install from GitLab/GitHub using VCS config
- PHP version matching: IMPERATIVE - must match Cloud environment
- composer.lock: Dependencies established here, used during build
- Read-only generated/: Cannot write at runtime, causes fatal errors
- ObjectManager problem: May write to generated/ outside constructor
- Marketplace extensions: Usually good, properly coded
- Enable command: bin/magento module:enable Vendor_Module
- config.php: Must be committed to git for module enablement
- Theme location: app/design/[AREA]/Vendor/theme-name/
- ObjectManager: Don't use except 0.01% of cases (code smell!)
- Dependency injection: ALWAYS use in constructors (proper pattern)