# `wc_get_products` 和产品查询

`wc_get_products` 和 `WC_Product_Query` 提供了获取产品的标准方法，这种方法安全可靠，并且不会因为未来 WooCommerce 版本的数据库更改而失效。构建自定义 WP_Queries 或数据库查询很可能会在未来版本的 WooCommerce 中导致您的代码失效，因为数据正在迁移到自定义表中以提高性能。 这是插件和主题开发者获取多个产品的最佳实践方法。 `wc_get_products` 和 `WC_Product_Query` 类似于 WordPress 的 [`get_posts` 和 `WP_Query`](https://developer.wordpress.org/reference/classes/wp_query/)。 就像它们一样，您需要传递一个参数数组，定义搜索的条件。

## 基本用法

### 示例

以下是一些示例：

```php
// 获取在 2016 年创建的可下载产品。
$products = wc_get_products( array(
    'downloadable' => true,
    'date_created' => '2016-01-01...2016-12-31',
) );
```

```php
// 获取最近的 10 个产品 ID，按日期降序排列。
$query = new WC_Product_Query( array(
    'limit' => 10,
    'orderby' => 'date',
    'order' => 'DESC',
    'return' => 'ids',
) );
$products = $query->get_products();
```

```php
// 获取包含特定 SKU 的产品。
// 支持部分匹配，因此这将获取 SKU 为 "PRDCT-1", "PRDCT-2" 等的产品。
$query = new WC_Product_Query();
$query->set( 'sku', 'PRDCT' );
$products = $query->get_products();
```

请注意，`wc_get_products()` 基本上是 `WC_Product_Query::get_products()` 的一个快捷方式。

## API 参考

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

以下描述了可用于这些函数的查询参数/参数。

## 查询参数参考

### General

| 参数 | 描述 |
| --------- | ----------- |
| **status** | 接受一个字符串或字符串数组：一个或多个值，可以是 `'draft'`, `'pending'`, `'private'`, `'publish'`，或者自定义的状态。 参见 [ProductStatus 类的常量](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Enums/ProductStatus.php)。 |
| **type** | 接受一个字符串或字符串数组：一个或多个值，可以是 `'external'`, `'grouped'`, `'simple'`, `'variable'`，或者自定义的类型。 参见 [ProductType 类的常量](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Enums/ProductType.php)。 |
| **include** | 接受一个整数数组：仅包含 ID 在数组中的产品。 |
| **exclude** | 接受一个整数数组：排除 ID 在数组中的产品。 |
| **parent** | 接受一个整数：产品父级的文章 ID。 |
| **parent_exclude** | 接受一个整数数组：排除父级 ID 在数组中的产品。 |
| **order** | 接受一个字符串：`'DESC'` 或 `'ASC'`。 与 `'orderby'` 配合使用。 默认值：`'DESC'`。 |
| **orderby** | 接受一个字符串：`'none'`, `'ID'`, `'name'`, `'type'`, `'rand'`, `'date'`, `'modified'`。 默认值：`'date'`。 |
| **return** | 返回类型。 接受一个字符串：`'ids'` 或 `'objects'`。 默认值：`'objects'`。 |

#### 示例

```php
// 获取草稿状态的产品。
$products = wc_get_products( array( 'status' => 'draft' ) );
```

```php
// 使用常量类获取状态。
$products = wc_get_products( array( 'status' => \Automattic\WooCommerce\Enums\ProductStatus::DRAFT ) );
```

```php
// 获取外部产品。
$products = wc_get_products( array( 'type' => 'external' ) );
```

```php
// 获取仅限于特定 ID 的外部产品。
$args = array(
    'type' => 'external',
    'include' => array( 134, 200, 210, 340 ),
);
$products = wc_get_products( $args );
```

```php
// 获取不是当前产品的产品。
$products = wc_get_products( array( 'exclude' => array( $product->get_id() ) ) );
```

```php
// 获取具有特定父级的产品。
$products = wc_get_products( array( 'parent' => 20 ) );
```

```php
// 获取最近修改的产品。
$args = array(
    'orderby' => 'modified',
    'order' => 'DESC',
);
$products = wc_get_products( $args );
```

```php
// 获取一些随机产品。
$products = wc_get_products( array( 'orderby' => 'rand' ) );
```

```php
// 仅返回产品 ID。
$products = wc_get_products( array( 'return' => 'ids' ) );
```

### 分页

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

#### 示例

```php
// 获取最新的 3 个产品。
$products = wc_get_products( array( 'limit' => 3 ) );
```

```php
// 获取前 3 个产品。
$args = array(
    'limit' => 3,
    'page'  => 1,
);
$page_1_products = wc_get_products( $args );

// 获取第二组 3 个产品。
$args = array(
    'limit' => 3,
    'page'  => 2,
);
$page_2_products = wc_get_products( $args );
```

```php
// 获取包含结果额外信息的 3 个产品。
$results = wc_get_products( array( 'paginate' => true ) );
echo $results->total . " 个产品已找到\n";
echo '第 1 页，共 ' . $results->max_num_pages . " 页\n";
if ( count( $results->products ) > 0 ) {
    echo '第一个产品的 ID 是: ' . $results->products[0]->get_id() . "\n";
}
```

```php
// 获取从第二个到第五个最新的产品。
$args = array(
    'limit' => 4,
    'offset' => 1,
);
$products = wc_get_products( $args );
```

### 产品查找

| 参数 | 描述 |
| --------- | ----------- |
| **sku** | 接受一个字符串：用于匹配的产品 SKU。 对 SKU 进行部分匹配。 |
| **name** | 接受一个字符串：用于匹配的产品名称（标题）。 区分大小写取决于 WordPress 帖子表的排序规则。 |
| **tag** | 接受一个数组：限制结果，仅显示分配了特定标签的产品，标签使用别名。 |
| **product_tag_id** | 接受一个整数或整数数组：限制结果，仅显示分配了特定标签的产品，标签使用 ID。 |
| **category** | 接受一个数组：限制结果，仅显示分配了特定分类的产品，分类使用别名。 |
| **product_category_id** | 接受一个整数或整数数组：限制结果，仅显示分配了特定分类的产品，分类使用 ID。 |

#### 示例

```php
// 获取 SKU 中包含 "PRDCT" 的产品（例如 PRDCT-1 和 PRDCT-2）。
$products = wc_get_products( array( 'sku' => 'PRDCT' ) );
```

```php
// 获取名为 "Test Product" 的产品。
$products = wc_get_products( array( 'name' => 'Test Product' ) );
```

```php
// 获取带有 "Excellent" 或 "Modern" 标签的产品。
$products = wc_get_products( array( 'tag' => array( 'excellent', 'modern' ) ) );
```

```php
// 通过标签 ID 获取产品。
$products = wc_get_products( array( 'product_tag_id' => array( 17, 23 ) ) );
```

```php
// 获取衬衫。
$products = wc_get_products( array( 'category' => array( 'shirts' ) ) );
```

```php
// 通过分类 ID 获取产品。
$products = wc_get_products( array( 'product_category_id' => array( 17, 23 ) ) );
```

### 尺寸和价格

| 参数 | 描述 |
| --------- | ----------- |
| **weight** | 接受一个浮点数：用于匹配的重量值。 |
| **length** | 接受一个浮点数：用于匹配的长度值。 |
| **width** | 接受一个浮点数：用于匹配的宽度值。 |
| **height** | 接受一个浮点数：用于匹配的高度值。 |
| **price** | 接受一个浮点数：用于匹配的当前价格。 |
| **regular_price** | 接受一个浮点数：用于匹配的常规价格。 |
| **sale_price** | 接受一个浮点数：用于匹配的促销价格。 |
| **total_sales** | 接受一个整数：获取销售数量为该值的产品。 |

#### 示例

```php
// 获取宽度为 5.5 个单位，长度为 10 个单位的产品。
$args = array(
    'width' => 5.5,
    'length' => 10,
);
$products = wc_get_products( $args );
```

```php
// 获取当前价格为 9.99 的产品。
$products = wc_get_products( array( 'price' => 9.99 ) );
```

```php
// 获取从未被购买过的产品。
$products = wc_get_products( array( 'total_sales' => 0 ) );
```

### 产品设置

| 参数 | 描述 |
| --------- | ----------- |
| **virtual** | 接受一个布尔值：限制为虚拟产品。 |
| **downloadable** | 接受一个布尔值：限制为可下载产品。 |
| **featured** | 接受一个布尔值：限制为推荐产品。 |
| **sold_individually** | 接受一个布尔值：限制为单独销售的产品。 |
| **manage_stock** | 接受一个布尔值：限制为启用了库存管理的产品。 |
| **reviews_allowed** | 接受一个布尔值：限制为允许评论的产品。 |
| **backorders** | 接受一个字符串：`'yes'`, `'no'` 或 `'notify'`。 |
| **visibility** | 接受一个字符串：`'visible'`, `'catalog'`, `'search'` 或 `'hidden'`。 参见 [CatalogVisibility 常量类](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Enums/CatalogVisibility.php)。 |
| **download_limit** | 接受一个整数：下载限制，或 `-1` 表示无限制。 |
| **download_expiry** | 接受一个整数：下载有效期（天数），或 `-1` 表示无限制。 |

#### 示例

```php
// 获取允许下载但不允许评论的产品。
$args = array(
    'downloadable' => true,
    'reviews_allowed' => false,
);
$products = wc_get_products( $args );
```

```php
// 获取允许延期交货的产品。
$products = wc_get_products( array( 'backorders' => 'yes' ) );
```

```php
// 获取在目录中显示的产品。
$products = wc_get_products( array( 'visibility' => 'catalog' ) );
```

```php
// 使用常量类进行可见性设置。
$products = wc_get_products( array( 'visibility' => \Automattic\WooCommerce\Enums\CatalogVisibility::CATALOG ) );
```

```php
// 获取下载次数无限制的产品。
$products = wc_get_products( array( 'download_limit' => -1 ) );
```

### 库存与库存状态

| 参数 | 描述 |
| --------- | ----------- |
| **stock_quantity** | 接受一个整数：产品在库存中的数量。 |
| **stock_status** | 接受一个字符串：`'outofstock'` (缺货), `'instock'` (有库存), 或 `'onbackorder'` (延期交货)。 参见 [ProductStockStatus 常量类](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Enums/ProductStockStatus.php)。 |

#### 示例

```php
// 获取库存数量仅剩一个的产品。
$products = wc_get_products( array( 'stock_quantity' => 1 ) );
```

```php
// 获取缺货的产品。
$products = wc_get_products( array( 'stock_status' => 'outofstock' ) );
```

```php
// 使用常量类进行库存状态设置。
$products = wc_get_products( array( 'stock_status' => \Automattic\WooCommerce\Enums\ProductStockStatus::OUT_OF_STOCK ) );
```

### 税费与配送

| 参数 | 描述 |
| --------- | ----------- |
| **tax_status** | 接受一个字符串：`'taxable'` (应税), `'shipping'` (包含运费), 或 `'none'` (免税)。 参见 [ProductTaxStatus 常量类](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Enums/ProductTaxStatus.php)。 |
| **tax_class** | 接受一个字符串：税类别名。 |
| **shipping_class** | 接受一个字符串或字符串数组：一个或多个配送类型别名。 |

#### 示例

```php
// 获取应税的产品。
$products = wc_get_products( array( 'tax_status' => 'taxable' ) );
```

```php
// 使用常量类进行税费状态设置。
$products = wc_get_products( array( 'tax_status' => \Automattic\WooCommerce\Enums\ProductTaxStatus::TAXABLE ) );
```

```php
// 获取属于 "Reduced Rate" 税类别的产品。
$products = wc_get_products( array( 'tax_class' => 'reduced-rate' ) );
```

```php
// 获取属于 "Bulky" 配送类型的产品。
$products = wc_get_products( array( 'shipping_class' => 'bulky' ) );
```

### 评论与评分

| 参数 | 描述 |
| --------- | ----------- |
| **average_rating** | 接受一个浮点数：平均评分。 |
| **review_count** | 接受一个整数：评论数量。 |

#### 示例

```php
// 获取所有评分均为 5 颗星的产品。
$products = wc_get_products( array( 'average_rating' => 5.0 ) );
```

```php
// 获取有 1 条评论的产品。
$products = wc_get_products( array( 'review_count' => 1 ) );
```

### 日期

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

| 参数 | 描述 |
| --------- | ----------- |
| **date_created** | 匹配产品创建日期。 接受标准格式的字符串。 |
| **date_modified** | 匹配产品修改日期。 接受标准格式的字符串。 |
| **date_on_sale_from** | 匹配促销开始日期。 接受标准格式的字符串。 |
| **date_on_sale_to** | 匹配促销结束日期。 接受标准格式的字符串。 |

#### 标准格式

- `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 年创建的可下载产品。
$products = wc_get_products( array(
    'downloadable' => true,
    'date_created' => '2016-01-01...2016-12-31',
) );
```

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

可以在 `wc_get_products()` 或 `WC_Product_Query` 中添加对自定义参数的支持。 要实现此功能，需要过滤生成的查询。

```php
/**
 * 处理自定义的 'customvar' 查询变量，以获取具有 'customvar' 元数据的产品。
 * @param array $query - WP_Query 的参数。
 * @param array $query_vars - WC_Product_Query 的查询变量。
 * @return array 修改后的 $query
 */
function handle_custom_query_var( $query, $query_vars ) {
	if ( ! empty( $query_vars['customvar'] ) ) {
		if ( ! isset( $query['meta_query'] ) ) {
			$query['meta_query'] = array();
		}
		$query['meta_query'][] = array(
			'key'   => 'customvar',
			'value' => sanitize_text_field( $query_vars['customvar'] ),
		);
	}

	return $query;
}
add_filter( 'woocommerce_product_data_store_cpt_get_products_query', 'handle_custom_query_var', 10, 2 );
```

用法：

```php
$products = wc_get_products( array( 'customvar' => 'somevalue' ) );
```