Skip to content

Commit 0c1f3fb

Browse files
authored
Merge pull request #156 from woocommerce/fix/119/product-term-decouple
Products: Decouple taxonomy term generation
2 parents bc76a53 + 378a54e commit 0c1f3fb

File tree

4 files changed

+275
-7
lines changed

4 files changed

+275
-7
lines changed

includes/CLI.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ function () use ( $progress ) {
263263

264264
WP_CLI::add_command( 'wc generate products', array( 'WC\SmoothGenerator\CLI', 'products' ), array(
265265
'shortdesc' => 'Generate products.',
266-
'synopsis' => array(
266+
'synopsis' => array(
267267
array(
268268
'name' => 'amount',
269269
'type' => 'positional',
@@ -278,8 +278,14 @@ function () use ( $progress ) {
278278
'optional' => true,
279279
'options' => array( 'simple', 'variable' ),
280280
),
281+
array(
282+
'name' => 'use-existing-terms',
283+
'type' => 'flag',
284+
'description' => 'Only apply existing categories and tags to products, rather than generating new ones.',
285+
'optional' => true,
286+
),
281287
),
282-
'longdesc' => "## EXAMPLES\n\nwc generate products 10\n\nwc generate products 20 --type=variable",
288+
'longdesc' => "## EXAMPLES\n\nwc generate products 10\n\nwc generate products 20 --type=variable --use-existing-terms",
283289
) );
284290

285291
WP_CLI::add_command( 'wc generate orders', array( 'WC\SmoothGenerator\CLI', 'orders' ), array(

includes/Generator/Generator.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ abstract class Generator {
2626
/**
2727
* Caches term IDs.
2828
*
29+
* @deprecated
30+
*
2931
* @var array Array of IDs.
3032
*/
3133
protected static $term_ids;
@@ -100,12 +102,17 @@ protected static function validate_batch_amount( $amount ) {
100102
/**
101103
* Get random term ids.
102104
*
105+
* @deprecated Use Product::get_term_ids instead.
106+
*
103107
* @param int $limit Number of term IDs to get.
104108
* @param string $taxonomy Taxonomy name.
105109
* @param string $name Product name to extract terms from.
110+
*
106111
* @return array
107112
*/
108113
protected static function generate_term_ids( $limit, $taxonomy, $name = '' ) {
114+
_deprecated_function( __METHOD__, '1.2.2', 'Product::get_term_ids' );
115+
109116
self::init_faker();
110117

111118
$term_ids = array();

includes/Generator/Product.php

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77

88
namespace WC\SmoothGenerator\Generator;
99

10+
use WC\SmoothGenerator\Util\RandomRuntimeCache;
11+
1012
/**
1113
* Product data generator.
1214
*/
1315
class Product extends Generator {
14-
1516
/**
1617
* Holds array of product IDs for generating relationships.
1718
*
@@ -132,13 +133,22 @@ public static function batch( $amount, array $args = array() ) {
132133
return $amount;
133134
}
134135

136+
$use_existing_terms = ! empty( $args['use-existing-terms'] );
137+
if ( ! $use_existing_terms ) {
138+
self::maybe_generate_terms( $amount );
139+
}
140+
135141
$product_ids = array();
136142

137143
for ( $i = 1; $i <= $amount; $i ++ ) {
138144
$product = self::generate( true, $args );
139145
$product_ids[] = $product->get_id();
140146
}
141147

148+
// In case multiple batches are being run in one request, refresh the cache data.
149+
RandomRuntimeCache::clear( 'product_cat' );
150+
RandomRuntimeCache::clear( 'product_tag' );
151+
142152
return $product_ids;
143153
}
144154

@@ -310,8 +320,8 @@ protected static function generate_variable_product() {
310320
'upsell_ids' => self::get_existing_product_ids(),
311321
'cross_sell_ids' => self::get_existing_product_ids(),
312322
'image_id' => self::get_image(),
313-
'category_ids' => self::generate_term_ids( self::$faker->numberBetween( 0, 5 ), 'product_cat', $name ),
314-
'tag_ids' => self::generate_term_ids( self::$faker->numberBetween( 0, 5 ), 'product_tag', $name ),
323+
'category_ids' => self::get_term_ids( 'product_cat', self::$faker->numberBetween( 0, 3 ) ),
324+
'tag_ids' => self::get_term_ids( 'product_tag', self::$faker->numberBetween( 0, 5 ) ),
315325
'gallery_image_ids' => $gallery,
316326
'reviews_allowed' => self::$faker->boolean(),
317327
'purchase_note' => self::$faker->boolean() ? self::$faker->text() : '',
@@ -405,8 +415,8 @@ protected static function generate_simple_product() {
405415
'menu_order' => self::$faker->numberBetween( 0, 10000 ),
406416
'virtual' => $is_virtual,
407417
'downloadable' => false,
408-
'category_ids' => self::generate_term_ids( self::$faker->numberBetween( 0, 5 ), 'product_cat', $name ),
409-
'tag_ids' => self::generate_term_ids( self::$faker->numberBetween( 0, 5 ), 'product_tag', $name ),
418+
'category_ids' => self::get_term_ids( 'product_cat', self::$faker->numberBetween( 0, 3 ) ),
419+
'tag_ids' => self::get_term_ids( 'product_tag', self::$faker->numberBetween( 0, 5 ) ),
410420
'shipping_class_id' => 0,
411421
'image_id' => $image_id,
412422
'gallery_image_ids' => $gallery,
@@ -415,6 +425,81 @@ protected static function generate_simple_product() {
415425
return $product;
416426
}
417427

428+
/**
429+
* Maybe generate a number of terms for use with products, if there aren't enough existing terms.
430+
*
431+
* Number of terms is determined by the number of products that will be generated.
432+
*
433+
* @param int $product_amount The number of products that will be generated.
434+
*
435+
* @return void
436+
*/
437+
protected static function maybe_generate_terms( int $product_amount ): void {
438+
if ( $product_amount < 10 ) {
439+
$cats = 5;
440+
$cat_depth = 1;
441+
$tags = 10;
442+
} elseif ( $product_amount < 50 ) {
443+
$cats = 10;
444+
$cat_depth = 2;
445+
$tags = 20;
446+
} else {
447+
$cats = 20;
448+
$cat_depth = 3;
449+
$tags = 40;
450+
}
451+
452+
$existing_cats = count( self::get_term_ids( 'product_cat', $cats ) );
453+
if ( $existing_cats < $cats ) {
454+
Term::batch( $cats - $existing_cats, 'product_cat', array( 'max-depth' => $cat_depth ) );
455+
}
456+
457+
$existing_tags = count( self::get_term_ids( 'product_tag', $tags ) );
458+
if ( $existing_tags < $tags ) {
459+
Term::batch( $tags - $existing_tags, 'product_tag' );
460+
}
461+
}
462+
463+
/**
464+
* Get a number of random term IDs for a specific taxonomy.
465+
*
466+
* @param string $taxonomy The taxonomy to get terms for.
467+
* @param int $limit The number of term IDs to get. Maximum value of 50.
468+
*
469+
* @return array
470+
*/
471+
protected static function get_term_ids( string $taxonomy, int $limit ): array {
472+
if ( $limit <= 0 ) {
473+
return array();
474+
}
475+
476+
if ( ! RandomRuntimeCache::exists( $taxonomy ) ) {
477+
$args = array(
478+
'taxonomy' => $taxonomy,
479+
'number' => 50,
480+
'orderby' => 'count',
481+
'order' => 'ASC',
482+
'hide_empty' => false,
483+
'fields' => 'ids',
484+
);
485+
486+
if ( 'product_cat' === $taxonomy ) {
487+
$uncategorized = get_term_by( 'slug', 'uncategorized', 'product_cat' );
488+
if ( $uncategorized ) {
489+
$args['exclude'] = $uncategorized->term_id;
490+
}
491+
}
492+
493+
$term_ids = get_terms( $args );
494+
495+
RandomRuntimeCache::set( $taxonomy, $term_ids );
496+
}
497+
498+
RandomRuntimeCache::shuffle( $taxonomy );
499+
500+
return RandomRuntimeCache::get( $taxonomy, $limit );
501+
}
502+
418503
/**
419504
* Generate an image gallery.
420505
*
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
<?php
2+
/**
3+
* A runtime object cache for storing and randomly retrieving reusable data.
4+
*
5+
* @package SmoothGenerator\Util
6+
*/
7+
8+
namespace WC\SmoothGenerator\Util;
9+
10+
/**
11+
* Class RandomRuntimeCache.
12+
*/
13+
class RandomRuntimeCache {
14+
/**
15+
* Associative array for storing groups of cache items.
16+
*
17+
* @var array
18+
*/
19+
private static $cache = array();
20+
21+
/**
22+
* Check if a specific cache group exists.
23+
*
24+
* @param string $group The specified cache group.
25+
*
26+
* @return bool
27+
*/
28+
public static function exists( string $group ): bool {
29+
return array_key_exists( $group, self::$cache );
30+
}
31+
32+
/**
33+
* Get a number of items from a specific cache group.
34+
*
35+
* The retrieved items will be from the top of the group's array.
36+
*
37+
* @param string $group The specified cache group.
38+
* @param int $limit Optional. Get up to this many items. Using 0 will return all the items in the group.
39+
* Default 0.
40+
*
41+
* @return array
42+
*/
43+
public static function get( string $group, int $limit = 0 ): array {
44+
$all_items = self::get_group( $group );
45+
46+
if ( $limit <= 0 || count( $all_items ) <= $limit ) {
47+
return $all_items;
48+
}
49+
50+
$items = array_slice( $all_items, 0, $limit );
51+
52+
return $items;
53+
}
54+
55+
/**
56+
* Remove a number of items from a specific cache group and return them.
57+
*
58+
* The items will be extracted from the top of the group's array.
59+
*
60+
* @param string $group The specified cache group.
61+
* @param int $limit Optional. Extract up to this many items. Using 0 will return all the items in the group and
62+
* delete it from the cache. Default 0.
63+
*
64+
* @return array
65+
*/
66+
public static function extract( string $group, int $limit = 0 ): array {
67+
$all_items = self::get_group( $group );
68+
69+
if ( $limit <= 0 || count( $all_items ) <= $limit ) {
70+
self::clear( $group );
71+
72+
return $all_items;
73+
}
74+
75+
$items = array_slice( $all_items, 0, $limit );
76+
$remaining_items = array_slice( $all_items, $limit );
77+
78+
self::set( $group, $remaining_items );
79+
80+
return $items;
81+
}
82+
83+
/**
84+
* Add items to a specific cache group.
85+
*
86+
* @param string $group The specified cache group.
87+
* @param array $items The items to add to the group.
88+
*
89+
* @return void
90+
*/
91+
public static function add( string $group, array $items ): void {
92+
$existing_items = self::get_group( $group );
93+
94+
self::set( $group, array_merge( $existing_items, $items ) );
95+
}
96+
97+
/**
98+
* Set a cache group to contain a specific set of items.
99+
*
100+
* @param string $group The specified cache group.
101+
* @param array $items The items that will be in the group.
102+
*
103+
* @return void
104+
*/
105+
public static function set( string $group, array $items ): void {
106+
self::$cache[ $group ] = $items;
107+
}
108+
109+
/**
110+
* Count the number of items in a specific cache group.
111+
*
112+
* @param string $group The specified cache group.
113+
*
114+
* @return int
115+
*/
116+
public static function count( string $group ): int {
117+
$group = self::get_group( $group );
118+
119+
return count( $group );
120+
}
121+
122+
/**
123+
* Shuffle the order of the items in a specific cache group.
124+
*
125+
* @param string $group The specified cache group.
126+
*
127+
* @return void
128+
*/
129+
public static function shuffle( string $group ): void {
130+
// Ensure group exists.
131+
self::get_group( $group );
132+
133+
shuffle( self::$cache[ $group ] );
134+
}
135+
136+
/**
137+
* Delete a group from the cache.
138+
*
139+
* @param string $group The specified cache group.
140+
*
141+
* @return void
142+
*/
143+
public static function clear( string $group ): void {
144+
unset( self::$cache[ $group ] );
145+
}
146+
147+
/**
148+
* Clear the entire cache.
149+
*
150+
* @return void
151+
*/
152+
public static function reset(): void {
153+
self::$cache = array();
154+
}
155+
156+
/**
157+
* Get the items in a cache group, ensuring that the group exists in the cache.
158+
*
159+
* @param string $group The specified cache group.
160+
*
161+
* @return array
162+
*/
163+
private static function get_group( string $group ): array {
164+
if ( ! self::exists( $group ) ) {
165+
self::set( $group, array() );
166+
}
167+
168+
return self::$cache[ $group ];
169+
}
170+
}

0 commit comments

Comments
 (0)