— Article — № 011

011 —Magento

Magento 1 in 2026: editing live without nuking the catalog cache

A Dutch agency, a frozen Magento 1 shop, a Friday at 23:41, and the catalog_product_flat tables that nearly took the storefront down at checkout time.

Wooden printer's type case open on dark oak workbench, brass handle, lead type sorted in compartments, red wax tag.
Hero · staged still№ 011

It was 23:41 on a Friday when the Loom landed in our inbox. A Dutch agency we work with, four developers, runs maintenance on a Magento 1.9.4.5 catalog for a B2B reseller doing about €11k a day in orders. The lead had recorded himself staring at a terminal: php -f shell/indexer.php reindexall had been running for nineteen minutes, the storefront was returning stale prices on roughly one in six product pages, and the client's buyer in Hamburg had just placed an order at the old price for 240 units.

Magento 1 reached end-of-life in June 2020. It is now May 2026. A surprising number of shops are still on it, usually because the replatform quote came in at €60k and the owner did the math against another two years of patching. If you maintain one of these, you already know the rules: you do not touch the catalog during business hours, you do not trust the admin cache flush button, and you never, ever edit a product attribute set on a live store without a plan.

This post is the plan. It is the sequence we worked out with the agency that night, refined over the next six weeks of similar incidents, and now run as muscle memory whenever we have to edit a legacy site catalog without taking the storefront down.

The thing that actually breaks

People say "the cache" as if Magento 1 has one. It does not. A production install with the flat catalog enabled has at least six caches in flight at any moment, and they invalidate on different signals.

  • var/cache/, the file backend, unless you moved it to Redis or APC.
  • var/full_page_cache/, Enterprise FPC, or the Lesti_Fpc fork if you are on Community.
  • catalog_product_flat_1, catalog_product_flat_2, and so on: one table per store view, regenerated by the flat catalog indexer.
  • catalog_category_flat_store_1, same idea for categories.
  • The block HTML cache, which holds rendered product listing fragments per customer group.
  • Varnish, if you are lucky enough to have it; the Turpentine VCL if you are unlucky enough to use Turpentine.

The failure mode that took down the Hamburg order was the third one. The agency had edited a tier-price row directly in catalog_product_entity_tier_price via phpMyAdmin to fix a typo. That bypassed Magento's event observers, which meant the flat tables were never marked for reindex, which meant the storefront kept serving the old tier price for another forty-three minutes until the next scheduled cron.sh run picked up an unrelated change and triggered a full reindex.

Direct SQL on a Magento 1 catalog table is the single most common way to break a live shop. The schema is normalised across EAV, the flat tables are denormalised copies, and the indexer is the only thing that knows how to reconcile them.

The pre-flight checklist

Before any catalog edit on a live store, we now run five checks. They take about ninety seconds and have saved us from incidents roughly once a month.

First, confirm which indexers are in manual mode and which are scheduled. On a healthy install most should be "Update on Save", except the two flat indexers, which should be "Manual" if your catalog is over about 8,000 SKUs.

php -f shell/indexer.php info
php -f shell/indexer.php mode

Second, check the size of the reindex queue. If index_process already has a row with status='working', walk away and come back in ten minutes. Two reindexers running at once is how you end up with a half-populated catalog_product_flat_1.

SELECT process_id, indexer_code, status, started_at
FROM index_process
WHERE status IN ('working','require_reindex')
ORDER BY started_at DESC;

Third, look at the core_cache table for any tag matching CATALOG_PRODUCT or CATALOG_CATEGORY that is older than the last deploy. Stale entries here are the reason the admin "Flush Cache Storage" button often does nothing useful.

Fourth, confirm cron is actually running. On about a third of the legacy Magento 1 shops we audit, cron.sh has been silently dead for months because someone moved the document root and the crontab path never got updated. tail -n 50 var/log/cron.log and check the timestamps.

Fifth, take a snapshot. Not a full database dump (those take twenty minutes on a real catalog), just the two or three tables you are about to touch. mysqldump --single-transaction with the table list, gzipped, parked next to the deploy.

The edit window

Once the checklist is clean, the edit itself follows a fixed order. The order matters because the event system is fragile and any deviation tends to leave one of the caches in a state that is neither valid nor explicitly invalidated.

  1. Set the two flat indexers to "Manual" if they are not already.
  2. Make the edit through the admin UI, not through SQL. If the admin UI cannot make the edit (a bulk attribute change across 4,000 SKUs, say), write a one-off PHP script that bootstraps Mage and uses Mage::getModel('catalog/product')->load($id)->setData(...)->save(). The save event fires the observers; raw SQL does not.
  3. Reindex only the affected indexers, one at a time, in dependency order: catalog_product_attribute, then catalog_product_price, then catalog_product_flat, then catalog_category_flat, then catalog_category_product.
  4. Flush the block HTML cache and the full page cache, in that order. Not the other way around.
  5. Hit three representative product URLs with curl -I and check the X-Magento-Cache-Debug header reads MISS on first hit and HIT on the second.

That last step is the one most engineers skip and it is the one that catches the silent failures. If a product page is still returning HIT on the first request after a flush, something upstream of Magento (Varnish, CloudFront, a CDN edge) is serving a stale copy and your edit will appear to have done nothing.

The PHP 8.2 problem looming over all of this

Magento 1 was never officially supported on PHP 7.2, let alone anything newer. The community patches from OpenMage LTS have kept it running on PHP 7.4 and 8.0, and the latest OpenMage 20.x branch claims PHP 8.2 compatibility. In practice we have found three classes of breakage on the 8.2 upgrade.

Dynamic property creation is now a deprecation warning, and the Varien_Object base class uses dynamic properties everywhere. The OpenMage patches add #[\AllowDynamicProperties] where it matters, but third-party modules from 2014 do not, and the warnings flood var/log/system.log until the disk fills up.

each() is gone. create_function() is gone. mb_strrpos() with negative offsets behaves differently. If you have any module that has not been touched since 2018, grep for these before you upgrade PHP, not after.

What we actually ship to the client

The deliverable at the end of an incident like the Friday-night one is never "we fixed it". It is a one-page runbook that the agency's developers can follow at 23:41 on the next Friday, when the senior engineer is asleep in another timezone. The runbook has the five pre-flight checks, the five-step edit window, and a list of the specific cache tags and indexer codes that matter for that client's catalog.

We also leave behind a versioned record of every file and database row we touched. On a Magento 1 store, where a single bad attribute edit can corrupt a flat table that takes thirty minutes to rebuild, being able to point at the exact change that caused the problem is the difference between a ten-minute rollback and a four-hour incident.

When we built Pier we ran into this exact thing with the agency above: every catalog edit needed to be auditable, reversible, and tied to the developer who made it, without bolting a deployment pipeline onto a 2014 codebase. The way we ended up handling it was a per-file version history on the FTP side and snapshot diffs on the MySQL editor, so the rollback is one click whether the change lived in app/code/local/ or in core_config_data.

If you maintain a Magento 1 shop, the smallest useful thing to do today is run php -f shell/indexer.php info on it and write down which indexers are in manual mode. Tape it to the monitor. The next time someone edits the catalog, that note is what stops the cache from eating the storefront.

— Questions —

Is Magento 1 safe to run in 2026?

Not officially. OpenMage LTS keeps it patched and the PHP 8.2 path works, but you are running unsupported software and your PCI scope grows every quarter. Treat it as a bridge, not a destination.

Can I edit the Magento 1 database directly with SQL?

Only on tables Magento does not index. Touching catalog_product_entity, tier prices, or stock items via raw SQL bypasses the observers and leaves the flat tables out of sync until the next full reindex.

Why does the admin Flush Cache button often not work?

It clears tagged entries in core_cache, but does not touch the flat catalog tables, the block HTML cache, or any upstream Varnish/CDN layer. You need to flush each layer explicitly, in order.

What is the safest order to reindex Magento 1?

Attributes first, then prices, then product flat, then category flat, then category-product. Running them out of order can leave flat tables referencing attribute values that no longer exist.