在 WooCommerce 订单管理页面中按订单商品 SKU 或 ID 搜索
Search by order item SKU or ID in WooCommerce Orders Admin page
我想要做的是能够在 WooCommerce 订单管理页面中按订单商品 SKU 或 ID 进行搜索。
到目前为止,我有 found/done,但没有成功的是 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']
试过,但没有成功。
关于将额外的元数据保存到订单中,您的想法是正确的。正如 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
的调用移动到一个钩子中,该钩子在订单最初保存到数据库时运行——这将防止您在搜索订单时进行不必要的跑腿工作。
@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'));
});
虽然@Nikos 和@blacksquare 的答案有效,但新的 post 元数据会添加到每次搜索的每个订单中。如果您有 100 个订单并进行 10 次搜索,则 wp_postmeta
table 中至少会有 100*10 = 1000 _product_sku
个条目。如果一些订单包含多个产品,则更多。
正如@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 的解决方案确实有一个 (debatable) 优势——如果您在下订单后更改产品的 SKU,Nikos 的解决方案将使用新的 SKU 找到这些订单,而上面的解决方案则不会。也就是说,产品的 SKU 无论如何都不应更改,而且搜索新 SKU 是否应显示旧订单还不确定table。
您可能还想查看 https://uk.wordpress.org/plugins/woo-search-order-by-sku/,它不会重载 post 元数据,但会改变 where 子句。
如 Ming Yeung 在回答中所述,任何使用 add_post_meta() 函数的解决方案都会增加您的数据库大小,这可能不适合大型商店。这种方法也可能会使在管理员中搜索 Woocommerce 订单非常缓慢。
另一种解决方案是利用 Woocommerce 使用的现有“索引”post 元记录之一,并将您的数据附加到这些记录(但仅附加一次)。
下面的代码正是这样做的。它不添加 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;
});
我想要做的是能够在 WooCommerce 订单管理页面中按订单商品 SKU 或 ID 进行搜索。
到目前为止,我有 found/done,但没有成功的是 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']
试过,但没有成功。
关于将额外的元数据保存到订单中,您的想法是正确的。正如 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
的调用移动到一个钩子中,该钩子在订单最初保存到数据库时运行——这将防止您在搜索订单时进行不必要的跑腿工作。
@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'));
});
虽然@Nikos 和@blacksquare 的答案有效,但新的 post 元数据会添加到每次搜索的每个订单中。如果您有 100 个订单并进行 10 次搜索,则 wp_postmeta
table 中至少会有 100*10 = 1000 _product_sku
个条目。如果一些订单包含多个产品,则更多。
正如@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 的解决方案确实有一个 (debatable) 优势——如果您在下订单后更改产品的 SKU,Nikos 的解决方案将使用新的 SKU 找到这些订单,而上面的解决方案则不会。也就是说,产品的 SKU 无论如何都不应更改,而且搜索新 SKU 是否应显示旧订单还不确定table。
您可能还想查看 https://uk.wordpress.org/plugins/woo-search-order-by-sku/,它不会重载 post 元数据,但会改变 where 子句。
如 Ming Yeung 在回答中所述,任何使用 add_post_meta() 函数的解决方案都会增加您的数据库大小,这可能不适合大型商店。这种方法也可能会使在管理员中搜索 Woocommerce 订单非常缓慢。
另一种解决方案是利用 Woocommerce 使用的现有“索引”post 元记录之一,并将您的数据附加到这些记录(但仅附加一次)。
下面的代码正是这样做的。它不添加 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;
});