PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.1
WooCommerce v10.9.1
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 / Admin / Notes / DataStore.php
woocommerce / src / Admin / Notes Last commit date
DataStore.php 4 weeks ago DeprecatedNotes.php 1 year ago Note.php 4 weeks ago NoteTraits.php 5 months ago Notes.php 4 weeks ago NotesUnavailableException.php 4 years ago
DataStore.php
558 lines
1 <?php
2 /**
3 * WC Admin Note Data_Store class file.
4 */
5
6 namespace Automattic\WooCommerce\Admin\Notes;
7
8 defined( 'ABSPATH' ) || exit;
9
10 /**
11 * WC Admin Note Data Store (Custom Tables)
12 */
13 class DataStore extends \WC_Data_Store_WP implements \WC_Object_Data_Store_Interface {
14 // Extensions should define their own contexts and use them to avoid applying woocommerce_note_where_clauses when not needed.
15 const WC_ADMIN_NOTE_OPER_GLOBAL = 'global';
16
17 /**
18 * Fixed values written to the deprecated `layout` and `image` columns. The columns and the
19 * values themselves will be removed in a follow-up release once the deprecation cycle ends.
20 */
21 const DEPRECATED_LAYOUT_VALUE = 'plain';
22 const DEPRECATED_IMAGE_VALUE = '';
23
24 /**
25 * Method to create a new note in the database.
26 *
27 * @param Note $note Admin note.
28 */
29 public function create( &$note ) {
30 $date_created = time();
31 $note->set_date_created( $date_created );
32
33 global $wpdb;
34
35 $note_to_be_inserted = array(
36 'name' => $note->get_name(),
37 'type' => $note->get_type(),
38 'locale' => $note->get_locale(),
39 'title' => $note->get_title(),
40 'content' => $note->get_content(),
41 'status' => $note->get_status(),
42 'source' => $note->get_source(),
43 'is_snoozable' => (int) $note->get_is_snoozable(),
44 'layout' => self::DEPRECATED_LAYOUT_VALUE,
45 'image' => self::DEPRECATED_IMAGE_VALUE,
46 'is_deleted' => (int) $note->get_is_deleted(),
47 'is_read' => (int) $note->get_is_read(),
48 );
49
50 $note_to_be_inserted['content_data'] = wp_json_encode( $note->get_content_data() );
51 $note_to_be_inserted['date_created'] = gmdate( 'Y-m-d H:i:s', $date_created );
52 $note_to_be_inserted['date_reminder'] = null;
53
54 $wpdb->insert( $wpdb->prefix . 'wc_admin_notes', $note_to_be_inserted );
55 $note_id = $wpdb->insert_id;
56 $note->set_id( $note_id );
57 $this->save_actions( $note );
58 $note->apply_changes();
59
60 /**
61 * Fires when an admin note is created.
62 *
63 * @param int $note_id Note ID.
64 */
65 do_action( 'woocommerce_note_created', $note_id );
66 }
67
68 /**
69 * Method to read a note.
70 *
71 * @param Note $note Admin note.
72 * @throws \Exception Throws exception when invalid data is found.
73 */
74 public function read( &$note ) {
75 global $wpdb;
76
77 $note->set_defaults();
78 $note_row = false;
79
80 $note_id = $note->get_id();
81 if ( 0 !== $note_id || '0' !== $note_id ) {
82 $note_row = $wpdb->get_row(
83 $wpdb->prepare(
84 "SELECT * FROM {$wpdb->prefix}wc_admin_notes WHERE note_id = %d LIMIT 1",
85 $note->get_id()
86 )
87 );
88 }
89
90 if ( 0 === $note->get_id() || '0' === $note->get_id() ) {
91 $this->read_actions( $note );
92 $note->set_object_read( true );
93
94 /**
95 * Fires when an admin note is loaded.
96 *
97 * @param int $note_id Note ID.
98 */
99 do_action( 'woocommerce_note_loaded', $note );
100 } elseif ( $note_row ) {
101 $note->set_name( $note_row->name );
102 $note->set_type( $note_row->type );
103 $note->set_locale( $note_row->locale );
104 $note->set_title( $note_row->title );
105 $note->set_content( $note_row->content );
106
107 // The default for 'content_value' used to be an array, so there might be rows with invalid data!
108 $content_data = json_decode( $note_row->content_data );
109 if ( ! $content_data ) {
110 $content_data = new \stdClass();
111 } elseif ( is_array( $content_data ) ) {
112 $content_data = (object) $content_data;
113 }
114 $note->set_content_data( $content_data );
115
116 $note->set_status( $note_row->status );
117 $note->set_source( $note_row->source );
118 $note->set_date_created( $note_row->date_created );
119 $note->set_date_reminder( $note_row->date_reminder );
120 $note->set_is_snoozable( (bool) $note_row->is_snoozable );
121 $note->set_is_deleted( (bool) $note_row->is_deleted );
122 isset( $note_row->is_read ) && $note->set_is_read( (bool) $note_row->is_read );
123 $this->read_actions( $note );
124 $note->set_object_read( true );
125
126 /**
127 * Fires when an admin note is loaded.
128 *
129 * @param int $note_id Note ID.
130 */
131 do_action( 'woocommerce_note_loaded', $note );
132 } else {
133 throw new \Exception( __( 'Invalid admin note', 'woocommerce' ) );
134 }
135 }
136
137 /**
138 * Updates a note in the database.
139 *
140 * @param Note $note Admin note.
141 */
142 public function update( &$note ) {
143 global $wpdb;
144
145 if ( $note->get_id() ) {
146 $date_created = $note->get_date_created();
147 $date_created_timestamp = $date_created->getTimestamp();
148 $date_created_to_db = gmdate( 'Y-m-d H:i:s', $date_created_timestamp );
149
150 $date_reminder = $note->get_date_reminder();
151 if ( is_null( $date_reminder ) ) {
152 $date_reminder_to_db = null;
153 } else {
154 $date_reminder_timestamp = $date_reminder->getTimestamp();
155 $date_reminder_to_db = gmdate( 'Y-m-d H:i:s', $date_reminder_timestamp );
156 }
157
158 $wpdb->update(
159 $wpdb->prefix . 'wc_admin_notes',
160 array(
161 'name' => $note->get_name(),
162 'type' => $note->get_type(),
163 'locale' => $note->get_locale(),
164 'title' => $note->get_title(),
165 'content' => $note->get_content(),
166 'content_data' => wp_json_encode( $note->get_content_data() ),
167 'status' => $note->get_status(),
168 'source' => $note->get_source(),
169 'date_created' => $date_created_to_db,
170 'date_reminder' => $date_reminder_to_db,
171 'is_snoozable' => (int) $note->get_is_snoozable(),
172 'layout' => self::DEPRECATED_LAYOUT_VALUE,
173 'image' => self::DEPRECATED_IMAGE_VALUE,
174 'is_deleted' => (int) $note->get_is_deleted(),
175 'is_read' => (int) $note->get_is_read(),
176 ),
177 array( 'note_id' => $note->get_id() )
178 );
179 }
180
181 $this->save_actions( $note );
182 $note->apply_changes();
183
184 /**
185 * Fires when an admin note is updated.
186 *
187 * @param int $note_id Note ID.
188 */
189 do_action( 'woocommerce_note_updated', $note->get_id() );
190 }
191
192 /**
193 * Deletes a note from the database.
194 *
195 * @param Note $note Admin note.
196 * @param array $args Array of args to pass to the delete method (not used).
197 */
198 public function delete( &$note, $args = array() ) {
199 $note_id = $note->get_id();
200 if ( $note_id ) {
201 global $wpdb;
202 $wpdb->delete( $wpdb->prefix . 'wc_admin_notes', array( 'note_id' => $note_id ) );
203 $wpdb->delete( $wpdb->prefix . 'wc_admin_note_actions', array( 'note_id' => $note_id ) );
204 $note->set_id( null );
205 }
206
207 /**
208 * Fires when an admin note is deleted.
209 *
210 * @param int $note_id Note ID.
211 */
212 do_action( 'woocommerce_note_deleted', $note_id );
213 }
214
215 /**
216 * Read actions from the database.
217 *
218 * @param Note $note Admin note.
219 */
220 private function read_actions( &$note ) {
221 global $wpdb;
222
223 $db_actions = $wpdb->get_results(
224 $wpdb->prepare(
225 "SELECT action_id, name, label, query, status, actioned_text, nonce_action, nonce_name
226 FROM {$wpdb->prefix}wc_admin_note_actions
227 WHERE note_id = %d",
228 $note->get_id()
229 )
230 );
231
232 $note_actions = array();
233
234 if ( $db_actions ) {
235 foreach ( $db_actions as $action ) {
236 $note_actions[] = (object) array(
237 'id' => (int) $action->action_id,
238 'name' => $action->name,
239 'label' => $action->label,
240 'query' => $action->query,
241 'status' => $action->status,
242 'actioned_text' => $action->actioned_text,
243 'nonce_action' => $action->nonce_action,
244 'nonce_name' => $action->nonce_name,
245 );
246 }
247 }
248
249 $note->set_actions( $note_actions );
250 }
251
252 /**
253 * Save actions to the database.
254 * This function clears old actions, then re-inserts new if any changes are found.
255 *
256 * @param Note $note Note object.
257 *
258 * @return bool|void
259 */
260 private function save_actions( &$note ) {
261 global $wpdb;
262
263 $changed_props = array_keys( $note->get_changes() );
264
265 if ( ! in_array( 'actions', $changed_props, true ) ) {
266 return false;
267 }
268
269 // Process action removal. Actions are removed from
270 // the note if they aren't part of the changeset.
271 // See Note::add_action().
272 $changed_actions = $note->get_actions( 'edit' );
273 $actions_to_keep = array();
274
275 foreach ( $changed_actions as $action ) {
276 if ( ! empty( $action->id ) ) {
277 $actions_to_keep[] = (int) $action->id;
278 }
279 }
280
281 $clear_actions_query = $wpdb->prepare(
282 "DELETE FROM {$wpdb->prefix}wc_admin_note_actions WHERE note_id = %d",
283 $note->get_id()
284 );
285
286 if ( $actions_to_keep ) {
287 $clear_actions_query .= sprintf( ' AND action_id NOT IN (%s)', implode( ',', $actions_to_keep ) );
288 }
289
290 $wpdb->query( $clear_actions_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
291
292 // Update/insert the actions in this changeset.
293 foreach ( $changed_actions as $action ) {
294 $action_data = array(
295 'note_id' => $note->get_id(),
296 'name' => $action->name,
297 'label' => $action->label,
298 'query' => $action->query,
299 'status' => $action->status,
300 'actioned_text' => $action->actioned_text,
301 'nonce_action' => $action->nonce_action,
302 'nonce_name' => $action->nonce_name,
303 );
304
305 $data_format = array(
306 '%d',
307 '%s',
308 '%s',
309 '%s',
310 '%s',
311 '%s',
312 '%s',
313 '%s',
314 );
315
316 if ( ! empty( $action->id ) ) {
317 $action_data['action_id'] = $action->id;
318 $data_format[] = '%d';
319 }
320
321 $wpdb->replace(
322 $wpdb->prefix . 'wc_admin_note_actions',
323 $action_data,
324 $data_format
325 );
326 }
327
328 // Update actions from DB (to grab new IDs).
329 $this->read_actions( $note );
330 }
331
332 /**
333 * Return an ordered list of notes.
334 *
335 * @param array $args Query arguments.
336 * @param string $context Optional argument that the woocommerce_note_where_clauses filter can use to determine whether to apply extra conditions. Extensions should define their own contexts and use them to avoid adding to notes where clauses when not needed.
337 * @return array An array of objects containing a note id.
338 */
339 public function get_notes( $args = array(), $context = self::WC_ADMIN_NOTE_OPER_GLOBAL ) {
340 global $wpdb;
341
342 $defaults = array(
343 'per_page' => get_option( 'posts_per_page' ),
344 'page' => 1,
345 'order' => 'DESC',
346 'orderby' => 'date_created',
347 );
348 $args = wp_parse_args( $args, $defaults );
349
350 $offset = $args['per_page'] * ( $args['page'] - 1 );
351 $where_clauses = $this->get_notes_where_clauses( $args, $context );
352
353 // sanitize order and orderby.
354 $order_by = '`' . str_replace( '`', '', $args['orderby'] ) . '`';
355 $order_dir = 'asc' === strtolower( $args['order'] ) ? 'ASC' : 'DESC';
356
357 $query = $wpdb->prepare(
358 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
359 "SELECT * FROM {$wpdb->prefix}wc_admin_notes WHERE 1=1{$where_clauses} ORDER BY {$order_by} {$order_dir} LIMIT %d, %d",
360 $offset,
361 $args['per_page']
362 );
363
364 return $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
365 }
366
367 /**
368 * Return an ordered list of notes, without paging or applying the 'woocommerce_note_where_clauses' filter.
369 * INTERNAL: This method is not intended to be used by external code, and may change without notice.
370 *
371 * @param array $args Query arguments.
372 * @return array An array of database records.
373 */
374 public function lookup_notes( $args = array() ) {
375 global $wpdb;
376
377 $defaults = array(
378 'order' => 'DESC',
379 'orderby' => 'date_created',
380 );
381 $args = wp_parse_args( $args, $defaults );
382
383 $where_clauses = $this->args_to_where_clauses( $args );
384
385 // sanitize order and orderby.
386 $order_by = '`' . str_replace( '`', '', $args['orderby'] ) . '`';
387 $order_dir = 'asc' === strtolower( $args['order'] ) ? 'ASC' : 'DESC';
388
389 $query = "SELECT * FROM {$wpdb->prefix}wc_admin_notes WHERE 1=1{$where_clauses} ORDER BY {$order_by} {$order_dir}";
390
391 return $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
392 }
393
394 /**
395 * Return a count of notes.
396 *
397 * @param string $type Comma separated list of note types.
398 * @param string $status Comma separated list of statuses.
399 * @param string $context Optional argument that the woocommerce_note_where_clauses filter can use to determine whether to apply extra conditions. Extensions should define their own contexts and use them to avoid adding to notes where clauses when not needed.
400 * @return string Count of objects with given type, status and context.
401 */
402 public function get_notes_count( $type = array(), $status = array(), $context = self::WC_ADMIN_NOTE_OPER_GLOBAL ) {
403 global $wpdb;
404
405 $where_clauses = $this->get_notes_where_clauses(
406 array(
407 'type' => $type,
408 'status' => $status,
409 ),
410 $context
411 );
412
413 if ( ! empty( $where_clauses ) ) {
414 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
415 return $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}wc_admin_notes WHERE 1=1{$where_clauses}" );
416 }
417
418 return $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}wc_admin_notes" );
419 }
420
421 /**
422 * Parses the query arguments passed in as arrays and escapes the values.
423 *
424 * @param array $args the query arguments.
425 * @param string $key the key of the specific argument.
426 * @param array|null $allowed_types optional allowed_types if only a specific set is allowed.
427 * @return array the escaped array of argument values.
428 */
429 private function get_escaped_arguments_array_by_key( $args = array(), $key = '', $allowed_types = null ) {
430 $arg_array = array();
431 if ( isset( $args[ $key ] ) ) {
432 foreach ( $args[ $key ] as $args_type ) {
433 $args_type = trim( $args_type );
434 $allowed = is_null( $allowed_types ) || in_array( $args_type, $allowed_types, true );
435 if ( $allowed ) {
436 $arg_array[] = sprintf( "'%s'", esc_sql( $args_type ) );
437 }
438 }
439 }
440 return $arg_array;
441 }
442
443 /**
444 * Return where clauses for getting notes by status and type. For use in both the count and listing queries.
445 * Applies woocommerce_note_where_clauses filter.
446 *
447 * @uses args_to_where_clauses
448 * @param array $args Array of args to pass.
449 * @param string $context Optional argument that the woocommerce_note_where_clauses filter can use to determine whether to apply extra conditions. Extensions should define their own contexts and use them to avoid adding to notes where clauses when not needed.
450 * @return string Where clauses for the query.
451 */
452 public function get_notes_where_clauses( $args = array(), $context = self::WC_ADMIN_NOTE_OPER_GLOBAL ) {
453 $where_clauses = $this->args_to_where_clauses( $args );
454
455 /**
456 * Filter the notes WHERE clause before retrieving the data.
457 *
458 * Allows modification of the notes select criterial.
459 *
460 * @param string $where_clauses The generated WHERE clause.
461 * @param array $args The original arguments for the request.
462 * @param string $context Optional argument that the woocommerce_note_where_clauses filter can use to determine whether to apply extra conditions. Extensions should define their own contexts and use them to avoid adding to notes where clauses when not needed.
463 */
464 return apply_filters( 'woocommerce_note_where_clauses', $where_clauses, $args, $context );
465 }
466
467 /**
468 * Return where clauses for notes queries without applying woocommerce_note_where_clauses filter.
469 * INTERNAL: This method is not intended to be used by external code, and may change without notice.
470 *
471 * @param array $args Array of arguments for query conditionals.
472 * @return string Where clauses.
473 */
474 protected function args_to_where_clauses( $args = array() ) {
475 $allowed_types = Note::get_allowed_types();
476 $where_type_array = $this->get_escaped_arguments_array_by_key( $args, 'type', $allowed_types );
477
478 $allowed_statuses = Note::get_allowed_statuses();
479 $where_status_array = $this->get_escaped_arguments_array_by_key( $args, 'status', $allowed_statuses );
480
481 $escaped_is_deleted = '';
482 if ( isset( $args['is_deleted'] ) ) {
483 $escaped_is_deleted = esc_sql( $args['is_deleted'] );
484 }
485
486 $where_name_array = $this->get_escaped_arguments_array_by_key( $args, 'name' );
487 $where_excluded_name_array = $this->get_escaped_arguments_array_by_key( $args, 'excluded_name' );
488 $where_source_array = $this->get_escaped_arguments_array_by_key( $args, 'source' );
489
490 $escaped_where_types = implode( ',', $where_type_array );
491 $escaped_where_status = implode( ',', $where_status_array );
492 $escaped_where_names = implode( ',', $where_name_array );
493 $escaped_where_excluded_names = implode( ',', $where_excluded_name_array );
494 $escaped_where_source = implode( ',', $where_source_array );
495 $where_clauses = '';
496
497 if ( ! empty( $escaped_where_types ) ) {
498 $where_clauses .= " AND type IN ($escaped_where_types)";
499 }
500
501 if ( ! empty( $escaped_where_status ) ) {
502 $where_clauses .= " AND status IN ($escaped_where_status)";
503 }
504
505 if ( ! empty( $escaped_where_names ) ) {
506 $where_clauses .= " AND name IN ($escaped_where_names)";
507 }
508
509 if ( ! empty( $escaped_where_excluded_names ) ) {
510 $where_clauses .= " AND name NOT IN ($escaped_where_excluded_names)";
511 }
512
513 if ( ! empty( $escaped_where_source ) ) {
514 $where_clauses .= " AND source IN ($escaped_where_source)";
515 }
516
517 if ( isset( $args['is_read'] ) ) {
518 $where_clauses .= $args['is_read'] ? ' AND is_read = 1' : ' AND is_read = 0';
519 }
520
521 $where_clauses .= $escaped_is_deleted ? ' AND is_deleted = 1' : ' AND is_deleted = 0';
522
523 return $where_clauses;
524 }
525
526 /**
527 * Find all the notes with a given name.
528 *
529 * @param string $name Name to search for.
530 * @return array An array of matching note ids.
531 */
532 public function get_notes_with_name( $name ) {
533 global $wpdb;
534 return $wpdb->get_col(
535 $wpdb->prepare(
536 "SELECT note_id FROM {$wpdb->prefix}wc_admin_notes WHERE name = %s ORDER BY note_id ASC",
537 $name
538 )
539 );
540 }
541
542 /**
543 * Find the ids of all notes with a given type.
544 *
545 * @param string $note_type Type to search for.
546 * @return array An array of matching note ids.
547 */
548 public function get_note_ids_by_type( $note_type ) {
549 global $wpdb;
550 return $wpdb->get_col(
551 $wpdb->prepare(
552 "SELECT note_id FROM {$wpdb->prefix}wc_admin_notes WHERE type = %s ORDER BY note_id ASC",
553 $note_type
554 )
555 );
556 }
557 }
558