Search code examples
phpwordpresswoocommercehook-woocommerce

WooCommerce order only shows one item meta but not the other one


For each order item, I want to display two meta fields. One is showing, but the other is not.

enter image description here

The one that is showing is a field that displays in the product and people select an option, and that one gets added fine. The one that is not showing is a required field that is calculated at the time of the order creation. I'm adding the meta like this:


function woo_save_course_to_order_items($item, $cart_item_key, $values, $order)
    {
        if (empty($values['course_to_enroll'])) {
            return;
        }
        // This one works
        $item->add_meta_data(__('Course', 'my-plugin'), intval($values['course_to_enroll'])); 
        
        $students_array = array();

        // Here goes some programming to grab all the student's ids and put them in $students_array. 
       //This part works.

        $item->add_meta_data(__('Students', 'my-plugin'), $students_array); 
        // The value is saved, but it is not shown in the order
    }
add_action('woocommerce_checkout_create_order_line_item', 'woo_save_course_to_order_items', 10, 4);

I am forcing it to display in the order like this:

function customizing_order_item_display($value, $meta, $item)
    {
        error_log(print_r($meta->key, true));// Only outputs 'Course', never 'Students'
        if ($item->get_type() === 'line_item' && $meta->key === 'Course') {

            $value = get_the_title(intval($value));

//Without the following, 'Students' would never appear in the order details (front and backend).
            $students = $item->get_meta('Students', true); //It is being saved fine
            if (is_array($students)) {
                $links = array_map(function ($s) {
                    return '<a href="' . get_the_permalink(intval($s)) . '">' . get_the_title(intval($s)) . '</a>';
                }, $students);
                $value .= "<br><strong>Students</strong>: " . implode(", ", $links);
            }
        }

        return $value;
    }
add_filter('woocommerce_order_item_display_meta_value', 'customizing_order_item_display', 10, 3);


Why do I have to force it to display my second meta value? Shouldn't it just show it? Why only show the first field, but not the second. It is being saved. This is a log of the item meta:

[meta_data:protected] => Array
        (
            [0] => WC_Meta_Data Object
                (
                    [current_data:protected] => Array
                        (
                            [id] => 121
                            [key] => Course
                            [value] => 60
                        )

                    [data:protected] => Array
                        (
                            [id] => 121
                            [key] => Course
                            [value] => 60
                        )

                )

            [1] => WC_Meta_Data Object
                (
                    [current_data:protected] => Array
                        (
                            [id] => 122
                            [key] => Students
                            [value] => Array
                                (
                                    [0] => 102
                                )

                        )

                    [data:protected] => Array
                        (
                            [id] => 122
                            [key] => Students
                            [value] => Array
                                (
                                    [0] => 102
                                )

                        )

                )

        )

Solution

  • Store the array as JSON data, then it will show the data without a code snippet.

    $students_array = array(12,14);
    
    // Here goes some programming to grab all the student's ids and put them in $students_array. 
    
    $item->add_meta_data(__('Students', 'my-plugin'), json_encode( $students_array )); 
    

    Below are the metadata validations that skip displaying.

    if ( '' === $meta->value || is_serialized( $meta->value ) || ( ! empty( $hideprefix ) && substr( $meta->key, 0, 1 ) === $hideprefix ) ) {
        continue;
    }
    

    Either empty or serialized or hidden meta ( meta start with an underscore ) will be skipped.