[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/ -> meta.php (source)

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


Generated : Sat Apr 20 08:20:01 2024 Cross-referenced by PHPXref