NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
Packagist · #3175 most downloaded on Packagist
Add into Magento 2 a CLI feature which allow to regenerate a Url Rewrites of products and categories
Last release today
07 Oct 2026
Ships unpredictably
gaps range from 9 days to 2.6 years
Nearly every release is documented
notes for 37 of 37 stable releases
Nothing withdrawn
no release was ever pulled
9 years old
37 releases · first in 2017
A feature release: preview a run with --dry-run , see every change with -v , and get short messages from the author (security notes, new releases) in
A feature release: preview a run with --dry-run, see every change with -v, and get short messages from the
author (security notes, new releases) in the admin and the console.
--dry-run (#149). Previews a run without saving anything. The whole regeneration runs in one database
transaction that is always rolled back, so the preview is exact, even for cascades such as a parent category's
new URL key changing its children's and products' URLs. It prints a Changes: … summary (every change with
-v) and Dry run: no changes were saved., and it skips reindex and cache refresh.
bin/magento ok:urlrewrites:regenerate --entity-type=category --category-id=3 --regen-url-key --dry-run -v
It can't be combined with --set-product-suffix/--set-category-suffix. The rows it touches stay locked
until it ends, so preview large runs off-peak. From code: RunOptionsBuilder::setDryRun(true).
-v prints every change a run makes (#91):
url_key/url_path changes with their scope;Changes: … summary.Without -v nothing is tracked, so ordinary runs cost the same as before.
Messages from the author:
ok:urlrewrites:regenerate runs started from aTurn them off in Stores > Configuration > Advanced > System > Notifications, or per run with
--no-messages.
Magento_AdminNotification, which is part of Magento Open Source.Test/) or the CI configuration (.github/).Compatibility: Magento Open Source 2.4.7–2.4.9, PHP 8.2–8.5 (unchanged). Verified on Magento 2.4.8-p5 with
sample data (1 and 2 store views):
--dry-run left the database identical to not running it;-v runs saved the same data as 1.11.1;-v change list matched the database diff;Full details: CHANGELOG.md
One column per quarter.
Stores > Configuration > Advanced > System > Notifications, or per
run with the new --no-messages option. See "Messages From the Author" in the README--dry-run (#149): preview a run — everything runs in one database transaction that is rolled back at the end,
so nothing is saved; prints a summary of what would change, and skips reindex and cache refresh. Can't be combined
with --set-product-suffix/--set-category-suffix. From code: RunOptionsBuilder::setDryRun()-v prints every change a run makes (#91): URL rewrites added, removed or updated, and url_key/url_path
changes with their scope, followed by a Changes: … summary. Without -v nothing is tracked, as beforeMagento_AdminNotification (part of Magento Open Source)Test/) or the CI configuration (.github/)A bug-fix release: URL regeneration no longer marks products as edited, and category runs no longer touch product URL keys.
A bug-fix release: URL regeneration no longer marks products as edited, and category runs no longer touch product
URL keys.
updated_at is preserved. Until now every regenerated product got updated_at set to the run time<lastmod>, ERP/PIM/feed delta syncs and "recently updated" reports all picked it up.updated_at; with --regen-url-key it changes--regen-url-key keep the products' URL keys. The products a category run regenerates geturl_key is no longer regenerated from the product name — which⚠️ Behavior change for
--entity-type=category --regen-url-key: it now regenerates only the categories'
URL keys. To regenerate product URL keys, run--entity-type=product --regen-url-key.
Compatibility: Magento Open Source 2.4.7–2.4.9, PHP 8.2–8.5 (unchanged). Verified against 1.11.0 in 14
old-vs-new scenarios on Magento 2.4.8-p5 with sample data (1 and 2 store views); unit tests in CI on PHP 8.2–8.5.
Full details: CHANGELOG.md
updated_at, including products processed
by category runs; explicit URL-key regeneration updates the timestamp only when the key changes--regen-url-key now preserve cascaded products' URL keys; only category URL keys are
regenerated, while the products' paths and rewrites are still refreshedThe regeneration is now available as a public service API for your own code (cron jobs, queue consumers, integrations), and the CLI command runs throu
The regeneration is now available as a public service API for your own code (cron jobs, queue consumers,
integrations), and the CLI command runs through it. Command options, results and exit codes are unchanged —
verified against 1.10.0 in 14 old-vs-new scenarios (1 and 2 store views): identical URL rewrites, identical
exit codes.
@api): Api\RegenerateServiceInterface (validate(), run()), options built withModel\RunOptionsBuilder, a result with failure and processed counts, an optional progress reporter (throwurl_key/url_path change of a run — detailed enough to log, audit or undo a run. See "Use From Code" in the--exact-categories: with --category-id/--categories-range, only the given categories are processed;url_key, so --regen-url-key stays on the categories you named. For precise fixes on large category trees.Processed: 38 category(ies), 2040 product(s) in 3 store(s).bin/magento indexer:reindex / cache:clean / cache:flush. They now use the run's own memoryphp -d memory_limit=... and could run out of memory without any[FAILURES] summary (exit code 1).app/etc/config.php is reported before anything is saved.--include-not-visible help and README now describe what it can do: Magento itself creates no URL rewrites for--regen-url-key left a stale store-level url_key when the regenerated key equalled the default one: theℹ️ If you extend the command or the models in your own code: the protected methods
_runReindexation(),_runClearCache()and_setSeoUrlSuffixes()of the command moved into the service, and
the models'_showProgress()/progressBarProgress/progressBarTotalwere replaced by the progress
reporter. The command's constructor gained an optional 9th argument (existing 8-argument subclasses keep
working). From this release on, the backward-compatibility policy in the README applies.
Compatibility: Magento Open Source 2.4.7–2.4.9, PHP 8.2–8.5 (unchanged). Unit tests run in CI on PHP 8.2–8.5
against Magento 2.4.8-p5 / 2.4.9 packages; verified end-to-end on Magento 2.4.8-p5 with sample data (PHP 8.3).
Full details: CHANGELOG.md
Api\RegenerateServiceInterface (validate(), run()), run options built with Model\RunOptionsBuilder,
a RunResultInterface with failure counts/details, and an optional ProgressReporterInterface. The CLI
command now runs through it; its options and output are unchanged (except the new summary line below). See "Use
From Code" in the README.
Also: a documented way to stop a run (throw from the reporter), processed counts in the result,
toArray()/RunOptionsBuilder::fromArray() to log and replay a run's options, and an
Api\ChangeListenerInterface that receives a run's changes (rewrites added/removed/updated with full rows,
url_key/url_path changes with their scope; not URL suffix config) — groundwork for a verbose output (#91)--exact-categories: with --category-id/--categories-range, process only the given categories —
their subcategories only when a given category's URL path changed, and then without regenerating their
url_key, so --regen-url-key stays on the given categories. Useful for precise fixes on large category treesProcessed: 38 category(ies), 2040 product(s) in 3 store(s)bin/magento indexer:reindex / cache:clean / cache:flush: they
use the run's own memory limit (e.g. php -d memory_limit=-1 bin/magento ...), which the spawned processes
didn't inherit, and a failing or locked indexer is now reported in the [FAILURES] summary (exit code 1)
instead of being ignored--include-not-visible help and README now say what the option does: "Not Visible Individually" products are
processed too (e.g. url_key regeneration), but Magento creates no URL rewrites for a product that isn't
visible in any store view — the option never could add those--set-product-suffix/--set-category-suffix value locked in app/etc/config.php is now reported before
anything is saved; before, the other suffix was still saved and then the run aborted_runReindexation(), _runClearCache()
and _setSeoUrlSuffixes() moved into the service, and the models' _showProgress() / progressBarProgress /
progressBarTotal were replaced by the progress reporter; the command's constructor gained an optional 9th
argument (8-argument subclasses keep working). The backward-compatibility policy applies from this release on--regen-url-key for a store view left a stale store-level url_key in place when the regenerated key was
the same as the default one (it only skipped writing a redundant copy, see #92): the rewrite used the new key
but the product/category kept the old one, and the next run without --regen-url-key switched the URL back.
The store-level value is now removed, so the store view inherits the default⚠️ Behavior change — exit code. The command now exits with code 1 when any product/category (or a cleanup step) fails, after reindex and cache refresh
⚠️ Behavior change — exit code. The command now exits with code 1 when any product/category (or a
cleanup step) fails, after reindex and cache refresh have still run, and prints a[FAILURES]summary.
Earlier versions always exited 0 and hid these failures, so cron jobs or scripts that check the exit
code may start reporting failures that were already happening.
url_key/url_path, and each store view is generated once — identical--save-old-urls now actually creates 301 redirects (#174, #142): when a URL changes, the old URL--add-sku-to-url together with --save-old-urls.--add-sku-to-url no longer appends the SKU to admin-created--store-id=0 runs no longer drop the rewrites of store views after the first, and now replace theCompatibility: Magento Open Source 2.4.7–2.4.9, PHP 8.2–8.5 (unchanged). Verified end-to-end on
Magento 2.4.8-p5 with sample data under PHP 8.3 and 8.4; lint-clean on 8.2–8.5.
Full details: CHANGELOG.md
url_key/url_path, and each store view is generated once — with identical
results; on a two-store-view sample catalog full runs were ~15–30% faster, and the saving grows with the
number of store views--store-id=0 (global scope) runs dropped the product rewrites of every store view after the first
(identical paths in different store views were treated as duplicates) and didn't replace the store views'
current rewrites, so old URLs kept serving pages and --save-old-urls redirects were lost--save-old-urls now actually creates 301 redirects: when a URL changes, the old URL redirects to the
new one. Before, the old URL kept serving the page as an ordinary rewrite (duplicate content) and the
redirect Magento generated was silently dropped when saving (#174, #142). This includes switching to
--add-sku-to-url with --save-old-urls: the old unsuffixed URL now redirects to the SKU URL--add-sku-to-url (and path clean-up/de-duplication in general) no longer alters custom URL
rewrites: admin-created rewrites, and old-URL redirects kept by --save-old-urls, keep their exact
request path. Before, --add-sku-to-url appended the SKU to them too, so a custom URL like
promo/sale became promo/sale-<sku> and the original URL stopped working.--add-sku-to-url, custom redirects (and --save-old-urls redirects) pointing at a product's URL
now follow it to the SKU-suffixed URL; before, they kept pointing at the old unsuffixed URL, which no
longer existed (redirect to a 404)new options --set-product-suffix / --set-category-suffix — set the product/category URL suffix (e.g. .html ) before regenerating, via the same write p
--set-product-suffix / --set-category-suffix — set the product/category URL suffix.html) before regenerating, via the same write path Magento's own config:set CLI command--store-id. If either suffix valueurl_path was not recalculated per store view: when a category's url_path had only everCategoryUrlPathGenerator short-circuited andurl_key,url_path made its dataHasChangedFor() checks lookurl_path is cleared on the category object before generation, matching the patternnew option --skip-products — skip regenerating associated product URLs when regenerating categories (useful on large catalogs when "Use Category Path
--skip-products — skip regenerating associated product URLs when regenerating categories (useful on large catalogs when "Use Category Path for Product URLs" is enabled)--skip-existing — skip an entity entirely if it already has any url_rewrite for the current store, instead of always deleting + regenerating--include-not-visible — also regenerate URLs for products with visibility "Not Visible Individually" (e.g. configurable child products), excluded by default since 1.6.2--add-sku-to-url — append the product's SKU as a URL segment in generated product Url Rewrites, e.g. screws.html -> screws-2244000004.htmlThe old --no-regen-url-key option is removed entirely (not deprecated) — passing it will now produce an "option does not exist" error. If your scripts…
url_key regeneration is now opt-in. Previously, url_key was regenerated automatically unless you passed --no-regen-url-key. That default is now inverted: url_key is not regenerated unless you explicitly pass the new --regen-url-key option.
The old --no-regen-url-key option is removed entirely (not deprecated) — passing it will now produce an "option does not exist" error. If your scripts/cron jobs relied on the previous default (url_key regenerated automatically), add --regen-url-key to them before upgrading. (#151)
saveUrlRewrites(): deleting existing rewrites and inserting new ones now happen in a single transaction, so a failed insert can no longer leave an entity with its rewrites deleted and nothing to replace them. (#137)--delete-orphaned-rewrites — deletes url_rewrite rows (for the given --entity-type) whose product/category no longer exists. (#158)Full Changelog: 1.7.3...1.8.0
--regen-url-key option to opt in. The old --no-regen-url-key option is removed entirely (not deprecated) — update any existing scripts/cron jobs that relied on the previous default.saveUrlRewrites(): deleting existing rewrites and inserting new ones now happen in a single transaction, so a failed insert can no longer leave an entity with its rewrites deleted and nothing to replace them--delete-orphaned-rewrites — deletes url_rewrite rows (for the given --entity-type) whose product/category no longer existsPHP 8.5 compatibility: replaced the deprecated non-canonical (double) type cast with (float) in the progress bar calculation, eliminating the deprecat…
Fixed
Changed
Compatibility
Thanks to @swnsma and @f123248 for reporting and helping diagnose the PHP 8.5 issue.
fixed deprecated functionality: ctype_digit()
This release improves compatibility, hardens query safety, and refines CLI behavior for URL rewrite regeneration.
Changed
Adapted for compatibility with PHP 8.4 (deprecated implicitly nullable types).
Adapted for compatibility with PHP 8.4 (deprecated implicitly nullable types).
Adapted for compatibility with Magento 2.4.7-p4. Adapted the composer.json file to be compatible with Composer 2.
Adapted for compatibility with Magento 2.4.7-p4.
Adapted the composer.json file to be compatible with Composer 2.
Fixed Symfony Command constant issue. Excluded non visible products from url regeneration.
Fixed Symfony Command constant issue.
Excluded non visible products from url regeneration.
Fixed compatibility with Symfony Console 5 and Magento 2.4.6. Updated contact email.
Fixed compatibility with Symfony Console 5 and Magento 2.4.6.
Updated contact email.
Adapted to Magento 2.3.5. Fixed incorrect generation when URL suffix is slash.
Adapted to Magento 2.3.5.
Fixed incorrect generation when URL suffix is slash.
Updated logic of "cleaning" of Url Rewrites and duplications check.
Updated logic of "cleaning" of Url Rewrites and duplications check.
updated logic of Url Rewrite regeneration via category entity
fixed issue of non-empty/non-false "request_path" of product entity.
updated Url Rewrite preparing function
updated logic of Url Rewrite regeneration via category entity
fixed issue of url_key and url rewrites regeneration based on product name value
modified functional logic of extension
### Added - new option "no-regen-url-key" ### Changed - fixed a "typo" issue
new option "--check-use-category-in-product-url"
fixed the issue of removing previously added URL rewrites of product when the same URL key exists;
modified logic of url rewrites regeneration
fixed issue of empty product URL keys
new option "--no-clean-url-key"
display additional debug information for "URL key for specified store already exists" error
fixed setStoreId() on null error
### Changed - fixed compilation issues
modified logic of url rewrites regeneration
### Changed - fix composer file format issue
new option to run URL rewrite generation without running full reindex
new option to save current URL rewrites
additional checks of storeId argument
### Added - check if area code is set
Release of Magento 2 "Regenerate Url Rewrites" extension
Release of Magento 2 "Regenerate Url Rewrites" extension
Your coding agent can read these notes before it upgrades. Set up the MCP server →