Created
November 13, 2025 07:16
-
-
Save kartikparmar/0c56fb04f80e6a2582a771df7755f814 to your computer and use it in GitHub Desktop.
Custom Field On Product page and edit button on the Cart/Checkout page : Compatible with Cart/Checkout Blocks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * WooCommerce Custom Item Meta Data with Edit Functionality | |
| * Compatible with both classic and block-based cart/checkout | |
| */ | |
| // 1. Add custom field on product page | |
| add_action('woocommerce_before_add_to_cart_button', 'add_custom_name_field'); | |
| function add_custom_name_field() { | |
| ?> | |
| <div class="custom-name-field" style="margin-bottom: 20px;"> | |
| <label for="custom_name"><?php _e('Enter Your Name:', 'woocommerce'); ?></label> | |
| <input type="text" id="custom_name" name="custom_name" value="" placeholder="Enter name" style="width: 100%; padding: 8px; margin-top: 5px;"> | |
| </div> | |
| <?php | |
| } | |
| // 2. Add custom field data to cart item | |
| add_filter('woocommerce_add_cart_item_data', 'add_custom_name_to_cart_item', 10, 3); | |
| function add_custom_name_to_cart_item($cart_item_data, $product_id, $variation_id) { | |
| if (isset($_POST['custom_name']) && !empty($_POST['custom_name'])) { | |
| $cart_item_data['custom_name'] = sanitize_text_field($_POST['custom_name']); | |
| } | |
| return $cart_item_data; | |
| } | |
| // 3. Display custom field in cart (Classic Cart) | |
| add_filter('woocommerce_get_item_data', 'display_custom_name_in_cart', 10, 2); | |
| function display_custom_name_in_cart($item_data, $cart_item) { | |
| if (isset($cart_item['custom_name'])) { | |
| $item_data[] = array( | |
| 'key' => __('Custom Name', 'woocommerce'), | |
| 'value' => wc_clean($cart_item['custom_name']), | |
| 'display' => '' | |
| ); | |
| } | |
| return $item_data; | |
| } | |
| // 4. Display custom field in cart blocks (Block-based Cart) | |
| add_filter('woocommerce_store_api_product_quantity_editable', '__return_true'); | |
| add_action('woocommerce_store_api_cart_update_item_before', 'handle_cart_item_meta_update', 10, 2); | |
| function handle_cart_item_meta_update($cart_item, $request) { | |
| if (isset($request['custom_name'])) { | |
| $cart_item['custom_name'] = sanitize_text_field($request['custom_name']); | |
| } | |
| } | |
| // 5. Save custom field to order items | |
| add_action('woocommerce_checkout_create_order_line_item', 'save_custom_name_to_order', 10, 4); | |
| function save_custom_name_to_order($item, $cart_item_key, $values, $order) { | |
| if (isset($values['custom_name'])) { | |
| $item->add_meta_data(__('Custom Name', 'woocommerce'), $values['custom_name']); | |
| } | |
| } | |
| // 6. Add edit button in cart (Classic Cart) | |
| add_action('woocommerce_after_cart_item_name', 'add_edit_button_in_cart', 10, 2); | |
| function add_edit_button_in_cart($cart_item, $cart_item_key) { | |
| if (isset($cart_item['custom_name'])) { | |
| ?> | |
| <button type="button" class="edit-custom-name-btn" | |
| data-cart-key="<?php echo esc_attr($cart_item_key); ?>" | |
| data-current-name="<?php echo esc_attr($cart_item['custom_name']); ?>" | |
| style="font-size: 12px; padding: 4px 8px; margin-left: 10px; cursor: pointer;"> | |
| <?php _e('Edit Name', 'woocommerce'); ?> | |
| </button> | |
| <?php | |
| } | |
| } | |
| // 7. Add edit button in checkout (Classic Checkout) | |
| add_action('woocommerce_checkout_after_order_review', 'add_edit_button_in_checkout'); | |
| function add_edit_button_in_checkout() { | |
| $cart = WC()->cart->get_cart(); | |
| foreach ($cart as $cart_item_key => $cart_item) { | |
| if (isset($cart_item['custom_name'])) { | |
| // Buttons are already added in review order table | |
| } | |
| } | |
| } | |
| // 8. Add popup modal HTML | |
| add_action('wp_footer', 'add_custom_name_edit_modal'); | |
| function add_custom_name_edit_modal() { | |
| if (is_cart() || is_checkout()) { | |
| ?> | |
| <div id="edit-name-modal" style="display:none; position:fixed; z-index:9999; left:0; top:0; width:100%; height:100%; background-color:rgba(0,0,0,0.5);"> | |
| <div style="background-color:#fff; margin:10% auto; padding:30px; width:90%; max-width:400px; border-radius:8px; position:relative;"> | |
| <span class="close-modal" style="position:absolute; right:15px; top:10px; font-size:28px; font-weight:bold; cursor:pointer;">×</span> | |
| <h3><?php _e('Edit Custom Name', 'woocommerce'); ?></h3> | |
| <div id="edit-name-form"> | |
| <input type="hidden" id="edit-cart-key" name="cart_key" value=""> | |
| <label for="edit-custom-name"><?php _e('Name:', 'woocommerce'); ?></label> | |
| <input type="text" id="edit-custom-name" name="custom_name" style="width:100%; padding:10px; margin:10px 0; border:1px solid #ddd; border-radius:4px;"> | |
| <div id="update-message" style="display:none; padding:10px; margin:10px 0; border-radius:4px; text-align:center;"></div> | |
| <button type="button" id="update-name-btn" style="width:100%; padding:12px; background-color:#0071a1; color:#fff; border:none; border-radius:4px; cursor:pointer; font-size:16px;"> | |
| <?php _e('Update Name', 'woocommerce'); ?> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <?php | |
| } | |
| } | |
| // 9. Enqueue JavaScript for modal and AJAX | |
| add_action('wp_enqueue_scripts', 'enqueue_custom_name_scripts'); | |
| function enqueue_custom_name_scripts() { | |
| if (is_cart() || is_checkout()) { | |
| // wp_enqueue_script('custom-name-edit', get_template_directory_uri() . '/js/custom-name-edit.js', array('jquery'), '1.0', true); | |
| // Inline script if you don't want separate file | |
| wp_add_inline_script('jquery', " | |
| jQuery(document).ready(function($) { | |
| // Open modal | |
| $(document).on('click', '.edit-custom-name-btn', function() { | |
| var cartKey = $(this).data('cart-key'); | |
| var currentName = $(this).data('current-name'); | |
| $('#edit-cart-key').val(cartKey); | |
| $('#edit-custom-name').val(currentName); | |
| $('#update-message').hide(); | |
| $('#edit-name-modal').fadeIn(); | |
| $('#edit-name-form').removeData('is-block').removeData('cart-index'); | |
| }); | |
| // Close modal | |
| $('.close-modal, #edit-name-modal').on('click', function(e) { | |
| if (e.target === this) { | |
| $('#edit-name-modal').fadeOut(); | |
| } | |
| }); | |
| // Handle button click | |
| $(document).on('click', '#update-name-btn', function(e) { | |
| e.preventDefault(); | |
| var button = $(this); | |
| var cartKey = $('#edit-cart-key').val(); | |
| var newName = $('#edit-custom-name').val(); | |
| var isBlock = $('#edit-name-form').data('is-block') || false; | |
| var cartIndex = $('#edit-name-form').data('cart-index') || null; | |
| // Disable button and show loading | |
| button.prop('disabled', true).text('Updating...'); | |
| $('#update-message').hide(); | |
| $.ajax({ | |
| url: wc_cart_params.ajax_url, | |
| type: 'POST', | |
| data: { | |
| action: 'update_cart_item_name', | |
| cart_key: cartKey, | |
| custom_name: newName, | |
| is_block: isBlock, | |
| cart_index: cartIndex, | |
| security: '" . wp_create_nonce('update-cart-item-name') . "' | |
| }, | |
| success: function(response) { | |
| if (response.success) { | |
| // Show success message | |
| $('#update-message') | |
| .removeClass('error') | |
| .addClass('success') | |
| .css({'background-color': '#d4edda', 'color': '#155724', 'border': '1px solid #c3e6cb'}) | |
| .text('Name updated successfully!') | |
| .fadeIn(); | |
| // For block-based cart/checkout - trigger proper cart refresh | |
| if (isBlock && typeof wp !== 'undefined' && wp.data) { | |
| // Invalidate cart cache to force re-fetch from API | |
| wp.data.dispatch('wc/store/cart').invalidateResolutionForStore(); | |
| // Also trigger receiveCart to refresh immediately | |
| setTimeout(function() { | |
| if (wp.data.select('wc/store/cart').getCartData) { | |
| // This will trigger the /wp-json/wc/store/v1/batch call | |
| wp.data.dispatch('wc/store/cart').receiveCart( | |
| wp.data.select('wc/store/cart').getCartData() | |
| ); | |
| } | |
| }, 100); | |
| } | |
| // Close modal after short delay | |
| setTimeout(function() { | |
| $('#edit-name-modal').fadeOut(); | |
| button.prop('disabled', false).text('Update Name'); | |
| // For classic cart - update the page manually or trigger mini-cart refresh | |
| if (!isBlock) { | |
| // Update displayed value | |
| $('[data-cart-key=\"' + cartKey + '\"]').data('current-name', newName); | |
| $('[data-cart-key=\"' + cartKey + '\"]').closest('tr, .cart_item').find('.wc-item-meta li').each(function() { | |
| if ($(this).text().includes('Custom Name')) { | |
| $(this).find('p').text(newName); | |
| } | |
| }); | |
| // Trigger WooCommerce cart updated event | |
| $(document.body).trigger('wc_update_cart'); | |
| $(document.body).trigger('updated_wc_div'); | |
| } | |
| }, 800); | |
| } else { | |
| // Show error message | |
| $('#update-message') | |
| .removeClass('success') | |
| .addClass('error') | |
| .css({'background-color': '#f8d7da', 'color': '#721c24', 'border': '1px solid #f5c6cb'}) | |
| .text(response.data.message || 'Error updating name') | |
| .fadeIn(); | |
| button.prop('disabled', false).text('Update Name'); | |
| } | |
| }, | |
| error: function() { | |
| $('#update-message') | |
| .removeClass('success') | |
| .addClass('error') | |
| .css({'background-color': '#f8d7da', 'color': '#721c24', 'border': '1px solid #f5c6cb'}) | |
| .text('Error updating name. Please try again.') | |
| .fadeIn(); | |
| button.prop('disabled', false).text('Update Name'); | |
| } | |
| }); | |
| }); | |
| }); | |
| "); | |
| } | |
| } | |
| // 10. AJAX handler to update cart item meta | |
| add_action('wp_ajax_update_cart_item_name', 'update_cart_item_name_ajax'); | |
| add_action('wp_ajax_nopriv_update_cart_item_name', 'update_cart_item_name_ajax'); | |
| function update_cart_item_name_ajax() { | |
| check_ajax_referer('update-cart-item-name', 'security'); | |
| $cart_item_key = sanitize_text_field($_POST['cart_key']); | |
| $new_name = sanitize_text_field($_POST['custom_name']); | |
| $cart = WC()->cart->get_cart(); | |
| if (isset($cart[$cart_item_key])) { | |
| $cart[$cart_item_key]['custom_name'] = $new_name; | |
| WC()->cart->set_cart_contents($cart); | |
| WC()->cart->calculate_totals(); | |
| wp_send_json_success(array('message' => __('Name updated successfully', 'woocommerce'))); | |
| } else { | |
| wp_send_json_error(array('message' => __('Cart item not found', 'woocommerce'))); | |
| } | |
| } | |
| // 11. For Block-based Cart/Checkout - Extend cart item schema | |
| add_filter('woocommerce_store_api_product_quantity_limit', '__return_true'); | |
| // Expose custom meta to Store API | |
| add_filter('woocommerce_store_api_cart_item_data', 'expose_custom_name_to_api', 10, 2); | |
| function expose_custom_name_to_api($item_data, $cart_item) { | |
| if (isset($cart_item['custom_name'])) { | |
| $item_data['custom_name'] = $cart_item['custom_name']; | |
| } | |
| return $item_data; | |
| } | |
| // 12. Add edit button for Block-based Cart/Checkout | |
| add_action('wp_footer', 'enqueue_block_cart_custom_scripts'); | |
| function enqueue_block_cart_custom_scripts() { | |
| if (has_block('woocommerce/cart') || has_block('woocommerce/checkout')) { | |
| ?> | |
| <script type="text/javascript"> | |
| jQuery(document).ready(function($) { | |
| // Function to add edit buttons to block cart items | |
| function addEditButtonsToBlocks() { | |
| // Get all cart items first | |
| var allCartItems = $('.wc-block-cart-item, tr.wc-block-cart-items__row'); | |
| // Target the exact structure from your HTML | |
| $('.wc-block-components-product-details__custom-name').each(function(index) { | |
| var detailRow = $(this); | |
| var nameLabel = detailRow.find('.wc-block-components-product-details__name').text().trim(); | |
| if (nameLabel.toLowerCase().includes('custom name')) { | |
| var valueElement = detailRow.find('.wc-block-components-product-details__value'); | |
| var metaValue = valueElement.text().trim(); | |
| // Check if button already exists | |
| if (detailRow.find('.edit-custom-name-btn-block').length === 0) { | |
| // Find the cart item - try multiple parent selectors | |
| var cartItem = detailRow.closest('.wc-block-cart-item'); | |
| if (cartItem.length === 0) { | |
| cartItem = detailRow.closest('tr.wc-block-cart-items__row'); | |
| } | |
| if (cartItem.length === 0) { | |
| cartItem = detailRow.closest('td.wc-block-cart-item__product').parent(); | |
| } | |
| var cartItemIndex = -1; | |
| if (cartItem.length > 0) { | |
| cartItemIndex = allCartItems.index(cartItem); | |
| } | |
| // Fallback: use the index of this detail row itself | |
| if (cartItemIndex === -1) { | |
| cartItemIndex = index; | |
| } | |
| // Add edit button | |
| var editButton = $('<button/>', { | |
| 'type': 'button', | |
| 'class': 'edit-custom-name-btn edit-custom-name-btn-block', | |
| 'data-current-name': metaValue, | |
| 'data-cart-index': cartItemIndex, | |
| 'html': '✏️ Edit Name', | |
| 'css': { | |
| 'font-size': '12px', | |
| 'padding': '5px 10px', | |
| 'margin-left': '10px', | |
| 'cursor': 'pointer', | |
| 'background': '#0071a1', | |
| 'color': '#fff', | |
| 'border': 'none', | |
| 'border-radius': '4px', | |
| 'display': 'inline-block', | |
| 'vertical-align': 'middle', | |
| 'font-weight': '500' | |
| } | |
| }); | |
| // Append button to the detail row (not inside value span) | |
| detailRow.append(' ').append(editButton); | |
| } | |
| } | |
| }); | |
| // Also check for dt/dd format (for other WC versions) | |
| $('.wc-block-components-product-metadata dt').each(function() { | |
| var label = $(this).text().trim(); | |
| if (label.toLowerCase().includes('custom name')) { | |
| var valueElement = $(this).next('dd'); | |
| var metaValue = valueElement.text().trim(); | |
| if (valueElement.find('.edit-custom-name-btn-block').length === 0) { | |
| var cartItem = $(this).closest('.wc-block-cart-item'); | |
| var cartItemIndex = $('.wc-block-cart-item').index(cartItem); | |
| var editButton = $('<button/>', { | |
| 'type': 'button', | |
| 'class': 'edit-custom-name-btn edit-custom-name-btn-block', | |
| 'data-current-name': metaValue, | |
| 'data-cart-index': cartItemIndex, | |
| 'html': '✏️ Edit Name', | |
| 'css': { | |
| 'font-size': '12px', | |
| 'padding': '5px 10px', | |
| 'margin-left': '10px', | |
| 'cursor': 'pointer', | |
| 'background': '#0071a1', | |
| 'color': '#fff', | |
| 'border': 'none', | |
| 'border-radius': '4px' | |
| } | |
| }); | |
| valueElement.append(' ').append(editButton); | |
| } | |
| } | |
| }); | |
| } | |
| // Try multiple times with different delays | |
| setTimeout(function() { addEditButtonsToBlocks(); }, 500); | |
| setTimeout(function() { addEditButtonsToBlocks(); }, 1000); | |
| setTimeout(function() { addEditButtonsToBlocks(); }, 2000); | |
| // Re-add buttons when cart updates (block cart uses React) | |
| if (window.MutationObserver) { | |
| var observer = new MutationObserver(function(mutations) { | |
| setTimeout(addEditButtonsToBlocks, 100); | |
| }); | |
| var cartContainer = document.querySelector('.wc-block-cart'); | |
| if (cartContainer) { | |
| observer.observe(cartContainer, { | |
| childList: true, | |
| subtree: true | |
| }); | |
| } | |
| } | |
| // Handle edit button click for blocks | |
| $(document).on('click', '.edit-custom-name-btn-block', function(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| var currentName = $(this).data('current-name'); | |
| var cartIndex = $(this).data('cart-index'); | |
| // Store the cart index for block updates | |
| $('#edit-cart-key').val('block_' + cartIndex); | |
| $('#edit-custom-name').val(currentName); | |
| $('#update-message').hide(); | |
| $('#edit-name-modal').fadeIn(); | |
| // Store additional data for block update | |
| $('#edit-name-form').data('is-block', true); | |
| $('#edit-name-form').data('cart-index', cartIndex); | |
| }); | |
| }); | |
| </script> | |
| <?php | |
| } | |
| } | |
| // 13. Enhanced AJAX handler for block-based cart | |
| add_action('wp_ajax_update_cart_item_name', 'update_cart_item_name_ajax_enhanced', 5); | |
| add_action('wp_ajax_nopriv_update_cart_item_name', 'update_cart_item_name_ajax_enhanced', 5); | |
| function update_cart_item_name_ajax_enhanced() { | |
| check_ajax_referer('update-cart-item-name', 'security'); | |
| $cart_item_key = sanitize_text_field($_POST['cart_key']); | |
| $new_name = sanitize_text_field($_POST['custom_name']); | |
| $is_block = isset($_POST['is_block']) ? (bool)$_POST['is_block'] : false; | |
| $cart_index = isset($_POST['cart_index']) ? intval($_POST['cart_index']) : null; | |
| $cart = WC()->cart->get_cart(); | |
| // For block-based cart, find item by index | |
| if ($is_block && $cart_index !== null && $cart_index >= 0) { | |
| $cart_items_array = array_values($cart); | |
| $cart_keys_array = array_keys($cart); | |
| // Check if index exists | |
| if (isset($cart_items_array[$cart_index]) && isset($cart_keys_array[$cart_index])) { | |
| $actual_key = $cart_keys_array[$cart_index]; | |
| // Update the cart item | |
| $cart[$actual_key]['custom_name'] = $new_name; | |
| WC()->cart->set_cart_contents($cart); | |
| WC()->cart->calculate_totals(); | |
| wp_send_json_success(array( | |
| 'message' => __('Name updated successfully', 'woocommerce'), | |
| 'cart_key' => $actual_key, | |
| 'index' => $cart_index | |
| )); | |
| return; | |
| } else { | |
| wp_send_json_error(array( | |
| 'message' => __('Cart item not found at index ' . $cart_index, 'woocommerce'), | |
| 'debug' => array( | |
| 'cart_index' => $cart_index, | |
| 'total_items' => count($cart_items_array), | |
| 'cart_keys' => $cart_keys_array | |
| ) | |
| )); | |
| return; | |
| } | |
| } | |
| // For classic cart | |
| if (isset($cart[$cart_item_key])) { | |
| $cart[$cart_item_key]['custom_name'] = $new_name; | |
| WC()->cart->set_cart_contents($cart); | |
| WC()->cart->calculate_totals(); | |
| wp_send_json_success(array('message' => __('Name updated successfully', 'woocommerce'))); | |
| } else { | |
| wp_send_json_error(array( | |
| 'message' => __('Cart item not found', 'woocommerce'), | |
| 'debug' => array( | |
| 'cart_key' => $cart_item_key, | |
| 'available_keys' => array_keys($cart) | |
| ) | |
| )); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment