如何添加过滤器来编辑数组的值

I am trying to change the styling format of the meta data that woocommerce collects when a product is purchased in my store.

I found the filter that I can hook into.. But I can not figure out how to get it to change the data.

So I hooked into $html = apply_filters( 'woocommerce_display_item_meta', $html, $item, $args );

I can strip the html from the output... But I cant seem to figure out how to edit the $args array with before, after, seperator, echo, autop, label_before, and label_after.

Any help is appriciated!

//Here is the Wooocommerce code I want to change - 
if ( ! function_exists( 'wc_display_item_meta' ) ) {
    /**
     * Display item meta data.
     *
     * @since  3.0.0
     * @param  WC_Order_Item $item Order Item.
     * @param  array         $args Arguments.
     * @return string|void
     */
    function wc_display_item_meta( $item, $args = array() ) {
        $strings = array();
        $html    = '';
        $args    = wp_parse_args(
            $args,
            array(
                'before'       => '<ul class="wc-item-meta"><li>',
                'after'        => '</li></ul>',
                'separator'    => '</li><li>',
                'echo'         => true,
                'autop'        => false,
                'label_before' => '<strong class="wc-item-meta-label">',
                'label_after'  => ':</strong> ',
            )
        );

        foreach ( $item->get_formatted_meta_data() as $meta_id => $meta ) {
            $value     = $args['autop'] ? wp_kses_post( $meta->display_value ) : wp_kses_post( make_clickable( trim( $meta->display_value ) ) );
            $strings[] = $args['label_before'] . wp_kses_post( $meta->display_key ) . $args['label_after'] . $value;
        }

        if ( $strings ) {
            $html = $args['before'] . implode( $args['separator'], $strings ) . $args['after'];
        }

        $html = apply_filters( 'woocommerce_display_item_meta', $html, $item, $args );

        if ( $args['echo'] ) {
            echo $html; // WPCS: XSS ok.
        } else {
            return $html;
        }
    }
}

I'd like to change the $args array to this:

'before'       => '<span for="booked_product" class="wcfm-title wcfm_title">',

That way the formating will match where the meta data is going.


Here is the code I am using in order to write the order meta details! On the front end, I use the woocommerce product add ons plugin to gather additional information... this code will put it anywhere. I have tested it in several places other than my desired location.

//Function to Write Order Details In Booking Page 
    function add_more_booking_details() {
        ///Get Access 
                    global $wp, $WCFM, $WCFMu, $thebooking, $wpdb;

                        if( !current_user_can( 'manage_bookings_settings' ) && !current_user_can( 'manage_bookings' ) ) {
                            wcfm_restriction_message_show( "Bookings" );
                            return;
                        }

                            if ( ! is_object( $thebooking ) ) {
                                if( isset( $wp->query_vars['wcfm-bookings-details'] ) && !empty( $wp->query_vars['wcfm-bookings-details'] ) ) {
                                    $thebooking = get_wc_booking( $wp->query_vars['wcfm-bookings-details'] );
                                }
                            }

                                    $booking_id = $wp->query_vars['wcfm-bookings-details'];
                                    if( $booking_id ) {
                                        $post = get_post($booking_id);
                                        $booking = new WC_Booking( $post->ID );
                                        $order             = $booking->get_order();
                                        $product_id        = $booking->get_product_id( 'edit' );
                                        $resource_id       = $booking->get_resource_id( 'edit' );
                                        $customer_id       = $booking->get_customer_id( 'edit' );
                                        $product           = $booking->get_product( $product_id );
                                        $resource          = new WC_Product_Booking_Resource( $resource_id );
                                        $customer          = $booking->get_customer();
                                        $statuses          = array_unique( array_merge( get_wc_booking_statuses( null, true ), get_wc_booking_statuses( 'user', true ), get_wc_booking_statuses( 'cancel', true ) ) );
                                        $statuses          = apply_filters( 'wcfm_allowed_booking_status', $statuses );
                                    } 
                                        if( wcfm_is_vendor() ) {
                                            $is_booking_for_vendor = $WCFM->wcfm_vendor_support->wcfm_is_component_for_vendor( $booking_id, 'booking' );
                                            if( !$is_booking_for_vendor ) {
                                                if( apply_filters( 'wcfm_is_show_booking_restrict_message', true, $booking_id ) ) {
                                                    wcfm_restriction_message_show( "Restricted Booking" );
                                                } 
                                            }
                                        }
                                        ?>
                                <?php
                                if( $allow_wp_admin_view = apply_filters( 'wcfm_allow_wp_admin_view', true ) ) {
                                    ?>
                                    <?php }
                                     if ( $order && is_a( $order, 'WC_Order' ) ) { ?>
                                <?php } 

                        ///Print Order Details                             
                            $order_detail = getOrderDetailById($order); 
                                  print_r($order_detail); 
                                }
                    //get order details  
                        if (!function_exists('getOrderDetailById')) {
                                  function getOrderDetailById($id) {
                                         $order = wc_get_order($id); 

                                              foreach ($order->get_items() as $item_id => $item) {
                                                   $product = $item;

                                          $order_data['line_items'][] =
                                              wc_display_item_meta($item);
                                        }
                                 }
                        }

        //Hook+Call Add Booking Details into Booking Details Block
              add_action('wcfm_booking_details_block', 'add_more_booking_details' );

Alright... So the new code provided below (when linked to wp_head just to see it) returns the meta data like this, without the formatting still. Stray Data happening

Something like this should do the trick

add_filter('woocommerce_display_item_meta', function ($html, $item, $args) {
    $strings = [];
    $html = '';

    foreach ($item->get_formatted_meta_data() as $meta_id => $meta) {
        $value = $args['autop'] ? wp_kses_post($meta->display_value) : wp_kses_post(make_clickable(trim($meta->display_value)));
        $strings[] = $args['label_before'] . wp_kses_post($meta->display_key) . $args['label_after'] . $value;
    }

    $args['before'] = '<span for="booked_product" class="wcfm-title wcfm">';
    $args['after'] = '</span>';

    if ($strings)
        $html = $args['before'] . implode($args['after'] . $args['before'], $strings) . $args['after'];

    return $html;
});

The above example recreates the $strings variable since this variable is not passed by the filter. We then change the before and after values in the $args array variable and recreate the $html variable with the new $args values.

This is not tested but I feel confident it will do what you asked. There might be a better solution on this but this is all I got for now.


Answer extension after additional information provided

So based on the code you just provided I would say you can change this line

$order_data['line_items'][] = wc_display_item_meta($item);

to this

$order_data['line_items'][] = wc_display_item_meta($item, [
                                  'echo'      => false,
                                  'before'    => '<span for="booked_product" class="wcfm-title wcfm">',
                                  'after'     => '</span>',
                                  'seperator' => '</span><span for="booked_product" class="wcfm-title wcfm">'
                              ]);

That should do the trick for you. The wc_display_item_meta function accepts the $args argument.

Also the code you provided has many errors, I'm not sure if you removed bits and pieces from the code but anyway here is a re-coded getOrderDetailById function.

function getOrderDetailById($id)
{
    if ($id instanceof WC_Order)
        $order = $id;
    else
        $order = wc_get_order($id);

    $order_data['line_items'] = [];

    foreach ($order->get_items() as $item_id => $item) {
        $order_data['line_items'][] = wc_display_item_meta($item, [
            'echo'      => false,
            'before'    => '<span for="booked_product" class="wcfm-title wcfm">',
            'after'     => '</span>',
            'seperator' => '</span><span for="booked_product" class="wcfm-title wcfm">'
        ]);
    }

    return $order_data['line_items'];
}

I added the instance check because from what I can see you are passing WC_Order instance and not the order id. I also added a return statement because I can see that you tried to put getOrderDetailById into an array but the function wasn't returning any data.

Hope it helps.