Skip Navigation

[Résolu] Using Woocommerce and cred_save_data to create a custom post type

Ce fil est résolu. Voici une description du problème et la solution proposée.

Problem:
The user collects payment for user registration, he would like to automatically create a post from a custom post type when the user completes the payment. And he would like to pass some data(custom fields) in the user registration form.

Solution:
This requires:

  • Post custom fields.
  • User custom fields, similar to the post fields needed.
  • CRED commerce form for users registration.
  • Custom code to create the post automatically when the order completes.

The cred_commerce_after_order_completed hook passes a $data object to the hooked function. The order_id is the "transaction_id" in the $data object. The created user is saved in a custom field of the order, called "_cred_post_id". Then we can pull the user fields from the user, create the custom post, and save the custom field values for the post.
Check this sample code:

add_action( 'cred_commerce_after_order_completed', 'my_cred_commerce_after_order_completed', 10, 1 );
function my_cred_commerce_after_order_completed( $data ) {
    // get the order id
    $order_id = $data['transaction_id'];
 
    // get the user id
    $user_id = get_post_meta( $order_id, '_cred_post_id', true);
 
    // get user data to have a title for the post.
    $user = get_userdata( $user_id );
 
    // prepare post object
    $post = array(
        'post_type'     => 'user-profile',           // <== CPT slug
        'post_title'    => $user->user_login, // <== post title
        'post_status'   => 'publish',
        'post_author'   => $user_id,                // <== Author
    );
 
    // Insert the post into the database
    $post_id = wp_insert_post( $post );
 
    // get user field
    $phone = get_user_meta( $user_id, 'wpcf-phone-number', true );
    $agency = get_user_meta( $user_id, 'wpcf-agency1', true );
    $speciality = get_user_meta( $user_id, 'wpcf-specialty', true );
 
    // create post field
    update_post_meta( $post_id, 'wpcf-agency1', $agency );
    update_post_meta( $post_id, 'wpcf-phone-number', $phone );
    update_post_meta( $post_id, 'wpcf-speciality', $speciality );
}

Relevant Documentation:

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.

Auteur
Publications
#1710591

I'm trying to create a custom post type (User Profile) from a user registration form. Waqar helped with this: when the form simply creates the user/user profile without a Woocommerce link, it works just fine.

The problem occurs when I hook up the form to Woocommerce in almost any variation. Once the order is completed (either by a code snipped or with a selection in the orders list to change status from processing to completed), the customer is created but the cred_save_data process isn't triggered. I suppose that's because the form isn't being processed when the order is completed, but what hook should i use instead? Are the generic fields defined on the form available at that time, or is there another process that needs to be followed?

#1711059

Jamal
Supporter

Languages: Anglais (English ) Français (Français )

Timezone: Africa/Casablanca (GMT+01:00)

Hello and thank you for contacting the Toolset support.

You said I suppose that's because the form isn't being processed when the order is completed
The form and its hooks will be processed when the form is submitted in the frontend and nowhere else. You will need to hook to the order complete event/hook, I found woocommerce_order_status_completed online, but I was not able to find it in the official documentation https://docs.woocommerce.com/wc-apidocs/hook-docs.html

Generic fields won't be available at this stage unless they are persisted to the database(persist argument).
Please elaborate more on your use case for me to understand, and I'll suggest what seems to be the best way/process.

#1712789

My use case is pretty simple -- I have a Real Estate Agent membership directory. Agents sign up, which should create a user as well as a custom post type 'user profile' -- I need to do this because I need to sort/select fields from the directory fields (e.g. select user's city or specialties), and I can't sort/select the user file. The form itself contains user information (user) and generic fields (custom post type).

"Basic" membership is free, so there's no need to go through Woocommerce -- the membership form is processed, the cred_save_data process is triggered, the user is created, and the custom post type is created with all the appropriate form fields updating as expected.

"Premium" membership isn't free, so I want to use Woocommerce to process the membership form. Creation of user and custom post type are delayed until the Woocommerce order is "completed." When the order is flagged as completed, the user is created, but the custom post type isn't.

I would need to know how to create the custom post type when the woocommerce order is completed. If there's a cred hook that would do this, great. If I have to save all the generic fields as user fields, I'd need to know which process I need to trigger to create the custom post type. Thanks.

#1713735

Jamal
Supporter

Languages: Anglais (English ) Français (Français )

Timezone: Africa/Casablanca (GMT+01:00)

Thank you for your feedback.

Check the cred_commerce_after_payment_completed hook, that's probably what you are looking for.
https://toolset.com/documentation/programmer-reference/cred-commerce-api/#cred_commerce_after_payment_completed

Otherwise, you may hook into the user creation process. There is a default action in WordPress user_register
https://developer.wordpress.org/reference/hooks/user_register/

I hope this answers your question. Let me know if you have any questions.

#1713953

I'm able to retrieve $form_id and $post_id, but I'm unable to retrieve the post itself for access to form fields.

add_action('cred_commerce_after_payment_completed', 'my_add_order_24592',10,2);
function my_add_order_24592($data) {

 // if a specific form
    $form_id = $data['extra_data'][0]['cred_form_id']; // Form ID
    $post_id = $data['extra_data'][0]['cred_post_id'];  // Post ID that was created/edited with the form

    if ($form_id == 24592) {
    
	// Create new entry after registration.
		$ary = get_post_meta($post_id);
		$results = print_r($ary,true);

       // Load up the ary to create the User Profile
       $my_post = array(
              {...code loading the $my_post variable...}
       );
       
       // Insert the post into the database 
       wp_insert_post( $my_post );
   }

$ary is empty ($result is empty). In fact, the value of $post_id is somewhat strange: draft_21, draft_22, draft_23, etc.
How do I access the form data, which I assume must be stored in the draft order?

#1714749

Jamal
Supporter

Languages: Anglais (English ) Français (Français )

Timezone: Africa/Casablanca (GMT+01:00)

I'll need more details about this issue to understand it better and to find a solution.
Would you allow me temporary access to your website to check it closely?

Can you, also, provide details of the process step-by-step. What page? what form? what content template? etc.

Your next reply will be private to let you share credentials safely. ** Make a database backup before sharing credentials. **

#1715033

Jamal
Supporter

Languages: Anglais (English ) Français (Français )

Timezone: Africa/Casablanca (GMT+01:00)

Generic fields are not persisted on the database, you will need to hook into the form submission to save them somewhere, then you can use them on the "cred_commerce_after_payment_completed" hook. Check this article https://toolset.com/course-lesson/adding-generic-fields-to-forms/

Form hook that you may use at this point is cred_save_data https://toolset.com/documentation/programmer-reference/cred-api/#cred_save_data

What I would suggest instead, is using user fields instead of generic fields. The form is for creating users. So if you use some user fields, the values will be saved on the user object. Then you can use get_user_meta instead of using get_post_meta. https://developer.wordpress.org/reference/functions/get_user_meta/

Does this make sense to you? Let me know if you have any questions.

#1715037

I still need to create a custom post type -- my directory view needs to select on a number of generic fields (specialties, user city, etc.), and views won't allow select fields on a user view. So, here are a couple of questions about proceeding:
1) why does the User Profile get created when the order is created and not after the order payment is completed?
2) if I want to store my generic fields on the order, how do I do that? I see that custom fields are allowed, I just don't know how to add them
3) if I wanted to store my generic fields as user fields, I still need to create the custom post type when the user is added -- how do I do that?

#1715063

Jamal
Supporter

Languages: Anglais (English ) Français (Français )

Timezone: Africa/Casablanca (GMT+01:00)

I still need to create a custom post type
I understand that, what I suggest, is storing the fields on the user object first, then retrieve them on the order completed hook and use them to create the profile custom post type.

1) why does the User Profile get created when the order is created and not after the order payment is completed?
Do you mean the user object(in wp_users table) instead of a custom post, right? That's expected, you are using a User Form, and it will create a user when the form is submitted.

2) if I want to store my generic fields on the order, how do I do that? I see that custom fields are allowed, I just don't know how to add them
You will need to use custom PHP code, hooked to the cred_save_data of the form to manipulate the generic fields value, and store them on the database the way it suits you.
Or, you can create User fields in Toolset->Custom Fields and use them on the form instead of generic fields. That way, when you hook into the order complete action, you can retrieve the values from the user object with get_user_meta function.

3) if I wanted to store my generic fields as user fields, I still need to create the custom post type when the user is added -- how do I do that?
You can use the WordPress update_user_meta function to store generic fields as user fields. Or you can directly use Toolset User Fields and let Toolset save them on the database.
https://developer.wordpress.org/reference/functions/update_user_meta/

Then you can create the custom post type, either on the cred_save_data hook or on the order complete hook. You will use the wp_insert_post function for that.

#1715425

I'm about ready to give up on this. If I use cred_save_data, I don't have the user_id (created when the user is saved). if I use cred_commerce_after_payment_completed, I don't have the user_id OR the custom user fields. If I use "user_register", which actually is what I'd like to use, I don't have any of the meta data, and I'm not sure how to get it. I've scoured Google for an idea on what WordPress hook to use that's AFTER the user's meta data is saved to the database, but no luck. There are questions in forums et al that date back 7 years, so I'm greatly frustrated that I can't get an answer to what should be a simple and attainable solution.

#1716057

Jamal
Supporter

Languages: Anglais (English ) Français (Français )

Timezone: Africa/Casablanca (GMT+01:00)

I understand the frustration that you may have felt handling this issue. So, I run a couple of tests locally and I came up with a solution.

The cred_commerce_after_payment_completed hook won't help, because the user is not yet created at this stage. It is being created when the order completes.

The user_registration hook is not helping too. We can use it to create the post, but the user fields are not yet updated for the created user.

We'll have to implement an action on the cred_commerce_after_order_completed hook. The order_id is the "transaction_id" in the $data object. The created user is saved in a custom field of the order, called "_cred_post_id". Then we can pull the user fields from the user, create the custom post, and enter the values for the post fields.

Check the following code, it assumes the following:
- 3 post fields for "User Profile" CPT (agency, specialty, phone-number).
- 3 user fields, similar to the post fields, (agency, specialty, phone-number).
Note, that my user field agency has a different slug('agency1')

add_action( 'cred_commerce_after_order_completed', 'my_cred_commerce_after_order_completed', 10, 1 );
function my_cred_commerce_after_order_completed( $data ) {
	// get the order id
	$order_id = $data['transaction_id'];

	// get the user id
	$user_id = get_post_meta( $order_id, '_cred_post_id', true);

	// get user data to have a title for the post.
	$user = get_userdata( $user_id );

	// prepare post object
	$post = array(
		'post_type'     => 'user-profile',           // <== CPT slug
		'post_title'    => $user->user_login, // <== post title
		'post_status'   => 'publish',
		'post_author'   => $user_id,                // <== Author
	);

	// Insert the post into the database
	$post_id = wp_insert_post( $post );

	// get user field
	$phone = get_user_meta( $user_id, 'wpcf-phone-number', true );
	$agency = get_user_meta( $user_id, 'wpcf-agency1', true );
	$speciality = get_user_meta( $user_id, 'wpcf-specialty', true );

	// create post field
	update_post_meta( $post_id, 'wpcf-agency1', $agency );
	update_post_meta( $post_id, 'wpcf-phone-number', $phone );
	update_post_meta( $post_id, 'wpcf-speciality', $speciality );
}

I'll let you test it from your end and confirm if it is working for you.

#1716335

This works perfectly. Thank you -- my issue is resolved now.