PluginProbe
WooCommerce / 11.1.0-beta.1
WooCommerce v11.1.0-beta.1
11.1.0 11.1.0-rc.2 11.1.0-rc.1 11.1.0-beta.2 11.1.0-beta.1 11.0.1 11.0.0 11.0.0-rc.3 11.0.0-rc.2 11.0.0-rc.1 11.0.0-beta.2 11.0.0-beta.1 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 All 648 releases
woocommerce / src / Admin / Notes / NoteTraits.php
NoteTraits.php
345 lines 8.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * WC Admin Note Traits
4 *
5 * WC Admin Note Traits class that houses shared functionality across notes.
6 */
7
8 namespace Automattic\WooCommerce\Admin\Notes;
9
10 use Automattic\WooCommerce\Admin\WCAdminHelper;
11
12 defined( 'ABSPATH' ) || exit;
13
14 /**
15 * NoteTraits class.
16 */
17 trait NoteTraits {
18 /**
19 * Test how long WooCommerce Admin has been active.
20 *
21 * @param int $seconds Time in seconds to check.
22 * @return bool Whether or not WooCommerce admin has been active for $seconds.
23 */
24 private static function wc_admin_active_for( $seconds ) {
25 return WCAdminHelper::is_wc_admin_active_for( $seconds );
26 }
27
28 /**
29 * Test if WooCommerce Admin has been active within a pre-defined range.
30 *
31 * @param string $range range available in WC_ADMIN_STORE_AGE_RANGES.
32 * @param int $custom_start custom start in range.
33 * @return bool Whether or not WooCommerce admin has been active within the range.
34 */
35 private static function is_wc_admin_active_in_date_range( $range, $custom_start = null ) {
36 return WCAdminHelper::is_wc_admin_active_in_date_range( $range, $custom_start );
37 }
38
39 /**
40 * Check if the note has been previously added.
41 *
42 * @return bool
43 * @throws NotesUnavailableException Throws exception when notes are unavailable.
44 */
45 public static function note_exists(): bool {
46 /**
47 * Data store instance.
48 *
49 * @var DataStore $data_store
50 */
51 $data_store = Notes::load_data_store();
52 $note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );
53 return ! empty( $note_ids );
54 }
55
56 /**
57 * Checks if a note can and should be added.
58 *
59 * @return bool
60 * @throws NotesUnavailableException Throws exception when notes are unavailable.
61 */
62 public static function can_be_added(): bool {
63 $note = self::get_note();
64
65 if ( ! $note instanceof Note && ! $note instanceof WC_Admin_Note ) {
66 return false;
67 }
68
69 if ( self::note_exists() ) {
70 return false;
71 }
72
73 if (
74 'no' === get_option( 'woocommerce_show_marketplace_suggestions', 'yes' ) &&
75 Note::E_WC_ADMIN_NOTE_MARKETING === $note->get_type()
76 ) {
77 return false;
78 }
79
80 return true;
81 }
82
83 /**
84 * Add the note if it passes predefined conditions.
85 *
86 * @return void
87 * @throws NotesUnavailableException Throws exception when notes are unavailable.
88 */
89 public static function possibly_add_note(): void {
90 $note = self::get_note();
91
92 if ( ! self::can_be_added() ) {
93 return;
94 }
95
96 if ( $note instanceof Note || $note instanceof WC_Admin_Note ) {
97 $note->save();
98 }
99 }
100
101 /**
102 * Alias this method for backwards compatibility.
103 *
104 * @return void
105 * @throws NotesUnavailableException Throws exception when notes are unavailable.
106 */
107 public static function add_note(): void {
108 self::possibly_add_note();
109 }
110
111 /**
112 * Should this note exist? (Default implementation is generous. Override as needed.)
113 */
114 public static function is_applicable() {
115 return true;
116 }
117
118 /**
119 * Delete this note if it is not applicable, unless has been soft-deleted or actioned already.
120 *
121 * @return void
122 */
123 public static function delete_if_not_applicable(): void {
124 if ( ! self::is_applicable() ) {
125 /**
126 * Data store instance.
127 *
128 * @var DataStore $data_store
129 */
130 $data_store = Notes::load_data_store();
131 $note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );
132
133 if ( ! empty( $note_ids ) ) {
134 $note = Notes::get_note( $note_ids[0] );
135
136 if ( $note instanceof Note && ! $note->get_is_deleted() && ( Note::E_WC_ADMIN_NOTE_ACTIONED !== $note->get_status() ) ) {
137 self::possibly_delete_note();
138 }
139 }
140 }
141 }
142
143 /**
144 * Possibly delete the note, if it exists in the database. Note that this
145 * is a hard delete, for where it doesn't make sense to soft delete or
146 * action the note.
147 *
148 * @return void
149 * @throws NotesUnavailableException Throws exception when notes are unavailable.
150 */
151 public static function possibly_delete_note(): void {
152 /**
153 * Data store instance.
154 *
155 * @var DataStore $data_store
156 */
157 $data_store = Notes::load_data_store();
158 $note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );
159
160 foreach ( $note_ids as $note_id ) {
161 $note = Notes::get_note( $note_id );
162
163 if ( $note instanceof Note ) {
164 $data_store->delete( $note );
165 }
166 }
167 }
168
169
170 /**
171 * Update the note if it passes predefined conditions.
172 *
173 * @return void
174 * @throws NotesUnavailableException Throws exception when notes are unavailable.
175 */
176 public static function possibly_update_note(): void {
177 $note_in_db = Notes::get_note_by_name( self::NOTE_NAME );
178 if ( ! $note_in_db instanceof Note ) {
179 return;
180 }
181
182 // Backwards compatibility for checking if the note class has a get_note method.
183 /**
184 * Backwards compatibility check.
185 *
186 * @phpstan-ignore-next-line
187 */
188 if ( ! method_exists( self::class, 'get_note' ) ) {
189 return;
190 }
191
192 $note = self::get_note();
193 if ( ! $note instanceof Note && ! $note instanceof WC_Admin_Note ) {
194 return;
195 }
196
197 $need_save = in_array(
198 true,
199 array(
200 self::update_note_field_if_changed( $note_in_db, $note, 'title' ),
201 self::update_note_field_if_changed( $note_in_db, $note, 'content' ),
202 self::update_note_field_if_changed( $note_in_db, $note, 'content_data' ),
203 self::update_note_field_if_changed( $note_in_db, $note, 'type' ),
204 self::update_note_field_if_changed( $note_in_db, $note, 'locale' ),
205 self::update_note_field_if_changed( $note_in_db, $note, 'source' ),
206 self::update_note_field_if_changed( $note_in_db, $note, 'actions' ),
207 ),
208 true
209 );
210
211 if ( $need_save ) {
212 $note_in_db->save();
213 }
214 }
215
216
217 /**
218 * Get if the note has been actioned.
219 *
220 * @return bool
221 * @throws NotesUnavailableException Throws exception when notes are unavailable.
222 */
223 public static function has_note_been_actioned(): bool {
224 /**
225 * Data store instance.
226 *
227 * @var DataStore $data_store
228 */
229 $data_store = Notes::load_data_store();
230 $note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );
231
232 if ( ! empty( $note_ids ) ) {
233 $note = Notes::get_note( $note_ids[0] );
234
235 if ( $note instanceof Note && Note::E_WC_ADMIN_NOTE_ACTIONED === $note->get_status() ) {
236 return true;
237 }
238 }
239
240 return false;
241 }
242
243 /**
244 * Update a note field of note1 if it's different from note2 with getter and setter.
245 *
246 * @param Note|WC_Admin_Note $note1 Note to update.
247 * @param Note|WC_Admin_Note $note2 Note to compare against.
248 * @param string $field_name Field to update.
249 * @return bool True if the field was updated.
250 */
251 private static function update_note_field_if_changed( $note1, $note2, string $field_name ): bool {
252 // We need to serialize the stdObject to compare it.
253 /**
254 * Getter method for note1.
255 *
256 * @var callable $getter1
257 */
258 $getter1 = array( $note1, 'get_' . $field_name );
259 /**
260 * Getter method for note2.
261 *
262 * @var callable $getter2
263 */
264 $getter2 = array( $note2, 'get_' . $field_name );
265 $note1_field_value = self::possibly_convert_object_to_array(
266 call_user_func( $getter1 )
267 );
268 $note2_field_value = self::possibly_convert_object_to_array(
269 call_user_func( $getter2 )
270 );
271
272 if ( 'actions' === $field_name ) {
273 // We need to individually compare the action fields because action object from db is different from action object of note.
274 // For example, action object from db has "id".
275 $diff = array_udiff(
276 (array) $note1_field_value,
277 (array) $note2_field_value,
278 function ( $action1, $action2 ): int {
279 /**
280 * First action object.
281 *
282 * @var object{name?: string, label?: string, query?: string} $action1
283 */
284 /**
285 * Second action object.
286 *
287 * @var object{name?: string, label?: string, query?: string} $action2
288 */
289 if (
290 isset(
291 $action1->name,
292 $action2->name,
293 $action1->label,
294 $action2->label,
295 $action1->query,
296 $action2->query
297 ) &&
298 $action1->name === $action2->name &&
299 $action1->label === $action2->label &&
300 $action1->query === $action2->query
301 ) {
302 return 0;
303 }
304 return -1;
305 }
306 );
307 $need_update = count( $diff ) > 0;
308 } else {
309 $need_update = $note1_field_value !== $note2_field_value;
310 }
311
312 if ( $need_update ) {
313 /**
314 * Getter method for note2 field.
315 *
316 * @var callable $getter2_again
317 */
318 $getter2_again = array( $note2, 'get_' . $field_name );
319 /**
320 * Setter method for note1 field.
321 *
322 * @var callable $setter1
323 */
324 $setter1 = array( $note1, 'set_' . $field_name );
325 // Get note2 field again because it may have been changed during the comparison.
326 call_user_func( $setter1, call_user_func( $getter2_again ) );
327 return true;
328 }
329 return false;
330 }
331
332 /**
333 * Convert a value to array if it's a stdClass.
334 *
335 * @param mixed $obj variable to convert.
336 * @return mixed
337 */
338 private static function possibly_convert_object_to_array( $obj ) {
339 if ( $obj instanceof \stdClass ) {
340 return (array) $obj;
341 }
342 return $obj;
343 }
344 }
345