<p>A little bit late but here it is.</p>

<ol>
<li>Go to <a href="https://pluginfactory.io/" rel="noreferrer">https://pluginfactory.io/</a> and create a plugin, you need at least 1 Controller but you can leave the Name value blank to create a controller with the same Name as your PluginHandle. So if you choose "Experiment" as your Pluginhandle your controller will be <code>ExperimentController</code></li>
<li>Click on "Build my Plugin" and save the files in your <code>craft/plugins/&gt;&gt;pluginhandle&lt;&lt;</code> folder (of course you need to create the >>pluginhandle&lt;&lt; directory eg.) Then you should install the plugin</li>
<li><p>Insert this function in your controller. Note: this is just an example. I don't know your fieldLayout or some special behaviors you might want to include. So this is just the basic logic with some error handling. <strong>Important</strong> please read the commands and change the entryType Ids</p>

<pre><code>     /**
     * @var    bool|array Allows anonymous access to this controller's actions.
     * @access protected
     */
    protected $allowAnonymous = true;

    /**
     * @throws Exception
     */
    public function actionSaveEntry(){
        $this-&gt;requirePostRequest();
        // check for an Id if there is one we update an existing entry if not we create a new one
        if($entryId = craft()-&gt;request-&gt;getParam('entryId')){
            if(!$entry = craft()-&gt;elements-&gt;getElementById($entryId)){
                throw new Exception('Could not find entry with id');
            }
        }else{
            $entry = new EntryModel();
            $entry-&gt;typeId = craft()-&gt;request-&gt;getParam('entryType');
            $entry-&gt;sectionId = craft()-&gt;request-&gt;getParam('sectionId');
        }

        // set the content of your entry/experiment
        $entryData = craft()-&gt;request-&gt;getParam('experiment');
        $entry-&gt;getContent()-&gt;setAttributes($entryData['fields']);

        // try to save the entry
        if(craft()-&gt;entries-&gt;saveEntry($entry)){
            // fetch the id from the experiment so we can use that as a parentId for the cage
            $entryId = $entry-&gt;id;
            // if everything is alright we can save the cage like we did it with the experiment
            if($cagesData = craft()-&gt;request-&gt;getParam('cage')){

                foreach ($cagesData as $cageData){
                    // like with the entry check for an Id
                    if($cageId = $cageData['entryId']){
                        if(!$cage = craft()-&gt;elements-&gt;getElementById($cageId)){
                            throw new Exception('Could not find cage with the given Id');
                        }
                    }else{
                        $cage = new EntryModel();
                        $cage-&gt;typeId = 5; // you could as well create a hidden field like for the entry itself but you must change the typeId to your entryType Id
                        $cage-&gt;sectionId = craft()-&gt;request-&gt;getParam('sectionId');
                    }

                    // save the content as well
                    $cage-&gt;getContent()-&gt;setAttributes($cageData['fields']);
                    // and set the parent
                    $cage-&gt;parentId = $entryId;
                    if(craft()-&gt;entries-&gt;saveEntry($cage)){
                        $cageId = $cage-&gt;id;
                        // and now we are going to do the same with the animals
                        if($rodentsData = $cageData['rodents']) {
                            $rodentErrors = [];
                            foreach ($rodentsData as $rodentData){
                                // like with the entry check for an Id
                                if (array_key_exists('entryId', $rodentData) &amp;&amp; $rodentId = $rodentData['entryId']) {
                                    if (!$rodent = craft()-&gt;elements-&gt;getElementById($rodentId)) {
                                        throw new Exception('Could not find rodent with the given Id');
                                    }
                                } else {
                                    $rodent = new EntryModel();
                                    $rodent-&gt;typeId = 6; // change your entryType Id here
                                    $rodent-&gt;sectionId = craft()-&gt;request-&gt;getParam('sectionId');
                                }

                                $rodent-&gt;getContent()-&gt;setAttributes($rodentData['fields']);
                                $rodent-&gt;parentId = $cageId;
                                if (!craft()-&gt;entries-&gt;saveEntry($rodent)) {
                                    // important note: if there are any errors here, the cage and the experiment is
                                    // saved anyway so you should insert the id of the experiment to the form in order
                                    // to update the form instead of creating a new one again and again
                                    // if the experiment has an Id but the cage/rodent not you'll just update the experiment
                                    // and create new cages/rodents for it
                                    $rodentErrors[] = $rodent-&gt;getErrors();
                                }else{
                                    $rodentErrors = [];
                                }
                            }
                            // include errors of each item
                            craft()-&gt;urlManager-&gt;setRouteVariables(array(
                                'rodentErrors' =&gt; $rodentErrors
                            ));
                        }
                    }else{
                        craft()-&gt;urlManager-&gt;setRouteVariables(array(
                            'cageErrors' =&gt; $cage-&gt;getErrors()
                        ));
                    }
                }

            }
        }else{
            // handle your errors here.. you can use $entry-&gt;getErrors()
            // return them to your frontend and render them in twig or something
            craft()-&gt;urlManager-&gt;setRouteVariables(array(
                'experimentErrors' =&gt; $entry-&gt;getErrors()
            ));
        }
    }
</code></pre></li>
<li><p>Your html template. Note I don't know your fieldLayout so I just included the title and the craft default <code>body</code> field. In order to add your custom fields to the html you need to set the input name to <code>entryType[fields][fieldHandle]</code> so if you want to add a field with the handle <code>foo</code> to the <code>cage</code> you would name it <code>cage[fields][foo]</code>. As for the routing: your <code>action</code> must be <code>pluginHandle/functionName</code></p>

<pre><code>&lt;form method="post" accept-charset="UTF-8"&gt;
    {{ getCsrfInput() }}
    {# your plugin name and function name #}
    &lt;input type="hidden" name="action" value="test/saveEntry"&gt;
    {# the id of your section for me its 4 you need to change this value to your section Id #}
    &lt;input type="hidden" name="sectionId" value="4"&gt;
    {# enable the entry #}
    &lt;input type="hidden" name="enabled" value="1"&gt;
    {# id of your entry leave it blank to insert a new entry, insert a id to change an existing entry#}
    &lt;input type="hidden" name="entryId" value=""&gt;
    {# the id of your experiments entryType for me its 4 you need to change this value #}
    &lt;input type="hidden" name="entryType" value="4"&gt;

    &lt;label for="title"&gt;Title&lt;/label&gt;
    &lt;input id="title" type="text" name="experiment[fields][title]"&gt;
    &lt;input  type="text" name="experiment[fields][body]"&gt;

    {# now the cage as a children #}
    &lt;div&gt;
        &lt;label for="title"&gt;cage title&lt;/label&gt;
        &lt;input type="text" name="cage[0][fields][title]"&gt;
        &lt;input type="text" name="cage[0][fields][body]"&gt;
        &lt;input type="hidden" name="cage[0][entryId]" value=""&gt;
        {# and some Rodents as children for the cages #}
        &lt;div&gt;
            &lt;label for="title"&gt;Rodent title&lt;/label&gt;
            &lt;input type="text" name="cage[0][rodents][0][fields][title]"&gt;
            &lt;input type="text" name="cage[0][rodents][0][fields][body]"&gt;
            &lt;input type="hidden" name="cage[0][rodents][0][entryId]" value=""&gt;
        &lt;/div&gt;

        &lt;div&gt;
            &lt;label for="title"&gt;Rodent title&lt;/label&gt;
            &lt;input type="text" name="cage[0][rodents][1][fields][title]"&gt;
            &lt;input type="text" name="cage[0][rodents][1][fields][body]"&gt;
            &lt;input type="hidden" name="cage[0][rodents][1][entryId]" value=""&gt;
        &lt;/div&gt;

        &lt;div&gt;
            &lt;label for="title"&gt;Rodent title&lt;/label&gt;
            &lt;input type="text" name="cage[0][rodents][2][fields][title]"&gt;
            &lt;input type="text" name="cage[0][rodents][2][fields][body]"&gt;
            &lt;input type="hidden" name="cage[0][rodents][2][entryId]" value=""&gt;
        &lt;/div&gt;
    &lt;/div&gt;

    {# and another cage #}
    &lt;div&gt;
        &lt;label for="title"&gt;cage title&lt;/label&gt;
        &lt;input type="text" name="cage[1][fields][title]"&gt;
        &lt;input type="text" name="cage[1][fields][body]"&gt;
        &lt;input type="hidden" name="cage[1][entryId]" value=""&gt;
        {# and some Rodents as children for the cages #}
        &lt;div&gt;
            &lt;label for="title"&gt;Rodent title&lt;/label&gt;
            &lt;input type="text" name="cage[1][rodents][0][fields][title]"&gt;
            &lt;input type="text" name="cage[1][rodents][0][fields][body]"&gt;
            &lt;input type="hidden" name="cage[1][rodents][0][entryId]" value=""&gt;
        &lt;/div&gt;
    &lt;/div&gt;

    &lt;input type="submit" value="Publish"&gt;
</code></pre>

<p></p>

<pre><code>{# just as an example how you could display errors or at least receive the error object #}
{% if rodentErrors is defined %}
    {% for errors in rodentErrors %}
        {% for fieldHandle, errorMessages in errors  %}
            {{ fieldHandle }} {{ errorMessages[0] }}&lt;br&gt;
        {% endfor %}
    {% endfor %}
{% endif %}
</code></pre></li>
</ol>

<p>Please let me know when you need help and feel free to ask what you like.<br>
If done right, you'll end up with a structure like this with your form (note: please ignore the titles...)
<a href="https://i.sstatic.net/HtMAw.png" rel="noreferrer"><img src="https://i.sstatic.net/HtMAw.png" alt="enter image description here"></a></p>

CC BY-SA 3.0
2017-11-10T11:59:45.487Z
Robin this is absolutely perfect - thank you so much for the help!
Graham Winston
CC BY-SA 3.0
2017-11-10T13:40:33.053Z
Wow Robin, this is beyond phenomenal. Thank you so much for posting this! I look forward to hopping in and implementing some of the things you did here; really has me thinking about a whole host of wonderful changes to make in workflow.
Jeremiah
CC BY-SA 4.0
2018-10-31T22:25:12.283Z
How can this be accomplished in Craft 3?
Andrea DeMers
CC BY-SA 3.0
2017-11-09T19:17:17.693Z
2017-11-09T20:12:28.823Z
2017-11-09T20:12:28.823Z
Robin Schambach
<p>I'm building an MVP for a project, I'm using Craft and would like to:</p>

<ol>
<li>Create an experiment (/experiments/)</li>
<li>Create multiple cages for the animals within the previous created experiment eg. 5 cages - (/experiments//cages/)</li>
<li>Add a number of rodents to each of those cages e.g. Create 5 cages with 5 rodents in each. (/experiments//cages/)</li>
<li>Add measurements to a specific mouse e.g., weight / tumour size (/experiments//cages/)</li>
</ol>

<p>I was thinking this would be possible by using an entry form to add entries to a structure that looks like this-</p>

<pre><code>--Experiments
----Cage 1
------Rodent 1
------Rodent 2
------Rodent 3
----Cage 2
------Rodent 1
------Rodent 2
------Rodent 3
...
</code></pre>

<p>My question is - </p>

<ol>
<li><p>Is it possible to create multiple entries per form eg.
<strong>Create 5 cages with 5 rodents in each.</strong> from a single entry form submission?</p></li>
<li><p>Is it possible to assign the entry type in an entry form? (eg. Cage or Mouse entry type?) </p></li>
<li><p>Is it possible to assign the parent to an entry via the entry form?</p></li>
</ol>

<p>If these aren't possible with an entry form + structure what would be the best way to approach it?</p>

<p>Thanks!</p>

CC BY-SA 3.0
2017-11-09T14:17:35.577Z
It's relatively easy and fast to achieve once you've learned how craft works. It would just be nice to know if you need this form in your frontend or only in your backend. I think the most difficult part is to create the dynamic form with pure Javascript/jquery if you don't want to use angular. If you don't refuse to create a custom plugin I could provide you the basic code you need but I need to know if it's only for your backend or for your frontend too. As for your question for frontend request: I can say yes - it's all possible with a custom controller
Robin Schambach
CC BY-SA 3.0
2017-11-09T14:52:08.340Z
Hi Robin - This is only on the front end, I can handle the javascript side (It's my strong point!) I've never actually coded a custom controller so any help would be really appreaciated!
Graham Winston
<entry><structure><entry-type><parents><entry-form>
Entry Form - Multiple Entries & Entry Type & Parent
# Entry Form - Multiple Entries & Entry Type & Parent

(Asked by: username_0 on 2017-11-09)

I'm building an MVP for a project, I'm using Craft and would like to:

Create an experiment (/experiments/)
Create multiple cages for the animals within the previous created experiment eg. 5 cages - (/experiments//cages/)
Add a number of rodents to each of those cages e.g. Create 5 cages with 5 rodents in each. (/experiments//cages/)
Add measurements to a specific mouse e.g., weight / tumour size (/experiments//cages/)

I was thinking this would be possible by using an entry form to add entries to a structure that looks like this-
--Experiments
----Cage 1
------Rodent 1
------Rodent 2
------Rodent 3
----Cage 2
------Rodent 1
------Rodent 2
------Rodent 3
...

My question is - 

Is it possible to create multiple entries per form eg.
Create 5 cages with 5 rodents in each. from a single entry form submission?
Is it possible to assign the entry type in an entry form? (eg. Cage or Mouse entry type?) 
Is it possible to assign the parent to an entry via the entry form?

If these aren't possible with an entry form + structure what would be the best way to approach it?
Thanks!

**Tags:** entry, structure, entry-type, parents, entry-form
> **Comments:**
> **username_1**: It's relatively easy and fast to achieve once you've learned how craft works. It would just be nice to know if you need this form in your frontend or only in your backend. I think the most difficult part is to create the dynamic form with pure Javascript/jquery if you don't want to use angular. If you don't refuse to create a custom plugin I could provide you the basic code you need but I need to know if it's only for your backend or for your frontend too. As for your question for frontend request: I can say yes - it's all possible with a custom controller  
> **username_0**: Hi Robin - This is only on the front end, I can handle the javascript side (It's my strong point!) I've never actually coded a custom controller so any help would be really appreaciated!  

---

## 1 answers

### Answer by username_1 on 2017-11-09. Score: 8 | Accepted answer

A little bit late but here it is.

Go to https://pluginfactory.io/ and create a plugin, you need at least 1 Controller but you can leave the Name value blank to create a controller with the same Name as your PluginHandle. So if you choose "Experiment" as your Pluginhandle your controller will be ExperimentController
Click on "Build my Plugin" and save the files in your craft/plugins/>>pluginhandle<< folder (of course you need to create the >>pluginhandle<< directory eg.) Then you should install the plugin
Insert this function in your controller. Note: this is just an example. I don't know your fieldLayout or some special behaviors you might want to include. So this is just the basic logic with some error handling. Important please read the commands and change the entryType Ids
     /**
     * @var    bool|array Allows anonymous access to this controller's actions.
     * @access protected
     */
    protected $allowAnonymous = true;

    /**
     * @throws Exception
     */
    public function actionSaveEntry(){
        $this->requirePostRequest();
        // check for an Id if there is one we update an existing entry if not we create a new one
        if($entryId = craft()->request->getParam('entryId')){
            if(!$entry = craft()->elements->getElementById($entryId)){
                throw new Exception('Could not find entry with id');
            }
        }else{
            $entry = new EntryModel();
            $entry->typeId = craft()->request->getParam('entryType');
            $entry->sectionId = craft()->request->getParam('sectionId');
        }

        // set the content of your entry/experiment
        $entryData = craft()->request->getParam('experiment');
        $entry->getContent()->setAttributes($entryData['fields']);

        // try to save the entry
        if(craft()->entries->saveEntry($entry)){
            // fetch the id from the experiment so we can use that as a parentId for the cage
            $entryId = $entry->id;
            // if everything is alright we can save the cage like we did it with the experiment
            if($cagesData = craft()->request->getParam('cage')){

                foreach ($cagesData as $cageData){
                    // like with the entry check for an Id
                    if($cageId = $cageData['entryId']){
                        if(!$cage = craft()->elements->getElementById($cageId)){
                            throw new Exception('Could not find cage with the given Id');
                        }
                    }else{
                        $cage = new EntryModel();
                        $cage->typeId = 5; // you could as well create a hidden field like for the entry itself but you must change the typeId to your entryType Id
                        $cage->sectionId = craft()->request->getParam('sectionId');
                    }

                    // save the content as well
                    $cage->getContent()->setAttributes($cageData['fields']);
                    // and set the parent
                    $cage->parentId = $entryId;
                    if(craft()->entries->saveEntry($cage)){
                        $cageId = $cage->id;
                        // and now we are going to do the same with the animals
                        if($rodentsData = $cageData['rodents']) {
                            $rodentErrors = [];
                            foreach ($rodentsData as $rodentData){
                                // like with the entry check for an Id
                                if (array_key_exists('entryId', $rodentData) && $rodentId = $rodentData['entryId']) {
                                    if (!$rodent = craft()->elements->getElementById($rodentId)) {
                                        throw new Exception('Could not find rodent with the given Id');
                                    }
                                } else {
                                    $rodent = new EntryModel();
                                    $rodent->typeId = 6; // change your entryType Id here
                                    $rodent->sectionId = craft()->request->getParam('sectionId');
                                }

                                $rodent->getContent()->setAttributes($rodentData['fields']);
                                $rodent->parentId = $cageId;
                                if (!craft()->entries->saveEntry($rodent)) {
                                    // important note: if there are any errors here, the cage and the experiment is
                                    // saved anyway so you should insert the id of the experiment to the form in order
                                    // to update the form instead of creating a new one again and again
                                    // if the experiment has an Id but the cage/rodent not you'll just update the experiment
                                    // and create new cages/rodents for it
                                    $rodentErrors[] = $rodent->getErrors();
                                }else{
                                    $rodentErrors = [];
                                }
                            }
                            // include errors of each item
                            craft()->urlManager->setRouteVariables(array(
                                'rodentErrors' => $rodentErrors
                            ));
                        }
                    }else{
                        craft()->urlManager->setRouteVariables(array(
                            'cageErrors' => $cage->getErrors()
                        ));
                    }
                }

            }
        }else{
            // handle your errors here.. you can use $entry->getErrors()
            // return them to your frontend and render them in twig or something
            craft()->urlManager->setRouteVariables(array(
                'experimentErrors' => $entry->getErrors()
            ));
        }
    }

Your html template. Note I don't know your fieldLayout so I just included the title and the craft default body field. In order to add your custom fields to the html you need to set the input name to entryType[fields][fieldHandle] so if you want to add a field with the handle foo to the cage you would name it cage[fields][foo]. As for the routing: your action must be pluginHandle/functionName

    {{ getCsrfInput() }}
    {# your plugin name and function name #}
    
    {# the id of your section for me its 4 you need to change this value to your section Id #}
    
    {# enable the entry #}
    
    {# id of your entry leave it blank to insert a new entry, insert a id to change an existing entry#}
    
    {# the id of your experiments entryType for me its 4 you need to change this value #}
    

    Title
    
    

    {# now the cage as a children #}
    
        cage title
        
        
        
        {# and some Rodents as children for the cages #}
        
            Rodent title
            
            
            
        

        
            Rodent title
            
            
            
        

        
            Rodent title
            
            
            
        
    

    {# and another cage #}
    
        cage title
        
        
        
        {# and some Rodents as children for the cages #}
        
            Rodent title
            
            
            
        
    

    


{# just as an example how you could display errors or at least receive the error object #}
{% if rodentErrors is defined %}
    {% for errors in rodentErrors %}
        {% for fieldHandle, errorMessages in errors  %}
            {{ fieldHandle }} {{ errorMessages[0] }}
        {% endfor %}
    {% endfor %}
{% endif %}


Please let me know when you need help and feel free to ask what you like.
If done right, you'll end up with a structure like this with your form (note: please ignore the titles...)

> **Comments:**
> **username_0**: Robin this is absolutely perfect - thank you so much for the help!  
> **username_2**: Wow Robin, this is beyond phenomenal. Thank you so much for posting this! I look forward to hopping in and implementing some of the things you did here; really has me thinking about a whole host of wonderful changes to make in workflow.  
> **username_3**: How can this be accomplished in Craft 3?  

---

