I've been trying for ages to figure out how to create and save a new Entry, via PHP with Craft 3.
I got as far as the following code:
$entry = new Entry();
$entry->sectionId = 4;
$entry->typeId = 4;
$entry->authorId = 1;
$id = uniqid('product_');
$entry->title = $id;
$entry->slug = $id;
$entry->setFieldValue('excerpt', 'Lorem...');
if(Craft::$app->elements->saveElement($entry)) {
return $entry;
} else {
throw new \Exception("Couldn't save new bespoke product: " . print_r($entry->getErrors(), true));
}
which saved without any errors, however my custom field values weren't being saved into the entry.
After lots of digging, I realised that it was because I was missing: $entry->fieldLayoutId = 10;.
I think that this can be improved in either of 2 ways:
$newEntry = Craft::$app->entries->createNewEntry('product', [
'title' => 'My Title',
'slug' => 'my-title',
'excerpt' => 'Lorem...',
'images' => $imageIds,
]);
etc. The sectionId, typeId and fieldLayoutId could be found automatically based on the handle of the entry type.
Yes, I've run into this.
Just fixed and blew through it as I was converting a big plugin, but truly matters would be much improved with a measage, something like 'one or more fields not saved, due to missing fieldLayoutId for them'
Now that I've figured out what I'm doing, I created this:
public static function saveNewEntry(string $handle, array $fields) {
$entryType = EntryType::find()->where(['handle' => $handle])->one();
$entry = new Entry();
$entry->sectionId = $entryType->getAttribute('sectionId');
$entry->typeId = $entryType->getAttribute('id');
$entry->fieldLayoutId = $entryType->getAttribute('fieldLayoutId');
$entry->authorId = 1;
if(isset($fields['title'])) {
$entry->title = $fields['title'];
unset($fields['title']);
}
if(isset($fields['slug'])) {
$entry->slug = $fields['slug'];
unset($fields['slug']);
}
$entry->setFieldValues($fields);
if(Craft::$app->elements->saveElement($entry)) {
return $entry;
} else {
throw new \Exception("Couldn't save new bespoke product: " . print_r($entry->getErrors(), true));
}
}
This lets me save anything with:
return self::saveNewEntry('article', [
'title' => $id,
'slug' => $id,
'excerpt' => $excerpt,
'body' => $body
]);
I think you're right, that this case already shows up as a save error.
Not in a spot to check it at moment, though.
Which is showing as a save error? My latest code for saveNewEntry?
no, the fault with lacking fieldLayoutId that you were concerned with.
Ah ok. Yeah when I saved it without a fieldLayoutId, it didn't throw any errors but just silently continued.
Ok, then my original comment's suggestion stands....
Unexpected things shouldn't happen or non-happen silently.
Yeah sorry, just clearing things up. I read "This case already shows up as a save error." as it meaning it causes errors when saving.
Starting in Beta 20, it will not be necessary to set $fieldLayoutId anymore. Thanks for the feedback!
(Oh and a quick note - you don't need to set the $id property when creating a new entry. That will be assigned automatically on save.)
@SteveEdson
I got Call to undefined method craft\models\EntryType::find() error
Is the EntryType class still work in the following way?
use craft\models\EntryType;
EntryType::find()->where(['handle' => $handle])->one()
@max8hine You need to use the ActiveRecord class. The example below should work.
use craft\records\EntryType;
EntryType::find()->where(['handle' => $handle])->one();
Most helpful comment
Starting in Beta 20, it will not be necessary to set
$fieldLayoutIdanymore. Thanks for the feedback!