diff --git a/resources/js/components/entries/BaseCreateForm.vue b/resources/js/components/entries/BaseCreateForm.vue
index de54611122..215ecf7413 100644
--- a/resources/js/components/entries/BaseCreateForm.vue
+++ b/resources/js/components/entries/BaseCreateForm.vue
@@ -18,6 +18,7 @@
:revisions-enabled="revisions"
:breadcrumbs="breadcrumbs"
:initial-site="site"
+ :parent="parent"
:can-manage-publish-state="canManagePublishState"
:create-another-url="createAnotherUrl"
:initial-listing-url="listingUrl"
@@ -41,6 +42,7 @@ export default {
'revisions',
'breadcrumbs',
'site',
+ 'parent',
'canManagePublishState',
'createAnotherUrl',
'listingUrl',
diff --git a/resources/js/components/entries/PublishForm.vue b/resources/js/components/entries/PublishForm.vue
index 28e13ad46f..a282f791db 100644
--- a/resources/js/components/entries/PublishForm.vue
+++ b/resources/js/components/entries/PublishForm.vue
@@ -401,6 +401,7 @@ export default {
collectionHasRoutes: Boolean,
previewTargets: Array,
autosaveInterval: Number,
+ parent: String,
},
data() {
@@ -620,6 +621,7 @@ export default {
...{
_blueprint: this.fieldset.handle,
_localized: this.localizedFields,
+ _parent: this.parent,
},
};
diff --git a/resources/views/entries/create.blade.php b/resources/views/entries/create.blade.php
index 434afdad9e..a7ba940aea 100644
--- a/resources/views/entries/create.blade.php
+++ b/resources/views/entries/create.blade.php
@@ -17,6 +17,7 @@
:revisions="{{ Statamic\Support\Str::bool($revisionsEnabled) }}"
:breadcrumbs="{{ $breadcrumbs->toJson() }}"
site="{{ $locale }}"
+ parent="{{ $parent }}"
create-another-url="{{ cp_route('collections.entries.create', [$collection, $locale, 'blueprint' => $blueprint['handle'], 'parent' => $values['parent'] ?? null]) }}"
listing-url="{{ cp_route('collections.show', $collection) }}"
:can-manage-publish-state="{{ Statamic\Support\Str::bool($canManagePublishState) }}"
diff --git a/src/Entries/Collection.php b/src/Entries/Collection.php
index 70e5c562d4..5eae3c180f 100644
--- a/src/Entries/Collection.php
+++ b/src/Entries/Collection.php
@@ -384,16 +384,6 @@ public function ensureEntryBlueprintFields($blueprint)
$blueprint->ensureField('date', ['type' => 'date', 'required' => true, 'default' => 'now'], 'sidebar');
}
- if ($this->hasStructure() && ! $this->orderable()) {
- $blueprint->ensureField('parent', [
- 'type' => 'entries',
- 'collections' => [$this->handle()],
- 'max_items' => 1,
- 'listable' => false,
- 'localizable' => true,
- ], 'sidebar');
- }
-
foreach ($this->taxonomies() as $taxonomy) {
if ($blueprint->hasField($taxonomy->handle())) {
continue;
diff --git a/src/Http/Controllers/CP/Collections/EntriesController.php b/src/Http/Controllers/CP/Collections/EntriesController.php
index 5535e11a30..2aa8457c22 100644
--- a/src/Http/Controllers/CP/Collections/EntriesController.php
+++ b/src/Http/Controllers/CP/Collections/EntriesController.php
@@ -233,27 +233,7 @@ public function update(Request $request, $collection, $entry)
$tree = $entry->structure()->in($entry->locale());
}
- $parent = $values->get('parent');
-
- if ($structure && ! $collection->orderable()) {
- $this->validateParent($entry, $tree, $parent);
-
- if (! $entry->revisionsEnabled()) {
- $entry->afterSave(function ($entry) use ($parent, $tree) {
- if ($parent && optional($tree->find($parent))->isRoot()) {
- $parent = null;
- }
-
- $tree
- ->move($entry->id(), $parent)
- ->save();
- });
-
- $entry->remove('parent');
- }
- }
-
- $this->validateUniqueUri($entry, $tree ?? null, $parent ?? null);
+ $this->validateUniqueUri($entry, $tree ?? null, $entry->parent()?->id());
if ($entry->revisionsEnabled() && $entry->published()) {
$saved = $entry
@@ -302,10 +282,6 @@ public function create(Request $request, $collection, $site)
$values = Entry::make()->collection($collection)->values()->all();
- if ($collection->hasStructure() && $request->parent) {
- $values['parent'] = $request->parent;
- }
-
$fields = $blueprint
->fields()
->addValues($values)
@@ -349,6 +325,7 @@ public function create(Request $request, $collection, $site)
'canManagePublishState' => User::current()->can('publish '.$collection->handle().' entries'),
'previewTargets' => $collection->previewTargets()->all(),
'autosaveInterval' => $collection->autosaveInterval(),
+ 'parent' => $collection->hasStructure() ? $request->parent : null,
];
if ($request->wantsJson()) {
@@ -403,7 +380,7 @@ public function store(Request $request, $collection, $site)
}
if ($structure && ! $collection->orderable()) {
- $parent = $values['parent'] ?? null;
+ $parent = $request->_parent;
$entry->afterSave(function ($entry) use ($parent, $tree) {
if ($parent && optional($tree->find($parent))->isRoot()) {
$parent = null;
@@ -465,34 +442,6 @@ protected function extractAssetsFromValues($values)
->values();
}
- private function validateParent($entry, $tree, $parent)
- {
- if ($entry->id() == $parent) {
- throw ValidationException::withMessages(['parent' => __('statamic::validation.parent_cannot_be_itself')]);
- }
-
- // If there's no parent selected, the entry will be at end of the top level, which is fine.
- // If the entry being edited is not the root, then we don't have anything to worry about.
- // If the parent is the root, that's fine, and is handled during the tree update later.
- if (! $parent || ! $entry->page()->isRoot()) {
- $maxDepth = $entry->collection()->structure()->maxDepth();
-
- // If a parent is selected, validate that it doesn't exceed the max depth of the structure.
- if ($parent && $maxDepth && Entry::find($parent)->page()->depth() >= $maxDepth) {
- throw ValidationException::withMessages(['parent' => __('statamic::validation.parent_exceeds_max_depth')]);
- }
-
- return;
- }
-
- // There will always be a next page since we couldn't have got this far with a single page.
- $nextTopLevelPage = $tree->pages()->all()->skip(1)->first();
-
- if ($nextTopLevelPage->id() === $parent || $nextTopLevelPage->pages()->all()->count() > 0) {
- throw ValidationException::withMessages(['parent' => __('statamic::validation.parent_causes_root_children')]);
- }
- }
-
private function validateUniqueUri($entry, $tree, $parent)
{
if (! $uri = $this->entryUri($entry, $tree, $parent)) {
diff --git a/src/Providers/ExtensionServiceProvider.php b/src/Providers/ExtensionServiceProvider.php
index 3712cde802..6883830cd2 100644
--- a/src/Providers/ExtensionServiceProvider.php
+++ b/src/Providers/ExtensionServiceProvider.php
@@ -246,6 +246,7 @@ class ExtensionServiceProvider extends ServiceProvider
Updates\AddSitePermissions::class,
Updates\UseClassBasedStatamicUniqueRules::class,
Updates\MigrateSitesConfigToYaml::class,
+ Updates\RemoveParentField::class,
];
public function register()
diff --git a/src/Revisions/Revisable.php b/src/Revisions/Revisable.php
index 2c1dfd0efc..8316a2afce 100644
--- a/src/Revisions/Revisable.php
+++ b/src/Revisions/Revisable.php
@@ -72,12 +72,6 @@ public function publishWorkingCopy($options = [])
{
$item = $this->fromWorkingCopy();
- if ($item instanceof Entry) {
- $parent = $item->get('parent');
-
- $item->remove('parent');
- }
-
$saved = $item
->published(true)
->updateLastModified($user = $options['user'] ?? false)
@@ -87,18 +81,6 @@ public function publishWorkingCopy($options = [])
return false;
}
- if ($item instanceof Entry && $item->collection()->hasStructure() && $parent) {
- $tree = $item->collection()->structure()->in($item->locale());
-
- if (optional($tree->find($parent))->isRoot()) {
- $parent = null;
- }
-
- $tree
- ->move($this->id(), $parent)
- ->save();
- }
-
$item
->makeRevision()
->user($user)
diff --git a/src/UpdateScripts/RemoveParentField.php b/src/UpdateScripts/RemoveParentField.php
new file mode 100644
index 0000000000..c13e9a196d
--- /dev/null
+++ b/src/UpdateScripts/RemoveParentField.php
@@ -0,0 +1,30 @@
+isUpdatingTo('6.0.0');
+ }
+
+ public function update()
+ {
+ Collection::all()->each(function ($collection) {
+ $collection->entryBlueprints()->each(function ($blueprint) use ($collection) {
+ if ($collection->hasStructure() && $blueprint->hasField('parent')) {
+ $blueprint->removeField('parent')->save();
+
+ $this->console->line(sprintf(
+ 'Parent field removed from the %s collection\'s %s blueprint.',
+ $collection->handle(),
+ $blueprint->handle()
+ ));
+ }
+ });
+ });
+ }
+}
diff --git a/tests/Feature/Entries/UpdateEntryTest.php b/tests/Feature/Entries/UpdateEntryTest.php
index 4531ade84d..d0b4020db9 100644
--- a/tests/Feature/Entries/UpdateEntryTest.php
+++ b/tests/Feature/Entries/UpdateEntryTest.php
@@ -437,38 +437,6 @@ public function user_without_permission_to_manage_publish_state_cannot_change_pu
$this->markTestIncomplete();
}
- #[Test]
- public function validates_max_depth()
- {
- [$user, $collection] = $this->seedUserAndCollection();
-
- $structure = (new CollectionStructure)->maxDepth(2)->expectsRoot(true);
- $collection->structure($structure)->save();
-
- EntryFactory::collection('test')->id('home')->slug('home')->data(['title' => 'Home', 'foo' => 'bar'])->create();
- EntryFactory::collection('test')->id('about')->slug('about')->data(['title' => 'About', 'foo' => 'baz'])->create();
- EntryFactory::collection('test')->id('team')->slug('team')->data(['title' => 'Team'])->create();
-
- $entry = EntryFactory::collection($collection)
- ->id('existing-entry')
- ->slug('existing-entry')
- ->data(['title' => 'Existing Entry', 'foo' => 'bar'])
- ->create();
-
- $collection->structure()->in('en')->tree([
- ['entry' => 'home'],
- ['entry' => 'about', 'children' => [
- ['entry' => 'team'],
- ]],
- ['entry' => 'existing-entry'],
- ])->save();
-
- $this
- ->actingAs($user)
- ->update($entry, ['title' => 'Existing Entry', 'slug' => 'existing-entry', 'parent' => ['team']]) // This would make it 3 levels deep, so it should fail.
- ->assertUnprocessable();
- }
-
#[Test]
public function does_not_validate_max_depth_when_collection_max_depth_is_null()
{
diff --git a/tests/UpdateScripts/RemoveParentFieldTest.php b/tests/UpdateScripts/RemoveParentFieldTest.php
new file mode 100644
index 0000000000..d0cdb2f1e7
--- /dev/null
+++ b/tests/UpdateScripts/RemoveParentFieldTest.php
@@ -0,0 +1,82 @@
+assertUpdateScriptRegistered(RemoveParentField::class);
+ }
+
+ #[Test]
+ public function it_removes_parent_field_from_structured_collection_blueprint()
+ {
+ $collection = tap(Collection::make('test')->structureContents(['tree' => []]))->save();
+
+ $blueprint = $collection->entryBlueprint();
+
+ $blueprint->setContents(['tabs' => [
+ 'main' => ['sections' => [
+ ['fields' => [
+ ['handle' => 'title', 'field' => ['type' => 'text']],
+ ]],
+ ]],
+ 'sidebar' => ['sections' => [
+ ['fields' => [
+ ['handle' => 'slug', 'field' => ['type' => 'slug']],
+ ['handle' => 'parent', 'field' => ['type' => 'entries', 'collections' => ['test'], 'max_items' => 1]],
+ ]],
+ ]],
+ ]]);
+
+ $blueprint->save();
+
+ $this->runUpdateScript(RemoveParentField::class);
+
+ $blueprint = Blueprint::find($blueprint->fullyQualifiedHandle());
+
+ $this->assertFalse($blueprint->hasField('parent'));
+ }
+
+ #[Test]
+ public function it_does_not_remove_parent_field_from_unstructured_collection_blueprint()
+ {
+ $collection = tap(Collection::make('test'))->save();
+
+ $blueprint = $collection->entryBlueprint();
+
+ $blueprint->setContents(['tabs' => [
+ 'main' => ['sections' => [
+ ['fields' => [
+ ['handle' => 'title', 'field' => ['type' => 'text']],
+ ]],
+ ]],
+ 'sidebar' => ['sections' => [
+ ['fields' => [
+ ['handle' => 'slug', 'field' => ['type' => 'slug']],
+ ['handle' => 'parent', 'field' => ['type' => 'entries', 'collections' => ['test'], 'max_items' => 1]],
+ ]],
+ ]],
+ ]]);
+
+ $blueprint->save();
+
+ $this->runUpdateScript(RemoveParentField::class);
+
+ $blueprint = Blueprint::find($blueprint->fullyQualifiedHandle());
+
+ $this->assertTrue($blueprint->hasField('parent'));
+ }
+}