Skip Navigation

[Resolved] Import relationships from API

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
- 10:00 – 13:00 10:00 – 13:00 10:00 – 13:00 10:00 – 13:00 10:00 – 13:00 -
- 14:00 – 18:00 14:00 – 18:00 14:00 – 18:00 14:00 – 18:00 14:00 – 18:00 -

Supporter timezone: Asia/Kolkata (GMT+05:30)

This topic contains 2 replies, has 2 voices.

Last updated by Minesh 2 days ago.

Assisted by: Minesh.

Author
Posts
#2763604

Tell us what you are trying to do?

I have registered the fields for my CPT in WP using a PHP script in my functions.php and am able to successfully update two CPTs individually on my site ('dealers' and 'buildings'). The problem is I can't figure out how to update the one to many relationship between them, to associate buildings with dealers through the API using the endpoint and JSON body.

I'm using the slug as it is seen in the relationship in Toolset, "dealers-building".
Do I need to append wpcf-?

Here is the endpoint I'm using:
hidden link{{ $json.id }} // the id is the WP post id

Here is a JSON body example using {{placeholders}} (because I'm doing this is in n8n):

{
  "building-design": "{{ $('Edit To Add').item.json['building-design'] }}",
  "price": "{{ $('Edit To Add').item.json.price }}",
  "serial": "{{ $('Edit To Add').item.json.serial }}",
  "condition": "{{ $('Edit To Add').item.json.condition }}",
  "checkout-url": "{{ $('Edit To Add').item.json['checkout-url'] }}",
  "featured-image1": "{{ $('Edit To Add').item.json['featured-image1'] }}",
  "build-date": "{{ $('Edit To Add').item.json['build-date'] }}",
  "building-owner": "{{ $('Edit To Add').item.json['building-owner'] }}",
  "category": "{{ $('Edit To Add').item.json.category }}",
  "buildingid": "{{ $('Edit To Add').item.json.buildingid }}",
  "dealers-building": "{{ $('Edit To Add').item.json['dealers-building'] }}"
}

Is there any documentation that you are following?

I've read these:
https://toolset.com/documentation/customizing-sites-using-php/post-relationships-api/#toolset_connect_posts
https://toolset.com/forums/topic/update-relationships-between-custom-post-types/
https://toolset.com/course-lesson/importing-content-from-csv-with-post-relationships/
https://toolset.com/course-lesson/import-posts-from-csv-with-relationships-using-wp-all-import/

Is there a similar example that we can see?

I haven't found any similar examples in my search.

What is the link to your site?

hidden link

Here is the PHP I'm using. I know you don't provide support for PHP, but I'm specifically trying to determine if I'm using the correct field name for the mapping (note the line: 'dealers-building' => 'wpcf-dealers-building', ) and if I'm using toolset_connect_posts correctly. If you happen to see anything that jumps out at you I'm all ears.

// ************************
// CUSTOM FUNCTIONS FOR TOOLSET REST API INTEGRATION
// ************************

// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * Register Custom Meta Fields for 'dealer' and 'buildings' CPTs
 *
 * This function registers custom meta fields for the 'dealer' and 'buildings' custom post types,
 * making them accessible via the REST API.
 */
function register_toolset_fields_for_rest_api() {
    // Define the CPTs to register meta fields for
    $cpts = array( 'dealer', 'buildings' );

    foreach ( $cpts as $cpt ) {
        if ( 'dealer' === $cpt ) {
            // Register meta fields specific to 'dealer'
            register_meta( 'post', 'wpcf-business-name', array(
                'type'         => 'string',
                'description'  => 'Business Name',
                'single'       => true,
                'show_in_rest' => true,
                'object_subtype' => $cpt,
            ));

            register_meta( 'post', 'wpcf-tsa-store-id', array(
                'type'         => 'number',
                'description'  => 'Store ID',
                'single'       => true,
                'show_in_rest' => true,
                'object_subtype' => $cpt,
            ));

            register_meta( 'post', 'wpcf-main-phone', array(
                'type'         => 'string',
                'description'  => 'Main Phone',
                'single'       => true,
                'show_in_rest' => true,
                'object_subtype' => $cpt,
            ));

            register_meta( 'post', 'wpcf-address', array(
                'type'         => 'string',
                'description'  => 'Address',
                'single'       => true,
                'show_in_rest' => true,
                'object_subtype' => $cpt,
            ));

            register_meta( 'post', 'wpcf-email', array(
                'type'         => 'string',
                'description'  => 'Email',
                'single'       => true,
                'show_in_rest' => true,
                'object_subtype' => $cpt,
            ));
        }

        if ( 'buildings' === $cpt ) {
            // Register meta fields specific to 'buildings'
            register_meta( 'post', 'wpcf-building-design', array(
                'type'         => 'string',
                'description'  => 'Building Design',
                'single'       => true,
                'show_in_rest' => true,
                'object_subtype' => $cpt,
            ));

            register_meta( 'post', 'wpcf-price', array(
                'type'         => 'number',
                'description'  => 'Price',
                'single'       => true,
                'show_in_rest' => true,
                'object_subtype' => $cpt,
            ));

            register_meta( 'post', 'wpcf-serial', array(
                'type'         => 'string',
                'description'  => 'Serial Number',
                'single'       => true,
                'show_in_rest' => true,
                'object_subtype' => $cpt,
            ));

            register_meta( 'post', 'wpcf-condition', array(
                'type'         => 'string',
                'description'  => 'Condition',
                'single'       => true,
                'show_in_rest' => true,
                'object_subtype' => $cpt,
            ));

            register_meta( 'post', 'wpcf-checkout-url', array(
                'type'         => 'string',
                'description'  => 'Checkout URL',
                'single'       => true,
                'show_in_rest' => true,
                'object_subtype' => $cpt,
            ));

            register_meta( 'post', 'wpcf-featured-image1', array(
                'type'         => 'string',
                'description'  => 'Featured Image 1 URL',
                'single'       => true,
                'show_in_rest' => true,
                'object_subtype' => $cpt,
            ));

            register_meta( 'post', 'wpcf-video', array(
                'type'         => 'string',
                'description'  => 'Video URL',
                'single'       => true,
                'show_in_rest' => true,
                'object_subtype' => $cpt,
            ));

            register_meta( 'post', 'wpcf-description', array(
                'type'         => 'string',
                'description'  => 'Description',
                'single'       => true,
                'show_in_rest' => true,
                'object_subtype' => $cpt,
            ));

            register_meta( 'post', 'wpcf-build-date', array(
                'type'         => 'string', // Use string to handle date formats
                'description'  => 'Build Date',
                'single'       => true,
                'show_in_rest' => true,
                'object_subtype' => $cpt,
            ));

            register_meta( 'post', 'wpcf-building-owner', array(
                'type'         => 'string',
                'description'  => 'Building Owner',
                'single'       => true,
                'show_in_rest' => true,
                'object_subtype' => $cpt,
            ));

            register_meta( 'post', 'wpcf-category', array(
                'type'         => 'string',
                'description'  => 'Category',
                'single'       => true,
                'show_in_rest' => true,
                'object_subtype' => $cpt,
            ));

            register_meta( 'post', 'wpcf-buildingid', array(
                'type'         => 'string',
                'description'  => 'Building ID',
                'single'       => true,
                'show_in_rest' => true,
                'object_subtype' => $cpt,
            ));

            // Register the relationship meta field
            register_meta( 'post', 'wpcf-dealers-building', array(
                'type'              => 'integer', // Dealer Post ID
                'description'       => 'Related Dealer',
                'single'            => true,
                'show_in_rest'      => true,
                'sanitize_callback' => 'absint',
                'auth_callback'     => function() {
                    return current_user_can( 'edit_posts' );
                },
                'object_subtype' => $cpt,
            ));
        }
    }
}
add_action( 'rest_api_init', 'register_toolset_fields_for_rest_api' );

/**
 * Increase the 'per_page' Limit for 'dealer' and 'buildings' CPTs
 *
 * This function removes the upper limit on the 'per_page' parameter for REST API queries,
 * allowing you to retrieve all posts if needed.
 */
function increase_per_page_limit_for_cpts( $params, WP_Post_Type $post_type ) {
    $cpts = array( 'dealer', 'buildings' );

    if ( in_array( $post_type->name, $cpts, true ) && isset( $params['per_page'] ) ) {
        $params['per_page']['maximum'] = PHP_INT_MAX; // Remove upper limit
    }

    return $params;
}
add_filter( 'rest_dealer_collection_params', 'increase_per_page_limit_for_cpts', 10, 2 );
add_filter( 'rest_buildings_collection_params', 'increase_per_page_limit_for_cpts', 10, 2 );

/**
 * Define Custom REST API Routes for Meta Data Handling
 *
 * This function registers a custom REST API route to handle GET, POST, and PUT requests
 * for updating and retrieving meta data for 'dealer' and 'buildings' CPTs.
 */
function register_toolset_meta_route() {
    register_rest_route( 'toolset/v1', '/toolset-meta/(?P<cpt>[a-zA-Z0-9_-]+)/(?P<id>\d+)', array(
        'methods'             => array( 'GET', 'POST', 'PUT' ),
        'callback'            => 'toolset_meta_handler',
        'permission_callback' => 'toolset_meta_permissions_check',
    ));
}
add_action( 'rest_api_init', 'register_toolset_meta_route' );

/**
 * Permission Callback for Custom REST API Route
 *
 * This function sets the permissions for the custom REST API route,
 * allowing public GET requests and restricting POST/PUT requests to users with 'edit_posts' capability.
 */
function toolset_meta_permissions_check( $request ) {
    if ( 'GET' === $request->get_method() ) {
        return true; // Allow GET requests
    }
    return current_user_can( 'edit_posts' ); // Restrict POST and PUT requests
}

/**
 * Handler for Custom REST API Route
 *
 * This function handles the REST API requests for getting and updating meta data.
 * It maps the meta fields, validates the request, and calls the appropriate function.
 */
function toolset_meta_handler( $request ) {
    $cpt = sanitize_text_field( $request['cpt'] );
    $id  = (int) $request['id'];

    $allowed_cpts = array( 'dealer', 'buildings' );

    if ( empty( $cpt ) || ! in_array( $cpt, $allowed_cpts, true ) ) {
        return new WP_Error( 'invalid_cpt', 'Invalid or missing CPT', array( 'status' => 400 ) );
    }

    if ( empty( $id ) || $id <= 0 ) {
        return new WP_Error( 'invalid_id', 'Invalid or missing ID', array( 'status' => 400 ) );
    }

    $post = get_post( $id );
    if ( ! $post || $post->post_type !== $cpt ) {
        return new WP_Error( 'no_post', 'Post not found or CPT mismatch', array( 'status' => 404 ) );
    }

    $method = $request->get_method();

    // Define meta field mappings based on CPT
    $meta_field_map = array();

    if ( 'dealer' === $cpt ) {
        $meta_field_map = array(
            'business-name' => 'wpcf-business-name',
            'tsa-store-id'  => 'wpcf-tsa-store-id',
            'main-phone'    => 'wpcf-main-phone',
            'address'       => 'wpcf-address',
            'email'         => 'wpcf-email',
        );
    }

    if ( 'buildings' === $cpt ) {
        $meta_field_map = array(
            'building-design'  => 'wpcf-building-design',
            'price'            => 'wpcf-price',
            'serial'           => 'wpcf-serial',
            'condition'        => 'wpcf-condition',
            'checkout-url'     => 'wpcf-checkout-url',
            'featured-image1'  => 'wpcf-featured-image1',
            'video'            => 'wpcf-video',
            'description'      => 'wpcf-description',
            'build-date'       => 'wpcf-build-date',
            'building-owner'   => 'wpcf-building-owner',
            'category'         => 'wpcf-category',
            'buildingid'       => 'wpcf-buildingid',
            'dealers-building' => 'wpcf-dealers-building', // Relationship meta field
        );
    }

    if ( 'GET' === $method ) {
        return get_toolset_meta_fields( $cpt, $id, $meta_field_map );
    } elseif ( 'POST' === $method || 'PUT' === $method ) {
        return update_toolset_meta_fields( $cpt, $id, $request, $meta_field_map );
    } else {
        return new WP_Error( 'invalid_method', 'Method not allowed', array( 'status' => 405 ) );
    }
}

/**
 * Retrieve Meta Fields for a Post
 *
 * This function retrieves the meta fields for a given post and returns them in the REST API response.
 */
function get_toolset_meta_fields( $cpt, $id, $meta_field_map ) {
    $meta_fields = array();

    foreach ( $meta_field_map as $api_field => $meta_key ) {
        $meta_value = get_post_meta( $id, $meta_key, true );

        if ( 'dealers-building' === $api_field && ! empty( $meta_value ) ) {
            $meta_fields[ $api_field ] = intval( $meta_value );
        } else {
            $meta_fields[ $api_field ] = $meta_value;
        }
    }

    return new WP_REST_Response( $meta_fields, 200 );
}

/**
 * Update Meta Fields for a Post and Synchronize Relationships
 *
 * This function updates the meta fields for a given post.
 * When the 'dealers-building' meta field is updated, it synchronizes the Toolset relationship
 * between the building and the dealer using 'toolset_connect_posts'.
 */
function update_toolset_meta_fields( $cpt, $id, $request, $meta_field_map ) {
    $params = $request->get_params();
    $updated_fields = array();

    foreach ( $meta_field_map as $api_field => $meta_key ) {
        if ( isset( $params[ $api_field ] ) ) {
            if ( 'dealers-building' === $api_field ) {
                $dealer_post_id = absint( $params[ $api_field ] );

                // Validate the dealer ID
                if ( get_post_type( $dealer_post_id ) !== 'dealer' ) {
                    return new WP_Error( 'invalid_dealer', 'Invalid Dealer Post ID', array( 'status' => 400 ) );
                }

                // Update the meta field
                update_post_meta( $id, $meta_key, $dealer_post_id );
                $updated_fields[] = $api_field;

                // Synchronize the Toolset relationship using 'toolset_connect_posts'
                if ( function_exists( 'toolset_connect_posts' ) && function_exists( 'toolset_disconnect_related_posts' ) ) {
                    $relationship_slug = 'dealers-building'; // Replace with your actual relationship slug

                    // Disconnect existing relationships for this child post
                    $connected_parents = toolset_get_related_posts( $id, $relationship_slug, 'parent', 1000, 0, array(), 'post_id', 'parent' );
                    if ( ! empty( $connected_parents ) ) {
                        foreach ( $connected_parents as $parent_id ) {
                            toolset_disconnect_related_posts( $parent_id, $id, $relationship_slug );
                        }
                    }

                    // Connect the new parent (dealer) and child (building)
                    $result = toolset_connect_posts( $relationship_slug, $dealer_post_id, $id );

                    if ( is_wp_error( $result ) ) {
                        return $result;
                    }
                } else {
                    return new WP_Error( 'toolset_functions_unavailable', 'Toolset relationship functions are unavailable', array( 'status' => 500 ) );
                }

                continue;
            }

            // Handle other meta fields
            switch ( $api_field ) {
                case 'building-design':
                case 'serial':
                case 'condition':
                case 'checkout-url':
                case 'featured-image1':
                case 'video':
                case 'description':
                case 'building-owner':
                case 'category':
                case 'buildingid':
                    update_post_meta( $id, $meta_key, sanitize_text_field( $params[ $api_field ] ) );
                    break;
                case 'price':
                    update_post_meta( $id, $meta_key, floatval( $params[ $api_field ] ) );
                    break;
                case 'build-date':
                    update_post_meta( $id, $meta_key, sanitize_text_field( $params[ $api_field ] ) );
                    break;
                default:
                    break;
            }
            $updated_fields[] = $api_field;
        }
    }

    if ( ! empty( $updated_fields ) ) {
        return new WP_REST_Response( array(
            'message'        => 'Meta updated successfully',
            'updated_fields' => $updated_fields,
        ), 200 );
    } else {
        return new WP_REST_Response( array(
            'message' => 'No meta fields updated',
        ), 200 );
    }
}
#2765297

If it helps any, I'm getting the error returned from the PHP code error handling:
Toolset relationship functions are unavailable

#2766846

Minesh
Supporter

Languages: English (English )

Timezone: Asia/Kolkata (GMT+05:30)

Hello. Thank you for contacting the Toolset support.

Well - Toolset offers following post-relationship functions:
- https://toolset.com/documentation/customizing-sites-using-php/post-relationships-api/

Where:
To connect the post in relationship function "toolset_connect_posts()" is used:
- https://toolset.com/documentation/customizing-sites-using-php/post-relationships-api/#toolset_connect_posts

To disconnect the post in relationship function "toolset_disconnect_posts()" is used:
- https://toolset.com/documentation/customizing-sites-using-php/post-relationships-api/#toolset_disconnect_posts

With the code you shared - I see you are using function name "toolset_disconnect_related_posts" - maybe you should replace that with the correct function name "toolset_disconnect_posts" and check if that help you to resolve the issue.

#2767444

That was it. Thanks!

georgeY-3 confirmed that the issue was resolved on 2024-10-04 18:44:34.
This ticket is now closed. If you're a Toolset client and need related help, please open a new support ticket.