Skip Navigation

[Resolved] How to pre-select more than one M2M parent on a child post submission form?

This thread is resolved. Here is a description of the problem and solution.

Problem: I have two custom post types in a many-to-many (M2M) relationship. In a Form that creates new child posts, I would like to allow Users to select multiple parent posts and create those relationships automatically.

Solution: Usually M2M relationships are managed in Relationship Forms after both parent and child posts are already created. To create M2M relationships between posts in a new child post Form, you must use a generic multiselect field and custom code. Here is the general approach:

1. Create a View of one of the parent post types. Click "Loop Wizard" above the Loop Editor and select the "list with separators" display type. In the next screen of the popup, click "Add a field" and add the post title, then click "Finish". In the loop editor, replace the code inside the wpv-loop tags with the following code:

<wpv-loop>
  [wpv-item index=1]
  {"value":"[wpv-post-id]","label":"[wpv-post-title]"}
  [wpv-item index=other]
  ,{"value":"[wpv-post-id]","label":"[wpv-post-title]"}
</wpv-loop>

Be sure the checkbox "Disable the wrapping DIV around the View" is checked, and delete all the content from inside the wpv-no-items-found shortcode, like so:

[wpv-no-items-found][/wpv-no-items-found]

This View will be used to generate JSON-like options for each parent post in one generic multiselect field in Forms. You will repeat this process to create Views of any additional parent post types. Note the slug of this View for step 2 below.

2. Edit the child post Form using Expert Mode in the Form Builder. Click "Add generic fields" above the code editor and choose a multiselect generic field. In the popup, choose the option to "Get options from a shortcode". Insert a View shortcode that includes your parent post type View slug in the name attribute, like so:

[wpv-view name="your-parent-post-type-view-slug"]

Save the field, and the expert builder will insert a new shortcode for you automatically in the Form contents. It will look like this:

[cred_generic_field type='multiselect' field='your-multiselect-field-slug']
{
"required":0,
"options":[ [wpv-view name="your-parent-post-type-view-slug"] ]
}
[/cred_generic_field]

3. Test the Form on the front-end of the site. You should see a multiselect field appear at this point with options for each parent post.

4. If the multiselect field is displaying correctly, now you need to add some PHP code using the cred_save_data hook that will capture the selected values from that multiselect field and loop over those values when the Form is submitted successfully. Inside this loop over the selected values, you will call the toolset_connect_posts API to create relationships between each selected option and the new child post. You can add this code in a child theme's functions.php file, or in a new custom code snippet in Toolset > Settings > Custom Code tab. Here is an example of such a cred_save_data hook:

add_action('cred_save_data', 'tssupp_associate_multiple_related_posts',10,2);
function tssupp_associate_multiple_related_posts($post_id, $form_data) {
  $forms = array( 123 );
  $relationship_1_slug = "parent-child-relationship-slug";
  $ms_field_slug = "your-multiselect-field-slug";
 
  if ( in_array( $form_data['id'], $forms ) ) // test if the form being submitted is in the list of form IDs we want to target
  {
    $ms_selections = $_POST[$ms_field_slug]; // the $_POST superglobal contains an array of the selected parent post IDs
    foreach($ms_selections as $ms_selection) {
      toolset_connect_posts( $relationship_1_slug, $ms_selection, $post_id); // while looping over selected parents, connect them to the new child post programmatically
    }
  }
}

In this example, you would replace 123 with the numeric ID of the child post Form, or a comma-separated list of child post Form IDs if there is more than one new child post Form. You would replace parent-child-relationship-slug with the slug of the relationship between the parent post type and the child post type. You would replace your-multiselect-field-slug with the slug of the generic multiselect field you created in the Form builder. Inside the "if" condition, you can create new foreach loops for each parent post type, but let's hold off on that for now and just get one parent type saving correctly.

Relevant Documentation:
https://toolset.com/documentation/programmer-reference/cred-api/#cred_save_data
https://toolset.com/documentation/customizing-sites-using-php/post-relationships-api/#toolset_connect_posts

100% of people find this useful.

This support ticket is created 3 years, 11 months ago. There's a good chance that you are reading advice that it now obsolete.

This is the technical support forum for Toolset - a suite of plugins for developing WordPress sites without writing PHP.

Everyone can read this forum, but only Toolset clients can post in it. Toolset support works 6 days per week, 19 hours per day.

Our next available supporter will start replying to tickets in about 2.23 hours from now. Thank you for your understanding.

Sun Mon Tue Wed Thu Fri Sat
8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 - -
13:00 – 17:00 13:00 – 17:00 13:00 – 17:00 13:00 – 17:00 13:00 – 17:00 - -

Supporter timezone: America/New_York (GMT-04:00)

Author
Posts
#1866983

Hey Team,

I have a many to many relationship between "project submissions" and endorsement requests". Users will first submit projects and then requests endorsements. A button on "project submission" template" will capture the project id and pass it to the child "endorsement request" form. But, I want to enable the user to select more "project submissions" if they want.

How do I make this happen? The post reference field works only for a one-to-many relationship. Also, the relationship form is used to connect two post types that have already been published. I want to pre-fill values of a parent to a child before I publish the child post.

Documentation:
https://toolset.com/course-lesson/front-end-relationship-forms-for-connecting-posts/
https://toolset.com/course-lesson/how-to-set-up-post-relationships-in-wordpress/
https://toolset.com/course-lesson/using-post-reference-field-to-set-up-one-to-many-relationships/

Thanks!

#1867043

Hi, a few things to note here:
1. In a Form that creates new child posts in a M2M relationship, there is no built-in feature to manage the relationships between the new child post and its parent(s) in that same Form. It is possible to select a single parent post for a new child in an O2M relationship, but that feature does not exist for M2M relationships. Normally those M2M relationships must be managed in a separate Relationship Form, after the child post is created in a New Post Form.

2. To automatically associate multiple parents from an M2M relationship to a new child post created in a Form, you would need to use a generic multiselect field that contains options for each parent post. You would have to use a View to generate those options dynamically, and preselect any options you pass into the page containing the new Child Post Form as URL parameters.

Then once that generic multiselect is created, you would need to use the Forms API cred_save_data to trigger some custom code when the child post is submitted. In that custom code, you would have to inspect the User's parent post selections from the global $_POST superglobal, loop over those selections, and use the Post Relationships API toolset_connect_posts to programmatically associate the new child post and its various parents after the child post is saved.

It's a fairly advanced customization that requires knowledge of HTML and PHP. If you're comfortable writing code that involves some HTML and some PHP, I can show you examples and other posts here on the site that you can use as a guide. If you're not comfortable writing custom code, the Relationship Form approach is recommended.

#1867209

Thanks for the detailed answer. I am comfortable with coding so please share some examples.

#1867895

Okay sure. Here is the general idea:

1. Create a View of one of the parent post types. Click "Loop Wizard" above the Loop Editor and select the "list with separators" display type. In the next screen of the popup, click "Add a field" and add the post title, then click "Finish". In the loop editor, replace the code inside the wpv-loop tags with the following code:

<wpv-loop>
  [wpv-item index=1]
  {"value":"[wpv-post-id]","label":"[wpv-post-title]"}
  [wpv-item index=other]
  ,{"value":"[wpv-post-id]","label":"[wpv-post-title]"}
</wpv-loop>

Be sure the checkbox "Disable the wrapping DIV around the View" is checked, and delete all the content from inside the wpv-no-items-found shortcode, like so:

[wpv-no-items-found][/wpv-no-items-found]

This View will be used to generate JSON-like options for each parent post in one generic multiselect field in Forms. You will repeat this process to create Views of any additional parent post types. Note the slug of this View for step 2 below.

2. Edit the child post Form using Expert Mode in the Form Builder. Click "Add generic fields" above the code editor and choose a multiselect generic field. In the popup, choose the option to "Get options from a shortcode". Insert a View shortcode that includes your parent post type View slug in the name attribute, like so:

[wpv-view name="your-parent-post-type-view-slug"]

Save the field, and the expert builder will insert a new shortcode for you automatically in the Form contents. It will look like this:

[cred_generic_field type='multiselect' field='your-multiselect-field-slug']
{
"required":0,
"options":[ [wpv-view name="your-parent-post-type-view-slug"] ]
}
[/cred_generic_field]

3. Test the Form on the front-end of the site. You should see a multiselect field appear at this point with options for each parent post. We can go back later and set up some extra code that will preselect an option based on a URL parameter, and another multiselect for another parent post type. For now, let's just get the one parent post type field implemented and saving correctly.

4. If the multiselect field is displaying correctly, now you need to add some PHP code using the cred_save_data hook that will capture the selected values from that multiselect field and loop over those values when the Form is submitted successfully. Inside this loop over the selected values, you will call the toolset_connect_posts API to create relationships between each selected option and the new child post. You can add this code in a child theme's functions.php file, or in a new custom code snippet in Toolset > Settings > Custom Code tab. Here is an example of such a cred_save_data hook:

add_action('cred_save_data', 'tssupp_associate_multiple_related_posts',10,2);
function tssupp_associate_multiple_related_posts($post_id, $form_data) {
  $forms = array( 123 );
  $relationship_1_slug = "parent-child-relationship-slug";
  $ms_field_slug = "your-multiselect-field-slug";

  if ( in_array( $form_data['id'], $forms ) ) // test if the form being submitted is in the list of form IDs we want to target
  {
    $ms_selections = $_POST[$ms_field_slug]; // the $_POST superglobal contains an array of the selected parent post IDs
    foreach($ms_selections as $ms_selection) {
      toolset_connect_posts( $relationship_1_slug, $ms_selection, $post_id); // while looping over selected parents, connect them to the new child post programmatically
    }
  }
}

In this example, you would replace 123 with the numeric ID of the child post Form, or a comma-separated list of child post Form IDs if there is more than one new child post Form. You would replace parent-child-relationship-slug with the slug of the relationship between the parent post type and the child post type. You would replace your-multiselect-field-slug with the slug of the generic multiselect field you created in the Form builder. Inside the "if" condition, you can create new foreach loops for each parent post type, but let's hold off on that for now and just get one parent type saving correctly.

Let's stop here for now and try to get this all working before tackling the preselected parent post in the multiselect field and other parent post types. Let me know if you're able to get this working with one parent post type alone, or if you get stuck with this code. See the documentation links below for more details about these APIs:
https://toolset.com/documentation/programmer-reference/cred-api/#cred_save_data
https://toolset.com/documentation/customizing-sites-using-php/post-relationships-api/#toolset_connect_posts

#1869255

Christian,

The solution worked. Thanks a lot!

A couple of modifications would help: 1) the generic field should be a drop down instead of a stretched list and, 2) the JSON should show only parent "project submissions" from the author who is the current user.

Regards,
Himanshu

#1869331

1) the generic field should be a drop down instead of a stretched list
Unfortunately the types of generic fields are limited, and there is no multiselect dropdown generic field type. You can show a dropdown select field, but it only allows for a single selection. Or you can use a multiselect field like you have implemented now, but it does not display as a dropdown. It is a standard HTML multiselect field. You might be able to apply some custom CSS to change the height of the visible area, but it will never function as a dropdown. You would have to create that type of input using your own custom PHP, CSS and HTML markup.

2) the JSON should show only parent "project submissions" from the author who is the current user.
The results produced by this View can be filtered just like the results of any other View using Query Filters. In Query Filter panel of the View editor, you can click "add a filter" to filter by post author, where the author is the same as the current User. If you cannot see the Query Filter panel in the View editor screen, scroll to the top right corner and click "Screen Options" to turn on the Query Filter panel.

#1869391

Perfect, My issue is resolved. Thank you Christian.

#1869403

My issue is resolved now. Thank you!