Display a product custom field for variable products in WooCommerce email order items

Viewed 614

I've added a Custom SKU in products to use for vendor SKU for order confirmation email. What I've created works only for simple products and not variable products.

Custom SKU, screenshot image

I added this to the functions.php

function jk_add_custom_sku() {
    $args = array(
        'label' => __( 'Custom SKU', 'woocommerce' ),
        'placeholder' => __( 'Enter custom SKU here', 'woocommerce' ),
        'id' => 'jk_sku',
        'desc_tip' => true,
        'description' => __( 'This SKU is for internal use only.', 'woocommerce' ),
    );
    woocommerce_wp_text_input( $args );
}
add_action( 'woocommerce_product_options_sku', 'jk_add_custom_sku' );

function jk_save_custom_sku( $post_id ) {
    // grab the custom SKU from $_POST
    $custom_sku = isset( $_POST[ 'jk_sku' ] ) ? sanitize_text_field( $_POST[ 'jk_sku' ] ) : '';
    
    // grab the product
    $product = wc_get_product( $post_id );
    
    // save the custom SKU using WooCommerce built-in functions
    $product->update_meta_data( 'jk_sku', $custom_sku );
    $product->save();
}
add_action( 'woocommerce_process_product_meta', 'jk_save_custom_sku' );

Next I modified the email template email-order-items.php adding to the SKU section to check if Custom SKU exists.

<?php

// Show title/image etc.
if ( $show_image ) {
    echo wp_kses_post( apply_filters( 'woocommerce_order_item_thumbnail', $image, $item ) );
}

// Product name.
echo wp_kses_post( apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, false ) );

// SKU.
if ( $show_sku && $sku ) {
    echo wp_kses_post( ' (#' . $sku . ')' );
    // load the custom SKU
    $custom_sku = get_post_meta( $product->get_id(), 'jk_sku', true );
    if ( is_string( $custom_sku ) ) { // only show the custom SKU if it's set
        echo "<br>" . wp_kses_post( "Custom SKU: $custom_sku" ); // change this line if needed
    }
}

// allow other plugins to add additional product information here.
do_action( 'woocommerce_order_item_meta_start', $item_id, $item, $order, $plain_text );

wc_display_item_meta(
    $item,
    array(
        'label_before' => '<strong class="wc-item-meta-label" style="float: ' . esc_attr( $text_align ) . '; margin-' . esc_attr( $margin_side ) . ': .25em; clear: both">',
    )
);

// allow other plugins to add additional product information here.
do_action( 'woocommerce_order_item_meta_end', $item_id, $item, $order, $plain_text );

?>
</td>

The Custom SKU only shows up on the email for Simple products. I need it to work with Variable products. There is only one Custom SKU for each product not for each variable product.

1 Answers

I have revisited a bit your code and changed the meta key to _sku2 just like WooCommerce meta keys starting with an underscore:

add_action( 'woocommerce_product_options_sku', 'add_product_sku2_custom_field' );
function add_product_sku2_custom_field() {
    $field_key = '_sku2';

    woocommerce_wp_text_input( array(
        'id'          => $field_key,
        'label'       => __( 'Custom SKU', 'woocommerce' ),
        'placeholder' => __( 'Enter custom SKU here', 'woocommerce' ),
        'desc_tip'    => true,
        'description' => __( 'This SKU is for internal use only.', 'woocommerce' ),
    ) );
}

add_action( 'woocommerce_admin_process_product_object', 'save_product_sku2_custom_field_value' );
function save_product_sku2_custom_field_value( $product ) {
    $field_key = '_sku2';

    if ( isset($_POST[$field_key]) ) {
        $product->update_meta_data( $field_key, sanitize_text_field($_POST[$field_key]) );
    }
}

For product variations, you need to get the parent variable product to get a "Custom sku" displayed (see at the code at the end)

Now to enable an additional custom SKU to product variations of a variable product too, use the following:

add_action( 'woocommerce_variation_options_pricing', 'add_product_variation_sku2_custom_field', 10, 3 );
function add_product_variation_sku2_custom_field( $loop, $variation_data, $variation ){
    $field_key = '_sku2';

    woocommerce_wp_text_input( array(
        'id'          => $field_key.'['.$loop.']',
        'label'       => __( 'Custom SKU', 'woocommerce' ),
        'placeholder' => __( 'Enter custom SKU here', 'woocommerce' ),
        'desc_tip'    => true,
        'description' => __( 'This SKU is for internal use only.', 'woocommerce' ),
        'value'       => get_post_meta( $variation->ID, $field_key, true )
    ) );
}

add_action( 'woocommerce_save_product_variation', 'save_product_variation_sku2_custom_field_value', 10, 2 );
function save_product_variation_sku2_custom_field_value( $variation_id, $i ){
    $field_key = '_sku2';

    if( isset($_POST[$field_key][$i]) ){
        update_post_meta( $variation_id, $field_key, sanitize_text_field($_POST[$field_key][$i]) );
    }
}

Code goes in functions.php file of the active child theme (or active theme). Tested and works.

And in your template custom code you will replace:

// SKU.
if ( $show_sku && $sku ) {
    echo wp_kses_post( ' (#' . $sku . ')' );
    // load the custom SKU
    $custom_sku = get_post_meta( $product->get_id(), 'jk_sku', true );
    if ( is_string( $custom_sku ) ) { // only show the custom SKU if it's set
        echo "<br>" . wp_kses_post( "Custom SKU: $custom_sku" ); // change this line if needed
    }
}

by the following (that will work for variable products or product variations):

// SKU (and SKU2)
if ( $show_sku && $sku ) {
    echo wp_kses_post( ' (#' . $sku . ')' );
    // load the custom SKU
    $sku2 = $product->get_meta('_sku2');
    
    // For product variations with empty SKU (get the parent variable product SKU)
    if ( empty($sku2) && $product->is_type('variation') ) { 
        // Get parent variable product Id
        $parent_product_id = $product->get_parent_id(); 
        $parent_product    = wc_get_product($parent_product_id);
        $sku2              = $parent_product->get_meta('_sku2');
    }
    
    // only show the custom SKU if it's set (and product variation too)
    if ( ! empty($sku2) ) {
        echo "<br>" . wp_kses_post( sprintf( __("Custom SKU: %s", "woocommerce"), $sku2 ) ); // change this line if needed
    }
}

For product variations, if there is not any "custom sku", it will try to get the parent variable product "custom sku".

It should work.

Related