[ Index ]

PHP Cross Reference of WordPress

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


Generated: Thu Oct 1 01:00:03 2020 Cross-referenced by PHPXref 0.7.1