【问题标题】:Search by order item SKU or ID in WooCommerce Orders Admin page在 WooCommerce 订单管理页面中按订单商品 SKU 或 ID 搜索
【发布时间】:2015-03-19 18:40:00
【问题描述】:

我想要做的是能够在 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'],但没有成功。

【问题讨论】:

  • 我不明白。听起来您不确定 $search_sku->sku 或其他变体是否具有价值。你为什么不直接运行 print_r($search_sku);死();在您的 foreach 循环中查看它以确定您需要引用的对象属性或数组键?
  • 查看 /woocommerce/includes/admin/class-wc-admin-post-types.php 中的函数 shop_order_search_custom_fields()(第 ~1284 行)。据我所知,那里的 SELECT 语句只搜索 wp_posts 和 wp_postmeta 表。 SKU 是特定于产品的。因此,您需要以某种方式在(和搜索)产品数据中构建自己的 UNION 查询。
  • 澄清:...仅在 wp_posts 和 wp_postmeta 表中搜索帖子类型 shop_order
  • select 语句确实会查找项目,但它会查找wp_woocommerce_order_items 表中的项目。 SKU 未保存在此表中,因此您必须将 wp_woocommerce_order_itemmeta _product_id 字段与 wp_postmeta post_id 字段合并,然后搜索 _sku。您的WP_Query 是否打算将 SKU 添加到订单项目表中?您应该能够将 SKU 添加为订单项元数据。
  • 或者,如果您能找到正确的 SQL 查询,则可能值得向 WooCommerce 发送拉取请求,以便可能包含在内。

标签: php search woocommerce


【解决方案1】:

您有正确的想法将额外的元数据保存到订单中。正如 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 的调用移动到一个钩子中,该钩子在订单最初保存到数据库时运行——这将防止您在搜索订单时进行不必要的跑腿。

【讨论】:

  • 代码错误(小):您需要将代码中未定义的$sku 替换为$search_sku
【解决方案2】:

@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'));
});

【讨论】:

    【解决方案3】:

    虽然@Nikos 和@blacksquare 的答案有效,但每次搜索时都会将新的帖子元数据添加到每个订单中。如果您有 100 个订单并进行 10 次搜索,那么wp_postmeta 表中将至少有 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活性。为简单起见,我只使用上面建议的解决方案。

    附言@Nikos 的解决方案确实有一个(有争议的)优势 - 如果您在下订单后更改产品的 SKU,Nikos 的解决方案将使用新 SKU 查找这些订单,而上述解决方案不会。也就是说,无论如何都不应该更改产品的 SKU,搜索新 SKU 是否应该显示旧订单是值得商榷的。

    【讨论】:

      【解决方案4】:

      您可能还想查看https://uk.wordpress.org/plugins/woo-search-order-by-sku/,它不会重载发布元数据,但会更改 where 子句。

      【讨论】:

        【解决方案5】:

        正如 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;
        });
        

        【讨论】:

          猜你喜欢
          • 2019-07-14
          • 1970-01-01
          • 2018-10-07
          • 2019-04-10
          • 1970-01-01
          • 2021-08-13
          • 2021-02-12
          • 2021-04-02
          • 1970-01-01
          相关资源
          最近更新 更多