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


Generated : Tue Jun 24 08:20:01 2025 Cross-referenced by PHPXref