在Woocommerce订单管理页面中按订单商品SKU或ID搜索

时间:2015-01-21 09:43:26

标签: php search woocommerce orders skus

我想要做的是能够在Woocommerce订单管理页面中按订单商品SKU或ID进行搜索。到目前为止我已经找到/完成了什么,但没有成功的是在functions.php文件中的以下内容。

add_filter( 'woocommerce_shop_order_search_fields', 'woocommerce_shop_order_search_sku' );

function woocommerce_shop_order_search_sku( $search_fields ) {

$args = array(
    'post_type' => 'shop_order'
    );

$orders = new WP_Query($args);

if($orders->have_posts()) {
        while($orders->have_posts()) {
        $post = $orders->the_post();
        $order_id = get_the_ID();
        $order = new WC_Order($order_id);
        $items = $order->get_items();
        foreach($items as $item) {
            $search_order_item_sku = wp_get_post_terms( $item['product_id'], 'search_sku' );
            foreach($search_order_item_sku as $search_sku) {
                add_post_meta($order_id, "_search_sku", $search_sku->sku);
            }
        }
    }
};

$search_fields[] = '_search_sku';

return $search_fields;

}

我认为问题是$ search_sku在" add_post_meta"行的价值。我也尝试过get_sku(),$ item [' sku']而没有运气。

有什么建议吗?

5 个答案:

答案 0 :(得分:2)

您有关于将额外元数据保存到订单的正确想法。正如jbby和helgatheviking建议的那样,在woocommerce订单api中默认没有product_id或sku的内置postmeta。但是,您访问和保存元数据的方法并不完全正确。 wp_get_post_terms将访问自定义分类信息,而不是元数据(使用get_post_meta)。您可以使用此过滤器执行您尝试执行的操作:

add_filter( 'woocommerce_shop_order_search_fields', function ($search_fields ) {
    $posts = get_posts(array('post_type' => 'shop_order'));

    foreach ($posts as $post) {
        $order_id = $post->ID;
        $order = new WC_Order($order_id);
        $items = $order->get_items();

        foreach($items as $item) {
            $product_id = $item['product_id'];
            $search_sku = get_post_meta($product_id, "_sku", true);
            add_post_meta($order_id, "_product_sku", $search_sku);
            add_post_meta($order_id, "_product_id", $product_id);
        }
    }

    return array_merge($search_fields, array('_product_sku', '_product_id'));
});

严格地说,您应该将对add_post_meta的调用移动到最初保存到数据库时运行的挂钩 - 这样可以防止在您搜索订单时出现不必要的工作。

答案 1 :(得分:1)

@blacksquare,@ jibby,@ helgatheviking你是男人们!由于您的帮助,这是有效的代码。

    //Search by product SKU in Admin Woocommerce Orders
add_filter( 'woocommerce_shop_order_search_fields', function ($search_fields ) {
    $posts = get_posts(array('post_type' => 'shop_order'));

    foreach ($posts as $post) {
        $order_id = $post->ID;
        $order = new WC_Order($order_id);
        $items = $order->get_items();

        foreach($items as $item) {
            $product_id = $item['product_id'];
            $search_sku = get_post_meta($product_id, "_sku", true);
            add_post_meta($order_id, "_product_sku", $search_sku);
        }
    }

    return array_merge($search_fields, array('_product_sku'));
});

答案 2 :(得分:1)

虽然@Nikos和@blacksquare的答案有效,但每次搜索都会在每个订单中添加新的帖子元数据。如果您有100个订单并进行10次搜索,则_product_sku表中至少会有100 * 10 = 1000个wp_postmeta条目。如果某些订单包含多个产品,则会有更多产品。

正如@blacksquare建议的那样,保存订单时应调用add_post_meta。也就是说,如果网站很小并且后端搜索性能不是太大问题,则以下代码可以在不创建冗余_product_sku条目的情况下工作。

add_filter( 'woocommerce_shop_order_search_fields', 'my_shop_order_search_fields') );

public function my_shop_order_search_fields( $search_fields ) {
    $orders = get_posts( array(
        'post_type' => 'shop_order',
        'post_status' => wc_get_order_statuses(), //get all available order statuses in an array
        'posts_per_page' => 999999, // query all orders
        'meta_query' => array(
            array(
                'key' => '_product_sku',
                'compare' => 'NOT EXISTS'
            )
        ) // only query orders without '_product_sku' postmeta
    ) );

    foreach ($orders as $order) {
        $order_id = $order->ID;
        $wc_order = new WC_Order($order_id);
        $items = $wc_order->get_items();
        foreach($items as $item) {
            $product_id = $item['product_id'];
            $search_sku = get_post_meta($product_id, '_sku', true);
            add_post_meta( $order_id, '_product_sku', $search_sku );
        }
    }

    return array_merge($search_fields, array('_product_sku')); // make '_product_sku' one of the meta keys we are going to search for.
}

虽然更好的解决方案可能是在创建订单时调用add_post_meta,但是需要额外的努力来为现有订单创建_product_sku,并且您必须为订单创建_product_sku而代码未激活。为简单起见,我只使用上面建议的解决方案。

P.S。 @Nikos的解决方案确实有一个(有争议的)优势 - 如果您在订单完成后更改产品的SKU,Nikos的解决方案将使用新的SKU找到这些订单,而上述解决方案则不会。也就是说,产品的SKU无论如何都不应该改变,搜索新的SKU是否应该显示旧订单是有争议的。

答案 3 :(得分:0)

您可能还想查看https://uk.wordpress.org/plugins/woo-search-order-by-sku/,它不会过载后meta,但会改变where子句。

答案 4 :(得分:0)

正如 Ming Yeung 的回答所述,任何使用 add_post_meta() 函数的解决方案都会增加您的数据库大小,这对于大型商店来说可能并不理想。这种方法还可能使管理员中 Woocommerce 订单的搜索速度相当慢。

另一种解决方案是利用 Woocommerce 使用的现有“索引”帖子元记录之一,并将您的数据附加到这些记录(但只附加一次)。

下面的代码正是这样做的。它不添加 SKU(如问题所问),而是允许 Woocommerce 订单搜索包含国家/地区名称(与国家/地区代码相反)。但是,如果需要,此代码可以很容易地进行调整以包含 SKU:

// when doing a search within Woocommerce orders screen, include the Country name as part of the search criteria
// this code has been optimised to do as little DB work as possible (looks for any index values which haven't been updated yet, and updates them)
// this code also makes use of existing post meta "index" records, instead of creating additional new post meta rows (which would fill up database unnecessarily)
add_filter('woocommerce_shop_order_search_fields', function($search_fields) {
    global $wpdb;
    $records_to_update = $wpdb->get_results("SELECT * FROM $wpdb->postmeta WHERE (meta_key LIKE '%_address_index%') AND (meta_value NOT LIKE '%[HAS_COUNTRY]%')");
    foreach ($records_to_update as $record) {
        $order = new WC_Order($record->post_id);
        if ($record->meta_key == '_billing_address_index') {
            $country_name = WC()->countries->countries[ $order->get_billing_country() ];
        } else {
            $country_name = WC()->countries->countries[ $order->get_shipping_country() ];
        }
        update_post_meta($record->post_id, $record->meta_key, $record->meta_value . ' ' . $country_name . ' [HAS_COUNTRY]');
    }
    return $search_fields;
});