
The short answer is:
NEVER!
The longer answer is somewhat less absolute and requires some explanation.
Often you will see Magento tutorials or forum posts that implement a feature or functionality change that is different from what the core does which requires changing something in the core of Magento. Someone may then advise that, instead of hacking core files it is better to copy them into the app/code/local/Mage location and perform the modifications there, so that, upon upgrade, the modifications are not lost. This process is called overriding Magento core functionality and is based on the fact that Magento sets its PHP include paths to first look in app/code/local/ then app/code/community/ and finally in app/code/core/. This has the effect that any files of the same name placed under the local or community name space will take precedence in loading, hence, we can override almost any core file in this way. To learn about how exactly Magento sets up its system, read the excellent series on the Magento Configuration by Alan Storm.
This is one, sometimes recommended, way of overriding core functionality without hacking the core but why is it, as you may conclude from my initial statement, so bad?
First, let’s see what scenarios would be compelling us to override core files:
- We want to change a piece of functionality in a core method so we copy the php file containing the code and modify one or more methods.
- We want to add a new method to a core block class, so it’s available for use in the phtml template so we copy the relevant core Block php file and add our method to it.
- We may have several modifications consisting of core functionality changes and additions over several files.
So, what are we actually doing here, when we override core files?
For one thing, we must override the complete core file because we can’t trim out the stuff that we don’t want changed since we would lose all that functionality and most likely break Magento. Once the overridden file is in place, this will be the file and code Magento will be using from now onwards. Given that most core classes contain several and many times a large number of methods it means that we are effectively overriding all those methods in our file.
Now, remember when we were advised to use this override approach so we can make sure that our customizations are going to be preserved after a Magento version upgrade? Well that, indeed, will be true, but, what if the new Magento version has changes in the very files we have previously overridden? What if they have newly implemented methods or bug fixes in existing methods? Since our override will always take precedence, these new features and fixes will never be operational as our override runs all the old code. If you’re lucky, you may get an error report because a new change falls over due to missing methods but what if you don’t get error reports and instead, somehow, some inexplicable and erratic behavior starts expressing itself on your site?
You can see the problem now, right? After each upgrade, you will have to go and check all your app/code/local/Mage/ overrides and compare them to the new core files and port any core changes to your local override in order to maintain your site’s integrity. If you have lots of such overrides, this will be tedious. Also, if you are a developer who gets passed on an existing site with these kinds of overrides, you will not be happy. Often you won’t even know what the purpose of the override was and you’d need to laboriously go from diff to diff and decipher the meaning of any changes. It gets worse if the previous developer already performed some Magento upgrades.
By now, I guess, you have a good idea about the dangers of applying this kind of override, so, let’s get back to our original question, when, if at all, should you use this approach?
There are a few cases when this approach may be justified, in my opinion, these are the cases:
- If you want to quickly try a core modification to see if it will solve your task as a proof of concept, but don’t want to create an extension just yet. When you are satisfied, you remove your override and implement a proper Magento extension with rewrites.
- If you are implementing a temporary override of some core functionality that you will remove after your task is complete. A prime example of this is overriding the Magento dataflow classes for importing, when you want to change the way the importer handles certain things in an initial customer or product import.
The key concept here is: temporary changes/experiments. You are not planning on leaving your overrides.
Note: There are some other scenarios where local Mage overrides are the only way to customize parts of Magento’s core functionality. I’d like to encourage a discussion in the comments to see what others think about this.
Conclusion
The take-away from this article is, never use the app/code/local/Mage/ approach to permanently override core functionality! If you must, then only use if for temporary changes that you will remove afterwards.
As for the question that now presents itself: how, then, should you implement core overrides? The answer is by creating a custom Magento module and using the available class rewrite mechanisms, or better yet, using event observers if possible.
Originally published on magebase.com. Copyright © 2012 Magebase - All Rights Reserved.




Proud members of the
Actually I think there are a few cases where you have to or there isn’t a better solution out there as of yet. For one, if you are working with Magento Enterprise and you need to change something like a cache container because it isn’t doing what you think it should be doing or there is a bug in it. You submit your bug to Magento but in the mean time you need to change the container code. The only thing you can do is override it in local/Enterprise.
That is the biggest one that I can see.
Yes, in some scenarios, local Mage overrides are the only way to achieve customizations. One of those scenarios is when core code doesn’t use the Mage::getModel() factory method but instantiates some class via the standard new [class]().
However, the point of this article is to discourage wide spread use of this override technique and encourage awareness and debate
.
ahh I was looking at it to literally when you said Never and then didn’t include this point in the scenarios where it might be all right.
The local overlay has it’s place imo. I prefer the overlay over rewrites when i need to change existing core functionality that is tied to this magento instance only. On updates those changes need to be revised either way and it lowers the risk of conflicts with 3rd party modules trying to rewrite the same class.
I agree with most of your points tho, using the overlay carelessly can get messy really fast. Documentation of your changes is a must.
@Erik Good to see various opinions. You have valid points. I’m glad that we have a discussion going around this and I’m keen to see what others think about this.
I agree that if you do this, you definitely should document your overrides thoroughly.
Great post, thank you Robert! I agree that in almost all cases using the include path to override core functionality is a bad idea.
You will only ever *need* to use app/code/local overrides for core functionality that doesn’t use the appropriate factory methods (Mage::getModel() for models, Mage::helper() for helpers and Mage::app()->getLayout()->createBlock() for blocks). I think it only is useful for the (very limited) cases where objects are instantiated using the new operator, or sometimes for fixing rewrite conflicts.
@Vinai quick question about “… or sometimes for fixing rewrite conflicts.” This sounds new to me … can you give a quick example if you have a chance?
Hi Tvetan,
rewrite conflicts are always messy, so depending on the rewritten methods this might or might not work.
That said, many rewrite conflicts can be resolved by copying the class of the module that is loaded last (that is the the rewrite that “wins”) to the local code pool and changing the inheritance so it extends the other class that rewrites the same core class.
The autoloader will then load both of the replacement classes. This works only if the changes/updated code in the two rewrites doesn’t conflict. In that case you will manually have to resolve the issue.
Also, when upgrading the modules you will have to update the changed copy in the local code pool manually.
One more note that I forgot to add to my previous comment, but which I think might be of interrest here: action controllers can’t be overridden using app/code/local, because the standard router always builds the full file system path including the code pool configured for the module. So to override controllers one of the many other options Magento offers must be used.
I totally agree that it should be a temporary way to alter core functionality, however I wonder how many people edit core files “just for a second whilst I do this thing”…? It depends on how temporary “temporary” is perhaps.
Don’t forget that under Magento’s license, your core hacks and local overrides on public sites should be made publicly available, too (as they’re clearly derivative works, a public site is distribution, and so you need to distribute your changes)
Hello,
I’m agree with you that temporary fix should be made with local override.
But there is many others situations where we must use this autoloading override mechanism instead of config.xml one:
- For all classes used by magento but not loaded with the magento api like abstract classes, lib classes, etc: hotfix for zend_framework is one of the example. one other example is address validation before varien rewrote customers attributes: address validation was made in an abstract class, so how can you update validation process with config.xml rewrite?
- If you do not allow that your code can be overwritten: one example could be a license manager module.
- To be able to provide a second rewrite mechanism. I’ll take example of classes frequently overwritten. If you wants to also overload it, you have no others choices.
If the local problem is only the Magento upgrade and compare updates, the source code documentation must be a solution.
And as you know Varien is not very efficient with backward compatibility so even if you overload source code in config.xml files, it’s important to check if code still work; I’ll take the example of magento upgrade between 1.3 and 1.4 where many events has been renamed. One other example is the acces methods to attributes which has changed; in this two cases, even if you override classes in config.xml, it won’t reduce the risk of backward compatibility.
And autoloading override has the advantage to be more performant than rewrite in config.xml file because it make class loading faster.
Hi Matthieu,
the only case I agree with your list is for classes that are instantiated with the new operator, for example Zend Framework components. Luckily these classes very rarely need to be rewritten. I don’t agree with most of your other reasoning.
- I find that, with more experience, there is less need to use rewrites. Instead, often event observers can be used to accomplish the same functionality. For abstract classes, rewriting of the concrete implementations is a better solution (in my opinion) then reverting to using the include path hack.
- PHP license manager modules are a PITA. In all projects I was involved with closed source modules or modules using a license manager where not used, precisely because they prohibit extensibility and upgradeability.
- Rewrite conflicts are a rare thing (unless a shop suffers from acute moduleinitis, maybe). If you encounter a rewrite conflict it’s ugly already, and in that case using the local include path is a possible solution, since you will not get around modifying some code anyway.
If you are a developer creating one of the conflicting rewrites, it is better to use event observers instead, which is quite often possible.
Backward compatibility is sometimes a problem with rewrites, that is true. Once again a reason to focus hard on event observers instead.
The argument that the files from the local code pool load faster is pretty awful
This problem should be tackled using the compiler instead of the include path hack.
Hello Vinai,
I understand your point of view.
Observers are a possible solution, and I use them, but make harder code source update. Article says that local overload make code source update harder because we need to make diff. honestly, I prefer make diff instead of going in config.xml and found which observers are called on an event.
My performance analysis was not to put core/Mage/Core in local. I know that we must used compilation. but between rewrite with config.xml and autoloading rewrite, autoloading is faster.
My reflexion about backward compatiblity was not about rewrites, but about Magento code source upgrade. Varien do not really take care about this point and so, if we made some overload, with rewrite or with autoloading, we must check backward compatibility.
For me, local override is a false problem based only upon work methods. this overloading mechanism can provide many solutions, for temporary fixes or for more longer ones.
But this is my point of view
I so agree with this “local override module” method. I’ve been using it for several months now and it is the best way I have found to gather all project specific Core rewrites. Using well targeted observers (that aren’t called unnecessarily) in this local override module is a great way to change Magento’s behavior from Blocks to Models, Layout… up to config.
For French readers of this post, may I link here to a blog post that explains this in French?
Here you go: http://blog.agence-soon.fr/magento-utiliser-un-module-local-de-surcharge/
Thank you all for your input on this topic. Clearly, there are various opinions and it’s great to see the reasoning behind each of them.
It seems that it ultimately comes to how pedantic we are in our approach to overriding core functionality and then how much effort we want to put into our overrides.
To me personally, creating a custom module and using observers as much as possible is the most elegant approach. I also work with WordPress a lot and there I use the WP action hooks and filters a lot for customizing core functionality so this paradigm is “second nature”. I agree that this approach requires more discipline also in terms of documenting your “injections” but if that is in place, you certainly have a robust approach that is as bulletproof as it can be.
The performance aspect of overrides may be another point of discussion but I think there is so much stuff going on in Magento that a few overrides here and there don’t make much of a difference as opposed to local/Mage include overrides. If anyone wants to make a test case in terms of performance of rewrite overrides vs. local include overrides be my guest
.
I’m using this approach only for applying patches from Magento Core Team.
Hello,
I can’t agree with this concept of not overriding app/core/local/mage/ . Recently I did a site where, the breadcrumbs need to be changed based on the catalog pages.
How to achieve this without overriding the Magento default functionality ?
Thanks And Regards,
Rupak Banerjee.
I’m quite new to Magento but trying to learn
I get an error “Could not determine temp directory, please specify a cache_dir manually”. I read various posts and they all tell me to make changes to the file:
“/lib/Zend/Cache/Backend/File.php”
And change ‘cache_dir’ => null to something like ‘cache_dir’ => ‘var/tmp’.
However, I can imagine that during a upgrade this setting will be overwritten. Someone told me it’s better to copy “/lib/Zend/Cache/Backend/File.php” to “/app/code/local/Zend/Cache/Backend/File.php” and use the Magento overwrite feature.
Is this in your opinion the right way to fix this or do you recommend other solutions?
Kind regards,
Gijsbert
This sounds more like a web server misconfiguration and the best thing is to contact your host or site admin.
We never had this error and never had to hack the zend cache files.
Hello Robert, I fixed the ‘Could not determine temp directory’ by simply adding a upload_tmp_dir to php-configuration in stead of changing /lib/Zend/Cache/Backend/File.php. Thanks!