# `wc_get_orders()` 和订单查询

`wc_get_orders()` 和 `WC_Order_Query` 提供了从数据库检索订单的标准方法，类似于 WordPress 的 [`get_posts()` 和 `WP_Query`](https://codex.wordpress.org/Class_Reference/WP_Query)，但专门用于订单。

插件和主题的开发者应避免编写自定义的 WordPress 查询或直接的 SQL 语句，因为 WordPress 或 WooCommerce 数据库的更改可能会导致问题。 这些 API 提供了最佳实践，并且是获取 WooCommerce 中订单的未来兼容方式。

## 基本用法

### 示例

以下是一些示例：

```php
// 获取名为 John 且于 2016 年付款的订单。
$orders = wc_get_orders(
    array(
        'billing_first_name' => 'John',
        'date_paid'          => '2016-01-01...2016-12-31',
    )
);
```

```php
// 获取 10 个最近的订单 ID。
$query = new WC_Order_Query(
    array(
        'limit'   => 10,
        'orderby' => 'date',
        'order'   => 'DESC',
        'return'  => 'ids',
    )
);
$orders = $query->get_orders();
```

```php
// 获取电子邮件为 'woocommerce@woocommerce.com' 的客户的订单。
$query = new WC_Order_Query();
$query->set( 'customer', 'woocommerce@woocommerce.com' );
$orders = $query->get_orders();
```

请注意，`wc_get_orders()` 主要是 `WC_Order_Query::get_orders()` 的一个快捷方式。

### 最佳实践

- 避免直接的数据库查询，而应使用 `wc_get_orders()`。
- 如果您的代码需要支持旧版本，请在启用和禁用 HPOS 时进行彻底测试。
- 使用特定的参数来限制结果并提高性能。
- 对于大型结果集，请考虑使用 `limit` 和 `offset` 进行分页。
- 在适当的情况下缓存结果。
- 对于复杂的过滤要求，请利用自 8.2 起在运行 HPOS 的站点上提供的新的查询参数 `meta_query`、`field_query` 和 `date_query`。

## API 参考

| 方法                                   | 描述                              |
|-------------------------------------------|------------------------------------------|
| `wc_get_orders ( $args )`            | 检索与查询 `$args` 匹配的订单。 |
| `WC_Order_Query::get_query_vars()`        | 获取当前查询对象上设置的所有查询变量的数组。         |
| `WC_Order_Query::get( string $key, mixed $default = '' )`               | 获取查询变量的值，如果未设置查询变量，则返回默认值。            |
| `WC_Order_Query::set( string $key, mixed $value )`       | 设置一个查询变量。                     |
| `WC_Order_Query::get_orders()`            | 获取与当前查询变量匹配的所有订单。  |

以下是可与这些函数一起使用的查询参数/参数。

## 查询参数参考

### General

|参数|描述|
|-|-|
|**status**| 接受一个字符串数组：默认情况下设置为 `wc_get_order_statuses()` 函数的键。|
|**type**| 接受一个字符串：'shop_order'、'shop_order_refund' 或自定义订单类型。|
|**version**| 接受一个字符串：订单创建时使用的 WooCommerce 版本号。|
|**created_via**| 接受一个字符串：'checkout'、'rest-api' 或自定义创建方法别名。|
|**parent**| 接受一个整数：父订单的帖子 ID。|
|**parent_exclude**| 接受一个整数数组：排除具有父 ID 在数组中的订单。|
|**exclude**| 接受一个整数数组：排除具有这些 ID 的订单。|
|**order**| 接受一个字符串：'DESC' 或 'ASC'。与 'orderby' 配合使用。默认值：'DESC'。|
|**orderby**| 接受一个字符串：'none'、'ID'、'name'、'type'、'rand'、'date'、'modified'。默认值：'date'。|
|**return**| 返回类型。接受一个字符串：'ids' 或 'objects'。默认值：'objects'。|

#### 示例

```php
// 获取最近修改的订单。
$args = array(
    'orderby' => 'modified',
    'order' => 'DESC',
);
$orders = wc_get_orders( $args );
```

```php
// 获取一些随机订单。
$orders = wc_get_orders( array( 'orderby' => 'rand' ) );
```

```php
// 仅返回订单 ID。
$orders = wc_get_orders( array( 'return' => 'ids' ) );
```

```php
// 获取处理中和待处理的订单。
$args = array(
    'status' => array( 'wc-processing', 'wc-on-hold' ),
);
$orders = wc_get_orders( $args );
```

```php
// 获取过去 24 小时的退款订单。
$args = array(
    'type'         => 'shop_order_refund',
    'date_created' => '>' . ( time() - DAY_IN_SECONDS ),
);
$orders = wc_get_orders( $args );
```

```php
// 获取在 WooCommerce 2.6.14 版本创建并通过网站结账的订单。
$args = array(
    'version'     => '2.6.14',
    'created_via' => 'checkout',
);
$orders = wc_get_orders( $args );
```

```php
// 获取父帖子 ID 为 20 且不是订单 12 的订单。
$args = array(
    'parent'  => 20,
    'exclude' => array( 12 ),
);
$orders = wc_get_orders( $args );
```

### 分页

|参数|描述|
|-|-|
|**limit**| 接受一个整数：要检索的最大结果数，或 -1 表示无限制。默认值：站点 'posts_per_page' 设置。|
|**paged**| 接受一个整数：要检索的结果页码。如果使用了 'offset'，则无效。|
|**offset**| 接受一个整数：订单结果的偏移量。|
|**paginate**| 接受一个布尔值：如果为真，则启用分页，否则禁用分页（默认：false）。如果启用，则修改返回结果，使其包含一个对象，该对象具有以下字段：`orders`（找到的订单数组）、`total`（找到的订单数量）和 `max_num_pages`（总页数）。|

#### 示例

```php
// 获取最新的 3 个订单。
$orders = wc_get_orders( array( 'limit' => 3 ) );
```

```php
// 前 3 个订单。
$args = array(
    'limit' => 3,
    'paged' => 1,
);
$page_1_orders = wc_get_orders( $args );

// 后 3 个订单。
$args = array(
    'limit' => 3,
    'paged' => 2,
);
$page_2_orders = wc_get_orders( $args );
```

```php
// 获取包含关于结果的额外信息的订单。
$results = wc_get_orders( array( 'paginate' => true ) );
echo $results->total . " 个订单已找到\n";
echo '第 1 页，共 ' . $results->max_num_pages . " 页\n";
echo '第一个订单 ID 是: ' . $results->orders[0]->get_id() . "\n";
```

### 支付和金额

| 参数 | 描述 |
|-|-|
| **currency** | 接受一个字符串：订单中使用的货币。 |
| **prices_include_tax** | 接受一个字符串：'yes' 或 'no'。 |
| **payment_method** | 接受一个字符串：使用的支付方法的别名。 |
| **payment_method_title** | 接受一个字符串：使用的支付方法的完整标题。 |
| **discount_total** | 接受一个浮点数：用于匹配的未四舍五入的金额。 |
| **discount_tax** | 接受一个浮点数：用于匹配的未四舍五入的金额。 |
| **shipping_total** | 接受一个浮点数：用于匹配的未四舍五入的金额。 |
| **shipping_tax** | 接受一个浮点数：用于匹配的未四舍五入的金额。 |
| **cart_tax** | 接受一个浮点数：用于匹配的未四舍五入的金额。 |
| **total** | 接受一个浮点数：用于匹配的未四舍五入的金额。 |

#### 示例

```php
// 获取使用 USD 支付的订单。
$orders = wc_get_orders( array( 'currency' => 'USD' ) );
```

```php
// 获取使用支票支付的订单。
$orders = wc_get_orders( array( 'payment_method' => 'cheque' ) );
```

```php
// 获取折扣总额为 20.00 的订单。
$orders = wc_get_orders( array( 'discount_total' => 20.00 ) );
```

### 客户

| 参数 | 描述 |
|-|-|
| **customer** | 接受一个字符串或一个整数：订单的账单电子邮件或客户 ID。 |
| **customer_id** | 接受一个整数：客户 ID。 |
| **customer_ip_address** | 接受字符串：用于匹配的值。 |

#### 示例

```php
// 获取客户电子邮件为 'woocommerce@woocommerce.com' 的订单。
$orders = wc_get_orders( array( 'customer' => 'woocommerce@woocommerce.com' ) );
```

```php
// 获取客户 ID 为 12 的订单。
$orders = wc_get_orders( array( 'customer_id' => 12 ) );
```

### 账单和配送

|参数|描述|
|-|-|
|**billing_first_name**|接受字符串：用于匹配的值。|
|**billing_last_name**|接受字符串：用于匹配的值。|
|**billing_company**|接受字符串：用于匹配的值。|
|**billing_address_1**|接受字符串：用于匹配的值。|
|**billing_address_2**|接受字符串：用于匹配的值。|
|**billing_city**|接受字符串：用于匹配的值。|
|**billing_state**|接受字符串：用于匹配的值。|
|**billing_postcode**|接受字符串：用于匹配的值。|
|**billing_country**|接受字符串：用于匹配的值。|
|**billing_email**|接受字符串：用于匹配的值。|
|**billing_phone**|接受字符串：用于匹配的值。|
|**shipping_first_name**|接受字符串：用于匹配的值。|
|**shipping_last_name**|接受字符串：用于匹配的值。|
|**shipping_company**|接受字符串：用于匹配的值。|
|**shipping_address_1**|接受字符串：用于匹配的值。|
|**shipping_address_2**|接受字符串：用于匹配的值。|
|**shipping_city**|接受字符串：用于匹配的值。|
|**shipping_state**|接受字符串：用于匹配的值。|
|**shipping_postcode**|接受字符串：用于匹配的值。|
|**shipping_country**|接受字符串：用于匹配的值。|

#### 示例

```php
// 获取来自美国的订单。
$orders = wc_get_orders( array( 'billing_country' => 'US' ) );
```

```php
// 获取名为 Bill Evans 的用户的订单。
$args = array(
    'billing_first_name' => 'Bill',
    'billing_last_name'  => 'Evans',
);
$orders = wc_get_orders( $args );
```

### 日期

日期参数接收以下标准格式的值，允许更灵活的查询。

|参数|描述|
|-|-|
|**date_created**|匹配订单创建日期。 接受标准格式的字符串。|
|**date_modified**|匹配订单修改日期。 接受标准格式的字符串。|
|**date_completed**|匹配订单完成日期。 接受标准格式的字符串。|
|**date_paid**|匹配订单支付日期。 接受标准格式的字符串。|

#### 标准格式

- `YYYY-MM-DD` - 匹配该站点时区内某一天内的订单。
- `>YYYY-MM-DD` - 匹配该站点时区内该一天之后的订单。
- `>=YYYY-MM-DD` - 匹配该站点时区内该一天及其之后的所有订单。
- `<YYYY-MM-DD` - 匹配该站点时区内该一天之前的订单。
- `<=YYYY-MM-DD` - 匹配该站点时区内该一天及其之前的订单。
- `YYYY-MM-DD...YYYY-MM-DD` - 匹配该站点时区内某一天及其之间所有订单。
- `TIMESTAMP` - 匹配 UTC 时区内某一个秒的订单。
- `>TIMESTAMP` - 匹配 UTC 时区内该一个秒之后的订单。
- `>=TIMESTAMP` - 匹配 UTC 时区内该一个秒及其之后的所有订单。
- `<TIMESTAMP` - 匹配 UTC 时区内该一个秒之前的订单。
- `<=TIMESTAMP` - 匹配 UTC 时区内该一个秒及其之前的订单。
- `TIMESTAMP...TIMESTAMP` - 匹配 UTC 时区内某一个秒及其之间所有订单。

#### 示例

```php
// 获取 2016 年 2 月 12 日已支付的订单。
$orders = wc_get_orders( array( 'date_paid' => '2016-02-12' ) );
```

```php
// 获取创建于过去一小时内的订单。
$args = array(
    'date_created' => '<' . ( time() - HOUR_IN_SECONDS ),
);
$orders = wc_get_orders( $args );
```

```php
// 获取 2017 年 5 月 16 日 21:46:17 UTC 到 2017 年 5 月 17 日 12:46:17 UTC 之间的已完成订单。
$args = array(
    'date_completed' => '1494938777...1494971177',
);
$orders = wc_get_orders( $args );
```

### 元数据

<!-- markdownlint-disable MD033 -->
|参数|描述|
|-|-|
|**meta_query**|一个或多个包含键 `key`（元数据键）、`value`（可选，字符串或数组）以及可选的 `type` 和 `compare` 的数组。<br />此参数类似于 [WP_Query 的 `meta_query`](https://developer.wordpress.org/reference/classes/wp_query/#custom-field-post-meta-parameters)，支持各种比较运算符以及通过 AND/OR 关系连接的查询级别。|
<!-- markdownlint-enable MD033 -->

有关更多详细信息和示例，请参阅 [HPOS 订单查询](/docs/features/high-performance-order-storage/wc-order-query-improvements#metadata-queries-meta_query) 指南。

:::警告

只有当 HPOS 是配置的订单数据存储时（自 WooCommerce 8.2 以来为默认设置），才支持 `meta_query`。

在使用之前，请使用 `OrderUtil::custom_orders_table_usage_is_enabled()` 检查是否已启用。
:::

#### 示例

```php
// 具有元数据 'custom_field' 设置为 'some_value' 且元数据 'weight' 大于 '50' 的订单。
$orders = wc_get_orders(
    array(
        'meta_query' => array(
            array(
                'key'     => 'custom_field',
                'value'   => 'some_value',
                'compare' => '='
            ),
            array(
                'key'     => 'weight',
                'value'   => '50',
                'compare' => '>='
            ),
            'relation' => 'AND'
        )
    )
);
```

### 订单字段

<!-- markdownlint-disable MD033 -->
|参数|描述|
|-|-|
|**field_query**|一个或多个包含键 `field`（任何订单属性）、`value` 以及可选的 `type` 和 `compare` 的数组。<br />此参数类似于前面部分中描述的 `meta_query` 参数，支持各种比较运算符以及通过 AND/OR 关系连接的查询级别。|
<!-- markdownlint-enable MD033 -->

有关更多详情和示例，请参考 [HPOS 订单查询](/docs/features/high-performance-order-storage/wc-order-query-improvements#order-field-queries-field_query) 指南。

:::警告

`field_query` 的支持仅在 HPOS 作为配置的订单数据存储时可用（自 WooCommerce 8.2 以来为默认设置）。

在使用前，请使用 `OrderUtil::custom_orders_table_usage_is_enabled()` 检查是否已启用。
:::

#### 示例

```php
// 获取总额大于 100 或来自纽约市的订单。
$orders = wc_get_orders(
    array(
        'field_query' => array(
            array(
                'field' => 'total',
                'value' => 100,
                'compare' => '>'
            ),
            array(
                'field' => 'billing_city',
                'value' => 'New York',
                'compare' => '='
            ),
            'relation' => 'OR'
        )
    )
);
```

### 高级日期查询

<!-- markdownlint-disable MD033 -->
|参数|描述|
|-|-|
|**date_query**|一个或多个包含键 `column`（订单日期：`date_completed`、`date_created`、`date_updated` 或 `date_paid`，可选地后跟 `_gmt` 表示 UTC 日期）、`value` 以及可选的 `type` 和 `compare` 的数组。<br />此参数类似于 [WP_Query 的 `date_query`](https://developer.wordpress.org/reference/classes/wp_query/#date-parameters)，支持各种比较运算符以及通过 AND/OR 关系连接的查询级别。|
<!-- markdownlint-enable MD033 -->

有关更多详情和示例，请参考 [HPOS 订单查询](/docs/features/high-performance-order-storage/wc-order-query-improvements#date-queries-date_query) 指南。

:::警告

`date_query` 的支持仅在 HPOS 作为配置的订单数据存储时可用（自 WooCommerce 8.2 以来为默认设置）。

在使用前，请使用 `OrderUtil::custom_orders_table_usage_is_enabled()` 检查是否已启用。
:::

#### 示例

```php
// 示例：获取过去一个月内已支付且创建时间在中午之前的订单。

$orders = wc_get_orders(
    array(
        'date_query' => array(
            'relation' => 'AND',
            array(
                'column'  => 'date_created_gmt',
                'hour'    => 12,
                'compare' => '<'
            ),
            array(
                'column'  => 'date_paid_gmt',
                'after'   => '1 month ago',
            ),
        ),
    )
);
```

## 添加对自定义参数的支持

开发者可以通过过滤生成的查询，为 `wc_get_orders()` 和 `WC_Order_Query` 添加对自定义参数的支持，从而扩展查询功能。

WooCommerce 当前支持两种订单存储机制：HPOS（默认）和旧版（使用 WordPress 帖子和元数据），每种机制都有自己的钩子，用于过滤生成的查询：

- (HPOS) `woocommerce_order_query_args` 用于将参数转换为现有参数，或者 `woocommerce_orders_table_query_clauses` 用于编写自己的 SQL。
- (旧版) `woocommerce_order_data_store_cpt_get_orders_query` 用于将参数转换为 `WP_Query` 参数。

```php
/**
 * 示例：处理自定义 'customvar' 查询变量，以获取具有 'customvar' 元数据的订单。
 */
use Automattic\WooCommerce\Utilities\OrderUtil;

// HPOS 版本。
function handle_custom_query_var_hpos( $query_args ) {
    if ( ! empty( $query_args['customvar'] ) ) {
        if ( ! isset( $query_args['meta_query'] ) ) {
            $query_args['meta_query'] = array();
        }

		$query_args['meta_query'][] = array(
			'key'   => 'customvar',
			'value' => esc_attr( $query_args['customvar'] ),
		);

        unset( $query_args['customvar'] );
    }


    return $query_args;
}

// 旧版版本。
function handle_custom_query_var_legacy( $query, $query_vars ) {
	if ( ! empty( $query_vars['customvar'] ) ) {
		$query['meta_query'][] = array(
			'key'   => 'customvar',
			'value' => esc_attr( $query_vars['customvar'] ),
		);
	}

	return $query;
}

if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
    // HPOS。
    add_filter(
        'woocommerce_order_query_args',
        'handle_custom_query_var_hpos'
    );
} else {
    // 旧版支持。
    add_filter(
        'woocommerce_order_data_store_cpt_get_orders_query',
        'handle_custom_query_var_legacy',
        10,
        2
    );
}
```

用法：

```php
$orders = wc_get_orders( array( 'customvar' => 'somevalue' ) );
```