PluginProbe
UpdraftCentral Dashboard / trunk
UpdraftCentral Dashboard vtrunk
0.8.33 0.7.2 0.7.3 0.7.4 0.8.0 0.8.1 0.8.10 0.8.11 0.8.12 0.8.13 0.8.14 0.8.15 0.8.16 0.8.17 0.8.18 0.8.19 0.8.2 0.8.20 0.8.21 0.8.22 0.8.23 0.8.24 0.8.25 0.8.26 0.8.27 All 51 releases
updraftcentral / classes / site-meta.php

site-meta.php in UpdraftCentral Dashboard trunk, at classes/site-meta.php

1,233 lines 39.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // @codingStandardsIgnoreFile
3 if (!defined('UD_CENTRAL_DIR')) die('Security check');
4
5 /**
6 * Largely from wp-includes/meta.php and wp-includes/user.php
7 *
8 * Firstly is our constructor, which accepts + stores the table prefix.
9 * Next come the methods for accessing meta data.
10 * Next comes the WP infrastructure, which only required very minor modifications (mostly, removing the table name check and calling $this->function instead of functions directly
11 */
12 class UpdraftCentral_Site_Meta {
13 private $_uc_table_prefix;
14
15 public function __construct($table_prefix) {
16 $this->_uc_table_prefix = $table_prefix;
17 }
18
19 /**
20 * Retrieve metadata for the specified website.
21 *
22 * @param mixed $data The value on which the filters hooked are applied on.
23 * @param int $site_id Website ID of the object metadata is for
24 * @param string $meta_key Optional. Metadata key. If not specified, retrieve all metadata for the specified website.
25 * @param bool $single Optional, default is false.
26 * If true, return only the first value of the specified meta_key.
27 * This parameter has no effect if meta_key is not specified.
28 * @param bool|int $maximum_age Optional, default is false.
29 * If value is integer, only return data that is equal or less than the maximum age.
30 * Otherwise (if false), it will return all data with any age.
31 * @param bool $with_fields Indicates whether a complete record with field names will be returned
32 *
33 * @return mixed For single the metadata value, or array of values if single = false or the original value of $data
34 */
35 public function updraftcentral_get_site_metadata($data, $site_id, $meta_key = "", $single = false, $maximum_age = false, $with_fields = false) {
36 $ucdb = UpdraftCentral()->db;
37
38 $table = $this->_get_meta_table('site');
39 if (!$table) {
40 return $data;
41 }
42
43 if (!absint($site_id)) {
44 return $data;
45 }
46
47 if (!empty($meta_key)) {
48 $meta_key = wp_unslash($meta_key);
49
50 $meta_values = array();
51 if (false !== $maximum_age) {
52 if (!is_numeric($maximum_age)) {
53 return $data;
54 }
55
56 if ($with_fields) {
57 $meta_values = $ucdb->get_results($ucdb->prepare("SELECT * FROM $table WHERE meta_key = %s AND site_id = %d AND (UNIX_TIMESTAMP()-created) <= %s", $meta_key, $site_id, $maximum_age), ARRAY_A);
58 } else {
59 $meta_values = $ucdb->get_col($ucdb->prepare("SELECT meta_value FROM $table WHERE meta_key = %s AND site_id = %d AND (UNIX_TIMESTAMP()-created) <= %s", $meta_key, $site_id, $maximum_age));
60 }
61 } else {
62 if ($with_fields) {
63 $meta_values = $ucdb->get_results($ucdb->prepare("SELECT * FROM $table WHERE meta_key = %s AND site_id = %d", $meta_key, $site_id), ARRAY_A);
64 } else {
65 $meta_values = $ucdb->get_col($ucdb->prepare("SELECT meta_value FROM $table WHERE meta_key = %s AND site_id = %d", $meta_key, $site_id));
66 }
67 }
68 } else {
69 if ($with_fields) {
70 $meta_values = $ucdb->get_results($ucdb->prepare("SELECT * FROM $table WHERE site_id = %d", $site_id), ARRAY_A);
71 } else {
72 $meta_values = $ucdb->get_col($ucdb->prepare("SELECT meta_value FROM $table WHERE site_id = %d", $site_id));
73 }
74 }
75
76 if (empty($meta_values)) {
77 // N.B. Here, we're returning false if $meta_values is empty since we are
78 // shortcircuiting the result from the current query it is best to return
79 // the actual "false" value rather than returning the default $data value
80 // which can be null. A return value of null does not actually return this
81 // result as empty (which is our expected result if the query fails) because it will still check
82 // WordPress's own caching implementation and fill it if this call returns null.
83 return false;
84 } else {
85 if ($single) {
86 $meta_values = $meta_values[0];
87 if (!is_array($meta_values)) return UpdraftCentral()->maybe_json_decode($meta_values);
88 }
89
90 return array_map(array(UpdraftCentral(), 'maybe_json_decode'), $meta_values);
91 }
92 }
93
94 /**
95 * Retrieve the value of the "created" column from the sitemeta table
96 *
97 * @param mixed $data The value on which the filters hooked are applied on.
98 * @param int $site_id Website ID of the object metadata is for
99 * @param string $meta_key Metadata key. If not specified, retrieve all metadata for the specified website.
100 *
101 * @return mixed Created column value, or the origin $data value
102 */
103 public function updraftcentral_get_site_metadata_created($data, $site_id, $meta_key) {
104 $ucdb = UpdraftCentral()->db;
105
106 $table = $this->_get_meta_table('site');
107 if (!$table) {
108 return $data;
109 }
110
111 if (!absint($site_id)) {
112 return $data;
113 }
114
115 if (!isset($meta_key) || empty($meta_key)) {
116 return $data;
117 }
118
119 $meta_key = wp_unslash($meta_key);
120 $result = $ucdb->get_col($ucdb->prepare("SELECT created FROM $table WHERE meta_key = %s AND site_id = %d", $meta_key, $site_id));
121
122 if (empty($result)) {
123 return $data;
124 } else {
125 return $result[0];
126 }
127
128 }
129
130 /**
131 * Delete all site meta belonging to a particular site through its ID
132 *
133 * @param int $site_id Website ID of the object metadata is from
134 *
135 * @return boolean
136 */
137 public function delete_site_meta_by_site_id($site_id) {
138 $ucdb = UpdraftCentral()->db;
139
140 $table = $this->_get_meta_table('site');
141 if (!$table) {
142 return false;
143 }
144
145 if (!$site_id) {
146 return false;
147 }
148
149 $count = $ucdb->query($ucdb->prepare("DELETE FROM $table WHERE `site_id` = %d", $site_id));
150 if (!$count)
151 return false;
152
153 return true;
154 }
155
156 /**
157 * Add meta data field to a site.
158 *
159 * @since 3.0.0
160 *
161 * @param int $site_id Site ID.
162 * @param string $meta_key Metadata name.
163 * @param mixed $meta_value Metadata value.
164 * @param bool $unique Optional, default is false. Whether the same key should not be added.
165 *
166 * @return int|false Meta ID on success, false on failure.
167 */
168 public function add_site_meta($site_id, $meta_key, $meta_value, $unique = false) {
169 return $this->add_metadata('site', $site_id, $meta_key, $meta_value, $unique);
170 }
171
172 /**
173 * Remove metadata matching criteria from a site.
174 *
175 * You can match based on the key, or key and value. Removing based on key and
176 * value, will keep from removing duplicate metadata with the same key. It also
177 * allows removing all metadata matching key, if needed.
178 *
179 * @param int $site_id Site ID
180 * @param string $meta_key Metadata name.
181 * @param mixed $meta_value Optional. Metadata value.
182 *
183 * @return bool True on success, false on failure.
184 */
185 public function delete_site_meta($site_id, $meta_key, $meta_value = '') {
186 return $this->delete_metadata('site', $site_id, $meta_key, $meta_value);
187 }
188
189 /**
190 * Retrieve site meta field for a site.
191 *
192 * @param int $site_id Site ID.
193 * @param string $key Optional. The meta key to retrieve. By default, returns data for all keys.
194 * @param bool $single Whether to return a single value.
195 * @param bool|int $maximum_age Optional, default is false.
196 * If value is integer, only return data that is equal or less than the maximum age.
197 * Otherwise (if false), it will return all data with any age.
198 * @param bool $with_fields Indicates whether a complete record with field names will be returned
199 *
200 * @return mixed Will be an array if $single is false. Will be value of meta data field if $single is true.
201 */
202 public function get_site_meta($site_id, $key = '', $single = false, $maximum_age = false, $with_fields = false) {
203 return $this->get_metadata('site', $site_id, $key, $single, $maximum_age, $with_fields);
204 }
205
206 /**
207 * Update site meta field based on site ID.
208 *
209 * Use the $prev_value parameter to differentiate between meta fields with the
210 * same key and site ID.
211 *
212 * If the meta field for the site does not exist, it will be added.
213 *
214 * @param int $site_id Site ID.
215 * @param string $meta_key Metadata key.
216 * @param mixed $meta_value Metadata value.
217 * @param mixed $prev_value Optional. Previous value to check before removing.
218 *
219 * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
220 */
221 public function update_site_meta($site_id, $meta_key, $meta_value, $prev_value = '') {
222 return $this->update_metadata('site', $site_id, $meta_key, $meta_value, $prev_value);
223 }
224
225 /**
226 * Retrieve the name of the metadata table for the specified object type.
227 *
228 * @since 2.9.0
229 *
230 * @global wpdb $wpdb WordPress database abstraction object.
231 *
232 * @param string $type Type of object to get metadata table for (e.g., comment, post, or user)
233 *
234 * @return string|false Metadata table name, or false if no metadata table exists
235 */
236 private function _get_meta_table($type) {
237 $table_name = $type.'meta';
238
239 if ('site' == $type) {
240 $ucdb = UpdraftCentral()->db;
241 return $ucdb->base_prefix.$this->_uc_table_prefix.$table_name;
242 } else {
243 global $wpdb;
244 return $wpdb->base_prefix.$this->_uc_table_prefix.$table_name;
245 }
246 }
247
248 /**
249 * Add metadata for the specified object.
250 *
251 * @global wpdb $wpdb WordPress database abstraction object.
252 *
253 * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
254 * @param int $object_id ID of the object metadata is for
255 * @param string $meta_key Metadata key
256 * @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
257 * @param bool $unique Optional, default is false.
258 * Whether the specified metadata key should be unique for the object.
259 * If true, and the object already has a value for the specified metadata key,
260 * no change will be made.
261 *
262 * @return int|false The meta ID on success, false on failure.
263 */
264 public function add_metadata($meta_type, $object_id, $meta_key, $meta_value, $unique = false) {
265 if ('site' == $meta_type) {
266 $metadb = UpdraftCentral()->db;
267 } else {
268 global $wpdb;
269 $metadb = $wpdb;
270 }
271
272 if (!$meta_type || !$meta_key || !is_numeric($object_id)) {
273 return false;
274 }
275
276 $object_id = absint($object_id);
277 if (!$object_id) {
278 return false;
279 }
280
281 $table = $this->_get_meta_table($meta_type);
282 if (!$table) {
283 return false;
284 }
285
286 $column = sanitize_key($meta_type.'_id');
287
288 // expected_slashed ($meta_key)
289 $meta_key = wp_unslash($meta_key);
290 $meta_value = wp_unslash($meta_value);
291 $meta_value = $this->sanitize_meta($meta_key, $meta_value, $meta_type);
292
293 /**
294 * Filter whether to add metadata of a specific type.
295 *
296 * The dynamic portion of the hook, `$meta_type`, refers to the meta
297 * object type (comment, post, or user). Returning a non-null value
298 * will effectively short-circuit the public function.
299 *
300 * @since 3.1.0
301 *
302 * @param null|bool $check Whether to allow adding metadata for the given type.
303 * @param int $object_id Object ID.
304 * @param string $meta_key Meta key.
305 * @param mixed $meta_value Meta value. Must be serializable if non-scalar.
306 * @param bool $unique Whether the specified meta key should be unique
307 * for the object. Optional. Default false.
308 */
309 $check = apply_filters("add_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $unique);
310 if (null !== $check)
311 return $check;
312
313 if ($unique && $metadb->get_var($metadb->prepare(
314 "SELECT COUNT(*) FROM $table WHERE meta_key = %s AND $column = %d",
315 $meta_key, $object_id)))
316 return false;
317
318 $_meta_value = $meta_value;
319 $meta_value = UpdraftCentral()->maybe_json_encode($meta_value);
320
321 /*
322 * Fires immediately before meta of a specific type is added.
323 *
324 * The dynamic portion of the hook, `$meta_type`, refers to the meta
325 * object type (comment, post, or user).
326 *
327 * @since 3.1.0
328 *
329 * @param int $object_id Object ID.
330 * @param string $meta_key Meta key.
331 * @param mixed $meta_value Meta value.
332 */
333 do_action("add_{$meta_type}_meta", $object_id, $meta_key, $_meta_value);
334
335 $result = $metadb->insert($table, array(
336 $column => $object_id,
337 'meta_key' => $meta_key,
338 'meta_value' => $meta_value,
339 'created' => time(),
340 ));
341
342 if (!$result)
343 return false;
344
345 $mid = (int) $metadb->insert_id;
346
347 wp_cache_delete($object_id, $meta_type.'_meta');
348
349 /*
350 * Fires immediately after meta of a specific type is added.
351 *
352 * The dynamic portion of the hook, `$meta_type`, refers to the meta
353 * object type (comment, post, or user).
354 *
355 * @since 2.9.0
356 *
357 * @param int $mid The meta ID after successful update.
358 * @param int $object_id Object ID.
359 * @param string $meta_key Meta key.
360 * @param mixed $meta_value Meta value.
361 */
362 do_action("added_{$meta_type}_meta", $mid, $object_id, $meta_key, $_meta_value);
363
364 return $mid;
365 }
366
367 /**
368 * Update metadata for the specified object. If no value already exists for the specified object
369 * ID and metadata key, the metadata will be added.
370 *
371 * @since 2.9.0
372 *
373 * @global wpdb $wpdb WordPress database abstraction object.
374 *
375 * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
376 * @param int $object_id ID of the object metadata is for
377 * @param string $meta_key Metadata key
378 * @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
379 * @param mixed $prev_value Optional. If specified, only update existing metadata entries with
380 * the specified value. Otherwise, update all entries.
381 *
382 * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
383 */
384 public function update_metadata($meta_type, $object_id, $meta_key, $meta_value, $prev_value = '') {
385 if ('site' == $meta_type) {
386 $metadb = UpdraftCentral()->db;
387 } else {
388 global $wpdb;
389 $metadb = $wpdb;
390 }
391
392 if (!$meta_type || !$meta_key || !is_numeric($object_id)) {
393 return false;
394 }
395
396 $object_id = absint($object_id);
397 if (!$object_id) {
398 return false;
399 }
400
401 $table = $this->_get_meta_table($meta_type);
402 if (!$table) {
403 return false;
404 }
405
406 $column = sanitize_key($meta_type.'_id');
407 $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
408
409 // expected_slashed ($meta_key)
410 $meta_key = wp_unslash($meta_key);
411 $passed_value = $meta_value;
412 $meta_value = wp_unslash($meta_value);
413 $meta_value = $this->sanitize_meta($meta_key, $meta_value, $meta_type);
414
415 /**
416 * Filter whether to update metadata of a specific type.
417 *
418 * The dynamic portion of the hook, `$meta_type`, refers to the meta
419 * object type (comment, post, or user). Returning a non-null value
420 * will effectively short-circuit the public function.
421 *
422 * @since 3.1.0
423 *
424 * @param null|bool $check Whether to allow updating metadata for the given type.
425 * @param int $object_id Object ID.
426 * @param string $meta_key Meta key.
427 * @param mixed $meta_value Meta value. Must be serializable if non-scalar.
428 * @param mixed $prev_value Optional. If specified, only update existing
429 * metadata entries with the specified value.
430 * Otherwise, update all entries.
431 */
432 $check = apply_filters("update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value);
433 if (null !== $check) return (bool) $check;
434
435 // Compare existing value to new value if no prev value given and the key exists only once.
436 if (empty($prev_value)) {
437 $old_value = $this->get_metadata($meta_type, $object_id, $meta_key);
438
439 $is_countable = function_exists('is_countable') ? is_countable($old_value) : is_array($old_value);
440 if ($is_countable && 1 === count($old_value)) {
441 if ($old_value[0] === $meta_value) return false;
442 }
443 }
444
445 $meta_ids = $metadb->get_col($metadb->prepare("SELECT $id_column FROM $table WHERE meta_key = %s AND $column = %d", $meta_key, $object_id));
446 if (empty($meta_ids)) {
447 return $this->add_metadata($meta_type, $object_id, $meta_key, $passed_value);
448 }
449
450 $_meta_value = $meta_value;
451 $meta_value = UpdraftCentral()->maybe_json_encode($meta_value);
452 $created = time();
453
454 $data = compact('meta_value', 'created');
455 $where = array($column => $object_id, 'meta_key' => $meta_key);
456
457 if (!empty($prev_value)) {
458 $prev_value = UpdraftCentral()->maybe_json_encode($prev_value);
459 $where['meta_value'] = $prev_value;
460 }
461
462 foreach ($meta_ids as $meta_id) {
463 /*
464 * Fires immediately before updating metadata of a specific type.
465 *
466 * The dynamic portion of the hook, `$meta_type`, refers to the meta
467 * object type (comment, post, or user).
468 *
469 * @since 2.9.0
470 *
471 * @param int $meta_id ID of the metadata entry to update.
472 * @param int $object_id Object ID.
473 * @param string $meta_key Meta key.
474 * @param mixed $meta_value Meta value.
475 */
476 do_action("update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value);
477 }
478
479 if ('post' == $meta_type) {
480 foreach ($meta_ids as $meta_id) {
481 /*
482 * Fires immediately before updating a post's metadata.
483 *
484 * @since 2.9.0
485 *
486 * @param int $meta_id ID of metadata entry to update.
487 * @param int $object_id Object ID.
488 * @param string $meta_key Meta key.
489 * @param mixed $meta_value Meta value.
490 */
491 do_action('update_postmeta', $meta_id, $object_id, $meta_key, $meta_value);
492 }
493 }
494
495 $result = $metadb->update($table, $data, $where);
496 if (!$result)
497 return false;
498
499 wp_cache_delete($object_id, $meta_type.'_meta');
500
501 foreach ($meta_ids as $meta_id) {
502 /*
503 * Fires immediately after updating metadata of a specific type.
504 *
505 * The dynamic portion of the hook, `$meta_type`, refers to the meta
506 * object type (comment, post, or user).
507 *
508 * @since 2.9.0
509 *
510 * @param int $meta_id ID of updated metadata entry.
511 * @param int $object_id Object ID.
512 * @param string $meta_key Meta key.
513 * @param mixed $meta_value Meta value.
514 */
515 do_action("updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value);
516 }
517
518 if ('post' == $meta_type) {
519 foreach ($meta_ids as $meta_id) {
520 /*
521 * Fires immediately after updating a post's metadata.
522 *
523 * @since 2.9.0
524 *
525 * @param int $meta_id ID of updated metadata entry.
526 * @param int $object_id Object ID.
527 * @param string $meta_key Meta key.
528 * @param mixed $meta_value Meta value.
529 */
530 do_action('updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value);
531 }
532 }
533
534 return true;
535 }
536
537 /**
538 * Delete metadata for the specified object.
539 *
540 * @since 2.9.0
541 *
542 * @global wpdb $wpdb WordPress database abstraction object.
543 *
544 * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
545 * @param int $object_id ID of the object metadata is for
546 * @param string $meta_key Metadata key
547 * @param mixed $meta_value Optional. Metadata value. Must be serializable if non-scalar. If specified, only delete
548 * metadata entries with this value. Otherwise, delete all entries with the specified meta_key.
549 * Pass `null, `false`, or an empty string to skip this check. (For backward compatibility,
550 * it is not possible to pass an empty string to delete those entries with an empty string
551 * for a value.)
552 * @param bool $delete_all Optional, default is false. If true, delete matching metadata entries for all objects,
553 * ignoring the specified object_id. Otherwise, only delete matching metadata entries for
554 * the specified object_id.
555 *
556 * @return bool True on successful delete, false on failure.
557 */
558 public function delete_metadata($meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false) {
559 if ('site' == $meta_type) {
560 $metadb = UpdraftCentral()->db;
561 } else {
562 global $wpdb;
563 $metadb = $wpdb;
564 }
565
566 if (!$meta_type || !$meta_key || !is_numeric($object_id) && !$delete_all) {
567 return false;
568 }
569
570 $object_id = absint($object_id);
571 if (!$object_id && !$delete_all) {
572 return false;
573 }
574
575 $table = $this->_get_meta_table($meta_type);
576 if (!$table) {
577 return false;
578 }
579
580 $type_column = sanitize_key($meta_type.'_id');
581 $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
582 // expected_slashed ($meta_key)
583 $meta_key = wp_unslash($meta_key);
584 $meta_value = wp_unslash($meta_value);
585
586 /*
587 * Filter whether to delete metadata of a specific type.
588 *
589 * The dynamic portion of the hook, `$meta_type`, refers to the meta
590 * object type (comment, post, or user). Returning a non-null value
591 * will effectively short-circuit the public function.
592 *
593 * @since 3.1.0
594 *
595 * @param null|bool $delete Whether to allow metadata deletion of the given type.
596 * @param int $object_id Object ID.
597 * @param string $meta_key Meta key.
598 * @param mixed $meta_value Meta value. Must be serializable if non-scalar.
599 * @param bool $delete_all Whether to delete the matching metadata entries
600 * for all objects, ignoring the specified $object_id.
601 * Default false.
602 */
603 $check = apply_filters("delete_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $delete_all);
604 if (null !== $check)
605 return (bool) $check;
606
607 $_meta_value = $meta_value;
608 $meta_value = UpdraftCentral()->maybe_json_encode($meta_value);
609
610 $query = $metadb->prepare("SELECT $id_column FROM $table WHERE meta_key = %s", $meta_key);
611
612 if (!$delete_all)
613 $query .= $metadb->prepare(" AND $type_column = %d", $object_id);
614
615 if ('' !== $meta_value && null !== $meta_value && false !== $meta_value)
616 $query .= $metadb->prepare(' AND meta_value = %s', $meta_value);
617
618 $meta_ids = $metadb->get_col($query);
619 if (!count($meta_ids))
620 return false;
621
622 if ($delete_all)
623 $object_ids = $metadb->get_col($metadb->prepare("SELECT $type_column FROM $table WHERE meta_key = %s", $meta_key));
624
625 /*
626 * Fires immediately before deleting metadata of a specific type.
627 *
628 * The dynamic portion of the hook, `$meta_type`, refers to the meta
629 * object type (comment, post, or user).
630 *
631 * @since 3.1.0
632 *
633 * @param array $meta_ids An array of metadata entry IDs to delete.
634 * @param int $object_id Object ID.
635 * @param string $meta_key Meta key.
636 * @param mixed $meta_value Meta value.
637 */
638 do_action("delete_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value);
639
640 // Old-style action.
641 if ('post' == $meta_type) {
642 /*
643 * Fires immediately before deleting metadata for a post.
644 *
645 * @since 2.9.0
646 *
647 * @param array $meta_ids An array of post metadata entry IDs to delete.
648 */
649 do_action('delete_postmeta', $meta_ids);
650 }
651
652 $query = "DELETE FROM $table WHERE $id_column IN( ".implode(',', $meta_ids).' )';
653
654 $count = $metadb->query($query);
655
656 if (!$count)
657 return false;
658
659 if ($delete_all) {
660 foreach ((array) $object_ids as $o_id) {
661 wp_cache_delete($o_id, $meta_type.'_meta');
662 }
663 } else {
664 wp_cache_delete($object_id, $meta_type.'_meta');
665 }
666
667 /*
668 * Fires immediately after deleting metadata of a specific type.
669 *
670 * The dynamic portion of the hook name, `$meta_type`, refers to the meta
671 * object type (comment, post, or user).
672 *
673 * @since 2.9.0
674 *
675 * @param array $meta_ids An array of deleted metadata entry IDs.
676 * @param int $object_id Object ID.
677 * @param string $meta_key Meta key.
678 * @param mixed $meta_value Meta value.
679 */
680 do_action("deleted_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value);
681
682 // Old-style action.
683 if ('post' == $meta_type) {
684 /*
685 * Fires immediately after deleting metadata for a post.
686 *
687 * @since 2.9.0
688 *
689 * @param array $meta_ids An array of deleted post metadata entry IDs.
690 */
691 do_action('deleted_postmeta', $meta_ids);
692 }
693
694 return true;
695 }
696
697 /**
698 * Retrieve metadata for the specified object.
699 *
700 * @since 2.9.0
701 *
702 * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
703 * @param int $object_id ID of the object metadata is for
704 * @param string $meta_key Optional. Metadata key. If not specified, retrieve all metadata for
705 * the specified object.
706 * @param bool $single Optional, default is false.
707 * If true, return only the first value of the specified meta_key.
708 * This parameter has no effect if meta_key is not specified.
709 * @param bool|int $maximum_age Optional, default is false.
710 * If value is integer, only return data that is equal or less than the maximum age.
711 * Otherwise (if false), it will return all data with any age.
712 * @param bool $with_fields Indicates whether a complete record with field names will be returned
713 *
714 * @return mixed Single metadata value, or array of values
715 */
716 public function get_metadata($meta_type, $object_id, $meta_key = '', $single = false, $maximum_age = false, $with_fields = false) {
717
718 if (!$meta_type || !is_numeric($object_id)) return false;
719
720 $object_id = absint($object_id);
721 if (!$object_id) return false;
722
723 /*
724 * Filter whether to retrieve metadata of a specific type.
725 *
726 * The dynamic portion of the hook, `$meta_type`, refers to the meta
727 * object type (comment, post, or user). Returning a non-null value
728 * will effectively short-circuit the public function.
729 *
730 * @since 3.1.0
731 *
732 * @param null|array|string $value The value get_metadata() should return - a single metadata value,
733 * or an array of values.
734 * @param int $object_id Object ID.
735 * @param string $meta_key Meta key.
736 * @param bool $single Whether to return only the first value of the specified $meta_key.
737 * @param int $maximum_age Determines how fresh the data that needs to be pulled.
738 * @param bool $with_fields Indicates whether a complete record with field names will be returned
739 */
740 $check = apply_filters("get_{$meta_type}_metadata", null, $object_id, $meta_key, $single, $maximum_age, $with_fields);
741 if (null !== $check) {
742 if ($single && is_array($check) && isset($check[0])) {
743 return $check[0];
744 } else {
745 return $check;
746 }
747 }
748
749 $meta_cache = wp_cache_get($object_id, $meta_type.'_meta');
750
751 if (!$meta_cache) {
752 $meta_cache = $this->update_meta_cache($meta_type, array($object_id));
753 $meta_cache = $meta_cache[$object_id];
754 }
755
756 if (!$meta_key) return $meta_cache;
757
758 if (isset($meta_cache[$meta_key])) {
759 if ($single)
760 return UpdraftCentral()->maybe_json_decode($meta_cache[$meta_key][0]);
761 else
762 return array_map(array(UpdraftCentral(), 'maybe_json_decode'), $meta_cache[$meta_key]);
763 }
764
765 if ($single) {
766 return '';
767 } else {
768 return array();
769 }
770 }
771
772 /**
773 * Determine if a meta key is set for a given object.
774 *
775 * @since 3.3.0
776 *
777 * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
778 * @param int $object_id ID of the object metadata is for
779 * @param string $meta_key Metadata key.
780 *
781 * @return bool True of the key is set, false if not.
782 */
783 public function metadata_exists($meta_type, $object_id, $meta_key) {
784 if (!$meta_type || !is_numeric($object_id)) {
785 return false;
786 }
787
788 $object_id = absint($object_id);
789 if (!$object_id) {
790 return false;
791 }
792
793 /* This filter is documented in wp-includes/meta.php */
794 $check = apply_filters("get_{$meta_type}_metadata", null, $object_id, $meta_key, true);
795 if (null !== $check)
796 return (bool) $check;
797
798 $meta_cache = wp_cache_get($object_id, $meta_type.'_meta');
799
800 if (!$meta_cache) {
801 $meta_cache = $this->update_meta_cache($meta_type, array($object_id));
802 $meta_cache = $meta_cache[$object_id];
803 }
804
805 if (isset($meta_cache[ $meta_key ]))
806 return true;
807
808 return false;
809 }
810
811 /**
812 * Get meta data by meta ID.
813 *
814 * @since 3.3.0
815 *
816 * @global wpdb $wpdb WordPress database abstraction object.
817 *
818 * @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
819 * @param int $meta_id ID for a specific meta row
820 *
821 * @return object|false Meta object or false.
822 */
823 public function get_metadata_by_mid($meta_type, $meta_id) {
824 if ('site' == $meta_type) {
825 $metadb = UpdraftCentral()->db;
826 } else {
827 global $wpdb;
828 $metadb = $wpdb;
829 }
830
831 if (!$meta_type || !is_numeric($meta_id)) {
832 return false;
833 }
834
835 $meta_id = absint($meta_id);
836 if (!$meta_id) {
837 return false;
838 }
839
840 $table = $this->_get_meta_table($meta_type);
841 if (!$table) {
842 return false;
843 }
844
845 $id_column = ('user' == $meta_type) ? 'umeta_id' : 'meta_id';
846
847 $meta = $metadb->get_row($metadb->prepare("SELECT * FROM $table WHERE $id_column = %d", $meta_id));
848
849 if (empty($meta))
850 return false;
851
852 if (isset($meta->meta_value))
853 $meta->meta_value = UpdraftCentral()->maybe_json_decode($meta->meta_value);
854
855 return $meta;
856 }
857
858 /**
859 * Update meta data by meta ID.
860 *
861 * @since 3.3.0
862 *
863 * @global wpdb $wpdb WordPress database abstraction object.
864 *
865 * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
866 * @param int $meta_id ID for a specific meta row
867 * @param string $meta_value Metadata value
868 * @param string $meta_key Optional, you can provide a meta key to update it
869 *
870 * @return bool True on successful update, false on failure.
871 */
872 public function update_metadata_by_mid($meta_type, $meta_id, $meta_value, $meta_key = false) {
873 if ('site' == $meta_type) {
874 $metadb = UpdraftCentral()->db;
875 } else {
876 global $wpdb;
877 $metadb = $wpdb;
878 }
879
880 // Make sure everything is valid.
881 if (!$meta_type || !is_numeric($meta_id)) {
882 return false;
883 }
884
885 $meta_id = absint($meta_id);
886 if (!$meta_id) {
887 return false;
888 }
889
890 $table = $this->_get_meta_table($meta_type);
891 if (!$table) {
892 return false;
893 }
894
895 $column = sanitize_key($meta_type.'_id');
896 $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
897
898 // Fetch the meta and go on if it's found.
899 if ($meta = $this->get_metadata_by_mid($meta_type, $meta_id)) {
900 $original_key = $meta->meta_key;
901 $object_id = $meta->{$column};
902
903 // If a new meta_key (last parameter) was specified, change the meta key,
904 // otherwise use the original key in the update statement.
905 if (false === $meta_key) {
906 $meta_key = $original_key;
907 } elseif (!is_string($meta_key)) {
908 return false;
909 }
910
911 // Sanitize the meta
912 $_meta_value = $meta_value;
913 $meta_value = $this->sanitize_meta($meta_key, $meta_value, $meta_type);
914 $meta_value = UpdraftCentral()->maybe_json_encode($meta_value);
915
916 // Format the data query arguments.
917 $data = array(
918 'meta_key' => $meta_key,
919 'meta_value' => $meta_value,
920 );
921
922 // Format the where query arguments.
923 $where = array();
924 $where[$id_column] = $meta_id;
925
926 /* This action is documented in wp-includes/meta.php */
927 do_action("update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value);
928
929 if ('post' == $meta_type) {
930 /* This action is documented in wp-includes/meta.php */
931 do_action('update_postmeta', $meta_id, $object_id, $meta_key, $meta_value);
932 }
933
934 // Run the update query, all fields in $data are %s, $where is a %d.
935 $result = $metadb->update($table, $data, $where, '%s', '%d');
936 if (!$result)
937 return false;
938
939 // Clear the caches.
940 wp_cache_delete($object_id, $meta_type.'_meta');
941
942 /* This action is documented in wp-includes/meta.php */
943 do_action("updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value);
944
945 if ('post' == $meta_type) {
946 /* This action is documented in wp-includes/meta.php */
947 do_action('updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value);
948 }
949
950 return true;
951 }
952
953 // And if the meta was not found.
954 return false;
955 }
956
957 /**
958 * Delete meta data by meta ID.
959 *
960 * @since 3.3.0
961 *
962 * @global wpdb $wpdb WordPress database abstraction object.
963 *
964 * @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
965 * @param int $meta_id ID for a specific meta row
966 *
967 * @return bool True on successful delete, false on failure.
968 */
969 public function delete_metadata_by_mid($meta_type, $meta_id) {
970 if ('site' == $meta_type) {
971 $metadb = UpdraftCentral()->db;
972 } else {
973 global $wpdb;
974 $metadb = $wpdb;
975 }
976
977 // Make sure everything is valid.
978 if (!$meta_type || !is_numeric($meta_id)) {
979 return false;
980 }
981
982 $meta_id = absint($meta_id);
983 if (!$meta_id) {
984 return false;
985 }
986
987 $table = $this->_get_meta_table($meta_type);
988 if (!$table) {
989 return false;
990 }
991
992 // object and id columns
993 $column = sanitize_key($meta_type.'_id');
994 $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
995
996 // Fetch the meta and go on if it's found.
997 if ($meta = $this->get_metadata_by_mid($meta_type, $meta_id)) {
998 $object_id = $meta->{$column};
999
1000 /* This action is documented in wp-includes/meta.php */
1001 do_action("delete_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value);
1002
1003 // Old-style action.
1004 if ('post' == $meta_type || 'comment' == $meta_type) {
1005 /*
1006 * Fires immediately before deleting post or comment metadata of a specific type.
1007 *
1008 * The dynamic portion of the hook, `$meta_type`, refers to the meta
1009 * object type (post or comment).
1010 *
1011 * @since 3.4.0
1012 *
1013 * @param int $meta_id ID of the metadata entry to delete.
1014 */
1015 do_action("delete_{$meta_type}meta", $meta_id);
1016 }
1017
1018 // Run the query, will return true if deleted, false otherwise
1019 $result = (bool) $metadb->delete($table, array($id_column => $meta_id));
1020
1021 // Clear the caches.
1022 wp_cache_delete($object_id, $meta_type.'_meta');
1023
1024 /* This action is documented in wp-includes/meta.php */
1025 do_action("deleted_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value);
1026
1027 // Old-style action.
1028 if ('post' == $meta_type || 'comment' == $meta_type) {
1029 /*
1030 * Fires immediately after deleting post or comment metadata of a specific type.
1031 *
1032 * The dynamic portion of the hook, `$meta_type`, refers to the meta
1033 * object type (post or comment).
1034 *
1035 * @since 3.4.0
1036 *
1037 * @param int $meta_ids Deleted metadata entry ID.
1038 */
1039 do_action("deleted_{$meta_type}meta", $meta_id);
1040 }
1041
1042 return $result;
1043
1044 }
1045
1046 // Meta id was not found.
1047 return false;
1048 }
1049
1050 /**
1051 * Update the metadata cache for the specified objects.
1052 *
1053 * @since 2.9.0
1054 *
1055 * @global wpdb $wpdb WordPress database abstraction object.
1056 *
1057 * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
1058 * @param int|array $object_ids Array or comma delimited list of object IDs to update cache for
1059 *
1060 * @return array|false Metadata cache for the specified objects, or false on failure.
1061 */
1062 public function update_meta_cache($meta_type, $object_ids) {
1063 if ('site' == $meta_type) {
1064 $metadb = UpdraftCentral()->db;
1065 } else {
1066 global $wpdb;
1067 $metadb = $wpdb;
1068 }
1069
1070 if (!$meta_type || !$object_ids) {
1071 return false;
1072 }
1073
1074 $table = $this->_get_meta_table($meta_type);
1075 if (!$table) {
1076 return false;
1077 }
1078
1079 $column = sanitize_key($meta_type.'_id');
1080
1081 if (!is_array($object_ids)) {
1082 $object_ids = preg_replace('|[^0-9,]|', '', $object_ids);
1083 $object_ids = explode(',', $object_ids);
1084 }
1085
1086 $object_ids = array_map('intval', $object_ids);
1087
1088 $cache_key = $meta_type.'_meta';
1089 $ids = array();
1090 $cache = array();
1091 foreach ($object_ids as $id) {
1092 $cached_object = wp_cache_get($id, $cache_key);
1093 if (false === $cached_object)
1094 $ids[] = $id;
1095 else
1096 $cache[$id] = $cached_object;
1097 }
1098
1099 if (empty($ids))
1100 return $cache;
1101
1102 // Get meta info
1103 $id_list = implode(',', $ids);
1104 $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
1105 $meta_list = $metadb->get_results("SELECT $column, meta_key, meta_value FROM $table WHERE $column IN ($id_list) ORDER BY $id_column ASC", ARRAY_A);
1106
1107 if (!empty($meta_list)) {
1108 foreach ($meta_list as $metarow) {
1109 $mpid = intval($metarow[$column]);
1110 $mkey = $metarow['meta_key'];
1111 $mval = $metarow['meta_value'];
1112
1113 // Force subkeys to be array type:
1114 if (!isset($cache[$mpid]) || !is_array($cache[$mpid]))
1115 $cache[$mpid] = array();
1116 if (!isset($cache[$mpid][$mkey]) || !is_array($cache[$mpid][$mkey]))
1117 $cache[$mpid][$mkey] = array();
1118
1119 // Add a value to the current pid/key:
1120 $cache[$mpid][$mkey][] = $mval;
1121 }
1122 }
1123
1124 foreach ($ids as $id) {
1125 if (!isset($cache[$id]))
1126 $cache[$id] = array();
1127 wp_cache_add($id, $cache[$id], $cache_key);
1128 }
1129
1130 return $cache;
1131 }
1132
1133 /**
1134 * Given a meta query, generates SQL clauses to be appended to a main query.
1135 *
1136 * @since 3.2.0
1137 * @see WP_Meta_Query
1138 *
1139 * @param array $meta_query A meta query.
1140 * @param string $type Type of meta.
1141 * @param string $primary_table Primary database table name.
1142 * @param string $primary_id_column Primary ID column name.
1143 * @param object $context Optional. The main query object
1144 *
1145 * @return array Associative array of `JOIN` and `WHERE` SQL.
1146 */
1147 public function get_meta_sql($meta_query, $type, $primary_table, $primary_id_column, $context = null) {
1148 $meta_query_obj = new WP_Meta_Query($meta_query);
1149
1150 return $meta_query_obj->get_sql($type, $primary_table, $primary_id_column, $context);
1151 }
1152
1153 /**
1154 * Determine whether a meta key is protected.
1155 *
1156 * @since 3.1.3
1157 *
1158 * @param string $meta_key Meta key
1159 * @param string|null $meta_type
1160 *
1161 * @return bool True if the key is protected, false otherwise.
1162 */
1163 public function is_protected_meta($meta_key, $meta_type = null) {
1164 $protected = ('_' == $meta_key[0]);
1165
1166 /*
1167 * Filter whether a meta key is protected.
1168 *
1169 * @since 3.2.0
1170 *
1171 * @param bool $protected Whether the key is protected. Default false.
1172 * @param string $meta_key Meta key.
1173 * @param string $meta_type Meta type.
1174 */
1175 return apply_filters('is_protected_meta', $protected, $meta_key, $meta_type);
1176 }
1177
1178 /**
1179 * Sanitize meta value.
1180 *
1181 * @since 3.1.3
1182 *
1183 * @param string $meta_key Meta key
1184 * @param mixed $meta_value Meta value to sanitize
1185 * @param string $meta_type Type of meta
1186 *
1187 * @return mixed Sanitized $meta_value
1188 */
1189 public function sanitize_meta($meta_key, $meta_value, $meta_type) {
1190
1191 /*
1192 * Filter the sanitization of a specific meta key of a specific meta type.
1193 *
1194 * The dynamic portions of the hook name, `$meta_type`, and `$meta_key`,
1195 * refer to the metadata object type (comment, post, or user) and the meta
1196 * key value,
1197 * respectively.
1198 *
1199 * @since 3.3.0
1200 *
1201 * @param mixed $meta_value Meta value to sanitize.
1202 * @param string $meta_key Meta key.
1203 * @param string $meta_type Meta type.
1204 */
1205 return apply_filters("sanitize_{$meta_type}_meta_{$meta_key}", $meta_value, $meta_key, $meta_type);
1206 }
1207
1208 /**
1209 * Register meta key.
1210 *
1211 * @since 3.3.0
1212 *
1213 * @param string $meta_type Type of meta
1214 * @param string $meta_key Meta key
1215 * @param string|array $sanitize_callback A public function or method to call when sanitizing the value of $meta_key.
1216 * @param string|array $auth_callback Optional. A public function or method to call when performing edit_post_meta, add_post_meta, and delete_post_meta capability checks.
1217 */
1218 public function register_meta($meta_type, $meta_key, $sanitize_callback, $auth_callback = null) {
1219 if (is_callable($sanitize_callback))
1220 add_filter("sanitize_{$meta_type}_meta_{$meta_key}", $sanitize_callback, 10, 3);
1221
1222 if (empty($auth_callback)) {
1223 if ($this->is_protected_meta($meta_key, $meta_type))
1224 $auth_callback = '__return_false';
1225 else
1226 $auth_callback = '__return_true';
1227 }
1228
1229 if (is_callable($auth_callback))
1230 add_filter("auth_{$meta_type}_meta_{$meta_key}", $auth_callback, 10, 6);
1231 }
1232 }
1233