[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Core Metadata API 4 * 5 * Functions for retrieving and manipulating metadata of various WordPress object types. Metadata 6 * for an object is a represented by a simple key-value pair. Objects may contain multiple 7 * metadata entries that share the same key and differ only in their value. 8 * 9 * @package WordPress 10 * @subpackage Meta 11 */ 12 13 require ABSPATH . WPINC . '/class-wp-metadata-lazyloader.php'; 14 15 /** 16 * Adds metadata for the specified object. 17 * 18 * @since 2.9.0 19 * 20 * @global wpdb $wpdb WordPress database abstraction object. 21 * 22 * @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 23 * or any other object type with an associated meta table. 24 * @param int $object_id ID of the object metadata is for. 25 * @param string $meta_key Metadata key. 26 * @param mixed $meta_value Metadata value. Arrays and objects are stored as serialized data and 27 * will be returned as the same type when retrieved. Other data types will 28 * be stored as strings in the database: 29 * - false is stored and retrieved as an empty string ('') 30 * - true is stored and retrieved as '1' 31 * - numbers (both integer and float) are stored and retrieved as strings 32 * Must be serializable if non-scalar. 33 * @param bool $unique Optional. Whether the specified metadata key should be unique for the object. 34 * If true, and the object already has a value for the specified metadata key, 35 * no change will be made. Default false. 36 * @return int|false The meta ID on success, false on failure. 37 */ 38 function add_metadata( $meta_type, $object_id, $meta_key, $meta_value, $unique = false ) { 39 global $wpdb; 40 41 if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) { 42 return false; 43 } 44 45 $object_id = absint( $object_id ); 46 if ( ! $object_id ) { 47 return false; 48 } 49 50 $table = _get_meta_table( $meta_type ); 51 if ( ! $table ) { 52 return false; 53 } 54 55 $meta_subtype = get_object_subtype( $meta_type, $object_id ); 56 57 $column = sanitize_key( $meta_type . '_id' ); 58 59 // expected_slashed ($meta_key) 60 $meta_key = wp_unslash( $meta_key ); 61 $meta_value = wp_unslash( $meta_value ); 62 $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type, $meta_subtype ); 63 64 /** 65 * Short-circuits adding metadata of a specific type. 66 * 67 * The dynamic portion of the hook name, `$meta_type`, refers to the meta object type 68 * (post, comment, term, user, or any other type with an associated meta table). 69 * Returning a non-null value will effectively short-circuit the function. 70 * 71 * Possible hook names include: 72 * 73 * - `add_post_metadata` 74 * - `add_comment_metadata` 75 * - `add_term_metadata` 76 * - `add_user_metadata` 77 * 78 * @since 3.1.0 79 * 80 * @param null|bool $check Whether to allow adding metadata for the given type. 81 * @param int $object_id ID of the object metadata is for. 82 * @param string $meta_key Metadata key. 83 * @param mixed $meta_value Metadata value. Must be serializable if non-scalar. 84 * @param bool $unique Whether the specified meta key should be unique for the object. 85 */ 86 $check = apply_filters( "add_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $unique ); 87 if ( null !== $check ) { 88 return $check; 89 } 90 91 if ( $unique && $wpdb->get_var( 92 $wpdb->prepare( 93 "SELECT COUNT(*) FROM $table WHERE meta_key = %s AND $column = %d", 94 $meta_key, 95 $object_id 96 ) 97 ) ) { 98 return false; 99 } 100 101 $_meta_value = $meta_value; 102 $meta_value = maybe_serialize( $meta_value ); 103 104 /** 105 * Fires immediately before meta of a specific type is added. 106 * 107 * The dynamic portion of the hook name, `$meta_type`, refers to the meta object type 108 * (post, comment, term, user, or any other type with an associated meta table). 109 * 110 * Possible hook names include: 111 * 112 * - `add_post_meta` 113 * - `add_comment_meta` 114 * - `add_term_meta` 115 * - `add_user_meta` 116 * 117 * @since 3.1.0 118 * 119 * @param int $object_id ID of the object metadata is for. 120 * @param string $meta_key Metadata key. 121 * @param mixed $_meta_value Metadata value. 122 */ 123 do_action( "add_{$meta_type}_meta", $object_id, $meta_key, $_meta_value ); 124 125 $result = $wpdb->insert( 126 $table, 127 array( 128 $column => $object_id, 129 'meta_key' => $meta_key, 130 'meta_value' => $meta_value, 131 ) 132 ); 133 134 if ( ! $result ) { 135 return false; 136 } 137 138 $mid = (int) $wpdb->insert_id; 139 140 wp_cache_delete( $object_id, $meta_type . '_meta' ); 141 142 /** 143 * Fires immediately after meta of a specific type is added. 144 * 145 * The dynamic portion of the hook name, `$meta_type`, refers to the meta object type 146 * (post, comment, term, user, or any other type with an associated meta table). 147 * 148 * Possible hook names include: 149 * 150 * - `added_post_meta` 151 * - `added_comment_meta` 152 * - `added_term_meta` 153 * - `added_user_meta` 154 * 155 * @since 2.9.0 156 * 157 * @param int $mid The meta ID after successful update. 158 * @param int $object_id ID of the object metadata is for. 159 * @param string $meta_key Metadata key. 160 * @param mixed $_meta_value Metadata value. 161 */ 162 do_action( "added_{$meta_type}_meta", $mid, $object_id, $meta_key, $_meta_value ); 163 164 return $mid; 165 } 166 167 /** 168 * Updates metadata for the specified object. If no value already exists for the specified object 169 * ID and metadata key, the metadata will be added. 170 * 171 * @since 2.9.0 172 * 173 * @global wpdb $wpdb WordPress database abstraction object. 174 * 175 * @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 176 * or any other object type with an associated meta table. 177 * @param int $object_id ID of the object metadata is for. 178 * @param string $meta_key Metadata key. 179 * @param mixed $meta_value Metadata value. Must be serializable if non-scalar. 180 * @param mixed $prev_value Optional. Previous value to check before updating. 181 * If specified, only update existing metadata entries with 182 * this value. Otherwise, update all entries. Default empty string. 183 * @return int|bool The new meta field ID if a field with the given key didn't exist 184 * and was therefore added, true on successful update, 185 * false on failure or if the value passed to the function 186 * is the same as the one that is already in the database. 187 */ 188 function update_metadata( $meta_type, $object_id, $meta_key, $meta_value, $prev_value = '' ) { 189 global $wpdb; 190 191 if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) { 192 return false; 193 } 194 195 $object_id = absint( $object_id ); 196 if ( ! $object_id ) { 197 return false; 198 } 199 200 $table = _get_meta_table( $meta_type ); 201 if ( ! $table ) { 202 return false; 203 } 204 205 $meta_subtype = get_object_subtype( $meta_type, $object_id ); 206 207 $column = sanitize_key( $meta_type . '_id' ); 208 $id_column = ( 'user' === $meta_type ) ? 'umeta_id' : 'meta_id'; 209 210 // expected_slashed ($meta_key) 211 $raw_meta_key = $meta_key; 212 $meta_key = wp_unslash( $meta_key ); 213 $passed_value = $meta_value; 214 $meta_value = wp_unslash( $meta_value ); 215 $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type, $meta_subtype ); 216 217 /** 218 * Short-circuits updating metadata of a specific type. 219 * 220 * The dynamic portion of the hook name, `$meta_type`, refers to the meta object type 221 * (post, comment, term, user, or any other type with an associated meta table). 222 * Returning a non-null value will effectively short-circuit the function. 223 * 224 * Possible hook names include: 225 * 226 * - `update_post_metadata` 227 * - `update_comment_metadata` 228 * - `update_term_metadata` 229 * - `update_user_metadata` 230 * 231 * @since 3.1.0 232 * 233 * @param null|bool $check Whether to allow updating metadata for the given type. 234 * @param int $object_id ID of the object metadata is for. 235 * @param string $meta_key Metadata key. 236 * @param mixed $meta_value Metadata value. Must be serializable if non-scalar. 237 * @param mixed $prev_value Optional. Previous value to check before updating. 238 * If specified, only update existing metadata entries with 239 * this value. Otherwise, update all entries. 240 */ 241 $check = apply_filters( "update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value ); 242 if ( null !== $check ) { 243 return (bool) $check; 244 } 245 246 // Compare existing value to new value if no prev value given and the key exists only once. 247 if ( empty( $prev_value ) ) { 248 $old_value = get_metadata_raw( $meta_type, $object_id, $meta_key ); 249 if ( is_countable( $old_value ) && count( $old_value ) === 1 ) { 250 if ( $old_value[0] === $meta_value ) { 251 return false; 252 } 253 } 254 } 255 256 $meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s AND $column = %d", $meta_key, $object_id ) ); 257 if ( empty( $meta_ids ) ) { 258 return add_metadata( $meta_type, $object_id, $raw_meta_key, $passed_value ); 259 } 260 261 $_meta_value = $meta_value; 262 $meta_value = maybe_serialize( $meta_value ); 263 264 $data = compact( 'meta_value' ); 265 $where = array( 266 $column => $object_id, 267 'meta_key' => $meta_key, 268 ); 269 270 if ( ! empty( $prev_value ) ) { 271 $prev_value = maybe_serialize( $prev_value ); 272 $where['meta_value'] = $prev_value; 273 } 274 275 foreach ( $meta_ids as $meta_id ) { 276 /** 277 * Fires immediately before updating metadata of a specific type. 278 * 279 * The dynamic portion of the hook name, `$meta_type`, refers to the meta object type 280 * (post, comment, term, user, or any other type with an associated meta table). 281 * 282 * Possible hook names include: 283 * 284 * - `update_post_meta` 285 * - `update_comment_meta` 286 * - `update_term_meta` 287 * - `update_user_meta` 288 * 289 * @since 2.9.0 290 * 291 * @param int $meta_id ID of the metadata entry to update. 292 * @param int $object_id ID of the object metadata is for. 293 * @param string $meta_key Metadata key. 294 * @param mixed $_meta_value Metadata value. 295 */ 296 do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value ); 297 298 if ( 'post' === $meta_type ) { 299 /** 300 * Fires immediately before updating a post's metadata. 301 * 302 * @since 2.9.0 303 * 304 * @param int $meta_id ID of metadata entry to update. 305 * @param int $object_id Post ID. 306 * @param string $meta_key Metadata key. 307 * @param mixed $meta_value Metadata value. This will be a PHP-serialized string representation of the value 308 * if the value is an array, an object, or itself a PHP-serialized string. 309 */ 310 do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value ); 311 } 312 } 313 314 $result = $wpdb->update( $table, $data, $where ); 315 if ( ! $result ) { 316 return false; 317 } 318 319 wp_cache_delete( $object_id, $meta_type . '_meta' ); 320 321 foreach ( $meta_ids as $meta_id ) { 322 /** 323 * Fires immediately after updating metadata of a specific type. 324 * 325 * The dynamic portion of the hook name, `$meta_type`, refers to the meta object type 326 * (post, comment, term, user, or any other type with an associated meta table). 327 * 328 * Possible hook names include: 329 * 330 * - `updated_post_meta` 331 * - `updated_comment_meta` 332 * - `updated_term_meta` 333 * - `updated_user_meta` 334 * 335 * @since 2.9.0 336 * 337 * @param int $meta_id ID of updated metadata entry. 338 * @param int $object_id ID of the object metadata is for. 339 * @param string $meta_key Metadata key. 340 * @param mixed $_meta_value Metadata value. 341 */ 342 do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value ); 343 344 if ( 'post' === $meta_type ) { 345 /** 346 * Fires immediately after updating a post's metadata. 347 * 348 * @since 2.9.0 349 * 350 * @param int $meta_id ID of updated metadata entry. 351 * @param int $object_id Post ID. 352 * @param string $meta_key Metadata key. 353 * @param mixed $meta_value Metadata value. This will be a PHP-serialized string representation of the value 354 * if the value is an array, an object, or itself a PHP-serialized string. 355 */ 356 do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value ); 357 } 358 } 359 360 return true; 361 } 362 363 /** 364 * Deletes metadata for the specified object. 365 * 366 * @since 2.9.0 367 * 368 * @global wpdb $wpdb WordPress database abstraction object. 369 * 370 * @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 371 * or any other object type with an associated meta table. 372 * @param int $object_id ID of the object metadata is for. 373 * @param string $meta_key Metadata key. 374 * @param mixed $meta_value Optional. Metadata value. Must be serializable if non-scalar. 375 * If specified, only delete metadata entries with this value. 376 * Otherwise, delete all entries with the specified meta_key. 377 * Pass `null`, `false`, or an empty string to skip this check. 378 * (For backward compatibility, it is not possible to pass an empty string 379 * to delete those entries with an empty string for a value.) 380 * Default empty string. 381 * @param bool $delete_all Optional. If true, delete matching metadata entries for all objects, 382 * ignoring the specified object_id. Otherwise, only delete 383 * matching metadata entries for the specified object_id. Default false. 384 * @return bool True on successful delete, false on failure. 385 */ 386 function delete_metadata( $meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false ) { 387 global $wpdb; 388 389 if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) && ! $delete_all ) { 390 return false; 391 } 392 393 $object_id = absint( $object_id ); 394 if ( ! $object_id && ! $delete_all ) { 395 return false; 396 } 397 398 $table = _get_meta_table( $meta_type ); 399 if ( ! $table ) { 400 return false; 401 } 402 403 $type_column = sanitize_key( $meta_type . '_id' ); 404 $id_column = ( 'user' === $meta_type ) ? 'umeta_id' : 'meta_id'; 405 406 // expected_slashed ($meta_key) 407 $meta_key = wp_unslash( $meta_key ); 408 $meta_value = wp_unslash( $meta_value ); 409 410 /** 411 * Short-circuits deleting metadata of a specific type. 412 * 413 * The dynamic portion of the hook name, `$meta_type`, refers to the meta object type 414 * (post, comment, term, user, or any other type with an associated meta table). 415 * Returning a non-null value will effectively short-circuit the function. 416 * 417 * Possible hook names include: 418 * 419 * - `delete_post_metadata` 420 * - `delete_comment_metadata` 421 * - `delete_term_metadata` 422 * - `delete_user_metadata` 423 * 424 * @since 3.1.0 425 * 426 * @param null|bool $delete Whether to allow metadata deletion of the given type. 427 * @param int $object_id ID of the object metadata is for. 428 * @param string $meta_key Metadata key. 429 * @param mixed $meta_value Metadata value. Must be serializable if non-scalar. 430 * @param bool $delete_all Whether to delete the matching metadata entries 431 * for all objects, ignoring the specified $object_id. 432 * Default false. 433 */ 434 $check = apply_filters( "delete_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $delete_all ); 435 if ( null !== $check ) { 436 return (bool) $check; 437 } 438 439 $_meta_value = $meta_value; 440 $meta_value = maybe_serialize( $meta_value ); 441 442 $query = $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s", $meta_key ); 443 444 if ( ! $delete_all ) { 445 $query .= $wpdb->prepare( " AND $type_column = %d", $object_id ); 446 } 447 448 if ( '' !== $meta_value && null !== $meta_value && false !== $meta_value ) { 449 $query .= $wpdb->prepare( ' AND meta_value = %s', $meta_value ); 450 } 451 452 $meta_ids = $wpdb->get_col( $query ); 453 if ( ! count( $meta_ids ) ) { 454 return false; 455 } 456 457 if ( $delete_all ) { 458 if ( '' !== $meta_value && null !== $meta_value && false !== $meta_value ) { 459 $object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $type_column FROM $table WHERE meta_key = %s AND meta_value = %s", $meta_key, $meta_value ) ); 460 } else { 461 $object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $type_column FROM $table WHERE meta_key = %s", $meta_key ) ); 462 } 463 } 464 465 /** 466 * Fires immediately before deleting metadata of a specific type. 467 * 468 * The dynamic portion of the hook name, `$meta_type`, refers to the meta object type 469 * (post, comment, term, user, or any other type with an associated meta table). 470 * 471 * Possible hook names include: 472 * 473 * - `delete_post_meta` 474 * - `delete_comment_meta` 475 * - `delete_term_meta` 476 * - `delete_user_meta` 477 * 478 * @since 3.1.0 479 * 480 * @param string[] $meta_ids An array of metadata entry IDs to delete. 481 * @param int $object_id ID of the object metadata is for. 482 * @param string $meta_key Metadata key. 483 * @param mixed $_meta_value Metadata value. 484 */ 485 do_action( "delete_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value ); 486 487 // Old-style action. 488 if ( 'post' === $meta_type ) { 489 /** 490 * Fires immediately before deleting metadata for a post. 491 * 492 * @since 2.9.0 493 * 494 * @param string[] $meta_ids An array of metadata entry IDs to delete. 495 */ 496 do_action( 'delete_postmeta', $meta_ids ); 497 } 498 499 $query = "DELETE FROM $table WHERE $id_column IN( " . implode( ',', $meta_ids ) . ' )'; 500 501 $count = $wpdb->query( $query ); 502 503 if ( ! $count ) { 504 return false; 505 } 506 507 if ( $delete_all ) { 508 $data = (array) $object_ids; 509 } else { 510 $data = array( $object_id ); 511 } 512 wp_cache_delete_multiple( $data, $meta_type . '_meta' ); 513 514 /** 515 * Fires immediately after deleting metadata of a specific type. 516 * 517 * The dynamic portion of the hook name, `$meta_type`, refers to the meta object type 518 * (post, comment, term, user, or any other type with an associated meta table). 519 * 520 * Possible hook names include: 521 * 522 * - `deleted_post_meta` 523 * - `deleted_comment_meta` 524 * - `deleted_term_meta` 525 * - `deleted_user_meta` 526 * 527 * @since 2.9.0 528 * 529 * @param string[] $meta_ids An array of metadata entry IDs to delete. 530 * @param int $object_id ID of the object metadata is for. 531 * @param string $meta_key Metadata key. 532 * @param mixed $_meta_value Metadata value. 533 */ 534 do_action( "deleted_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value ); 535 536 // Old-style action. 537 if ( 'post' === $meta_type ) { 538 /** 539 * Fires immediately after deleting metadata for a post. 540 * 541 * @since 2.9.0 542 * 543 * @param string[] $meta_ids An array of metadata entry IDs to delete. 544 */ 545 do_action( 'deleted_postmeta', $meta_ids ); 546 } 547 548 return true; 549 } 550 551 /** 552 * Retrieves the value of a metadata field for the specified object type and ID. 553 * 554 * If the meta field exists, a single value is returned if `$single` is true, 555 * or an array of values if it's false. 556 * 557 * If the meta field does not exist, the result depends on get_metadata_default(). 558 * By default, an empty string is returned if `$single` is true, or an empty array 559 * if it's false. 560 * 561 * @since 2.9.0 562 * 563 * @see get_metadata_raw() 564 * @see get_metadata_default() 565 * 566 * @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 567 * or any other object type with an associated meta table. 568 * @param int $object_id ID of the object metadata is for. 569 * @param string $meta_key Optional. Metadata key. If not specified, retrieve all metadata for 570 * the specified object. Default empty string. 571 * @param bool $single Optional. If true, return only the first value of the specified `$meta_key`. 572 * This parameter has no effect if `$meta_key` is not specified. Default false. 573 * @return mixed An array of values if `$single` is false. 574 * The value of the meta field if `$single` is true. 575 * False for an invalid `$object_id` (non-numeric, zero, or negative value), 576 * or if `$meta_type` is not specified. 577 * An empty array if a valid but non-existing object ID is passed and `$single` is false. 578 * An empty string if a valid but non-existing object ID is passed and `$single` is true. 579 * Note: Non-serialized values are returned as strings: 580 * - false values are returned as empty strings ('') 581 * - true values are returned as '1' 582 * - numbers (both integer and float) are returned as strings 583 * Arrays and objects retain their original type. 584 */ 585 function get_metadata( $meta_type, $object_id, $meta_key = '', $single = false ) { 586 $value = get_metadata_raw( $meta_type, $object_id, $meta_key, $single ); 587 if ( ! is_null( $value ) ) { 588 return $value; 589 } 590 591 return get_metadata_default( $meta_type, $object_id, $meta_key, $single ); 592 } 593 594 /** 595 * Retrieves raw metadata value for the specified object. 596 * 597 * @since 5.5.0 598 * 599 * @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 600 * or any other object type with an associated meta table. 601 * @param int $object_id ID of the object metadata is for. 602 * @param string $meta_key Optional. Metadata key. If not specified, retrieve all metadata for 603 * the specified object. Default empty string. 604 * @param bool $single Optional. If true, return only the first value of the specified `$meta_key`. 605 * This parameter has no effect if `$meta_key` is not specified. Default false. 606 * @return mixed An array of values if `$single` is false. 607 * The value of the meta field if `$single` is true. 608 * False for an invalid `$object_id` (non-numeric, zero, or negative value), 609 * or if `$meta_type` is not specified. 610 * Null if the value does not exist. 611 */ 612 function get_metadata_raw( $meta_type, $object_id, $meta_key = '', $single = false ) { 613 if ( ! $meta_type || ! is_numeric( $object_id ) ) { 614 return false; 615 } 616 617 $object_id = absint( $object_id ); 618 if ( ! $object_id ) { 619 return false; 620 } 621 622 /** 623 * Short-circuits the return value of a meta field. 624 * 625 * The dynamic portion of the hook name, `$meta_type`, refers to the meta object type 626 * (post, comment, term, user, or any other type with an associated meta table). 627 * Returning a non-null value will effectively short-circuit the function. 628 * 629 * Possible filter names include: 630 * 631 * - `get_post_metadata` 632 * - `get_comment_metadata` 633 * - `get_term_metadata` 634 * - `get_user_metadata` 635 * 636 * @since 3.1.0 637 * @since 5.5.0 Added the `$meta_type` parameter. 638 * 639 * @param mixed $value The value to return, either a single metadata value or an array 640 * of values depending on the value of `$single`. Default null. 641 * @param int $object_id ID of the object metadata is for. 642 * @param string $meta_key Metadata key. 643 * @param bool $single Whether to return only the first value of the specified `$meta_key`. 644 * @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 645 * or any other object type with an associated meta table. 646 */ 647 $check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, $single, $meta_type ); 648 if ( null !== $check ) { 649 if ( $single && is_array( $check ) ) { 650 return $check[0]; 651 } else { 652 return $check; 653 } 654 } 655 656 $meta_cache = wp_cache_get( $object_id, $meta_type . '_meta' ); 657 658 if ( ! $meta_cache ) { 659 $meta_cache = update_meta_cache( $meta_type, array( $object_id ) ); 660 if ( isset( $meta_cache[ $object_id ] ) ) { 661 $meta_cache = $meta_cache[ $object_id ]; 662 } else { 663 $meta_cache = null; 664 } 665 } 666 667 if ( ! $meta_key ) { 668 return $meta_cache; 669 } 670 671 if ( isset( $meta_cache[ $meta_key ] ) ) { 672 if ( $single ) { 673 return maybe_unserialize( $meta_cache[ $meta_key ][0] ); 674 } else { 675 return array_map( 'maybe_unserialize', $meta_cache[ $meta_key ] ); 676 } 677 } 678 679 return null; 680 } 681 682 /** 683 * Retrieves default metadata value for the specified meta key and object. 684 * 685 * By default, an empty string is returned if `$single` is true, or an empty array 686 * if it's false. 687 * 688 * @since 5.5.0 689 * 690 * @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 691 * or any other object type with an associated meta table. 692 * @param int $object_id ID of the object metadata is for. 693 * @param string $meta_key Metadata key. 694 * @param bool $single Optional. If true, return only the first value of the specified `$meta_key`. 695 * This parameter has no effect if `$meta_key` is not specified. Default false. 696 * @return mixed An array of default values if `$single` is false. 697 * The default value of the meta field if `$single` is true. 698 */ 699 function get_metadata_default( $meta_type, $object_id, $meta_key, $single = false ) { 700 if ( $single ) { 701 $value = ''; 702 } else { 703 $value = array(); 704 } 705 706 /** 707 * Filters the default metadata value for a specified meta key and object. 708 * 709 * The dynamic portion of the hook name, `$meta_type`, refers to the meta object type 710 * (post, comment, term, user, or any other type with an associated meta table). 711 * 712 * Possible filter names include: 713 * 714 * - `default_post_metadata` 715 * - `default_comment_metadata` 716 * - `default_term_metadata` 717 * - `default_user_metadata` 718 * 719 * @since 5.5.0 720 * 721 * @param mixed $value The value to return, either a single metadata value or an array 722 * of values depending on the value of `$single`. 723 * @param int $object_id ID of the object metadata is for. 724 * @param string $meta_key Metadata key. 725 * @param bool $single Whether to return only the first value of the specified `$meta_key`. 726 * @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 727 * or any other object type with an associated meta table. 728 */ 729 $value = apply_filters( "default_{$meta_type}_metadata", $value, $object_id, $meta_key, $single, $meta_type ); 730 731 if ( ! $single && ! wp_is_numeric_array( $value ) ) { 732 $value = array( $value ); 733 } 734 735 return $value; 736 } 737 738 /** 739 * Determines if a meta field with the given key exists for the given object ID. 740 * 741 * @since 3.3.0 742 * 743 * @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 744 * or any other object type with an associated meta table. 745 * @param int $object_id ID of the object metadata is for. 746 * @param string $meta_key Metadata key. 747 * @return bool Whether a meta field with the given key exists. 748 */ 749 function metadata_exists( $meta_type, $object_id, $meta_key ) { 750 if ( ! $meta_type || ! is_numeric( $object_id ) ) { 751 return false; 752 } 753 754 $object_id = absint( $object_id ); 755 if ( ! $object_id ) { 756 return false; 757 } 758 759 /** This filter is documented in wp-includes/meta.php */ 760 $check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, true, $meta_type ); 761 if ( null !== $check ) { 762 return (bool) $check; 763 } 764 765 $meta_cache = wp_cache_get( $object_id, $meta_type . '_meta' ); 766 767 if ( ! $meta_cache ) { 768 $meta_cache = update_meta_cache( $meta_type, array( $object_id ) ); 769 $meta_cache = $meta_cache[ $object_id ]; 770 } 771 772 if ( isset( $meta_cache[ $meta_key ] ) ) { 773 return true; 774 } 775 776 return false; 777 } 778 779 /** 780 * Retrieves metadata by meta ID. 781 * 782 * @since 3.3.0 783 * 784 * @global wpdb $wpdb WordPress database abstraction object. 785 * 786 * @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 787 * or any other object type with an associated meta table. 788 * @param int $meta_id ID for a specific meta row. 789 * @return stdClass|false { 790 * Metadata object, or boolean `false` if the metadata doesn't exist. 791 * 792 * @type string $meta_key The meta key. 793 * @type mixed $meta_value The unserialized meta value. 794 * @type string $meta_id Optional. The meta ID when the meta type is any value except 'user'. 795 * @type string $umeta_id Optional. The meta ID when the meta type is 'user'. 796 * @type string $post_id Optional. The object ID when the meta type is 'post'. 797 * @type string $comment_id Optional. The object ID when the meta type is 'comment'. 798 * @type string $term_id Optional. The object ID when the meta type is 'term'. 799 * @type string $user_id Optional. The object ID when the meta type is 'user'. 800 * } 801 */ 802 function get_metadata_by_mid( $meta_type, $meta_id ) { 803 global $wpdb; 804 805 if ( ! $meta_type || ! is_numeric( $meta_id ) || floor( $meta_id ) != $meta_id ) { 806 return false; 807 } 808 809 $meta_id = (int) $meta_id; 810 if ( $meta_id <= 0 ) { 811 return false; 812 } 813 814 $table = _get_meta_table( $meta_type ); 815 if ( ! $table ) { 816 return false; 817 } 818 819 /** 820 * Short-circuits the return value when fetching a meta field by meta ID. 821 * 822 * The dynamic portion of the hook name, `$meta_type`, refers to the meta object type 823 * (post, comment, term, user, or any other type with an associated meta table). 824 * Returning a non-null value will effectively short-circuit the function. 825 * 826 * Possible hook names include: 827 * 828 * - `get_post_metadata_by_mid` 829 * - `get_comment_metadata_by_mid` 830 * - `get_term_metadata_by_mid` 831 * - `get_user_metadata_by_mid` 832 * 833 * @since 5.0.0 834 * 835 * @param stdClass|null $value The value to return. 836 * @param int $meta_id Meta ID. 837 */ 838 $check = apply_filters( "get_{$meta_type}_metadata_by_mid", null, $meta_id ); 839 if ( null !== $check ) { 840 return $check; 841 } 842 843 $id_column = ( 'user' === $meta_type ) ? 'umeta_id' : 'meta_id'; 844 845 $meta = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table WHERE $id_column = %d", $meta_id ) ); 846 847 if ( empty( $meta ) ) { 848 return false; 849 } 850 851 if ( isset( $meta->meta_value ) ) { 852 $meta->meta_value = maybe_unserialize( $meta->meta_value ); 853 } 854 855 return $meta; 856 } 857 858 /** 859 * Updates metadata 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. Accepts 'post', 'comment', 'term', 'user', 866 * or any other object type with an associated meta table. 867 * @param int $meta_id ID for a specific meta row. 868 * @param string $meta_value Metadata value. Must be serializable if non-scalar. 869 * @param string|false $meta_key Optional. You can provide a meta key to update it. Default false. 870 * @return bool True on successful update, false on failure. 871 */ 872 function update_metadata_by_mid( $meta_type, $meta_id, $meta_value, $meta_key = false ) { 873 global $wpdb; 874 875 // Make sure everything is valid. 876 if ( ! $meta_type || ! is_numeric( $meta_id ) || floor( $meta_id ) != $meta_id ) { 877 return false; 878 } 879 880 $meta_id = (int) $meta_id; 881 if ( $meta_id <= 0 ) { 882 return false; 883 } 884 885 $table = _get_meta_table( $meta_type ); 886 if ( ! $table ) { 887 return false; 888 } 889 890 $column = sanitize_key( $meta_type . '_id' ); 891 $id_column = ( 'user' === $meta_type ) ? 'umeta_id' : 'meta_id'; 892 893 /** 894 * Short-circuits updating metadata of a specific type by meta ID. 895 * 896 * The dynamic portion of the hook name, `$meta_type`, refers to the meta object type 897 * (post, comment, term, user, or any other type with an associated meta table). 898 * Returning a non-null value will effectively short-circuit the function. 899 * 900 * Possible hook names include: 901 * 902 * - `update_post_metadata_by_mid` 903 * - `update_comment_metadata_by_mid` 904 * - `update_term_metadata_by_mid` 905 * - `update_user_metadata_by_mid` 906 * 907 * @since 5.0.0 908 * 909 * @param null|bool $check Whether to allow updating metadata for the given type. 910 * @param int $meta_id Meta ID. 911 * @param mixed $meta_value Meta value. Must be serializable if non-scalar. 912 * @param string|false $meta_key Meta key, if provided. 913 */ 914 $check = apply_filters( "update_{$meta_type}_metadata_by_mid", null, $meta_id, $meta_value, $meta_key ); 915 if ( null !== $check ) { 916 return (bool) $check; 917 } 918 919 // Fetch the meta and go on if it's found. 920 $meta = get_metadata_by_mid( $meta_type, $meta_id ); 921 if ( $meta ) { 922 $original_key = $meta->meta_key; 923 $object_id = $meta->{$column}; 924 925 /* 926 * If a new meta_key (last parameter) was specified, change the meta key, 927 * otherwise use the original key in the update statement. 928 */ 929 if ( false === $meta_key ) { 930 $meta_key = $original_key; 931 } elseif ( ! is_string( $meta_key ) ) { 932 return false; 933 } 934 935 $meta_subtype = get_object_subtype( $meta_type, $object_id ); 936 937 // Sanitize the meta. 938 $_meta_value = $meta_value; 939 $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type, $meta_subtype ); 940 $meta_value = maybe_serialize( $meta_value ); 941 942 // Format the data query arguments. 943 $data = array( 944 'meta_key' => $meta_key, 945 'meta_value' => $meta_value, 946 ); 947 948 // Format the where query arguments. 949 $where = array(); 950 $where[ $id_column ] = $meta_id; 951 952 /** This action is documented in wp-includes/meta.php */ 953 do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value ); 954 955 if ( 'post' === $meta_type ) { 956 /** This action is documented in wp-includes/meta.php */ 957 do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value ); 958 } 959 960 // Run the update query, all fields in $data are %s, $where is a %d. 961 $result = $wpdb->update( $table, $data, $where, '%s', '%d' ); 962 if ( ! $result ) { 963 return false; 964 } 965 966 // Clear the caches. 967 wp_cache_delete( $object_id, $meta_type . '_meta' ); 968 969 /** This action is documented in wp-includes/meta.php */ 970 do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value ); 971 972 if ( 'post' === $meta_type ) { 973 /** This action is documented in wp-includes/meta.php */ 974 do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value ); 975 } 976 977 return true; 978 } 979 980 // And if the meta was not found. 981 return false; 982 } 983 984 /** 985 * Deletes metadata by meta ID. 986 * 987 * @since 3.3.0 988 * 989 * @global wpdb $wpdb WordPress database abstraction object. 990 * 991 * @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 992 * or any other object type with an associated meta table. 993 * @param int $meta_id ID for a specific meta row. 994 * @return bool True on successful delete, false on failure. 995 */ 996 function delete_metadata_by_mid( $meta_type, $meta_id ) { 997 global $wpdb; 998 999 // Make sure everything is valid. 1000 if ( ! $meta_type || ! is_numeric( $meta_id ) || floor( $meta_id ) != $meta_id ) { 1001 return false; 1002 } 1003 1004 $meta_id = (int) $meta_id; 1005 if ( $meta_id <= 0 ) { 1006 return false; 1007 } 1008 1009 $table = _get_meta_table( $meta_type ); 1010 if ( ! $table ) { 1011 return false; 1012 } 1013 1014 // Object and ID columns. 1015 $column = sanitize_key( $meta_type . '_id' ); 1016 $id_column = ( 'user' === $meta_type ) ? 'umeta_id' : 'meta_id'; 1017 1018 /** 1019 * Short-circuits deleting metadata of a specific type by meta ID. 1020 * 1021 * The dynamic portion of the hook name, `$meta_type`, refers to the meta object type 1022 * (post, comment, term, user, or any other type with an associated meta table). 1023 * Returning a non-null value will effectively short-circuit the function. 1024 * 1025 * Possible hook names include: 1026 * 1027 * - `delete_post_metadata_by_mid` 1028 * - `delete_comment_metadata_by_mid` 1029 * - `delete_term_metadata_by_mid` 1030 * - `delete_user_metadata_by_mid` 1031 * 1032 * @since 5.0.0 1033 * 1034 * @param null|bool $delete Whether to allow metadata deletion of the given type. 1035 * @param int $meta_id Meta ID. 1036 */ 1037 $check = apply_filters( "delete_{$meta_type}_metadata_by_mid", null, $meta_id ); 1038 if ( null !== $check ) { 1039 return (bool) $check; 1040 } 1041 1042 // Fetch the meta and go on if it's found. 1043 $meta = get_metadata_by_mid( $meta_type, $meta_id ); 1044 if ( $meta ) { 1045 $object_id = (int) $meta->{$column}; 1046 1047 /** This action is documented in wp-includes/meta.php */ 1048 do_action( "delete_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value ); 1049 1050 // Old-style action. 1051 if ( 'post' === $meta_type || 'comment' === $meta_type ) { 1052 /** 1053 * Fires immediately before deleting post or comment metadata of a specific type. 1054 * 1055 * The dynamic portion of the hook name, `$meta_type`, refers to the meta 1056 * object type (post or comment). 1057 * 1058 * Possible hook names include: 1059 * 1060 * - `delete_postmeta` 1061 * - `delete_commentmeta` 1062 * - `delete_termmeta` 1063 * - `delete_usermeta` 1064 * 1065 * @since 3.4.0 1066 * 1067 * @param int $meta_id ID of the metadata entry to delete. 1068 */ 1069 do_action( "delete_{$meta_type}meta", $meta_id ); 1070 } 1071 1072 // Run the query, will return true if deleted, false otherwise. 1073 $result = (bool) $wpdb->delete( $table, array( $id_column => $meta_id ) ); 1074 1075 // Clear the caches. 1076 wp_cache_delete( $object_id, $meta_type . '_meta' ); 1077 1078 /** This action is documented in wp-includes/meta.php */ 1079 do_action( "deleted_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value ); 1080 1081 // Old-style action. 1082 if ( 'post' === $meta_type || 'comment' === $meta_type ) { 1083 /** 1084 * Fires immediately after deleting post or comment metadata of a specific type. 1085 * 1086 * The dynamic portion of the hook name, `$meta_type`, refers to the meta 1087 * object type (post or comment). 1088 * 1089 * Possible hook names include: 1090 * 1091 * - `deleted_postmeta` 1092 * - `deleted_commentmeta` 1093 * - `deleted_termmeta` 1094 * - `deleted_usermeta` 1095 * 1096 * @since 3.4.0 1097 * 1098 * @param int $meta_id Deleted metadata entry ID. 1099 */ 1100 do_action( "deleted_{$meta_type}meta", $meta_id ); 1101 } 1102 1103 return $result; 1104 1105 } 1106 1107 // Meta ID was not found. 1108 return false; 1109 } 1110 1111 /** 1112 * Updates the metadata cache for the specified objects. 1113 * 1114 * @since 2.9.0 1115 * 1116 * @global wpdb $wpdb WordPress database abstraction object. 1117 * 1118 * @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 1119 * or any other object type with an associated meta table. 1120 * @param string|int[] $object_ids Array or comma delimited list of object IDs to update cache for. 1121 * @return array|false Metadata cache for the specified objects, or false on failure. 1122 */ 1123 function update_meta_cache( $meta_type, $object_ids ) { 1124 global $wpdb; 1125 1126 if ( ! $meta_type || ! $object_ids ) { 1127 return false; 1128 } 1129 1130 $table = _get_meta_table( $meta_type ); 1131 if ( ! $table ) { 1132 return false; 1133 } 1134 1135 $column = sanitize_key( $meta_type . '_id' ); 1136 1137 if ( ! is_array( $object_ids ) ) { 1138 $object_ids = preg_replace( '|[^0-9,]|', '', $object_ids ); 1139 $object_ids = explode( ',', $object_ids ); 1140 } 1141 1142 $object_ids = array_map( 'intval', $object_ids ); 1143 1144 /** 1145 * Short-circuits updating the metadata cache of a specific type. 1146 * 1147 * The dynamic portion of the hook name, `$meta_type`, refers to the meta object type 1148 * (post, comment, term, user, or any other type with an associated meta table). 1149 * Returning a non-null value will effectively short-circuit the function. 1150 * 1151 * Possible hook names include: 1152 * 1153 * - `update_post_metadata_cache` 1154 * - `update_comment_metadata_cache` 1155 * - `update_term_metadata_cache` 1156 * - `update_user_metadata_cache` 1157 * 1158 * @since 5.0.0 1159 * 1160 * @param mixed $check Whether to allow updating the meta cache of the given type. 1161 * @param int[] $object_ids Array of object IDs to update the meta cache for. 1162 */ 1163 $check = apply_filters( "update_{$meta_type}_metadata_cache", null, $object_ids ); 1164 if ( null !== $check ) { 1165 return (bool) $check; 1166 } 1167 1168 $cache_key = $meta_type . '_meta'; 1169 $non_cached_ids = array(); 1170 $cache = array(); 1171 $cache_values = wp_cache_get_multiple( $object_ids, $cache_key ); 1172 1173 foreach ( $cache_values as $id => $cached_object ) { 1174 if ( false === $cached_object ) { 1175 $non_cached_ids[] = $id; 1176 } else { 1177 $cache[ $id ] = $cached_object; 1178 } 1179 } 1180 1181 if ( empty( $non_cached_ids ) ) { 1182 return $cache; 1183 } 1184 1185 // Get meta info. 1186 $id_list = implode( ',', $non_cached_ids ); 1187 $id_column = ( 'user' === $meta_type ) ? 'umeta_id' : 'meta_id'; 1188 1189 $meta_list = $wpdb->get_results( "SELECT $column, meta_key, meta_value FROM $table WHERE $column IN ($id_list) ORDER BY $id_column ASC", ARRAY_A ); 1190 1191 if ( ! empty( $meta_list ) ) { 1192 foreach ( $meta_list as $metarow ) { 1193 $mpid = (int) $metarow[ $column ]; 1194 $mkey = $metarow['meta_key']; 1195 $mval = $metarow['meta_value']; 1196 1197 // Force subkeys to be array type. 1198 if ( ! isset( $cache[ $mpid ] ) || ! is_array( $cache[ $mpid ] ) ) { 1199 $cache[ $mpid ] = array(); 1200 } 1201 if ( ! isset( $cache[ $mpid ][ $mkey ] ) || ! is_array( $cache[ $mpid ][ $mkey ] ) ) { 1202 $cache[ $mpid ][ $mkey ] = array(); 1203 } 1204 1205 // Add a value to the current pid/key. 1206 $cache[ $mpid ][ $mkey ][] = $mval; 1207 } 1208 } 1209 1210 $data = array(); 1211 foreach ( $non_cached_ids as $id ) { 1212 if ( ! isset( $cache[ $id ] ) ) { 1213 $cache[ $id ] = array(); 1214 } 1215 $data[ $id ] = $cache[ $id ]; 1216 } 1217 wp_cache_add_multiple( $data, $cache_key ); 1218 1219 return $cache; 1220 } 1221 1222 /** 1223 * Retrieves the queue for lazy-loading metadata. 1224 * 1225 * @since 4.5.0 1226 * 1227 * @return WP_Metadata_Lazyloader Metadata lazyloader queue. 1228 */ 1229 function wp_metadata_lazyloader() { 1230 static $wp_metadata_lazyloader; 1231 1232 if ( null === $wp_metadata_lazyloader ) { 1233 $wp_metadata_lazyloader = new WP_Metadata_Lazyloader(); 1234 } 1235 1236 return $wp_metadata_lazyloader; 1237 } 1238 1239 /** 1240 * Given a meta query, generates SQL clauses to be appended to a main query. 1241 * 1242 * @since 3.2.0 1243 * 1244 * @see WP_Meta_Query 1245 * 1246 * @param array $meta_query A meta query. 1247 * @param string $type Type of meta. 1248 * @param string $primary_table Primary database table name. 1249 * @param string $primary_id_column Primary ID column name. 1250 * @param object $context Optional. The main query object. Default null. 1251 * @return string[]|false { 1252 * Array containing JOIN and WHERE SQL clauses to append to the main query, 1253 * or false if no table exists for the requested meta type. 1254 * 1255 * @type string $join SQL fragment to append to the main JOIN clause. 1256 * @type string $where SQL fragment to append to the main WHERE clause. 1257 * } 1258 */ 1259 function get_meta_sql( $meta_query, $type, $primary_table, $primary_id_column, $context = null ) { 1260 $meta_query_obj = new WP_Meta_Query( $meta_query ); 1261 return $meta_query_obj->get_sql( $type, $primary_table, $primary_id_column, $context ); 1262 } 1263 1264 /** 1265 * Retrieves the name of the metadata table for the specified object type. 1266 * 1267 * @since 2.9.0 1268 * 1269 * @global wpdb $wpdb WordPress database abstraction object. 1270 * 1271 * @param string $type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 1272 * or any other object type with an associated meta table. 1273 * @return string|false Metadata table name, or false if no metadata table exists 1274 */ 1275 function _get_meta_table( $type ) { 1276 global $wpdb; 1277 1278 $table_name = $type . 'meta'; 1279 1280 if ( empty( $wpdb->$table_name ) ) { 1281 return false; 1282 } 1283 1284 return $wpdb->$table_name; 1285 } 1286 1287 /** 1288 * Determines whether a meta key is considered protected. 1289 * 1290 * @since 3.1.3 1291 * 1292 * @param string $meta_key Metadata key. 1293 * @param string $meta_type Optional. Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 1294 * or any other object type with an associated meta table. Default empty string. 1295 * @return bool Whether the meta key is considered protected. 1296 */ 1297 function is_protected_meta( $meta_key, $meta_type = '' ) { 1298 $sanitized_key = preg_replace( "/[^\x20-\x7E\p{L}]/", '', $meta_key ); 1299 $protected = strlen( $sanitized_key ) > 0 && ( '_' === $sanitized_key[0] ); 1300 1301 /** 1302 * Filters whether a meta key is considered protected. 1303 * 1304 * @since 3.2.0 1305 * 1306 * @param bool $protected Whether the key is considered protected. 1307 * @param string $meta_key Metadata key. 1308 * @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 1309 * or any other object type with an associated meta table. 1310 */ 1311 return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type ); 1312 } 1313 1314 /** 1315 * Sanitizes meta value. 1316 * 1317 * @since 3.1.3 1318 * @since 4.9.8 The `$object_subtype` parameter was added. 1319 * 1320 * @param string $meta_key Metadata key. 1321 * @param mixed $meta_value Metadata value to sanitize. 1322 * @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 1323 * or any other object type with an associated meta table. 1324 * @param string $object_subtype Optional. The subtype of the object type. Default empty string. 1325 * @return mixed Sanitized $meta_value. 1326 */ 1327 function sanitize_meta( $meta_key, $meta_value, $object_type, $object_subtype = '' ) { 1328 if ( ! empty( $object_subtype ) && has_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" ) ) { 1329 1330 /** 1331 * Filters the sanitization of a specific meta key of a specific meta type and subtype. 1332 * 1333 * The dynamic portions of the hook name, `$object_type`, `$meta_key`, 1334 * and `$object_subtype`, refer to the metadata object type (comment, post, term, or user), 1335 * the meta key value, and the object subtype respectively. 1336 * 1337 * @since 4.9.8 1338 * 1339 * @param mixed $meta_value Metadata value to sanitize. 1340 * @param string $meta_key Metadata key. 1341 * @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 1342 * or any other object type with an associated meta table. 1343 * @param string $object_subtype Object subtype. 1344 */ 1345 return apply_filters( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $meta_value, $meta_key, $object_type, $object_subtype ); 1346 } 1347 1348 /** 1349 * Filters the sanitization of a specific meta key of a specific meta type. 1350 * 1351 * The dynamic portions of the hook name, `$meta_type`, and `$meta_key`, 1352 * refer to the metadata object type (comment, post, term, or user) and the meta 1353 * key value, respectively. 1354 * 1355 * @since 3.3.0 1356 * 1357 * @param mixed $meta_value Metadata value to sanitize. 1358 * @param string $meta_key Metadata key. 1359 * @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 1360 * or any other object type with an associated meta table. 1361 */ 1362 return apply_filters( "sanitize_{$object_type}_meta_{$meta_key}", $meta_value, $meta_key, $object_type ); 1363 } 1364 1365 /** 1366 * Registers a meta key. 1367 * 1368 * It is recommended to register meta keys for a specific combination of object type and object subtype. If passing 1369 * an object subtype is omitted, the meta key will be registered for the entire object type, however it can be partly 1370 * overridden in case a more specific meta key of the same name exists for the same object type and a subtype. 1371 * 1372 * If an object type does not support any subtypes, such as users or comments, you should commonly call this function 1373 * without passing a subtype. 1374 * 1375 * @since 3.3.0 1376 * @since 4.6.0 {@link https://core.trac.wordpress.org/ticket/35658 Modified 1377 * to support an array of data to attach to registered meta keys}. Previous arguments for 1378 * `$sanitize_callback` and `$auth_callback` have been folded into this array. 1379 * @since 4.9.8 The `$object_subtype` argument was added to the arguments array. 1380 * @since 5.3.0 Valid meta types expanded to include "array" and "object". 1381 * @since 5.5.0 The `$default` argument was added to the arguments array. 1382 * @since 6.4.0 The `$revisions_enabled` argument was added to the arguments array. 1383 * @since 6.7.0 The `label` argument was added to the arguments array. 1384 * 1385 * @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 1386 * or any other object type with an associated meta table. 1387 * @param string $meta_key Meta key to register. 1388 * @param array $args { 1389 * Data used to describe the meta key when registered. 1390 * 1391 * @type string $object_subtype A subtype; e.g. if the object type is "post", the post type. If left empty, 1392 * the meta key will be registered on the entire object type. Default empty. 1393 * @type string $type The type of data associated with this meta key. 1394 * Valid values are 'string', 'boolean', 'integer', 'number', 'array', and 'object'. 1395 * @type string $label A human-readable label of the data attached to this meta key. 1396 * @type string $description A description of the data attached to this meta key. 1397 * @type bool $single Whether the meta key has one value per object, or an array of values per object. 1398 * @type mixed $default The default value returned from get_metadata() if no value has been set yet. 1399 * When using a non-single meta key, the default value is for the first entry. 1400 * In other words, when calling get_metadata() with `$single` set to `false`, 1401 * the default value given here will be wrapped in an array. 1402 * @type callable $sanitize_callback A function or method to call when sanitizing `$meta_key` data. 1403 * @type callable $auth_callback Optional. A function or method to call when performing edit_post_meta, 1404 * add_post_meta, and delete_post_meta capability checks. 1405 * @type bool|array $show_in_rest Whether data associated with this meta key can be considered public and 1406 * should be accessible via the REST API. A custom post type must also declare 1407 * support for custom fields for registered meta to be accessible via REST. 1408 * When registering complex meta values this argument may optionally be an 1409 * array with 'schema' or 'prepare_callback' keys instead of a boolean. 1410 * @type bool $revisions_enabled Whether to enable revisions support for this meta_key. Can only be used when the 1411 * object type is 'post'. 1412 * } 1413 * @param string|array $deprecated Deprecated. Use `$args` instead. 1414 * @return bool True if the meta key was successfully registered in the global array, false if not. 1415 * Registering a meta key with distinct sanitize and auth callbacks will fire those callbacks, 1416 * but will not add to the global registry. 1417 */ 1418 function register_meta( $object_type, $meta_key, $args, $deprecated = null ) { 1419 global $wp_meta_keys; 1420 1421 if ( ! is_array( $wp_meta_keys ) ) { 1422 $wp_meta_keys = array(); 1423 } 1424 1425 $defaults = array( 1426 'object_subtype' => '', 1427 'type' => 'string', 1428 'label' => '', 1429 'description' => '', 1430 'default' => '', 1431 'single' => false, 1432 'sanitize_callback' => null, 1433 'auth_callback' => null, 1434 'show_in_rest' => false, 1435 'revisions_enabled' => false, 1436 ); 1437 1438 // There used to be individual args for sanitize and auth callbacks. 1439 $has_old_sanitize_cb = false; 1440 $has_old_auth_cb = false; 1441 1442 if ( is_callable( $args ) ) { 1443 $args = array( 1444 'sanitize_callback' => $args, 1445 ); 1446 1447 $has_old_sanitize_cb = true; 1448 } else { 1449 $args = (array) $args; 1450 } 1451 1452 if ( is_callable( $deprecated ) ) { 1453 $args['auth_callback'] = $deprecated; 1454 $has_old_auth_cb = true; 1455 } 1456 1457 /** 1458 * Filters the registration arguments when registering meta. 1459 * 1460 * @since 4.6.0 1461 * 1462 * @param array $args Array of meta registration arguments. 1463 * @param array $defaults Array of default arguments. 1464 * @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 1465 * or any other object type with an associated meta table. 1466 * @param string $meta_key Meta key. 1467 */ 1468 $args = apply_filters( 'register_meta_args', $args, $defaults, $object_type, $meta_key ); 1469 unset( $defaults['default'] ); 1470 $args = wp_parse_args( $args, $defaults ); 1471 1472 // Require an item schema when registering array meta. 1473 if ( false !== $args['show_in_rest'] && 'array' === $args['type'] ) { 1474 if ( ! is_array( $args['show_in_rest'] ) || ! isset( $args['show_in_rest']['schema']['items'] ) ) { 1475 _doing_it_wrong( __FUNCTION__, __( 'When registering an "array" meta type to show in the REST API, you must specify the schema for each array item in "show_in_rest.schema.items".' ), '5.3.0' ); 1476 1477 return false; 1478 } 1479 } 1480 1481 $object_subtype = ! empty( $args['object_subtype'] ) ? $args['object_subtype'] : ''; 1482 if ( $args['revisions_enabled'] ) { 1483 if ( 'post' !== $object_type ) { 1484 _doing_it_wrong( __FUNCTION__, __( 'Meta keys cannot enable revisions support unless the object type supports revisions.' ), '6.4.0' ); 1485 1486 return false; 1487 } elseif ( ! empty( $object_subtype ) && ! post_type_supports( $object_subtype, 'revisions' ) ) { 1488 _doing_it_wrong( __FUNCTION__, __( 'Meta keys cannot enable revisions support unless the object subtype supports revisions.' ), '6.4.0' ); 1489 1490 return false; 1491 } 1492 } 1493 1494 // If `auth_callback` is not provided, fall back to `is_protected_meta()`. 1495 if ( empty( $args['auth_callback'] ) ) { 1496 if ( is_protected_meta( $meta_key, $object_type ) ) { 1497 $args['auth_callback'] = '__return_false'; 1498 } else { 1499 $args['auth_callback'] = '__return_true'; 1500 } 1501 } 1502 1503 // Back-compat: old sanitize and auth callbacks are applied to all of an object type. 1504 if ( is_callable( $args['sanitize_callback'] ) ) { 1505 if ( ! empty( $object_subtype ) ) { 1506 add_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['sanitize_callback'], 10, 4 ); 1507 } else { 1508 add_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'], 10, 3 ); 1509 } 1510 } 1511 1512 if ( is_callable( $args['auth_callback'] ) ) { 1513 if ( ! empty( $object_subtype ) ) { 1514 add_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['auth_callback'], 10, 6 ); 1515 } else { 1516 add_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'], 10, 6 ); 1517 } 1518 } 1519 1520 if ( array_key_exists( 'default', $args ) ) { 1521 $schema = $args; 1522 if ( is_array( $args['show_in_rest'] ) && isset( $args['show_in_rest']['schema'] ) ) { 1523 $schema = array_merge( $schema, $args['show_in_rest']['schema'] ); 1524 } 1525 1526 $check = rest_validate_value_from_schema( $args['default'], $schema ); 1527 if ( is_wp_error( $check ) ) { 1528 _doing_it_wrong( __FUNCTION__, __( 'When registering a default meta value the data must match the type provided.' ), '5.5.0' ); 1529 1530 return false; 1531 } 1532 1533 if ( ! has_filter( "default_{$object_type}_metadata", 'filter_default_metadata' ) ) { 1534 add_filter( "default_{$object_type}_metadata", 'filter_default_metadata', 10, 5 ); 1535 } 1536 } 1537 1538 // Global registry only contains meta keys registered with the array of arguments added in 4.6.0. 1539 if ( ! $has_old_auth_cb && ! $has_old_sanitize_cb ) { 1540 unset( $args['object_subtype'] ); 1541 1542 $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] = $args; 1543 1544 return true; 1545 } 1546 1547 return false; 1548 } 1549 1550 /** 1551 * Filters into default_{$object_type}_metadata and adds in default value. 1552 * 1553 * @since 5.5.0 1554 * 1555 * @param mixed $value Current value passed to filter. 1556 * @param int $object_id ID of the object metadata is for. 1557 * @param string $meta_key Metadata key. 1558 * @param bool $single If true, return only the first value of the specified `$meta_key`. 1559 * This parameter has no effect if `$meta_key` is not specified. 1560 * @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 1561 * or any other object type with an associated meta table. 1562 * @return mixed An array of default values if `$single` is false. 1563 * The default value of the meta field if `$single` is true. 1564 */ 1565 function filter_default_metadata( $value, $object_id, $meta_key, $single, $meta_type ) { 1566 global $wp_meta_keys; 1567 1568 if ( wp_installing() ) { 1569 return $value; 1570 } 1571 1572 if ( ! is_array( $wp_meta_keys ) || ! isset( $wp_meta_keys[ $meta_type ] ) ) { 1573 return $value; 1574 } 1575 1576 $defaults = array(); 1577 foreach ( $wp_meta_keys[ $meta_type ] as $sub_type => $meta_data ) { 1578 foreach ( $meta_data as $_meta_key => $args ) { 1579 if ( $_meta_key === $meta_key && array_key_exists( 'default', $args ) ) { 1580 $defaults[ $sub_type ] = $args; 1581 } 1582 } 1583 } 1584 1585 if ( ! $defaults ) { 1586 return $value; 1587 } 1588 1589 // If this meta type does not have subtypes, then the default is keyed as an empty string. 1590 if ( isset( $defaults[''] ) ) { 1591 $metadata = $defaults['']; 1592 } else { 1593 $sub_type = get_object_subtype( $meta_type, $object_id ); 1594 if ( ! isset( $defaults[ $sub_type ] ) ) { 1595 return $value; 1596 } 1597 $metadata = $defaults[ $sub_type ]; 1598 } 1599 1600 if ( $single ) { 1601 $value = $metadata['default']; 1602 } else { 1603 $value = array( $metadata['default'] ); 1604 } 1605 1606 return $value; 1607 } 1608 1609 /** 1610 * Checks if a meta key is registered. 1611 * 1612 * @since 4.6.0 1613 * @since 4.9.8 The `$object_subtype` parameter was added. 1614 * 1615 * @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 1616 * or any other object type with an associated meta table. 1617 * @param string $meta_key Metadata key. 1618 * @param string $object_subtype Optional. The subtype of the object type. Default empty string. 1619 * @return bool True if the meta key is registered to the object type and, if provided, 1620 * the object subtype. False if not. 1621 */ 1622 function registered_meta_key_exists( $object_type, $meta_key, $object_subtype = '' ) { 1623 $meta_keys = get_registered_meta_keys( $object_type, $object_subtype ); 1624 1625 return isset( $meta_keys[ $meta_key ] ); 1626 } 1627 1628 /** 1629 * Unregisters a meta key from the list of registered keys. 1630 * 1631 * @since 4.6.0 1632 * @since 4.9.8 The `$object_subtype` parameter was added. 1633 * 1634 * @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 1635 * or any other object type with an associated meta table. 1636 * @param string $meta_key Metadata key. 1637 * @param string $object_subtype Optional. The subtype of the object type. Default empty string. 1638 * @return bool True if successful. False if the meta key was not registered. 1639 */ 1640 function unregister_meta_key( $object_type, $meta_key, $object_subtype = '' ) { 1641 global $wp_meta_keys; 1642 1643 if ( ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) { 1644 return false; 1645 } 1646 1647 $args = $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ]; 1648 1649 if ( isset( $args['sanitize_callback'] ) && is_callable( $args['sanitize_callback'] ) ) { 1650 if ( ! empty( $object_subtype ) ) { 1651 remove_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['sanitize_callback'] ); 1652 } else { 1653 remove_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'] ); 1654 } 1655 } 1656 1657 if ( isset( $args['auth_callback'] ) && is_callable( $args['auth_callback'] ) ) { 1658 if ( ! empty( $object_subtype ) ) { 1659 remove_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['auth_callback'] ); 1660 } else { 1661 remove_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'] ); 1662 } 1663 } 1664 1665 unset( $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] ); 1666 1667 // Do some clean up. 1668 if ( empty( $wp_meta_keys[ $object_type ][ $object_subtype ] ) ) { 1669 unset( $wp_meta_keys[ $object_type ][ $object_subtype ] ); 1670 } 1671 if ( empty( $wp_meta_keys[ $object_type ] ) ) { 1672 unset( $wp_meta_keys[ $object_type ] ); 1673 } 1674 1675 return true; 1676 } 1677 1678 /** 1679 * Retrieves a list of registered metadata args for an object type, keyed by their meta keys. 1680 * 1681 * @since 4.6.0 1682 * @since 4.9.8 The `$object_subtype` parameter was added. 1683 * 1684 * @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 1685 * or any other object type with an associated meta table. 1686 * @param string $object_subtype Optional. The subtype of the object type. Default empty string. 1687 * @return array[] List of registered metadata args, keyed by their meta keys. 1688 */ 1689 function get_registered_meta_keys( $object_type, $object_subtype = '' ) { 1690 global $wp_meta_keys; 1691 1692 if ( ! is_array( $wp_meta_keys ) || ! isset( $wp_meta_keys[ $object_type ] ) || ! isset( $wp_meta_keys[ $object_type ][ $object_subtype ] ) ) { 1693 return array(); 1694 } 1695 1696 return $wp_meta_keys[ $object_type ][ $object_subtype ]; 1697 } 1698 1699 /** 1700 * Retrieves registered metadata for a specified object. 1701 * 1702 * The results include both meta that is registered specifically for the 1703 * object's subtype and meta that is registered for the entire object type. 1704 * 1705 * @since 4.6.0 1706 * 1707 * @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 1708 * or any other object type with an associated meta table. 1709 * @param int $object_id ID of the object the metadata is for. 1710 * @param string $meta_key Optional. Registered metadata key. If not specified, retrieve all registered 1711 * metadata for the specified object. 1712 * @return mixed A single value or array of values for a key if specified. An array of all registered keys 1713 * and values for an object ID if not. False if a given $meta_key is not registered. 1714 */ 1715 function get_registered_metadata( $object_type, $object_id, $meta_key = '' ) { 1716 $object_subtype = get_object_subtype( $object_type, $object_id ); 1717 1718 if ( ! empty( $meta_key ) ) { 1719 if ( ! empty( $object_subtype ) && ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) { 1720 $object_subtype = ''; 1721 } 1722 1723 if ( ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) { 1724 return false; 1725 } 1726 1727 $meta_keys = get_registered_meta_keys( $object_type, $object_subtype ); 1728 $meta_key_data = $meta_keys[ $meta_key ]; 1729 1730 $data = get_metadata( $object_type, $object_id, $meta_key, $meta_key_data['single'] ); 1731 1732 return $data; 1733 } 1734 1735 $data = get_metadata( $object_type, $object_id ); 1736 if ( ! $data ) { 1737 return array(); 1738 } 1739 1740 $meta_keys = get_registered_meta_keys( $object_type ); 1741 if ( ! empty( $object_subtype ) ) { 1742 $meta_keys = array_merge( $meta_keys, get_registered_meta_keys( $object_type, $object_subtype ) ); 1743 } 1744 1745 return array_intersect_key( $data, $meta_keys ); 1746 } 1747 1748 /** 1749 * Filters out `register_meta()` args based on an allowed list. 1750 * 1751 * `register_meta()` args may change over time, so requiring the allowed list 1752 * to be explicitly turned off is a warranty seal of sorts. 1753 * 1754 * @access private 1755 * @since 5.5.0 1756 * 1757 * @param array $args Arguments from `register_meta()`. 1758 * @param array $default_args Default arguments for `register_meta()`. 1759 * @return array Filtered arguments. 1760 */ 1761 function _wp_register_meta_args_allowed_list( $args, $default_args ) { 1762 return array_intersect_key( $args, $default_args ); 1763 } 1764 1765 /** 1766 * Returns the object subtype for a given object ID of a specific type. 1767 * 1768 * @since 4.9.8 1769 * 1770 * @param string $object_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user', 1771 * or any other object type with an associated meta table. 1772 * @param int $object_id ID of the object to retrieve its subtype. 1773 * @return string The object subtype or an empty string if unspecified subtype. 1774 */ 1775 function get_object_subtype( $object_type, $object_id ) { 1776 $object_id = (int) $object_id; 1777 $object_subtype = ''; 1778 1779 switch ( $object_type ) { 1780 case 'post': 1781 $post_type = get_post_type( $object_id ); 1782 1783 if ( ! empty( $post_type ) ) { 1784 $object_subtype = $post_type; 1785 } 1786 break; 1787 1788 case 'term': 1789 $term = get_term( $object_id ); 1790 if ( ! $term instanceof WP_Term ) { 1791 break; 1792 } 1793 1794 $object_subtype = $term->taxonomy; 1795 break; 1796 1797 case 'comment': 1798 $comment = get_comment( $object_id ); 1799 if ( ! $comment ) { 1800 break; 1801 } 1802 1803 $object_subtype = 'comment'; 1804 break; 1805 1806 case 'user': 1807 $user = get_user_by( 'id', $object_id ); 1808 if ( ! $user ) { 1809 break; 1810 } 1811 1812 $object_subtype = 'user'; 1813 break; 1814 } 1815 1816 /** 1817 * Filters the object subtype identifier for a non-standard object type. 1818 * 1819 * The dynamic portion of the hook name, `$object_type`, refers to the meta object type 1820 * (post, comment, term, user, or any other type with an associated meta table). 1821 * 1822 * Possible hook names include: 1823 * 1824 * - `get_object_subtype_post` 1825 * - `get_object_subtype_comment` 1826 * - `get_object_subtype_term` 1827 * - `get_object_subtype_user` 1828 * 1829 * @since 4.9.8 1830 * 1831 * @param string $object_subtype Empty string to override. 1832 * @param int $object_id ID of the object to get the subtype for. 1833 */ 1834 return apply_filters( "get_object_subtype_{$object_type}", $object_subtype, $object_id ); 1835 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Tue Jan 21 08:20:01 2025 | Cross-referenced by PHPXref |