Upgrade from 1.x to 2.x
Follow these steps when moving an existing application from Laravel Feeds 1.x to 2.x. If your installed 1.x version already includes feed slugs or the updated generated titles, keep those changes and skip the completed steps.
Runtime requirements
| Component | 1.x | 2.x |
|---|---|---|
| PHP | ^8.2 | ^8.4 |
| Laravel components | ^11.0 || ^12.0 || ^13.0 | ^13.0 |
Upgrade the application's Laravel dependencies and the PHP runtimes used by the web application, CLI, scheduler, and queue workers before installing 2.x. Applications on PHP 8.2 or 8.3, or Laravel 11.x or 12.x, must remain on 1.x. See compatibility for the supported environment.
Before upgrading
- Save the current application code,
composer.json,composer.lock, and publishedconfig/feeds.php. Back up the feed registration table and generated files needed for rollback. - Record registration IDs, titles, existing slugs, schedules, and output destinations.
- Find calls to
feed:generatein deployment scripts, cron jobs, manual schedules, tests, and application code. - Generate representative feeds and retain their output for comparison.
- During deployment, pause feed schedules and finish running or queued feed jobs before replacing the package and changing the schema.
Apply the update
composer require dragon-code/laravel-feeds:^2.0 --with-all-dependencies
composer check-platform-reqs
Compare the installed package's config/feeds.php with the application's published copy and retain application-specific settings. Do not republish with --force: it overwrites that copy.
Add feed slugs
PR #287 changes single-feed selection from a database ID to a slug derived with Str::slug(title).
If the package's slug migration has not run yet, publish the migrations:
php artisan vendor:publish --tag=feeds-migrations
The command publishes all migration files. Validate the published files and delete any unnecessary ones.
Set the filename timestamp of the new add_slug_to_feeds_table migration after the application's actual create_feeds_table migration and before every feed-registration migration. This order ensures migrate:fresh adds the slug column before registrations write to it. Then run the migrations:
php artisan migrate
The migration adds a nullable slug column and fills it from existing titles, including soft-deleted records. Existing titles and IDs are preserved.
If the application already owns a slug column and the package migration has not run, the migration fails before backfilling any data. Resolve that schema conflict before deployment; do not drop an application-owned column without preserving its data and updating its callers.
Inspect stored values in php artisan tinker:
app(\DragonCode\LaravelFeed\Queries\FeedQuery::class)
->all()
->get(['id', 'title', 'slug']);
Slugs used for selection must be non-empty and distinct among non-deleted registrations, including inactive ones. Different titles can normalize to the same slug. Ambiguous lookups throw MultipleRecordsFoundException; unknown slugs throw FeedNotFoundException. Resolve collisions or empty slugs by updating titles through the feed model.
In 2.3.0, PR #334 replaces the fireModelEvent() override with FeedObserver::saving(). Previously, slug derivation used raw attributes after saving, creating, and updating, including quiet saves. It now uses the accessor-visible title when the saving observer runs; quiet saves skip it and later listeners do not trigger another calculation.
PR #335 adds an $feed->isDirty('slug') check: an explicitly changed slug is normalized with Str::slug() and preserved for the current save, even when title changes too. FeedQuery::create() accepts it through extra: ['slug' => 'Custom Catalog']. An unchanged slug is still derived from title; a later ordinary save can therefore replace a previously supplied custom slug. Assigning a value that normalizes to the current slug does not prevent recalculation.
When upgrading from an earlier 1.x or 2.x release, audit explicit slug assignments, quiet saves, title accessors, event listeners, partial selects, custom casts, and bulk writes. Test the resulting stored title and slug, a later ordinary save, lookup by slug, and scheduled generation. Existing rows are not rewritten merely by installing the update, but the next ordinary save can change a custom or accessor-derived slug even without a title change. Update hardcoded command and schedule slugs if needed. See Eloquent for explicit slug, quiet-save, and listener handling.
Replace IDs in generation calls
For registration ID 42 with stored title Products, the migrated slug is products.
Before:
php artisan feed:generate 42
After:
php artisan feed:generate products
The argument is always a slug in 2.x; a numeric string no longer selects a database ID. Calling php artisan feed:generate without an argument still processes all active registrations. With --target, replace only the registration argument; target keys stay the same:
php artisan feed:generate products --target=42
Update manual schedules and programmatic command calls in the same way. Before:
use DragonCode\LaravelFeed\Commands\FeedGenerateCommand;
use Illuminate\Support\Facades\Schedule;
Schedule::command(FeedGenerateCommand::class, [42])->daily();
After:
use DragonCode\LaravelFeed\Commands\FeedGenerateCommand;
use Illuminate\Support\Facades\Schedule;
Schedule::command(FeedGenerateCommand::class, ['products'])->daily();
Keep the manual schedule's existing overlap, background, and frequency settings. Update hardcoded slugs when renaming registrations. ScheduleFeedHelper::register() uses stored slugs automatically and keeps overlap locks tied to the registration when its title or cron expression changes.
FeedQuery::find(int $id), delete(int $id), and restore(int $id) still use IDs. Use FeedQuery::findBySlug(string $slug) when selecting by slug. See generation and scheduling.
Check generated titles
PR #293 removes the Feed suffix from titles written into new registration migrations or deploy operations by make:feed.
For php artisan make:feed ProductsFeed:
| Value | Before | After |
|---|---|---|
| Generated registration title | Products Feed | Products |
| Slug derived from that title | products-feed | products |
Existing database titles and previously generated registration files are not rewritten. Keep using each registration's actual stored slug. The feed class name and output filename are not changed by this title update.
Documentation and package development
PR #294 renames the documentation page from Machine Learning to AI Agents. The page is now available at /ai-agents/; redirects preserve links to its previous URL.
PR #297 establishes the new runtime requirements and preserves the 1.x documentation. Select the documentation version that matches the installed package; search results and LLM context are scoped to that version.
The package's own development environment moves to Pest ^5.0 and Testbench ^11.0. Its Pest commands use --tia, with --fresh for full reruns in CI, benchmarks, and snapshot updates. These are package development dependencies, not requirements for an application's test suite.
Verify
- Rebuild the application's configuration cache if used and restart queue workers and long-running scheduler processes with the new code.
- Confirm that every selected registration has a non-empty, distinct slug and that commands and manual schedules use it.
- Generate one feed for every used format; verify split-file counts, filenames, and representative output against the saved
1.xoutput. - Check target selection, automatic and manual schedules, and queued generation where used.
- Run application tests covering custom feed models, transformers, macros, and preset subclasses.
- Resume feed schedules and queue processing after the schema and generation checks pass.
Rollback
Pause feed generation again and finish in-flight jobs. Restore the previous application code, composer.json, composer.lock, configuration, and generation commands, then run composer install on a compatible runtime.
Apply the application's migration rollback policy only after confirming whether the restored 1.x package already uses slugs. The slug migration's down() method drops only that column; it does not restore renamed titles or generated files. Restore changed registration data and output files from the backups when needed. Rebuild configuration caches and restart workers and scheduler processes before resuming generation.