PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.3
WooCommerce v10.9.3
10.9.4 10.9.3 10.9.2 10.9.1 10.9.0 10.9.0-rc.1 10.9.0-beta.2 10.9.0-beta.1 10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / src / Internal / ShopperLists / ShopperList.php
woocommerce / src / Internal / ShopperLists Last commit date
ShopperList.php 1 month ago ShopperListItem.php 2 weeks ago ShopperListRenderer.php 1 month ago ShopperListsController.php 1 month ago
ShopperList.php
239 lines
1 <?php
2 declare( strict_types = 1 );
3
4 namespace Automattic\WooCommerce\Internal\ShopperLists;
5
6 use Automattic\WooCommerce\Internal\Utilities\Users;
7
8 /**
9 * A user's saved list of products.
10 */
11 class ShopperList {
12 /**
13 * Prefix for per-list usermeta key for list details.
14 */
15 const META_KEY_PREFIX = '_wc_shopper_list_';
16
17 /**
18 * User ID.
19 *
20 * @var int
21 */
22 private $user_id;
23
24 /**
25 * List slug.
26 *
27 * @var string
28 */
29 private $slug;
30
31 /**
32 * Datetime the list was created.
33 *
34 * @var string
35 */
36 private $date_created_gmt;
37
38 /**
39 * Items in the list.
40 *
41 * @var array<string, ShopperListItem>
42 */
43 private $items;
44
45 /**
46 * Private constructor. Use the static factories to obtain concrete instances.
47 *
48 * @param int $user_id Owning user ID.
49 * @param string $slug List slug.
50 * @param string $date_created_gmt MySQL DATETIME, GMT.
51 * @param array<string, ShopperListItem> $items Items keyed by storage key.
52 */
53 private function __construct(
54 int $user_id,
55 string $slug,
56 string $date_created_gmt,
57 array $items
58 ) {
59 $this->user_id = $user_id;
60 $this->slug = $slug;
61 $this->date_created_gmt = $date_created_gmt;
62 $this->items = $items;
63 }
64
65 /**
66 * Load a list by slug. Returns false for any other list that doesn't exist.
67 *
68 * @param string $slug List identifier.
69 * @param int|null $user_id Defaults to the current user.
70 * @return self|false
71 */
72 public static function get_by_slug( string $slug, ?int $user_id = null ) {
73 // Gate disabled or unknown slugs upfront so previously-persisted lists
74 // don't bypass the feature flag (the Store API surfaces this as 404).
75 if ( ! wc_get_container()->get( ShopperListsController::class )->is_enabled( $slug ) ) {
76 return false;
77 }
78
79 $user_id = absint( $user_id ? $user_id : get_current_user_id() );
80 if ( ! $user_id ) {
81 return false;
82 }
83
84 $stored = Users::get_site_user_meta( $user_id, self::META_KEY_PREFIX . $slug );
85
86 if ( is_array( $stored ) ) {
87 return self::from_array( $stored, $user_id );
88 }
89
90 // In-memory list; saved on the first save().
91 return new self(
92 $user_id,
93 $slug,
94 current_time( 'mysql', true ),
95 array()
96 );
97 }
98
99 /**
100 * Get all of the user's lists.
101 *
102 * @param int|null $user_id Defaults to the current user.
103 * @return array<string, self>
104 */
105 public static function get_all_for_user( ?int $user_id = null ): array {
106 $result = array();
107 foreach ( wc_get_container()->get( ShopperListsController::class )->get_enabled_slugs() as $slug ) {
108 $list = self::get_by_slug( $slug, $user_id );
109 if ( $list ) {
110 $result[ $slug ] = $list;
111 }
112 }
113 return $result;
114 }
115
116 /**
117 * The list slug (e.g. 'saved-for-later').
118 */
119 public function get_slug(): string {
120 return $this->slug;
121 }
122
123 /**
124 * Creation time as a MySQL DATETIME in GMT.
125 */
126 public function get_date_created_gmt(): string {
127 return $this->date_created_gmt;
128 }
129
130 /**
131 * Add an item, or merge quantities if it already exists.
132 *
133 * @param ShopperListItem $item Item to add.
134 */
135 public function add_item( ShopperListItem $item ): void {
136 $key = $item->get_key();
137
138 if ( isset( $this->items[ $key ] ) ) {
139 $this->items[ $key ] = ShopperListItem::from_array(
140 array_merge(
141 $this->items[ $key ]->to_array(),
142 array( 'quantity' => $this->items[ $key ]->get_quantity() + $item->get_quantity() )
143 )
144 );
145 return;
146 }
147
148 $this->items[ $key ] = $item;
149 }
150
151 /**
152 * Remove an item by key. Returns false if the key wasn't present.
153 *
154 * @param string $key Storage key of the item to remove.
155 */
156 public function remove_item( string $key ): bool {
157 if ( ! isset( $this->items[ $key ] ) ) {
158 return false;
159 }
160 unset( $this->items[ $key ] );
161 return true;
162 }
163
164 /**
165 * Get all items currently in the list.
166 *
167 * @return array<string, ShopperListItem>
168 */
169 public function get_items(): array {
170 return $this->items;
171 }
172
173 /**
174 * Find an item by key.
175 *
176 * @param string $key Storage key.
177 */
178 public function find_item( string $key ): ?ShopperListItem {
179 return $this->items[ $key ] ?? null;
180 }
181
182 /**
183 * Persist the current state to user meta.
184 */
185 public function save(): void {
186 Users::update_site_user_meta(
187 $this->user_id,
188 self::META_KEY_PREFIX . $this->slug,
189 $this->to_array()
190 );
191 }
192
193 /**
194 * Storage / response shape.
195 */
196 public function to_array(): array {
197 $items_array = array();
198 foreach ( $this->items as $key => $item ) {
199 $items_array[ $key ] = $item->to_array();
200 }
201
202 return array(
203 'slug' => $this->slug,
204 'date_created_gmt' => $this->date_created_gmt,
205 'items' => $items_array,
206 );
207 }
208
209 /**
210 * Build a ShopperList from a stored array.
211 *
212 * @param array $data Stored list record.
213 * @param int $user_id Owning user ID.
214 */
215 private static function from_array( array $data, int $user_id ): self {
216 $items = array();
217 if ( ! empty( $data['items'] ) && is_array( $data['items'] ) ) {
218 foreach ( $data['items'] as $key => $item_data ) {
219 if ( ! is_array( $item_data ) ) {
220 continue;
221 }
222
223 try {
224 $items[ (string) $key ] = ShopperListItem::from_array( $item_data );
225 } catch ( \Throwable $e ) {
226 continue;
227 }
228 }
229 }
230
231 return new self(
232 $user_id,
233 $data['slug'] ?? '',
234 $data['date_created_gmt'] ?? current_time( 'mysql', true ),
235 $items
236 );
237 }
238 }
239