Upgrade from 3.2 to 3.3

A guide for upgrading from 3.2 to 3.3. For most sites, the process will take less than 5 minutes. If your site is running an old version of PHP or Laravel, it may take a bit longer.


First read through this guide to see if there's anything that you might need to adjust. When upgrading, Statamic may automate some things for you. They'll be noted below.

In your composer.json, change the statamic/cms requirement:

"statamic/cms": "3.3.*"

Then run:

composer update statamic/cms --with-dependencies

High impact changes

PHP >=7.4 required

Statamic 3.3 now requires at least PHP 7.4.

If you're running a lower version, we recommend upgrading all the way to 8.1.

Laravel 8 required

Statamic 3.3 now requires at least Laravel 8.

If you're running a lower version, we recommend upgrading all the way to 9.

You can check your version of Laravel by running php artisan -V.

Find out how to upgrade from Laravel 7 to Laravel 8.

Medium impact changes

Entries fieldtype augments to query builders

The entries fieldtype would previously augment to an EntryCollection of Entry objects. In 3.3, they will augment to a query builder.

In Antlers

If you were adding modifiers to your loop, you'll need to apply them to an inner aliased loop.


{{ related_posts modifier="param" }}
{{ /related_posts }}


{{ related_posts as="whatever" }}
{{ whatever modifier="param" }}
{{ /whatever }}
{{ /related_posts }}


If you're using them in PHP, you'll need to add a ->get() to grab the entries from the query before continuing.





Low impact changes

New Experimental Antlers Parser

3.3 includes an overhauled Antlers parser. It fixes many issues with the existing parser and brings many new features.

By upgrading to 3.3 you will not automatically get the new parser.

If you'd like to use the new parser, read about it in the docs, where it explains the experimental nature and how to use it.

Date field's time_required setting has been removed

The time_required option has been removed from the date fieldtype.
The time_enabled setting still exists, and we suggest you use that.

v-calendar upgraded to v2

If you were relying on the v-calendar package within the Control Panel, be aware that it has been upgraded to v2.

Property access on items now performs augmentation

See PR #5297 for more details.

Previously if you were to do $entry->something, it would get the raw value on the entry. It would not factor in fallbacks from any origin entries, or the collection's injected data. It would not do any augmentation. It would not give you method-based values you might expect automatically in templates (like id, slug, etc).

In 3.3, doing $entry->something will do all of those. It will factor in fallbacks, augment, and give you method based values.

id: 123
intro: 'hello' # (a "text" fieldtype)
foo: 'bar' # (not even in the blueprint at all)
content: | # (a "markdown" fieldtype)
# Heading
// 3.2
$entry->content; // "# Heading\nParagraph"
$entry->intro; // "hello"
$entry->foo; // "bar"
$entry->id; // null
$entry->slug; // null
$entry->url; // null
// 3.3
$entry->content; // "<h1>Heading</h1><p>Paragraph</p>
$entry->intro; // "hello"
$entry->foo; // "bar"
$entry->id; // 123
$entry->slug; // "my-entry"
$entry->url; // "/blog/my-entry"

On 3.2, property access on terms did nothing. You'd get a warning and null.

Augmentation methods return Value instances

See PR #5302 for more details. This change will only affect custom PHP code.

This is considered a low impact change since it should only affect edge cases.

  • If you were explicitly coding something expecting a non-Value, it will now be a Value.
  • If it was being cast to a string or array, no change is needed since the Value class knows how to cast itself.

For example, previously toAugmentedArray() you'd only get Value objects for fields that exist in the blueprint.

$arr = $entry->toAugmentedArray();
// [
// 'published' => false,
// 'url' => '/blog/my-post'
// 'some_blueprint_field' => Value('some value'),
// ...
// ]
$inBlog = (Str::startsWith($arr['url'], '/blog')) ? 'yes' : 'no'; // yes
$isPublished = ($arr['published']) ? 'yes' : 'no'; // 'no'

In 3.3, everything in the array would be wrapped in Value objects.

$arr = $entry->toAugmentedArray();
// [
// 'published' => Value(false),
// 'url' => Value('/my-post')
// 'some_blueprint_field' => Value('some value'),
// ...
// ]
// ✅ No change. It would cast the Value to a string, giving you the same outcome.
$inBlog = (Str::startsWith($arr['url'], '/blog')) ? 'yes' : 'no'; // yes
// 🚨 This is changing.
// Previously it would check "if true/false". But now it's "if object" which will always be true.
$isPublished = ($arr['published']) ? 'yes' : 'no'; // 'yes'

You'll now need to add ->value() to get the underlying value.

$isPublished = ($arr['published']->value()) ? 'yes' : 'no'; // 'yes'

The same goes for other augmentation methods:

  • $entry->toAugmentedArray() will only contain Value instances.
  • $entry->toAugmentedCollection() will only contain Value instances.
  • $entry->augmentedValue('field') will always return a Value instance.
  • $entry->augmented()->get('field') will always return a Value instance.

But really, the fix would be to avoid the manual augmentation methods entirely and just do $entry->fieldname, $entry->published, etc.

$isPublished = ($entry->published) ? 'yes' : 'no'; // 'yes'

Form submission data is an unfiltered collection

In 3.2, if you did $submission->data() you would sometimes get an array, sometimes an Illuminate\Support\Collection (the inconsistency was a bug) and any keys that didn't exist in the blueprint would get filtered out.

In 3.3, you will always get a Collection, and it will not have any filtering applied.

Live Preview

If you're not overriding the toLivePreviewResponse in the Entry or Term classes, there is no change for you.

The toLivePreviewResponse methods have been removed in favor of a token based system. You can instead migrate to a dedicated route that will get the Live Preview version of the entry/term via a token.

See the Live Preview Custom Rendering docs for how to do this.

Custom date fields are now Carbon instances

Custom date fields are now stored in the Stache as Carbon instances.

This will only affect you if you're performing a query on a date field expecting it to be a string. For instance, $query->where('datefield', 'like', '2020-%') or :datefield:starts_with="2020"

The actual date field on an entry (i.e. the publish date) would have already been a Carbon instance. This only applies to date fields that aren't named date.

Grids, Replicators, and Bards augment differently

Previously, these fields all augment to arrays containing arrays for each row or set.

In 3.3, it will be an array of Values instances representing each row or set.

In your templates there will be no changes. There's only a change necessary if you are writing PHP and expecting those to be arrays. You can get the underlying array by doing $row->all().

Commonmark 2 is supported

Laravel 8 and Statamic 3.3 now support both CommonMark 1 or 2. When you do a composer update, Composer will try to install the latest available version, which may be v2.

If you have any custom Markdown extensions you will need to either:

If you don't have any custom extensions, the switch from Commonmark v1 to v2 should make no difference to you.

Control panel forms now only submit visible fields

Control Panel forms now only submit visible fields (as originally intended) which fixes sometimes / required_if / etc. validation rules, among other things.

This could potentially be a breaking change if you were using field conditions purely for cosmetic showing/hiding of form fields, in which case we might recommend using the revealer fieldtype.

Read more: Conditional Fields Data Flow

Zero impact changes

These are items that you can completely ignore. They are suggestions on how to improve your code using newly added features.

You probably don't need to manually augment

If you were manually grabbing an augmented value instance, then getting the actual augmented value from that - you can now just use the magic getters to get the underlying augmented value.


Leverage relationship magic methods

If you were manually performing a new query based on selections from an entries fieldtype, you can now use the magic method to get a query builder.

$relatedIds = $entry->get('related_posts');
$selectedFeaturedEntries = Entry::query()->whereIn('id', $relatedIds)->where('featured', true)->get();
$selectedFeaturedEntries = $entry->related_posts()->where('featured', true)->get();

Use Tags in Blade

If you were using the Blade Directives addon to work with Statamic data in your Blade templates, you can now use a whole bunch of native features instead.

@collection('pages', ['title:is' => 'My Title', 'author:is' => 'Erin', 'limit' => 3, 'sort' => 'title:desc'])
@foreach (Statamic::tag('collection:pages')
->params(['title:is' => 'My Title', 'author:is' => 'Erin'])
as $entry
<p>There are no results</p>
{{ $entry['title'] }}
{{ $entry->title }}
return [
'providers' => [
Docs feedback

Submit improvements, related content, or suggestions through Github.

Betterify this page →