Subscribe to Martyr2's Programming Underground        RSS Feed
-----

Loading Gravity Forms From A Database

Icon Leave Comment
If you are a developer that has been working with the Gravity Form plugin, you undoubtedly have run across the need to load a form based on a row from the database. Finding documentation on how exactly to go about doing this is very sparse. Unless you have reasoned it out well, you are probably pulling your hair right about now and are at a standstill. In this blog post I will show you how I went about loading a custom three page form containing date pickers, textboxes, dropdowns and checkboxes using database data.

First Things First, Enable Dynamic Field Population

The first thing you must do with your form is set it up to accept dynamic field input. In your Gravity Form this is relatively easy. Login to your WordPress dashboard, select the form from your menu on the left and select "Edit" for the desired form. Here you should see the various fields you have setup for the form. Selecting each one will show you a series of tabs. The last tab (currently there are three labeled "General", "Appearance" and "Advanced") is the tab labeled "Advanced". In this tab, towards the bottom, you will see a checkbox labeled "Allow field to be populated dynamically". Selecting this checkbox should open up some additional fields. Depending on the field type, these fields may be different but they all work the same. They allow you to specify a "Parameter Name". Think of this as a placeholder we will fill in with our database data later. Give each field you want to automatically fill with a unique name. For example I used "first_name" for the first name field of our form.

Setting Up the gform_field_value Filter

The next thing we need to do is write some code that will be called upon when a field is to be dynamically loaded. Now obviously each time the form is displayed, we may not want to fill it with some previous values because we don't have any. We have to write in some logic to determine when and when not to fill in the form. The filter we will be using is gform_field_value. I thought perhaps using something like gform_pre_render might have been a better choice, but I found it was a bit difficult to load fields without direct access to $value. If you do find a nice clean example of gform_pre_render that simply lets you load all kinds of controls, let me know in the comments! In the meanwhile, this filter is called EACH TIME a field is to be loaded. It is important to understand that it is run for each field on each form. We have to take care that we only start processing data that is relevant to a specific form and only in specific circumstances.

Below is some code I wrote to process a form with the ID 4 (use the ID of the form you wish to target). All other forms are going to get their value passed back unprocessed. If we want to target more forms, we can just add more functions using add_filter. In addition to looking at the form ID, I am also looking for a parameter called "submission_id" to know if this is a form I need to fetch from the database and load into the form. Again, if this parameter is not present or not the right type, I will pass the value back unprocessed. Let's take a look at the code and I will explain more afterwards.

add_filter('gform_field_value', 'populate_fields', 10, 3);
function populate_fields($value, $field, $name) {
    global $wpdb;

    if ($field['formId'] !== 4) {
        return $value;
    }

    // Check to make a submission ID was presented and is of the correct type.
    if (isset($_GET['submission_id']) && ctype_digit($_GET['submission_id'])) {
        $submission_id = intval($_GET['submission_id']);
    } else {
        return $value;
    }

    // By making this static, we prevent having to fetch the row again and again, drawing on our database for repeat data.
    static $submission = null;

    if (is_null($submission)) {
        $submission = $wpdb->get_row($wpdb->prepare('SELECT * FROM submissions where id = %d', $submission_id));
    }

    if (empty($submission)) {
        $submission = false;
        return $value;
    }

    // Check to make sure that the person trying to edit this is the same who submitted it in the first place.
    if (empty($submission->submission_user_id) || !checkSubmitterId($submission->submission_user_id)) {
        return $value;
    }

    // Map our database row values to those of the dynamic field names we setup in the form earlier.
    $values = [
        'first_name' => $submission->first_name, // Regular textbox example (part of name field)
        'last_name' => $submission->last_name, // Regular textbox example (again part of same name field)
        'contact_email' => $submission->contact_email, // Email field example
        'institution_name' => $submission->institution_name,
        'institution_location' => $submission->institution_location,
        'course_num' => $submission->course_number,
        'course_title' => $submission->course_title,
        'course_syllabus' => $submission->syllabus_url,
        'course_start_date' => (new DateTime($submission->course_start_date))->format('m/d/Y'),
        'course_end_date' => (new DateTime($submission->course_end_date))->format('m/d/Y'),
        'course_qualification_level' => $submission->course_qualification_lvl, // Drop down example
        'license_start_date' => (new DateTime($submission->license_start_date))->format('m/d/Y'), // Date picker example
        'license_end_date' => (new DateTime($submission->license_end_date))->format('m/d/Y'),
        'number_of_licenses' => $submission->number_of_licenses,
        'license_configuration' => $submission->license_configuration,
        'license_select_core' => explode(",", $submission->license_select_core) // Checkboxes example
    ];
 
 	// If the dynamic field name is found in our array, use that value. Otherwise pass back original value unchanged.
    return isset($values[$name]) ? $values[$name] : $value;
}

// Helper function to check if the user who originally submitted this record is the one currently loading it back
// into the form. 
function checkSubmitterId($submission_user_id) {
    return (intval($submission_user_id) === get_current_user_id());
}



Code Explanation

As mentioned earlier, this filter is going to be run for every form and every field. To prevent us from trying to process every form, we start off by checking to see if the form field's parent form ID is the target form. Here we are checking to see if the field is part of form 4. If not, we are going to pass back the value unchanged. Next we look for a parameter being passed to this form page called "submission_id". This parameter is telling us which previous submission ID in our database we want to load. If this is not present, or is of the wrong type, we again pass back the original value and be done with it. However, if this field is present, we will call our database and use that ID to fetch the row we need to load.

Now you may notice here that we are using a static variable called $submission. This is for a good reason. Since this function is going to be called for every field of form 4, we want to make sure we don't call our database repeatedly to obtain the same data. Why do this to our poor database? By making the variable static, we can preserve the row data between calls of this function resulting in the row being fetched only once. If the loading of this row is invalid or false, our $submission variable is going to return null (since we are taking objects here). If the submission doesn't exist, we set $submission to false so next time we don't try to fetch a record again. We just pass back the value.

One other check we made here was the user making the edit. During the original submission I stored the user's ID along with the submission. Then when it comes time to reload the submission, I check the user's ID against the ID of the user that originally submitted the form. This makes it so that only the user who submitted can then see and resubmit this data.

At this point we have all the data we need to start mapping the columns of the database row to the dynamic fields we added earlier to the form fields. In the code I marked the lines showing how we are loading various types of controls. For date pickers, we create a date and format it into a date that is what is expected for that field (in our example an American date). For checkboxes, I stored the various box values into a comma delimited string (Yeah I know, violating 3rd normal form on the database normalization. It was just easier this way for this particular circumstance. I don't usually do it!) and then explode() the strings into an array and feed it to the checkbox control. The name field, which is made up of various textboxes, can be loaded individually.

Last but not least, we check the field name being examined and see if it is in our defined array. If the field name matches, we put in the value of the database column. If not, we again just pass back the original value, unmodified.

Quick Troubleshooting Tip

If for any reason you don't see a field being filled with the value from the database, you should check three things.

  • Is the dynamic field name correctly spelled and matches what you have defined in the $values array?
  • Is the column name in the row correct?
  • Is there an actual value in the field of the database for that column? (This one actually got me since it was test data)


Conclusion

That is all there is to it. We pulled out a record from the database and mapped it to various previously defined dynamic fields setup in our form. We took precautions to make sure we only target our form and that not just anyone can see and load this form data. If they were not the one that submitted the data, they are not the one that can see it! We also checked various conditions before placing the database data into each field. Any tests that failed, we simply passed the $value back in a return statement. Lastly we covered a few quick troubleshooting tips in the event that a field isn't being displayed in the form.

I hope this article helps you get an idea of how to reload a Gravity Form using gform_field_value filter and a database row. I was surprised how little information regarding this was available and there was a lot of trial and error. But this solid solution can help you bypass all the pain of actually trying to do this alone. Enjoy and thanks for reading! :)

If you are in need of a project and don't know what to write up with your new found programming skills, consider our ebook called "The Programmers Idea Book" which features 200 programming project ideas. All ideas are language neutral, features tips for getting you started and presented with a skill difficulty rating so you don't get in over your head. Perfect for anyone learning a new language or trying to brush up on their skills in an existing language.

0 Comments On This Entry