Skip Navigation

[Resolved] Automatically check checkboxes when creating intermediary post (many-to-many relationship) programmatically using toolset_connect_posts

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

Problem: I have a custom checkboxes group field applied to the intermediary post type in a M2M relationship. Some of the checkboxes in this group are configured to be "checked" automatically when new posts are created, but the intermediary post created automatically by the toolset_connect_posts API does not have these checkboxes checked automatically.

Solution: Our developers are investigating this issue. Until it is addressed, an undocumented custom code workaround is required.

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.

No supporters are available to work today on Toolset forum. Feel free to create tickets and we will handle it as soon as we are online. 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)

This topic contains 13 replies, has 2 voices.

Last updated by Lara 3 years, 10 months ago.

Assisted by: Christian Cox.

Author
Posts
#1871011

Tell us what you are trying to do?

I have two post types: Studios and Artists. A Studio can have many Artists, and an Artist can belong to many Studios (set up as a many-many relationship). I have Toolset forms to create each post type.

Documentation: https://toolset.com/forums/topic/automatically-connecting-post-types-in-many-many-relationship/#post-1074784
I follow the steps as in the documentation:

1) You are using below many-many relationship, the relationship slug is "studio-artist", you can get the relationship slug by editing the many-many relationship, make sure "studio" post type is in the left place of the relationship, and "artist" post type is in the right place.

2) In the single "studio" post, you can display a Toolset post form for creating "artist" post

3) In the Toolset post form, you can get the current "studio" post ID with Views shortcode
[wpv-post-id], use it in a hidden field "studio_id", and pass parameter to Toolset form, for example:

[cred_generic_field field='studio_id' type='hidden' class='' urlparam='']
{
"required":0,
"validate_format":0,
"default":"[wpv-post-id]"
}
[/cred_generic_field]

4) Use action hook cred_save_data to trigger a custom PHP function, in this function connect the "studio" post with the new "artist" post, like this:

add_action('cred_save_data', 'connect_studio_artist_func',10,2);
function connect_studio_artist_func($artist_id, $form_data)
{
    // if a specific form
    if ($form_data['id']== 35 && isset($_POST['studio_id']))
    {
        $studio_id = $_POST['studio_id'];
        if($studio_id){
            toolset_connect_posts(
                $relationship = 'studio-artist',
                $studio_id,
                $artist_id
            );
        }
    }
}

It works perfectly. However in my case, I also need an intermediary post. How do I insert the id of the intermediary post in the toolset_connect_posts( $relationship = 'studio-artist', $studio_id, $artist_id); ? Is it toolset_connect_posts( $relationship = 'studio-artist', $studio_id, $artist_id, $intermediary_id); ?

Something like..

add_action('cred_save_data', 'connect_studio_artist_func',10,2);
function connect_studio_artist_func($artist_id, $form_data)
{
    // if a specific form
    if ($form_data['id']== 35 && isset($_POST['studio_id']))
    {
        $studio_id = $_POST['studio_id'];
        if($studio_id){

// Create post object
$intermediary = array(
'post_title' => 'dynamic',
'post_status' => 'publish',
'post_type' => 'booking-times',
'post_author'   =>  $studio_id,
);
 
// Insert the post into the database
$intermediary_id = wp_insert_post( $intermediary );

            toolset_connect_posts(
                $relationship = 'studio-artist',
                $studio_id,
                $artist_id,
               $intermediary_id 
            );
        }
    }
}

Is there any documentation that you are following?
https://toolset.com/forums/topic/automatically-connecting-post-types-in-many-many-relationship/#post-1074784
https://toolset.com/forums/topic/relationship-of-dynamically-created-child-post/

Is there a similar example that we can see?
In the documentation

What is the link to your site?
hidden link

#1872307

Hello, it depends on whether the intermediary post already exists yet or not when the cred_save_data hook is triggered. In most cases, the intermediary post does not exist yet, unless you're doing something very custom. So there's no ID available for a non-existent post. If the intermediary post does not exist yet when the new cred_save_data hook is triggered, that intermediary post ID information must be omitted from the toolset_connect_posts API. If an intermediary is needed for the M2M but not provided in the API parameters, an intermediary post should be generated automatically, with all the relationships maintained as expected.

The documentation for this API is available here for your reference:
https://toolset.com/documentation/customizing-sites-using-php/post-relationships-api/#toolset_connect_posts

See the information about the 4th argument to this function:
The intermediary post to use for a many-to-many post relationship. If it is not provided and it is needed, a new post will be created

See the information about the response Array:
int 'intermediary_post': This element is present only if the operation has succeeded and contains the ID of the newly created intermediary post or zero if there is none.

Let me know if this automatic intermediary post generation process isn't working as expected, and I can take a closer look. There may be something else going on.

#1872459

Hello Christian, many thanks for your answer. I apologize, I phrased my question not good enough. The automatic intermediary post generation process is working. But there is a problem with the newly created intermediary post.

All newly created intermediary posts should have all checkboxes checked in a custom checkboxes field. The intermediary custom checkboxes field is set to "Set checked by default (on new post)". But it doesn't seem to work. This field is unchecked in all newly created posts. So, I was looking for a workaround. That's why I came up with the idea to create a new intermediary post through code...

I have seen that there seems to be an issue with checked checkboxes fields and post relationship forms, but I am unsure, if this applies for my situation as well...

Do you have an idea where the unchecked checkboxes problem may stem from?

#1874639

Okay I understand, the problem is that the checkboxes in a checkboxes group field are not automatically "checked" when the intermediary post is created programmatically, despite setting up those checkboxes to be automatically "checked" in new posts. I'm not sure whether this is a bug, or whether extra custom code is required to set custom field values programmatically when a new post is generated programmatically. I'm asking my 2nd tier support team for their opinion, and I will let you know what I find out.

#1875175

Many thanks Christian 🙂

#1875661

We've asked the developers for feedback on this, and I'll keep you posted here.

#1875721

We've escalated this to the developers as a consistency/usability issue, since posts created programmatically using wp_insert_post have default field values applied automatically. It seems that this toolset_connect_posts API should work in a similar way, automatically setting those field values. I don't have a timeline available for resolving this problem just yet. In the meantime, there is an undocumented custom code workaround, since programmatically setting checkboxes groups fields is not officially supported. I can provide some code examples, but I cannot guarantee they will work in the future as the software evolves. Let me know if you want to try this undocumented workaround in the meantime, with that warning in mind.

#1876175

Many thanks Christian, I want to try the undocumented workaround.

It's ok, if it might stop at one point - and also thanks for the warning - I will keep it in mind and test it after every toolset update. If it stops one day - maybe, the problem will be resolved by then or it's possible to figure out another workaround...

#1876183

Okay here is an undocumented custom function you can include in your functions.php file or in a custom code snippet in Toolset > Settings > Custom Code:

/**
 * Unofficial API function to check/uncheck checkboxes options
 * 
 * @param int $post_id
 * @param string $field // slug of checkboxes field
 * @param string $option // title of checkbox option to manipulate
 * @param string $action : 'check' | 'uncheck' | 'value' (default, returns current value)
 * 
 * Important: assumes recommended checkboxes setting of save nothing to database when unchecked
 */

function ts_checkboxes( $post_id, $field, $option, $action = 'value' ){

    if ( isset($post_id) && isset($field) && isset($option) ){

		$field_settings = types_get_field( $field );
		
        $field_options = $field_settings['data']['options'];

		// Locate the option key
        $key = array_search( $option, array_column( $field_options, 'title' ) );
        $keys = array_keys( $field_options );
		$option_key = $keys[$key];

		// Get the current post meta value
		$meta = get_post_meta( $post_id, 'wpcf-'.$field, true );

		// If action = 'value' just return the value
		if ( $action == 'value' && isset( $meta[$option_key] ) ){
			return $meta[$option_key][0];
		} else {
			// Remove the existing key if it exists (i.e. uncheck)
			// because recommended setting is to save nothing when unchecked
			unset( $meta[$option_key] );
			
			// If $checked == true then add back the key + value
			if ( $action == 'check' ){
				$meta[$option_key] = array($field_options[$option_key]['set_value']);
			}
			update_post_meta( $post_id, 'wpcf-'.$field, $meta );		
		}
    }
}

You can then call this function to set any single checkbox in a checkboxes group to be 'checked' like so:

ts_checkboxes( 12345, 'available-options, 'Second checkbox', 'check' );

In this example, 12345 represents the post ID for the post where you want to set the checkbox as checked. In your case, you would get this post ID information from the response of the toolset_connect_posts API, which returns the ID of the automatically generated intermediary post in an array like this:

array( "success" => true, "intermediary_post" => 12345)

The second argument, available-options, represents the slug of the checkboxes group field. You can find the field slug when editing the custom checkboxes group field in Types > Custom Fields.

The third argument, Second checkbox, represents the title of the individual checkbox within that checkboxes group, which you wish to 'check' programmatically.

The fourth argument, check, tells the function what to do with that individual checkbox. In this case, 'check' will check this option programmatically. An argument of uncheck would uncheck that checkbox, and an empty argument would simply return the current value of the checkbox.

#1876383

Many thanks Christian. I just have two short questions:

Where do I insert this:

ts_checkboxes( 12345, 'available-options, 'Second checkbox', 'check' );

... and how do I connect the dots with this ...

array( "success" => true, "intermediary_post" => 12345)
#1876927

The idea here is that you capture the response from toolset_connect_posts in a variable:

...
$relationship_response = toolset_connect_posts(
  $relationship = 'studio-artist',
  $studio_id,
  $artist_id
);
...

If the toolset_connect_posts API creates the intermediary post successfully, the intermediary post ID becomes available in the $relationship_response variable array, like so:

...
$intermediary_post_id = $relationship_response['intermediary_post'];
...

Then you would be able to call ts_checkboxes immediately after toolset_connect_posts:

...
ts_checkboxes( $intermediary_post_id, 'available-options, 'First checkbox', 'check' );
ts_checkboxes( $intermediary_post_id, 'available-options, 'Second checkbox', 'check' );
...and so on for each checkbox...
#1878165

Many thanks Christian 🙂
Now, I got it.

It's a beautifull solution.

#1878173

Sure, I'll keep you posted here as I receive information from the developers. Hopefully this will be addressed in our software and the workaround will no longer be required.

#1895229

Thanks 🙂