Headless Digital 6 min readmagentodev-workflow

How to fix - products not showing in categories Magento 2

The original video this piece is based on.

This is a reference piece, pulled together from a run of short fix-it videos I recorded between 2020 and 2023. They were each filmed against whatever Magento version I was running at the time, somewhere across the 2.4 line, so treat the exact commands and version numbers as the shape of the problem rather than something to paste straight in. The problems themselves have not changed much. These are still the things that have a Magento store on its knees at nine on a Monday, and the fixes still start in the same places.

Products vanish from categories

You add products, assign them to a category, and the category page shows nothing. No error, just an empty grid. Nine times out of ten this is search. Since 2.4 Magento has required a real search engine, originally Elasticsearch and now OpenSearch on current versions, and category browsing leans on it more than people expect. If the engine is not running, or the index is stale, products quietly disappear from the front end even though they are sitting right there in the admin.

The fix is dull and reliable. Check the search service is actually running. Reset and rebuild your indexes with bin/magento indexer:reindex, flush the cache, and the products come back. If you have just upgraded or moved environments, this is the first thing to rule out before you go hunting for anything cleverer. I have watched developers lose an afternoon to a category template when the real answer was a stopped Elasticsearch container.

The 503 maintenance page, and why you sometimes do not see it

Put a store into maintenance with bin/magento maintenance:enable and you get a 503. A lot of people then want to customise that page so customers see something on brand instead of the stock holding screen. Worth doing, and it is just a phtml template you override.

The gotcha that catches beginners is mode. You only get the proper 503 page in production mode. In developer mode Magento shows you a different bootstrap style error instead, so you can test your nice custom 503 all you like and never see it. Switch to production mode first, then enable maintenance, then look. If your maintenance page is not appearing the way you built it, the mode is almost always why.

Installing extensions the way that does not bite later

There is endless hand wringing about whether you are allowed to drop a module into app/code from a zip. Here is my honest take after years of it. There is nothing morally wrong with app/code as long as your deployment is sane and the module is in your repo. But Composer is the better way, and I would use it as a tie breaker when choosing between two similar extensions. If a vendor publishes to Packagist and the other only ships a zip, take the Composer one. The payoff comes at upgrade time, when composer update can pull a compatible version instead of you re-downloading and re-merging files by hand.

The mechanics are simple. composer require vendor/package, then run setup:upgrade, di:compile and static content deploy as needed. The thing to actually understand is that both composer.json and composer.lock have to make it into your deploy, because the lock file is what guarantees the server installs the same versions you tested locally. Get that right and module installs stop being a source of drama.

Configuration that travels between developers

The old way to share a setting was to make the change in the admin, dump a SQL file, and send it round. Magento gives you something better through configuration in config.php. You can hold non sensitive settings there, commit them, and every developer who pulls the repo gets the same configuration after a quick bin/magento app:config:import. There is even an app:config:dump command that scrapes every current setting into the file in one go, which is genuinely useful when you are checking that settings carried across during a migration.

One sharp edge to know about. A value locked in config.php becomes the boss. The admin field for it goes read only, because the file overrides the database. That is exactly what you want for something like URL rewrites that should never change, and exactly what you do not want for a setting a client needs to flip themselves. Sensitive values such as payment keys belong in env.php, not in the shared file, and frankly I leave most of the truly sensitive ones in the admin rather than dumping everything. Use config.php for the settings a team needs to stay in sync on, not as a place to empty the whole database.

The categoryProductByCustomSortOrder error after a 2.4.5 upgrade

This one is a public service announcement more than a tutorial. If you upgrade to 2.4.5 with an Amasty layered navigation extension installed, you can hit a fault in the search result applier with categoryProductByCustomSortOrder in the trace. It is a horrible one to search for, and because the third party module sits well down the stack trace, it reads at first like a core bug. It is the interaction between the upgrade and that extension. The fix was already documented on the Magento issue tracker by the community, which is the real lesson here. When a stack trace looks like core but does not quite add up, search the issue tracker and your installed extensions before you start patching framework files.

When you genuinely have to patch core

Sometimes the fix lives in a vendor file and you cannot wait for an official release. Editing files in vendor directly is a trap, because the next composer install wipes it. The right approach is a patch. Capture the change as a diff, then apply it through cweagans/composer-patches so the patch is declared in composer.json and re-applied automatically on every install. That keeps the change in version control, survives upgrades, and documents exactly what you altered and why. A core change that is invisible to the next developer is how you end up debugging the same ghost twice.

The thread running through all of these

Look at the list. Reindex when the front end lies to you. Mind which mode you are in. Trust the lock file. Know what overrides what. Read the stack trace properly. Patch instead of hacking vendor. None of it is exotic. It is the boring operational discipline that keeping a Magento store alive demands, day after day, and the sheer amount of it is a fair part of why I moved a lot of my work to a lighter stack, which I wrote about in why I moved from Magento to headless. Learn these anyway. Whatever platform you land on, the habit of checking the dull thing first will save you more time than any clever trick.