Fancy Gravity Forms Site Creation with Teams

This is an odd one but I think worth writing down so I don’t forget and because it walks me through some patterns that are useful in both Gravity Forms and WordPress Multisite. You can see the whole thing here.

The goal was to allow students to sign up and create profile posts on a main Multisite using Gravity Forms. Those initial posts would help them get to know one another and allow the professor to decide who was on what team. Those teams would be assigned via Gravity Forms (just editing a field and updating the entry). Each team would then end up with a single team-site on the multisite. All the team members would be added to that site as admins. We also needed some posts to enable the faculty member to sort through all this stuff and keep track of things.

Functionally, all this stuff happens.

  • On form submission, two posts are created for the intros. One full version and one version for guessing with some redacted elements.
  • Once teams are assigned, assigning the first team member creates a site and assigns the student to that site as an admin. All subsequent students on that team are added as admins to the correct team site.
  • For each team assigned, a post is created on the root blog that shows the students associated with the team site and is categorized in various ways based on the form fields (section, semester, etc.).
  • The student intro posts are updated to be associated with the team as it gets assigned.
  • If the team changes the display name of their blog site, it changes the display name on the post. So Team A could decide to become the Mighty Condores and the blog post name would reflect that change.

Making a Post After Adding a Team to a Gravity Form Entry

We left a hidden field on the form for teams. The professor will come along and edit the entry to assign the team to the students. It’s easy to make posts on form submissions, but it takes a bit more effort to do it after the fact. That’s where we rely on a built in action- gform_after_update_entry.

add_action( 'gform_after_update_entry_1', 'dlinq_team_added', 10, 3 );

In the example above, I’m using
gform_after_update_entry. By appending _1, I’m only running in when entries from the form with ID 1 are updated. If I left it blank, it’d run after all form entry updates.

When a form entry is updated, this action will trigger the dlinq_team_added function (or whatever function you put there). First, we’ll break down how we’re going to make the team post. Automatically, there are three variables (note the 3 up there as the last element in the add_ction portion) included that we can use ($form, $entry_id, $original_entry). That’s built into this particular action and we’ll use them as the source for the information we need.

In Gravity Forms, you can access the form data by first getting the entry. Since the action is giving us the entry_id, we get the right big chunk of data like so.

 $entry = GFAPI::get_entry( $entry_id );

That gets us the big chunk of data and we can get individual field data by using the IDs of the fields.

   $entry = GFAPI::get_entry( $entry_id );
   $user_email = $entry['16'];//user email
   $team = $entry['17'];//team
   $tag = $entry['19'];//semester 

The IDs will be dependent on your form setup and you can see the field ID when you select the form field in the editor.
Gravity Forms field view indicating there's a field ID in the upper right portion of the screen.

What we need to do is check to make sure that a post hasn’t already been created for the team. We can search for posts via slug which is handy. That way we can change the title without concern. We do that with a basic get_posts query.

For our later purposes, we have to get some of this data in the right formats. For instance, to add a custom taxonomy for a post we need to use get_term_by to get the term ID and we use sanitize_title to clean up spaces, get rid of capitals etc.

$section = get_term_by('name', $entry['22'], 'section')->term_id;//get term ID in custom taxonomy 'section'
 $team_slug = sanitize_title($team );//make the team title into a slugified text chunk   

Now let’s check for the post by searching by the permalink (aka name in the search argument) and if we can’t find it, let’s make a new post.

 $args = array(
      'name'        => $team_slug,//searching by permalink
      'post_type'   => 'post',
      'post_status' => 'publish',
      'numberposts' => 1
   $project = get_posts($args);//look for a post that has that slug
   $team_cat_id = get_category_by_slug('team')->term_id;
//if you can't find the project post with a matching slug, make the post
      //create the index post
      $args = array(
         'post_title' => $team,
         'post_category' => array($team_cat_id),
         'post_status' => 'publish',
         'tags_input' => array($tag),
         'tax_input' => array(
            'section' => array($section),

Add a User

This is simpler, we’re looking to see if a user exists, if not, we’ll make one and then we’ll return the user ID.

function dlinq_add_user($email){
   if (get_user_by('email', $email)){
      $user = get_user_by('email', $email);
      $user_id = $user->ID;      
   } else {
      $chop = strpos($email,'@', 0);
      $username = substr($email, 0, $chop);
      $pw = wp_generate_password();
      $user_id = wp_create_user($username, $pw, $email);
   return $user_id;

Make a Site

It’s a very similar pattern here. We look to see if a site exists and we look via the site path (in case the name has been changed). If it exists, we just add the student to the site. If not, we create the site and add the student as the admin. get_sites arguments were new to me and it took a bit to figure out the path search pattern.

//make the network site 
function dlinq_blog_creation($slug, $user_id, $team){
   if(get_sites(array( 'fields' => 'ids', 'path' => '/'. $slug . '/'))){
      $sites = get_sites(array( 'fields' => 'ids', 'path' => '/'. $slug . '/'));
      $blog_id = $sites[0];
      $admin = add_user_to_blog($blog_id, $user_id, 'administrator');
   } else {
      $current_network = get_network();
      $domain = $current_network->domain;
      $args = array(
      'domain' => $domain,
      'path' => sanitize_title($team),
      'user_id' => $user_id,
      'title' => $team,      
      $new_site = wp_insert_site($args);

Showing the Users from Another Site as the Post Content

Since we have a post for each team, we want to associate the users that get added to that team site with that post. I could have written them to the body as regular content but I felt it was better to link them to avoid having to deal with changes.

So that leads to a filter called the_content which lets us manipulate the post content in any way we want. We don’t want to do that to all our posts so we use the “team” category and in_category to make sure we’re only applying this to those pots.

We get the details from the team site in a similar way. We search based on the path and get the site ID. That enables us to use get_blog_details to get the site title (blogname), the url, etc. We can also use get_users to get the members of that site since we have the site ID.

//gets the users from the network site and display in the post body
add_filter( 'the_content', 'dlinq_associate_users', 1 );

function dlinq_associate_users($content){
   global $post;
   if(in_category('team', $post->ID)){
         $slug = $post->post_name;
         $site_id = get_sites(array( 'fields' => 'ids', 'path' => '/'. $slug . '/'))[0];
         $args = array(
               'blog_id' => $site_id,
         //site information
         $current_blog_details = get_blog_details( array( 'blog_id' => $site_id ) );
         echo "<h2>Team Name</h2><a href='{$current_blog_details->siteurl}' class='team-link'>{$current_blog_details->blogname}</a>";

         //users from the other blog
         $users = get_users($args);
               echo "<h2>Team Members</h2><ol>";
            foreach($users as $user) {
               echo "<li>{$user->display_name}</li>";
               echo "</ul>";
   return $content;

Team Title Change?

We want to allow teams to change their names. We’re using the same pattern to get the site and the blog details and then applying another filter, the_title, to the post title.

//fix title if the network site changes the title after initial team creation
function dlinq_team_title_adjust( $title, $id ) {
   global $post;
    if ( in_category('team', $post->ID ) ) {
         $slug = $post->post_name;
         $site_id = get_sites(array( 'fields' => 'ids', 'path' => '/'. $slug . '/'))[0];
         $args = array(
               'blog_id' => $site_id,
         //site information
         $current_blog_details = get_blog_details( array( 'blog_id' => $site_id ) );
         $new_title = $current_blog_details->blogname;
        return $new_title; 
    return $title;
add_filter( 'the_title', 'dlinq_team_title_adjust', 10, 2 );

Adding Teams to Previously Created Posts

In our process, Gravity Forms created two posts for the student. Once they get assigned to a team by editing that entry, we want to add the team name to a custom taxonomy (team).

I tried to do that a few different ways but I struggled with capturing both IDs.1 I did note that Gravity Forms was displaying posts created via this entry on the side so I dove into how that was working. I did some searching in the Advanced Post Creation Gravity Forms extension and I found that the post IDs were being logged in the database under gravityformsadvancedpostcreation_post_id. This allowed me to grab those post IDs and loop through them using wp_set_post_terms to add my team custom taxonomy.

function dlinq_add_team_to_posts($entry, $team){
   $try = gform_get_meta( $entry['id'], 'gravityformsadvancedpostcreation_post_id' );
   foreach($try as $post){
      $post_id = $post['post_id'];
      wp_set_post_terms( $post_id, $team, 'team');

1 Not sure why. I sometimes struggle with things that feel basic.