WooCommerce:修复结账页供应商选择后post_author未保存及产品关联问题
Solution for WooCommerce Vendor Selection on Checkout
Let's work through your issues and implement the required features step by step:
1. Fix Selected Vendor ID Not Saving
Your current code only stores the vendor ID as order metadata, but it doesn't update the product's post_author as your requirement specifies. We'll adjust the checkout logic to both save the vendor association to the order and update the product's author ID.
2. Implement Product-Based Vendor Filtering
Right now you're pulling all available vendors, so we'll modify the vendor list function to only show vendors authorized to sell the single product in the cart (tailored for WCFM marketplace setups).
3. Enforce Single Product in Cart
Add a check to prevent users from adding more than one product to their cart at a time.
Full Modified Code
// Enforce single product in cart add_filter( 'woocommerce_add_to_cart_validation', 'enforce_single_product_cart', 10, 3 ); function enforce_single_product_cart( $passed, $product_id, $quantity ) { if ( WC()->cart->get_cart_contents_count() >= 1 ) { wc_add_notice( __( 'You can only add one product to your cart at a time.', 'woocommerce' ), 'error' ); $passed = false; } return $passed; } // Add vendor select field to checkout add_action('woocommerce_before_order_notes', 'wps_add_select_checkout_field3'); function wps_add_select_checkout_field3( $checkout ) { // Get the single product from cart $cart_items = WC()->cart->get_cart(); if ( empty( $cart_items ) ) return; $cart_item = reset( $cart_items ); $product = $cart_item['data']; $product_id = $cart_item['product_id']; $current_vendor_id = get_post_field( 'post_author', $product_id ); // Get filtered vendor list for this product function wcfm_get_product_vendors( $product_id ) { global $WCFM; $is_marketplace = wcfm_is_marketplace(); $vendor_arr = array( '' => __('Choose Vendor ...', 'wc-frontend-manager' ) ); if( !$is_marketplace || wcfm_is_vendor() ) return $vendor_arr; // Fetch vendors allowed to sell this product (WCFM-compatible) $allowed_vendor_ids = apply_filters( 'wcfm_product_allowed_vendors', array(), $product_id ); $args = array( 'role__in' => array( 'dc_vendor', 'vendor', 'seller' ), 'orderby' => 'display_name', 'order' => 'ASC', 'include' => !empty($allowed_vendor_ids) ? $allowed_vendor_ids : array(), 'count_total' => false, 'fields' => array( 'ID', 'display_name' ) ); $all_users = get_users( $args ); if( !empty( $all_users ) ) { foreach( $all_users as $all_user ) { $vendor_arr[$all_user->ID] = $all_user->display_name; } } // Pre-select current product vendor if available if ( isset($vendor_arr[$current_vendor_id]) ) { $checkout->set_value( 'post_author', $current_vendor_id ); } return $vendor_arr; } $author_options = wcfm_get_product_vendors( $product_id ); // Only show field if there are multiple vendors to choose from if ( count($author_options) > 1 ) { echo '<h4>'.__('Selectionner un établissement').'</h4>'; woocommerce_form_field( 'post_author', array( 'type' => 'select', 'class' => array( 'wps-drop' ), 'label' => __( 'Delivery options' ), 'options' => $author_options ), $checkout->get_value( 'post_author' )); } } // Validate checkout vendor selection add_action('woocommerce_checkout_process', 'wps_select_checkout_field_process'); function wps_select_checkout_field_process() { if ( isset($_POST['post_author']) && empty($_POST['post_author']) ) { wc_add_notice( '<strong>Please select a vendor</strong>', 'error' ); } } // Update order meta AND product post_author add_action('woocommerce_checkout_update_order_meta', 'wps_select_checkout_field_update_order_meta', 10, 2); function wps_select_checkout_field_update_order_meta( $order_id, $posted_data ) { if ( isset($_POST['post_author']) && !empty($_POST['post_author']) ) { $vendor_id = esc_attr($_POST['post_author']); $vendor_name = get_the_author_meta('display_name', $vendor_id); // Save vendor details to order meta update_post_meta( $order_id, '_selected_vendor_id', $vendor_id ); update_post_meta( $order_id, '_selected_vendor_name', $vendor_name ); // Update the product's post_author (permanent change) $order = wc_get_order( $order_id ); foreach ( $order->get_items() as $item ) { $product_id = $item->get_product_id(); wp_update_post( array( 'ID' => $product_id, 'post_author' => $vendor_id ) ); } } } // Display selected vendor in admin order page add_action( 'woocommerce_admin_order_data_after_billing_address', 'wps_select_checkout_field_display_admin_order_meta', 10, 1 ); function wps_select_checkout_field_display_admin_order_meta($order){ $vendor_id = get_post_meta( $order->get_id(), '_selected_vendor_id', true ); $vendor_name = get_post_meta( $order->get_id(), '_selected_vendor_name', true ); if ( $vendor_id && $vendor_name ) { echo '<p><strong>'.__('Selected Vendor').':</strong> ' . esc_html($vendor_name) . ' (ID: ' . esc_html($vendor_id) . ')</p>'; } } // Add selected vendor to order emails add_filter('woocommerce_email_order_meta_fields', 'wps_add_vendor_to_order_emails'); function wps_add_vendor_to_order_emails( $fields ) { $fields['_selected_vendor_name'] = array( 'label' => __( 'Selected Vendor' ), 'value' => get_post_meta( get_the_ID(), '_selected_vendor_name', true ), ); return $fields; }
Key Changes Explained
- Single Product Enforcement: The
enforce_single_product_cartfunction blocks adding additional products to the cart with a clear error message. - Filtered Vendors: The
wcfm_get_product_vendorsfunction now only pulls vendors associated with the cart product, using WCFM's built-in filter for product-vendor associations. - Proper Saving Logic: We now save vendor details to the order metadata and update the product's
post_authorto the selected vendor ID. - Improved Validation: Fixed checkout validation to properly check for an empty vendor selection.
- Enhanced Admin/Email Display: Shows the vendor's name and ID in the order admin panel, and adds a clean, readable field to order confirmation emails.
Notes
- If your WCFM setup uses a different method to link products to vendors (e.g., category-based vendor assignments), adjust the
allowed_vendor_idslogic to match your workflow. - If you don't want to permanently change the product's owner, remove the
wp_update_postsection from the checkout update function.
内容的提问来源于stack exchange,提问作者benjfree
相关产品推荐
相关产品推荐

