\d+)/status', array( 'methods' => 'POST', 'callback' => array( $this, 'handle' ), 'permission_callback' => array( $this->verifier, 'verify' ), ) ); } /** * Store the status. * * @param WP_REST_Request $request Signed request from the cloud. * @return WP_REST_Response|WP_Error */ public function handle( WP_REST_Request $request ) { // get_param() prefers the JSON body over the URL; the id must come from the signed path. $product_id = (int) ( $request->get_url_params()['woo_product_id'] ?? 0 ); $data = json_decode( $request->get_body(), true ); try { $status = ProductSyncStatus::from_array( is_array( $data ) ? $data : array() ); } catch ( \Throwable $e ) { return new WP_Error( 'storebridge_invalid_body', 'The product status is invalid.', array( 'status' => 400 ) ); } if ( $status->woo_product_id !== $product_id ) { return new WP_Error( 'storebridge_invalid_body', 'The product id in the body does not match the URL.', array( 'status' => 400 ) ); } if ( 'product' !== get_post_type( $product_id ) ) { return new WP_Error( 'storebridge_not_found', 'Unknown product.', array( 'status' => 404 ) ); } $stored_at = (string) get_post_meta( $product_id, ProductMeta::STATUS_AT, true ); if ( null !== $status->occurred_at && '' !== $stored_at && strtotime( $stored_at ) > strtotime( $status->occurred_at ) ) { return new WP_REST_Response( null, 204 ); } update_post_meta( $product_id, ProductMeta::STATUS, $status->sync_state->value ); $this->set_or_delete( $product_id, ProductMeta::TIKTOK_STATUS, $status->tiktok_status ); $this->set_or_delete( $product_id, ProductMeta::PRODUCT_ID, $status->tiktok_product_id ); $this->set_or_delete( $product_id, ProductMeta::SYNCED_AT, $status->last_synced_at ); $this->set_or_delete( $product_id, ProductMeta::STATUS_AT, $status->occurred_at ); $errors = array_map( static fn ( $error ) => $error->to_array(), $status->errors ); if ( array() === $errors && null !== $status->last_error ) { $errors = array( $status->last_error->to_array() ); } $this->set_or_delete( $product_id, ProductMeta::ERRORS, array() === $errors ? null : (string) wp_json_encode( $errors ) ); foreach ( $status->skus as $sku ) { $target = 0 === $sku->woo_variation_id ? $product_id : $sku->woo_variation_id; if ( $target === $product_id || wp_get_post_parent_id( $target ) === $product_id ) { update_post_meta( $target, ProductMeta::SKU_ID, $sku->tiktok_sku_id ); } } return new WP_REST_Response( null, 204 ); } /** * Update a meta value, or delete it when null. * * @param int $product_id Product id. * @param string $key Meta key. * @param string|null $value Value. */ private function set_or_delete( int $product_id, string $key, ?string $value ): void { if ( null === $value ) { delete_post_meta( $product_id, $key ); return; } update_post_meta( $product_id, $key, $value ); } }