How can I add a dynamic number of rows to a matrix via plugin? I would like to have a front-end profile form on my website that contains a matrix field. The matrix field will allow the user to add an infinite number of awards they have earned. How can I do this?
There are a few threads on this that I found helpful. I think they are all worth looking at and reading through as my solution may vary based on your needs. 


Save matrix block to new entry in plugin
How to save a matrix content of a new entry in my plugin?
Saving new Matrix data


Here is the complete solution that ended up working. If there are improvements, please let me know so I can update the thread accordingly!

twig

&lt;form method="post" accept-charset="utf-8"&gt;

    {{ getCsrfInput() }}
    &lt;input type="hidden" name="action" value="profile/saveProfile"&gt;

    ...

    {% if profile.awardsHonors|length %}
        &lt;div id="awards"&gt;
            {% for block in profile.awardsHonors %}
                &lt;div class="matrixblock award"&gt;
                    &lt;div class="form-group"&gt;
                        &lt;input type="hidden" name="fields[awardsHonors][{{ block.id }}][type]" value="award"&gt;
                        &lt;input type="hidden" name="fields[awardsHonors][{{ block.id }}][enabled]" value="1"&gt;

                        &lt;input type="text" name="fields[awardsHonors][{{ block.id }}][fields][award]" class="form-control" value="{{ block.award }}"&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
                {% set blockId = block.id %}
            {% endfor %}
        &lt;/div&gt;
    {% else %}
        &lt;div id="awards"&gt;&lt;/div&gt;
    {% endif %}

    ...

    &lt;button type="button" id="addAward"&gt;Add Award&lt;/button&gt;

    ...
&lt;/form&gt;


javascript

var awardBlockNum = 1;

$('#addAward').click(function (event) {
    var markup = '&lt;div class="matrixblock award"&gt;' +
        '&lt;div class="form-group"&gt;' +
        '&lt;input type="hidden" name="fields[awardsHonors][new' + awardBlockNum + '][type]" value="award"&gt;' +
        '&lt;input type="hidden" name="fields[awardsHonors][new' + awardBlockNum + '][enabled]" value="1"&gt;' +
        '&lt;input type="text" name="fields[awardsHonors][new' + awardBlockNum + '][fields][award]" class="form-control"&gt;' +
        '&lt;/div&gt;' +
        '&lt;/div&gt;';

        $(markup).appendTo($('#awards'));

        awardBlockNum++;
    });


MyPluginController

public function actionSaveProfile()
{
    $criteria = craft()-&gt;elements-&gt;getCriteria(ElementType::Entry);
    $criteria-&gt;section = 'mySectionHandle';
    $criteria-&gt;limit = 1;
    $criteria-&gt;status = null;
    $criteria-&gt;authorId = craft()-&gt;request-&gt;getPost('userId');

    $entries = $criteria-&gt;find();

    if ($entries) {
        foreach ($criteria as $entry) {
            $awardMatrixData = array();

            /**
             * New matrix fields are prefixed with 'new1'.
             * To compensate we need to create a new increment variable to correctly store the matrix number
             * while looping the correct amount of times.
             */

            foreach (craft()-&gt;request-&gt;getPost('fields.awardsHonors') as $key =&gt; $value) {
                $i = 1;

                if ($key == 'new' . $i) { // Check for a new award.
                    $awardMatrixData['new' . $i] = array(
                        'type' =&gt; 'award',
                        'enabled' =&gt; true,
                        'fields' =&gt; array(
                            'award' =&gt; craft()-&gt;request-&gt;getPost('fields.awardsHonors.new' . $i . '.fields.award')
                        )
                    );
                } else { // Update existing awards.
                    $awardMatrixData[$key] = array(
                        'type' =&gt; 'award',
                        'enabled' =&gt; true,
                        'fields' =&gt; array(
                            'award' =&gt; craft()-&gt;request-&gt;getPost('fields.awardsHonors.' . $key . '.fields.award')
                        )
                    );
                }

                $i++;
            }

            $entry-&gt;setContentFromPost(array(
                ...
                ...
                'awardsHonors' =&gt; $matrixData
            ));

            if (craft()-&gt;entries-&gt;saveEntry($entry)) {
                // Profile updated!;
            } else {
                // Could not save entry (profile).
            }
        }
    } else {
        // No entry found that matches criteria.
    }
}