从 Woocommerce 电子邮件通知中过滤掉不需要的订单项元数据

Filter out unwanted order item meta data from Woocommerce email notifications

在订单电子邮件模板中(例如 email-order-items.php),WooCommerce 使用函数 wc_display_item_meta 在订单 table 中显示产品详细信息。函数代码存在于 wc-template-functions.php 文件中(行号 3011)。我复制下面的功能代码以供参考

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,
    ) );

    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[] = '<strong class="wc-item-meta-label">' . wp_kses_post( $meta->display_key ) . ':</strong> ' . $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;
    }
}

问题是:它没有任何参数来帮助我过滤掉我不想在订单电子邮件中显示的项目数据。我不想在 wc-template-functions.php 中更改此功能,因为它是一个核心文件。所以,我想知道是否有一段代码可以添加到 functions.php 中,它会以某种方式修改此 wc_display_item_meta 函数以过滤掉特定的项目元数据。

注意:我知道有人可能会建议为什么不从产品详细信息中删除该特定项目数据,但该数据对于内部订单处理至关重要。我只是不希望它显示给客户。

更新 #1: 我不想在订单电子邮件中显示哪些元数据?以下是订单电子邮件的屏幕截图。我突出显示了三个项目数据.."Qty Selector"、"Qty" 和"Total"。我希望这三个都不要显示在订单电子邮件中。

在没有任何保证的情况下尝试以下操作(因为我真的没有真正必要的密钥):

add_filter( 'woocommerce_order_item_get_formatted_meta_data', 'unset_specific_order_item_meta_data', 10, 2);
function unset_specific_order_item_meta_data($formatted_meta, $item){
    // Only on emails notifications
    if( is_admin() || is_wc_endpoint_url() )
        return $formatted_meta;

    foreach( $formatted_meta as $key => $meta ){
        if( in_array( $meta->key, array('Qty Selector', 'Qty', 'Total') ) )
            unset($formatted_meta[$key]);
    }
    return $formatted_meta;
}

代码进入您的活动子主题(活动主题)的 function.php 文件。 已使用您的元数据之外的其他元数据进行测试并且有效。我希望它也对你有用。

Now, the hook used with this code is the right filter hook. It's located in the WC_Order_Item method get_formatted_meta_data() and allows to filter the order item meta data.

已接受的答案以及我在互联网上找到的所有其他片段都存在错误,所以我在这里发布我自己的答案,希望世界各地的商店不会意外泄露信息。

问题是当您使用 Order actions meta box 重新发送电子邮件时,过滤器检查失败,因为 is_admin() === true.

订单操作是订单页面下方的元框:

因此,第一次创建订单时,它会按照您的要求过滤电子邮件,但如果管理员将电子邮件重新发送给客户,那么它就会被破坏并向用户显示所有元字段在重新发送的电子邮件中。

解决这个问题的代码是这样的:

$is_resend = isset($_POST['wc_order_action']) ?  wc_clean( wp_unslash( $_POST['wc_order_action'] ) ) === 'send_order_details' : false;

if ( !$is_resend && (is_admin() || is_wc_endpoint_url() ) ) {
  return $formatted_meta;
}

因此,如果您查看链接的代码段,您将看到元框将该字段添加到 $_POST。也必须这样清理,否则不匹配。

集成到已接受解决方案答案中的完整示例是:

add_filter( 'woocommerce_order_item_get_formatted_meta_data', 'unset_specific_order_item_meta_data', 10, 2);

function unset_specific_order_item_meta_data($formatted_meta, $item){
    // Only on emails notifications
    $is_resend = isset($_POST['wc_order_action']) ?  wc_clean( wp_unslash( $_POST['wc_order_action'] ) ) === 'send_order_details' : false;

    if ( !$is_resend && (is_admin() || is_wc_endpoint_url() ) ) {
      return $formatted_meta;
    }

    foreach( $formatted_meta as $key => $meta ){
        if( in_array( $meta->key, array('Qty Selector', 'Qty', 'Total') ) )
            unset($formatted_meta[$key]);
    }
    return $formatted_meta;
}

我听说,您想在管理后端 中显示订单项目元数据。这实际上是一个棘手的问题。我已经玩了几个小时但没有找到解决方案,保证订单 Itema 元数据不会出现在给客户的电子邮件中。

问题是,有几种方式可以触发这些电子邮件(例如,通过重新发送元框(@rtpHarry 提到)或通过在订单概览、单个订单视图或automatic/programmatically 订单状态改变)。这给出了很多情况,其中需要取消设置订单项目元数据 - 你需要找到 所有 个案例,除了管理后端。

因此,我的建议是首先使用上述 woocommerce_order_item_get_formatted_meta_data 过滤器完全删除订单项元数据,然后使用仅在管理后端触发的 woocommerce_before_order_itemmeta 之类的操作再次添加它们.因为未设置订单项元数据,所以您不能使用 get_formatted_meta_data 方法获取数据。相反,您可以使用函数 wc_get_order_item_meta.

完整代码(已测试并有效):

//Hide 'Qty Selector', 'Qty' and 'Total' completely
add_filter( 'woocommerce_order_item_get_formatted_meta_data', 'unset_specific_order_item_meta_data');
function unset_specific_order_item_meta_data($formatted_meta){
    foreach( $formatted_meta as $key => $meta ){
        if( in_array( $meta->key, array('Qty Selector', 'Qty', 'Total') ) )
            unset($formatted_meta[$key]);
    }
    
    return $formatted_meta;
}

//Add 'Qty Selector', 'Qty' and 'Total' in the admin backend only
add_action('woocommerce_before_order_itemmeta', 'add_specific_order_item_meta_data_in_backend', 10, 2);
function add_specific_order_item_meta_data_in_backend( $item_id, $item ) {
    //Only applies for line items
    if( $item->get_type() !== 'line_item' ) return;
    
    $qty_sel_lines = wc_get_order_item_meta($item_id, 'Qty Selector', false);
    $qty_lines = wc_get_order_item_meta($item_id, 'Qty', false);
    $total_lines = wc_get_order_item_meta($item_id, 'Total', false);
    
    foreach ($qty_sel_lines as $qty_sel_line){
        echo $qty_sel_line . '<br>';
    }
    
    foreach ($qty_lines as $qty_line){
        echo $qty_line . '<br>';
    }
    
    foreach ($total_lines as $total_line){
        echo $total_line. '<br>';
    }
}

注: 如果您需要将订单项目元数据添加到管理电子邮件中,则需要单独进行。我还没有检查关于那个的选项。

我有点同意@pstidsen 的说法。所以我在考虑如何在不 re-add 所有元数据的情况下解决这个问题,因为不按照之前添加的方式处理它让我有点不安。我有额外的过滤器来添加 css 类 等等到元数据。所以需要照顾。

这是我的方法,您可以将其用于电子邮件、自定义电子邮件、pdf 发票或类似场景。我还使用回退来过滤我们的前端或我们没有考虑的任何情况。 请记住 if else 的顺序。我最后检查了管理员过滤器,以确保之前触发了任何其他过滤器。例如,电子邮件的情况是:它是从管理界面发送的,因此管理过滤器为真,但也是电子邮件过滤器。

还提供了针对管理员电子邮件的不同过滤器的功能。

/**
* This function filters all unwanted item metadata, if the specific filter are hooked in
* we also use a fallback filter, if none of the hooks are fired
*
* @params array() $metadata
*
*/
add_filter( 'woocommerce_order_item_get_formatted_meta_data', 'custom_filter_item_meta_data', 50, 1);
function custom_filter_item_meta_data( $metadata ){
    if ( empty( $metadata ) ) return $metadata;
    $filter_array = array();
    if ( apply_filters( 'custom_filter_item_meta_email', false ) ){
        // email filter goes here
        $filter_array = array( 'whatever','you', 'wanna', 'filter, 'for', 'email' );
    }elseif ( apply_filters( 'custom_filter_item_meta_admin_email', false ) ){
        // admin email filter goes here
        // pass
    elseif ( apply_filters( 'custom_filter_item_meta_invoice', false ) ){
        // invoice filter goes here
        $filter_array = array( 'whatever','you', 'wanna', 'filter, 'for', 'invoices' );
    }elseif ( apply_filters( 'custom_filter_item_meta_admin', false ) ){
        // general admin filter goes here
        $filter_array = array( 'whatever','you', 'wanna', 'filter, 'for', 'admin_backend' );
    }else{
        // fallback filter
        $filter_array = array( 'whatever','you', 'wanna', 'filter, 'for', 'fallback' );
    }
    foreach ( $metadata as $key => $meta ){
        if ( in_array( $meta->key, $filter_array ) ){
            unset ( $metadata[ $key ] );
        }
    }
    return $metadata;
}

/**
* Is used to enable our item meta filter for our admin backend
* Hooked:
* @admin_init
*/
add_action( 'admin_init', 'custom_init_item_meta_filter_admin', 50, 1 );
function custom_init_item_meta_filter_admin(){
    add_filter( 'custom_filter_item_meta_admin', function(){ return true; });
}

/**
* Is used to enable our item meta filter for emails
* Hooked:
* @woocommerce_email_order_details
*/
add_action( 'woocommerce_email_order_details', 'custom_init_item_meta_filter_email' ), 10, 2);
function custom_init_item_meta_filter_email( $order, $sent_to_admin ){
    if ( $sent_to_admin ){
        add_filter('custom_filter_item_meta_admin_email', function(){ return true; } );
    }else{
        add_filter('custom_filter_item_meta_email', function(){ return true; } );
    }
}

/**
* Is used to enable our item meta filter for invoices
* Hooked:
* @wpo_wcpdf_before_order_details
*/
add_filter( 'wpo_wcpdf_before_order_details', 'custom_init_item_meta_filter_invoice', 10, 1);
function custom_init_item_meta_filter_invoice(){
    add_filter( 'custom_filter_item_meta_invoice', function(){ return true; });
}

我没有以那种“扁平化”格式对其进行测试。我在我的 oop 编码插件的不同 类 中使用了它,并在此处将其编辑为 post。

Structure of the html code of the metadata tags

如果我想删除meta_data 2和meta_data 3:

add_filter( 'woocommerce_display_item_meta', 'filter_woocommerce_display_item_meta', 10, 3 ); 

function filter_woocommerce_display_item_meta( $html, $item, $args ) { 
        
    $arrayPortionsTags = explode("<li", $html);
    unset($arrayPortionsTags[2],$arrayPortionsTags[3]);
    $firstLi = array( '<li' );
    $lastUl = array( '</ul>' ); 
    array_splice( $arrayPortionsTags, 1, 0, $firstLi );
    array_splice( $arrayPortionsTags, 3, 0, $lastUl );
    $html= implode('',$arrayPortionsTags);
    return $html; 
};