This article covers how to create and apply patches to Magento 2. This article assumes you’re using Composer to install Magento (the second method listed in the “How to get the Magento software” table here), which is the method I recommend for any merchant running Magento on a production site.
If you install Magento using Composer, it’s impossible to directly edit the core files in a way that will cause those edits to persist, as they are never committed to version control, but are instead pulled in with Composer. However, with the help of the Composer plugin composer-patches, it’s possible to apply patches in a manner that will cause those changes to be tracked within version control.
The most common use case for patching the core of Magento is that you’ve encountered a core bug, and that’s the use case we’re going to assume in this article. There are rare occasions where a patch may be necessary to do other things, such as tweak core functionality or do something that’s not possible with a preference, plugin, event, or other standard Magento development method. However, this should not be done lightly and only when all other options have been exhausted.
First, let’s talk about some of the ways that you can create/obtain a patch:
Creating Patches
Github
One of the great things about Magento 2 is the fact that it’s an open source platform with a very active community. Chances are if you’ve run into an issue with the core application, someone else has as well. If you search for an issue or pull request on the Magento 2 Github account, you can often find a pull request or a specific commit that looks like it will fix your issue. For example, if you’re using Magento 2.1.9 or earlier, you might run into an issue where it’s impossible to save a product in the admin with a negative quantity. If you search for this issue on the Magento Github, you might come across this issue. If you look towards the bottom of that issue, you’ll see a link to this commit. You can turn commit and pull request pages into a patch by appending “.patch” to the URL. (For example: https://github.com/magento/magento2/commit/11bcdcc83d6d5d3adc4151cfefd62b6f4cdcd680.patch) In the Applying Patches section below, we’ll cover how to apply a patch like this to Magento.
Magento Support
When Magento Commerce merchants run into core issues, they can submit issues to Magento Support, who will commonly reply with patches to solve those issues. When dealing with Magento Support, you should request patches that can be applied to Magento installed via Composer. In other words, patches with paths mapped to the vendor/***
directories, rather than app/code/Magento
.
Custom Patch
There are occasions when a core bug needs to be fixed by editing core code. While some core bugs are more appropriately fixed by writing a plugin/preference/etc., to circumvent the issue, some times writing a patch is a better course of action. The benefit of writing a core patch is that if the underlying code changes in a future release, the patch should fail to apply, thereby alerting you that the patch should be removed/changed. Creating a patch may also take less time, depending on the nature of what is being fixed.
There are several ways patches can be created for files that are not tracked by Git, but here is one way to do it (the example is assuming you want to patch the vendor/magento/module-catalog/Setup/UpgradeSchema.php
file):
# cd to the package that you're going to patch, as the paths in # the patch need to be relative to the Composer package cd vendor/magento/module-catalog git init . git add -A . git commit -m "Adding files to create diff" # Make changes to the vendor/magento/module-catalog/Setup/UpgradeSchema.php file and then proceed git add -A . git commit -m "Commit explaining the changes contained in the patch" git format-patch -1 HEAD # Rename the new patch # Get rid of the temp Git repo rm -rf .git
When naming patches, use a name that allows the patch to be easily linked back to the source issue, such as github-issue-6474.patch
or MAGETWO-56699.patch
. If there is no source issue to link to, you can use a short dash-delimited description of the issue.
Preparing Patches
To apply patches using composer-patches, there are a couple of prerequisites:
- Paths in the patch file must be relative to the Composer package that you’re planning to patch. For example, if you need to patch the
MagentoCatalogInventoryModelStock
class, the path in your patch needs to beModel/Stock.php
, notvendor/magento/module-catalog-inventory/Model/Stock.php
. - You’ll need to ensure that a patch file is only changing files in a single Composer package. If a patch applies to multiple Composer packages, you’ll need to split the patch file into multiple patch files.
For example, let’s say you’re running into the issue linked to in the Github section above. Here is how you’d prepare the patch file:
- Download the https://github.com/magento/magento2/commit/11bcdcc83d6d5d3adc4151cfefd62b6f4cdcd680.patch file
- You’ll see that the patch applies to both
app/code/Magento/CatalogInventory
andapp/code/Magento/Ui
. Those directories won’t exist in your installation, but the corresponding paths will:vendor/magento/module-catalog-inventory
andvendor/magento/ui
. Since those are two separate composer packages, you’ll need to split the contents of that file into two separate files. - You’ll then need to find all instances of
app/code/Magento/CatalogInventory
andapp/code/Magento/Ui
and delete them since the patch file must be relative to the composer package. - Here is what the two resulting files should look like:
github-9139_module-catalog-inventory.patch
github-9139_module-ui.patch
Applying Patches
Follow these steps to apply a patch to a Magento site:
- Create a
patches/
directory in the root of your Magento installation. - Move the patch(es) you want to apply to the
patches/
directory. - Run this command in the root of your local project:
composer require cweagans/composer-patches
- Open the
composer.json
file at the root of your Magento installation and edit the existingextra
object to look like this, specifying the Composer package to apply the patch(es) to as well as a description of the patch(es) and a reference to the file location:"extra": { "magento-force": "override", "composer-exit-on-patch-failure": true, "patches": { "magento/module-catalog-inventory": { "GITHUB-9139: Unable to save product with negative quantity": "patches/github-9139_module-catalog-inventory.patch" }, "magento/module-ui": { "GITHUB-9139: Unable to save product with negative quantity": "patches/github-9139_module-ui.patch" } } }
The
composer-exit-on-patch-failure
option is important to enable so that if a patch fails to apply, Composer will return a non-zero exit code. If you’re using an automated deployment tool like Capistrano, this is helpful as it will prevent a deployment from succeeding. A common scenario where this might occur is if a patch is applied to fix something that then gets fixed in a new release of Magento. The patch will fail to apply when that new version of Magento is deployed because the changes will be contained in the new release. In that scenario, the failing patch would need to be removed. - Run
composer install
to apply the patch(es). - Run
composer update <PACKAGE NAME>
(e.g.composer update magento/module-catalog-inventory
) to update the composer lock file. The lock file tracks which patches have been applied to each composer package in anextra > patches_applied
object. - Add the
composer.json
,composer.lock
, and the newly addedpatches/***
patch file to your version control system, commit, and then push the changes.
Now, whenever you deploy your Magento application to development, stage, or production environments, those patches should get applied whenever “composer install” is run.
Conclusion
Now that you know how to apply patches to Magento 2, enjoy squashing those core bugs. If you have any questions about anything in this article, feel free to hit me up on Twitter.