/wp-includes/meta.php

  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. * Add 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 (e.g., comment, post, or user) 
  21. * @param int $object_id ID of the object metadata is for 
  22. * @param string $meta_key Metadata key 
  23. * @param mixed $meta_value Metadata value. Must be serializable if non-scalar. 
  24. * @param bool $unique Optional, default is false. 
  25. * 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. 
  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. $object_id = absint( $object_id ); 
  37. if ( ! $object_id ) { 
  38. return false; 
  39.  
  40. $table = _get_meta_table( $meta_type ); 
  41. if ( ! $table ) { 
  42. return false; 
  43.  
  44. $column = sanitize_key($meta_type . '_id'); 
  45.  
  46. // expected_slashed ($meta_key) 
  47. $meta_key = wp_unslash($meta_key); 
  48. $meta_value = wp_unslash($meta_value); 
  49. $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type ); 
  50.  
  51. /** 
  52. * Filters whether to add metadata of a specific type. 
  53. * 
  54. * The dynamic portion of the hook, `$meta_type`, refers to the meta 
  55. * object type (comment, post, or user). Returning a non-null value 
  56. * will effectively short-circuit the function. 
  57. * 
  58. * @since 3.1.0 
  59. * 
  60. * @param null|bool $check Whether to allow adding metadata for the given type. 
  61. * @param int $object_id Object ID. 
  62. * @param string $meta_key Meta key. 
  63. * @param mixed $meta_value Meta value. Must be serializable if non-scalar. 
  64. * @param bool $unique Whether the specified meta key should be unique 
  65. * for the object. Optional. Default false. 
  66. */ 
  67. $check = apply_filters( "add_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $unique ); 
  68. if ( null !== $check ) 
  69. return $check; 
  70.  
  71. if ( $unique && $wpdb->get_var( $wpdb->prepare( 
  72. "SELECT COUNT(*) FROM $table WHERE meta_key = %s AND $column = %d",  
  73. $meta_key, $object_id ) ) ) 
  74. return false; 
  75.  
  76. $_meta_value = $meta_value; 
  77. $meta_value = maybe_serialize( $meta_value ); 
  78.  
  79. /** 
  80. * Fires immediately before meta of a specific type is added. 
  81. * 
  82. * The dynamic portion of the hook, `$meta_type`, refers to the meta 
  83. * object type (comment, post, or user). 
  84. * 
  85. * @since 3.1.0 
  86. * 
  87. * @param int $object_id Object ID. 
  88. * @param string $meta_key Meta key. 
  89. * @param mixed $meta_value Meta value. 
  90. */ 
  91. do_action( "add_{$meta_type}_meta", $object_id, $meta_key, $_meta_value ); 
  92.  
  93. $result = $wpdb->insert( $table, array( 
  94. $column => $object_id,  
  95. 'meta_key' => $meta_key,  
  96. 'meta_value' => $meta_value 
  97. ) ); 
  98.  
  99. if ( ! $result ) 
  100. return false; 
  101.  
  102. $mid = (int) $wpdb->insert_id; 
  103.  
  104. wp_cache_delete($object_id, $meta_type . '_meta'); 
  105.  
  106. /** 
  107. * Fires immediately after meta of a specific type is added. 
  108. * 
  109. * The dynamic portion of the hook, `$meta_type`, refers to the meta 
  110. * object type (comment, post, or user). 
  111. * 
  112. * @since 2.9.0 
  113. * 
  114. * @param int $mid The meta ID after successful update. 
  115. * @param int $object_id Object ID. 
  116. * @param string $meta_key Meta key. 
  117. * @param mixed $meta_value Meta value. 
  118. */ 
  119. do_action( "added_{$meta_type}_meta", $mid, $object_id, $meta_key, $_meta_value ); 
  120.  
  121. return $mid; 
  122.  
  123. /** 
  124. * Update metadata for the specified object. If no value already exists for the specified object 
  125. * ID and metadata key, the metadata will be added. 
  126. * 
  127. * @since 2.9.0 
  128. * 
  129. * @global wpdb $wpdb WordPress database abstraction object. 
  130. * 
  131. * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) 
  132. * @param int $object_id ID of the object metadata is for 
  133. * @param string $meta_key Metadata key 
  134. * @param mixed $meta_value Metadata value. Must be serializable if non-scalar. 
  135. * @param mixed $prev_value Optional. If specified, only update existing metadata entries with 
  136. * the specified value. Otherwise, update all entries. 
  137. * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure. 
  138. */ 
  139. function update_metadata($meta_type, $object_id, $meta_key, $meta_value, $prev_value = '') { 
  140. global $wpdb; 
  141.  
  142. if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) { 
  143. return false; 
  144.  
  145. $object_id = absint( $object_id ); 
  146. if ( ! $object_id ) { 
  147. return false; 
  148.  
  149. $table = _get_meta_table( $meta_type ); 
  150. if ( ! $table ) { 
  151. return false; 
  152.  
  153. $column = sanitize_key($meta_type . '_id'); 
  154. $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id'; 
  155.  
  156. // expected_slashed ($meta_key) 
  157. $raw_meta_key = $meta_key; 
  158. $meta_key = wp_unslash($meta_key); 
  159. $passed_value = $meta_value; 
  160. $meta_value = wp_unslash($meta_value); 
  161. $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type ); 
  162.  
  163. /** 
  164. * Filters whether to update metadata of a specific type. 
  165. * 
  166. * The dynamic portion of the hook, `$meta_type`, refers to the meta 
  167. * object type (comment, post, or user). Returning a non-null value 
  168. * will effectively short-circuit the function. 
  169. * 
  170. * @since 3.1.0 
  171. * 
  172. * @param null|bool $check Whether to allow updating metadata for the given type. 
  173. * @param int $object_id Object ID. 
  174. * @param string $meta_key Meta key. 
  175. * @param mixed $meta_value Meta value. Must be serializable if non-scalar. 
  176. * @param mixed $prev_value Optional. If specified, only update existing 
  177. * metadata entries with the specified value. 
  178. * Otherwise, update all entries. 
  179. */ 
  180. $check = apply_filters( "update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value ); 
  181. if ( null !== $check ) 
  182. return (bool) $check; 
  183.  
  184. // Compare existing value to new value if no prev value given and the key exists only once. 
  185. if ( empty($prev_value) ) { 
  186. $old_value = get_metadata($meta_type, $object_id, $meta_key); 
  187. if ( count($old_value) == 1 ) { 
  188. if ( $old_value[0] === $meta_value ) 
  189. return false; 
  190.  
  191. $meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s AND $column = %d", $meta_key, $object_id ) ); 
  192. if ( empty( $meta_ids ) ) { 
  193. return add_metadata( $meta_type, $object_id, $raw_meta_key, $passed_value ); 
  194.  
  195. $_meta_value = $meta_value; 
  196. $meta_value = maybe_serialize( $meta_value ); 
  197.  
  198. $data = compact( 'meta_value' ); 
  199. $where = array( $column => $object_id, 'meta_key' => $meta_key ); 
  200.  
  201. if ( !empty( $prev_value ) ) { 
  202. $prev_value = maybe_serialize($prev_value); 
  203. $where['meta_value'] = $prev_value; 
  204.  
  205. foreach ( $meta_ids as $meta_id ) { 
  206. /** 
  207. * Fires immediately before updating metadata of a specific type. 
  208. * 
  209. * The dynamic portion of the hook, `$meta_type`, refers to the meta 
  210. * object type (comment, post, or user). 
  211. * 
  212. * @since 2.9.0 
  213. * 
  214. * @param int $meta_id ID of the metadata entry to update. 
  215. * @param int $object_id Object ID. 
  216. * @param string $meta_key Meta key. 
  217. * @param mixed $meta_value Meta value. 
  218. */ 
  219. do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value ); 
  220.  
  221. if ( 'post' == $meta_type ) { 
  222. /** 
  223. * Fires immediately before updating a post's metadata. 
  224. * 
  225. * @since 2.9.0 
  226. * 
  227. * @param int $meta_id ID of metadata entry to update. 
  228. * @param int $object_id Object ID. 
  229. * @param string $meta_key Meta key. 
  230. * @param mixed $meta_value Meta value. 
  231. */ 
  232. do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value ); 
  233.  
  234. $result = $wpdb->update( $table, $data, $where ); 
  235. if ( ! $result ) 
  236. return false; 
  237.  
  238. wp_cache_delete($object_id, $meta_type . '_meta'); 
  239.  
  240. foreach ( $meta_ids as $meta_id ) { 
  241. /** 
  242. * Fires immediately after updating metadata of a specific type. 
  243. * 
  244. * The dynamic portion of the hook, `$meta_type`, refers to the meta 
  245. * object type (comment, post, or user). 
  246. * 
  247. * @since 2.9.0 
  248. * 
  249. * @param int $meta_id ID of updated metadata entry. 
  250. * @param int $object_id Object ID. 
  251. * @param string $meta_key Meta key. 
  252. * @param mixed $meta_value Meta value. 
  253. */ 
  254. do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value ); 
  255.  
  256. if ( 'post' == $meta_type ) { 
  257. /** 
  258. * Fires immediately after updating a post's metadata. 
  259. * 
  260. * @since 2.9.0 
  261. * 
  262. * @param int $meta_id ID of updated metadata entry. 
  263. * @param int $object_id Object ID. 
  264. * @param string $meta_key Meta key. 
  265. * @param mixed $meta_value Meta value. 
  266. */ 
  267. do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value ); 
  268.  
  269. return true; 
  270.  
  271. /** 
  272. * Delete metadata for the specified object. 
  273. * 
  274. * @since 2.9.0 
  275. * 
  276. * @global wpdb $wpdb WordPress database abstraction object. 
  277. * 
  278. * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) 
  279. * @param int $object_id ID of the object metadata is for 
  280. * @param string $meta_key Metadata key 
  281. * @param mixed $meta_value Optional. Metadata value. Must be serializable if non-scalar. If specified, only delete 
  282. * metadata entries with this value. Otherwise, delete all entries with the specified meta_key. 
  283. * Pass `null, `false`, or an empty string to skip this check. (For backward compatibility,  
  284. * it is not possible to pass an empty string to delete those entries with an empty string 
  285. * for a value.) 
  286. * @param bool $delete_all Optional, default is false. If true, delete matching metadata entries for all objects,  
  287. * ignoring the specified object_id. Otherwise, only delete matching metadata entries for 
  288. * the specified object_id. 
  289. * @return bool True on successful delete, false on failure. 
  290. */ 
  291. function delete_metadata($meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false) { 
  292. global $wpdb; 
  293.  
  294. if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) && ! $delete_all ) { 
  295. return false; 
  296.  
  297. $object_id = absint( $object_id ); 
  298. if ( ! $object_id && ! $delete_all ) { 
  299. return false; 
  300.  
  301. $table = _get_meta_table( $meta_type ); 
  302. if ( ! $table ) { 
  303. return false; 
  304.  
  305. $type_column = sanitize_key($meta_type . '_id'); 
  306. $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id'; 
  307. // expected_slashed ($meta_key) 
  308. $meta_key = wp_unslash($meta_key); 
  309. $meta_value = wp_unslash($meta_value); 
  310.  
  311. /** 
  312. * Filters whether to delete metadata of a specific type. 
  313. * 
  314. * The dynamic portion of the hook, `$meta_type`, refers to the meta 
  315. * object type (comment, post, or user). Returning a non-null value 
  316. * will effectively short-circuit the function. 
  317. * 
  318. * @since 3.1.0 
  319. * 
  320. * @param null|bool $delete Whether to allow metadata deletion of the given type. 
  321. * @param int $object_id Object ID. 
  322. * @param string $meta_key Meta key. 
  323. * @param mixed $meta_value Meta value. Must be serializable if non-scalar. 
  324. * @param bool $delete_all Whether to delete the matching metadata entries 
  325. * for all objects, ignoring the specified $object_id. 
  326. * Default false. 
  327. */ 
  328. $check = apply_filters( "delete_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $delete_all ); 
  329. if ( null !== $check ) 
  330. return (bool) $check; 
  331.  
  332. $_meta_value = $meta_value; 
  333. $meta_value = maybe_serialize( $meta_value ); 
  334.  
  335. $query = $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s", $meta_key ); 
  336.  
  337. if ( !$delete_all ) 
  338. $query .= $wpdb->prepare(" AND $type_column = %d", $object_id ); 
  339.  
  340. if ( '' !== $meta_value && null !== $meta_value && false !== $meta_value ) 
  341. $query .= $wpdb->prepare(" AND meta_value = %s", $meta_value ); 
  342.  
  343. $meta_ids = $wpdb->get_col( $query ); 
  344. if ( !count( $meta_ids ) ) 
  345. return false; 
  346.  
  347. if ( $delete_all ) { 
  348. $value_clause = ''; 
  349. if ( '' !== $meta_value && null !== $meta_value && false !== $meta_value ) { 
  350. $value_clause = $wpdb->prepare( " AND meta_value = %s", $meta_value ); 
  351.  
  352. $object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $type_column FROM $table WHERE meta_key = %s $value_clause", $meta_key ) ); 
  353.  
  354. /** 
  355. * Fires immediately before deleting metadata of a specific type. 
  356. * 
  357. * The dynamic portion of the hook, `$meta_type`, refers to the meta 
  358. * object type (comment, post, or user). 
  359. * 
  360. * @since 3.1.0 
  361. * 
  362. * @param array $meta_ids An array of metadata entry IDs to delete. 
  363. * @param int $object_id Object ID. 
  364. * @param string $meta_key Meta key. 
  365. * @param mixed $meta_value Meta value. 
  366. */ 
  367. do_action( "delete_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value ); 
  368.  
  369. // Old-style action. 
  370. if ( 'post' == $meta_type ) { 
  371. /** 
  372. * Fires immediately before deleting metadata for a post. 
  373. * 
  374. * @since 2.9.0 
  375. * 
  376. * @param array $meta_ids An array of post metadata entry IDs to delete. 
  377. */ 
  378. do_action( 'delete_postmeta', $meta_ids ); 
  379.  
  380. $query = "DELETE FROM $table WHERE $id_column IN( " . implode( ', ', $meta_ids ) . " )"; 
  381.  
  382. $count = $wpdb->query($query); 
  383.  
  384. if ( !$count ) 
  385. return false; 
  386.  
  387. if ( $delete_all ) { 
  388. foreach ( (array) $object_ids as $o_id ) { 
  389. wp_cache_delete($o_id, $meta_type . '_meta'); 
  390. } else { 
  391. wp_cache_delete($object_id, $meta_type . '_meta'); 
  392.  
  393. /** 
  394. * Fires immediately after deleting metadata of a specific type. 
  395. * 
  396. * The dynamic portion of the hook name, `$meta_type`, refers to the meta 
  397. * object type (comment, post, or user). 
  398. * 
  399. * @since 2.9.0 
  400. * 
  401. * @param array $meta_ids An array of deleted metadata entry IDs. 
  402. * @param int $object_id Object ID. 
  403. * @param string $meta_key Meta key. 
  404. * @param mixed $meta_value Meta value. 
  405. */ 
  406. do_action( "deleted_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value ); 
  407.  
  408. // Old-style action. 
  409. if ( 'post' == $meta_type ) { 
  410. /** 
  411. * Fires immediately after deleting metadata for a post. 
  412. * 
  413. * @since 2.9.0 
  414. * 
  415. * @param array $meta_ids An array of deleted post metadata entry IDs. 
  416. */ 
  417. do_action( 'deleted_postmeta', $meta_ids ); 
  418.  
  419. return true; 
  420.  
  421. /** 
  422. * Retrieve metadata for the specified object. 
  423. * 
  424. * @since 2.9.0 
  425. * 
  426. * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) 
  427. * @param int $object_id ID of the object metadata is for 
  428. * @param string $meta_key Optional. Metadata key. If not specified, retrieve all metadata for 
  429. * the specified object. 
  430. * @param bool $single Optional, default is false. 
  431. * If true, return only the first value of the specified meta_key. 
  432. * This parameter has no effect if meta_key is not specified. 
  433. * @return mixed Single metadata value, or array of values 
  434. */ 
  435. function get_metadata($meta_type, $object_id, $meta_key = '', $single = false) { 
  436. if ( ! $meta_type || ! is_numeric( $object_id ) ) { 
  437. return false; 
  438.  
  439. $object_id = absint( $object_id ); 
  440. if ( ! $object_id ) { 
  441. return false; 
  442.  
  443. /** 
  444. * Filters whether to retrieve metadata of a specific type. 
  445. * 
  446. * The dynamic portion of the hook, `$meta_type`, refers to the meta 
  447. * object type (comment, post, or user). Returning a non-null value 
  448. * will effectively short-circuit the function. 
  449. * 
  450. * @since 3.1.0 
  451. * 
  452. * @param null|array|string $value The value get_metadata() should return - a single metadata value,  
  453. * or an array of values. 
  454. * @param int $object_id Object ID. 
  455. * @param string $meta_key Meta key. 
  456. * @param bool $single Whether to return only the first value of the specified $meta_key. 
  457. */ 
  458. $check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, $single ); 
  459. if ( null !== $check ) { 
  460. if ( $single && is_array( $check ) ) 
  461. return $check[0]; 
  462. else 
  463. return $check; 
  464.  
  465. $meta_cache = wp_cache_get($object_id, $meta_type . '_meta'); 
  466.  
  467. if ( !$meta_cache ) { 
  468. $meta_cache = update_meta_cache( $meta_type, array( $object_id ) ); 
  469. $meta_cache = $meta_cache[$object_id]; 
  470.  
  471. if ( ! $meta_key ) { 
  472. return $meta_cache; 
  473.  
  474. if ( isset($meta_cache[$meta_key]) ) { 
  475. if ( $single ) 
  476. return maybe_unserialize( $meta_cache[$meta_key][0] ); 
  477. else 
  478. return array_map('maybe_unserialize', $meta_cache[$meta_key]); 
  479.  
  480. if ($single) 
  481. return ''; 
  482. else 
  483. return array(); 
  484.  
  485. /** 
  486. * Determine if a meta key is set for a given object 
  487. * 
  488. * @since 3.3.0 
  489. * 
  490. * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) 
  491. * @param int $object_id ID of the object metadata is for 
  492. * @param string $meta_key Metadata key. 
  493. * @return bool True of the key is set, false if not. 
  494. */ 
  495. function metadata_exists( $meta_type, $object_id, $meta_key ) { 
  496. if ( ! $meta_type || ! is_numeric( $object_id ) ) { 
  497. return false; 
  498.  
  499. $object_id = absint( $object_id ); 
  500. if ( ! $object_id ) { 
  501. return false; 
  502.  
  503. /** This filter is documented in wp-includes/meta.php */ 
  504. $check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, true ); 
  505. if ( null !== $check ) 
  506. return (bool) $check; 
  507.  
  508. $meta_cache = wp_cache_get( $object_id, $meta_type . '_meta' ); 
  509.  
  510. if ( !$meta_cache ) { 
  511. $meta_cache = update_meta_cache( $meta_type, array( $object_id ) ); 
  512. $meta_cache = $meta_cache[$object_id]; 
  513.  
  514. if ( isset( $meta_cache[ $meta_key ] ) ) 
  515. return true; 
  516.  
  517. return false; 
  518.  
  519. /** 
  520. * Get meta data by meta ID 
  521. * 
  522. * @since 3.3.0 
  523. * 
  524. * @global wpdb $wpdb WordPress database abstraction object. 
  525. * 
  526. * @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user). 
  527. * @param int $meta_id ID for a specific meta row 
  528. * @return object|false Meta object or false. 
  529. */ 
  530. function get_metadata_by_mid( $meta_type, $meta_id ) { 
  531. global $wpdb; 
  532.  
  533. if ( ! $meta_type || ! is_numeric( $meta_id ) || floor( $meta_id ) != $meta_id ) { 
  534. return false; 
  535.  
  536. $meta_id = intval( $meta_id ); 
  537. if ( $meta_id <= 0 ) { 
  538. return false; 
  539.  
  540. $table = _get_meta_table( $meta_type ); 
  541. if ( ! $table ) { 
  542. return false; 
  543.  
  544. $id_column = ( 'user' == $meta_type ) ? 'umeta_id' : 'meta_id'; 
  545.  
  546. $meta = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table WHERE $id_column = %d", $meta_id ) ); 
  547.  
  548. if ( empty( $meta ) ) 
  549. return false; 
  550.  
  551. if ( isset( $meta->meta_value ) ) 
  552. $meta->meta_value = maybe_unserialize( $meta->meta_value ); 
  553.  
  554. return $meta; 
  555.  
  556. /** 
  557. * Update meta data by meta ID 
  558. * 
  559. * @since 3.3.0 
  560. * 
  561. * @global wpdb $wpdb WordPress database abstraction object. 
  562. * 
  563. * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) 
  564. * @param int $meta_id ID for a specific meta row 
  565. * @param string $meta_value Metadata value 
  566. * @param string $meta_key Optional, you can provide a meta key to update it 
  567. * @return bool True on successful update, false on failure. 
  568. */ 
  569. function update_metadata_by_mid( $meta_type, $meta_id, $meta_value, $meta_key = false ) { 
  570. global $wpdb; 
  571.  
  572. // Make sure everything is valid. 
  573. if ( ! $meta_type || ! is_numeric( $meta_id ) || floor( $meta_id ) != $meta_id ) { 
  574. return false; 
  575.  
  576. $meta_id = intval( $meta_id ); 
  577. if ( $meta_id <= 0 ) { 
  578. return false; 
  579.  
  580. $table = _get_meta_table( $meta_type ); 
  581. if ( ! $table ) { 
  582. return false; 
  583.  
  584. $column = sanitize_key($meta_type . '_id'); 
  585. $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id'; 
  586.  
  587. // Fetch the meta and go on if it's found. 
  588. if ( $meta = get_metadata_by_mid( $meta_type, $meta_id ) ) { 
  589. $original_key = $meta->meta_key; 
  590. $object_id = $meta->{$column}; 
  591.  
  592. // If a new meta_key (last parameter) was specified, change the meta key,  
  593. // otherwise use the original key in the update statement. 
  594. if ( false === $meta_key ) { 
  595. $meta_key = $original_key; 
  596. } elseif ( ! is_string( $meta_key ) ) { 
  597. return false; 
  598.  
  599. // Sanitize the meta 
  600. $_meta_value = $meta_value; 
  601. $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type ); 
  602. $meta_value = maybe_serialize( $meta_value ); 
  603.  
  604. // Format the data query arguments. 
  605. $data = array( 
  606. 'meta_key' => $meta_key,  
  607. 'meta_value' => $meta_value 
  608. ); 
  609.  
  610. // Format the where query arguments. 
  611. $where = array(); 
  612. $where[$id_column] = $meta_id; 
  613.  
  614. /** This action is documented in wp-includes/meta.php */ 
  615. do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value ); 
  616.  
  617. if ( 'post' == $meta_type ) { 
  618. /** This action is documented in wp-includes/meta.php */ 
  619. do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value ); 
  620.  
  621. // Run the update query, all fields in $data are %s, $where is a %d. 
  622. $result = $wpdb->update( $table, $data, $where, '%s', '%d' ); 
  623. if ( ! $result ) 
  624. return false; 
  625.  
  626. // Clear the caches. 
  627. wp_cache_delete($object_id, $meta_type . '_meta'); 
  628.  
  629. /** This action is documented in wp-includes/meta.php */ 
  630. do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value ); 
  631.  
  632. if ( 'post' == $meta_type ) { 
  633. /** This action is documented in wp-includes/meta.php */ 
  634. do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value ); 
  635.  
  636. return true; 
  637.  
  638. // And if the meta was not found. 
  639. return false; 
  640.  
  641. /** 
  642. * Delete meta data by meta ID 
  643. * 
  644. * @since 3.3.0 
  645. * 
  646. * @global wpdb $wpdb WordPress database abstraction object. 
  647. * 
  648. * @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user). 
  649. * @param int $meta_id ID for a specific meta row 
  650. * @return bool True on successful delete, false on failure. 
  651. */ 
  652. function delete_metadata_by_mid( $meta_type, $meta_id ) { 
  653. global $wpdb; 
  654.  
  655. // Make sure everything is valid. 
  656. if ( ! $meta_type || ! is_numeric( $meta_id ) || floor( $meta_id ) != $meta_id ) { 
  657. return false; 
  658.  
  659. $meta_id = intval( $meta_id ); 
  660. if ( $meta_id <= 0 ) { 
  661. return false; 
  662.  
  663. $table = _get_meta_table( $meta_type ); 
  664. if ( ! $table ) { 
  665. return false; 
  666.  
  667. // object and id columns 
  668. $column = sanitize_key($meta_type . '_id'); 
  669. $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id'; 
  670.  
  671. // Fetch the meta and go on if it's found. 
  672. if ( $meta = get_metadata_by_mid( $meta_type, $meta_id ) ) { 
  673. $object_id = $meta->{$column}; 
  674.  
  675. /** This action is documented in wp-includes/meta.php */ 
  676. do_action( "delete_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value ); 
  677.  
  678. // Old-style action. 
  679. if ( 'post' == $meta_type || 'comment' == $meta_type ) { 
  680. /** 
  681. * Fires immediately before deleting post or comment metadata of a specific type. 
  682. * 
  683. * The dynamic portion of the hook, `$meta_type`, refers to the meta 
  684. * object type (post or comment). 
  685. * 
  686. * @since 3.4.0 
  687. * 
  688. * @param int $meta_id ID of the metadata entry to delete. 
  689. */ 
  690. do_action( "delete_{$meta_type}meta", $meta_id ); 
  691.  
  692. // Run the query, will return true if deleted, false otherwise 
  693. $result = (bool) $wpdb->delete( $table, array( $id_column => $meta_id ) ); 
  694.  
  695. // Clear the caches. 
  696. wp_cache_delete($object_id, $meta_type . '_meta'); 
  697.  
  698. /** This action is documented in wp-includes/meta.php */ 
  699. do_action( "deleted_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value ); 
  700.  
  701. // Old-style action. 
  702. if ( 'post' == $meta_type || 'comment' == $meta_type ) { 
  703. /** 
  704. * Fires immediately after deleting post or comment metadata of a specific type. 
  705. * 
  706. * The dynamic portion of the hook, `$meta_type`, refers to the meta 
  707. * object type (post or comment). 
  708. * 
  709. * @since 3.4.0 
  710. * 
  711. * @param int $meta_ids Deleted metadata entry ID. 
  712. */ 
  713. do_action( "deleted_{$meta_type}meta", $meta_id ); 
  714.  
  715. return $result; 
  716.  
  717.  
  718. // Meta id was not found. 
  719. return false; 
  720.  
  721. /** 
  722. * Update the metadata cache for the specified objects. 
  723. * 
  724. * @since 2.9.0 
  725. * 
  726. * @global wpdb $wpdb WordPress database abstraction object. 
  727. * 
  728. * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) 
  729. * @param int|array $object_ids Array or comma delimited list of object IDs to update cache for 
  730. * @return array|false Metadata cache for the specified objects, or false on failure. 
  731. */ 
  732. function update_meta_cache($meta_type, $object_ids) { 
  733. global $wpdb; 
  734.  
  735. if ( ! $meta_type || ! $object_ids ) { 
  736. return false; 
  737.  
  738. $table = _get_meta_table( $meta_type ); 
  739. if ( ! $table ) { 
  740. return false; 
  741.  
  742. $column = sanitize_key($meta_type . '_id'); 
  743.  
  744. if ( !is_array($object_ids) ) { 
  745. $object_ids = preg_replace('|[^0-9, ]|', '', $object_ids); 
  746. $object_ids = explode(', ', $object_ids); 
  747.  
  748. $object_ids = array_map('intval', $object_ids); 
  749.  
  750. $cache_key = $meta_type . '_meta'; 
  751. $ids = array(); 
  752. $cache = array(); 
  753. foreach ( $object_ids as $id ) { 
  754. $cached_object = wp_cache_get( $id, $cache_key ); 
  755. if ( false === $cached_object ) 
  756. $ids[] = $id; 
  757. else 
  758. $cache[$id] = $cached_object; 
  759.  
  760. if ( empty( $ids ) ) 
  761. return $cache; 
  762.  
  763. // Get meta info 
  764. $id_list = join( ', ', $ids ); 
  765. $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id'; 
  766. $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 ); 
  767.  
  768. if ( !empty($meta_list) ) { 
  769. foreach ( $meta_list as $metarow) { 
  770. $mpid = intval($metarow[$column]); 
  771. $mkey = $metarow['meta_key']; 
  772. $mval = $metarow['meta_value']; 
  773.  
  774. // Force subkeys to be array type: 
  775. if ( !isset($cache[$mpid]) || !is_array($cache[$mpid]) ) 
  776. $cache[$mpid] = array(); 
  777. if ( !isset($cache[$mpid][$mkey]) || !is_array($cache[$mpid][$mkey]) ) 
  778. $cache[$mpid][$mkey] = array(); 
  779.  
  780. // Add a value to the current pid/key: 
  781. $cache[$mpid][$mkey][] = $mval; 
  782.  
  783. foreach ( $ids as $id ) { 
  784. if ( ! isset($cache[$id]) ) 
  785. $cache[$id] = array(); 
  786. wp_cache_add( $id, $cache[$id], $cache_key ); 
  787.  
  788. return $cache; 
  789.  
  790. /** 
  791. * Retrieves the queue for lazy-loading metadata. 
  792. * 
  793. * @since 4.5.0 
  794. * 
  795. * @return WP_Metadata_Lazyloader $lazyloader Metadata lazyloader queue. 
  796. */ 
  797. function wp_metadata_lazyloader() { 
  798. static $wp_metadata_lazyloader; 
  799.  
  800. if ( null === $wp_metadata_lazyloader ) { 
  801. $wp_metadata_lazyloader = new WP_Metadata_Lazyloader(); 
  802.  
  803. return $wp_metadata_lazyloader; 
  804.  
  805. /** 
  806. * Given a meta query, generates SQL clauses to be appended to a main query. 
  807. * 
  808. * @since 3.2.0 
  809. * 
  810. * @see WP_Meta_Query 
  811. * 
  812. * @param array $meta_query A meta query. 
  813. * @param string $type Type of meta. 
  814. * @param string $primary_table Primary database table name. 
  815. * @param string $primary_id_column Primary ID column name. 
  816. * @param object $context Optional. The main query object 
  817. * @return array Associative array of `JOIN` and `WHERE` SQL. 
  818. */ 
  819. function get_meta_sql( $meta_query, $type, $primary_table, $primary_id_column, $context = null ) { 
  820. $meta_query_obj = new WP_Meta_Query( $meta_query ); 
  821. return $meta_query_obj->get_sql( $type, $primary_table, $primary_id_column, $context ); 
  822.  
  823. /** 
  824. * Retrieve the name of the metadata table for the specified object type. 
  825. * 
  826. * @since 2.9.0 
  827. * 
  828. * @global wpdb $wpdb WordPress database abstraction object. 
  829. * 
  830. * @param string $type Type of object to get metadata table for (e.g., comment, post, or user) 
  831. * @return string|false Metadata table name, or false if no metadata table exists 
  832. */ 
  833. function _get_meta_table($type) { 
  834. global $wpdb; 
  835.  
  836. $table_name = $type . 'meta'; 
  837.  
  838. if ( empty($wpdb->$table_name) ) 
  839. return false; 
  840.  
  841. return $wpdb->$table_name; 
  842.  
  843. /** 
  844. * Determine whether a meta key is protected. 
  845. * 
  846. * @since 3.1.3 
  847. * 
  848. * @param string $meta_key Meta key 
  849. * @param string|null $meta_type 
  850. * @return bool True if the key is protected, false otherwise. 
  851. */ 
  852. function is_protected_meta( $meta_key, $meta_type = null ) { 
  853. $protected = ( '_' == $meta_key[0] ); 
  854.  
  855. /** 
  856. * Filters whether a meta key is protected. 
  857. * 
  858. * @since 3.2.0 
  859. * 
  860. * @param bool $protected Whether the key is protected. Default false. 
  861. * @param string $meta_key Meta key. 
  862. * @param string $meta_type Meta type. 
  863. */ 
  864. return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type ); 
  865.  
  866. /** 
  867. * Sanitize meta value. 
  868. * 
  869. * @since 3.1.3 
  870. * 
  871. * @param string $meta_key Meta key. 
  872. * @param mixed $meta_value Meta value to sanitize. 
  873. * @param string $object_type Type of object the meta is registered to. 
  874. * 
  875. * @return mixed Sanitized $meta_value. 
  876. */ 
  877. function sanitize_meta( $meta_key, $meta_value, $object_type ) { 
  878. /** 
  879. * Filters the sanitization of a specific meta key of a specific meta type. 
  880. * 
  881. * The dynamic portions of the hook name, `$meta_type`, and `$meta_key`,  
  882. * refer to the metadata object type (comment, post, or user) and the meta 
  883. * key value, respectively. 
  884. * 
  885. * @since 3.3.0 
  886. * 
  887. * @param mixed $meta_value Meta value to sanitize. 
  888. * @param string $meta_key Meta key. 
  889. * @param string $object_type Object type. 
  890. */ 
  891. return apply_filters( "sanitize_{$object_type}_meta_{$meta_key}", $meta_value, $meta_key, $object_type ); 
  892.  
  893. /** 
  894. * Registers a meta key. 
  895. * 
  896. * @since 3.3.0 
  897. * @since 4.6.0 {@link https://core.trac.wordpress.org/ticket/35658 Modified 
  898. * to support an array of data to attach to registered meta keys}. Previous arguments for 
  899. * `$sanitize_callback` and `$auth_callback` have been folded into this array. 
  900. * 
  901. * @param string $object_type Type of object this meta is registered to. 
  902. * @param string $meta_key Meta key to register. 
  903. * @param array $args { 
  904. * Data used to describe the meta key when registered. 
  905. * 
  906. * @type string $type The type of data associated with this meta key. 
  907. * @type string $description A description of the data attached to this meta key. 
  908. * @type bool $single Whether the meta key has one value per object, or an array of values per object. 
  909. * @type string $sanitize_callback A function or method to call when sanitizing `$meta_key` data. 
  910. * @type string $auth_callback Optional. A function or method to call when performing edit_post_meta, add_post_meta, and delete_post_meta capability checks. 
  911. * @type bool $show_in_rest Whether data associated with this meta key can be considered public. 
  912. * } 
  913. * @param string|array $deprecated Deprecated. Use `$args` instead. 
  914. * 
  915. * @return bool True if the meta key was successfully registered in the global array, false if not. 
  916. * Registering a meta key with distinct sanitize and auth callbacks will fire those 
  917. * callbacks, but will not add to the global registry. 
  918. */ 
  919. function register_meta( $object_type, $meta_key, $args, $deprecated = null ) { 
  920. global $wp_meta_keys; 
  921.  
  922. if ( ! is_array( $wp_meta_keys ) ) { 
  923. $wp_meta_keys = array(); 
  924.  
  925. $defaults = array( 
  926. 'type' => 'string',  
  927. 'description' => '',  
  928. 'single' => false,  
  929. 'sanitize_callback' => null,  
  930. 'auth_callback' => null,  
  931. 'show_in_rest' => false,  
  932. ); 
  933.  
  934. // There used to be individual args for sanitize and auth callbacks 
  935. $has_old_sanitize_cb = false; 
  936. $has_old_auth_cb = false; 
  937.  
  938. if ( is_callable( $args ) ) { 
  939. $args = array( 
  940. 'sanitize_callback' => $args,  
  941. ); 
  942.  
  943. $has_old_sanitize_cb = true; 
  944. } else { 
  945. $args = (array) $args; 
  946.  
  947. if ( is_callable( $deprecated ) ) { 
  948. $args['auth_callback'] = $deprecated; 
  949. $has_old_auth_cb = true; 
  950.  
  951. /** 
  952. * Filters the registration arguments when registering meta. 
  953. * 
  954. * @since 4.6.0 
  955. * 
  956. * @param array $args Array of meta registration arguments. 
  957. * @param array $defaults Array of default arguments. 
  958. * @param string $object_type Object type. 
  959. * @param string $meta_key Meta key. 
  960. */ 
  961. $args = apply_filters( 'register_meta_args', $args, $defaults, $object_type, $meta_key ); 
  962. $args = wp_parse_args( $args, $defaults ); 
  963.  
  964. // If `auth_callback` is not provided, fall back to `is_protected_meta()`. 
  965. if ( empty( $args['auth_callback'] ) ) { 
  966. if ( is_protected_meta( $meta_key, $object_type ) ) { 
  967. $args['auth_callback'] = '__return_false'; 
  968. } else { 
  969. $args['auth_callback'] = '__return_true'; 
  970.  
  971. // Back-compat: old sanitize and auth callbacks are applied to all of an object type. 
  972. if ( is_callable( $args['sanitize_callback'] ) ) { 
  973. add_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'], 10, 3 ); 
  974.  
  975. if ( is_callable( $args['auth_callback'] ) ) { 
  976. add_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'], 10, 6 ); 
  977.  
  978. // Global registry only contains meta keys registered with the array of arguments added in 4.6.0. 
  979. if ( ! $has_old_auth_cb && ! $has_old_sanitize_cb ) { 
  980. $wp_meta_keys[ $object_type ][ $meta_key ] = $args; 
  981.  
  982. return true; 
  983.  
  984. return false; 
  985.  
  986. /** 
  987. * Checks if a meta key is registered. 
  988. * 
  989. * @since 4.6.0 
  990. * 
  991. * @param string $object_type The type of object. 
  992. * @param string $meta_key The meta key. 
  993. * 
  994. * @return bool True if the meta key is registered to the object type. False if not. 
  995. */ 
  996. function registered_meta_key_exists( $object_type, $meta_key ) { 
  997. global $wp_meta_keys; 
  998.  
  999. if ( ! is_array( $wp_meta_keys ) ) { 
  1000. return false; 
  1001.  
  1002. if ( ! isset( $wp_meta_keys[ $object_type ] ) ) { 
  1003. return false; 
  1004.  
  1005. if ( isset( $wp_meta_keys[ $object_type ][ $meta_key ] ) ) { 
  1006. return true; 
  1007.  
  1008. return false; 
  1009.  
  1010. /** 
  1011. * Unregisters a meta key from the list of registered keys. 
  1012. * 
  1013. * @since 4.6.0 
  1014. * 
  1015. * @param string $object_type The type of object. 
  1016. * @param string $meta_key The meta key. 
  1017. * @return bool True if successful. False if the meta key was not registered. 
  1018. */ 
  1019. function unregister_meta_key( $object_type, $meta_key ) { 
  1020. global $wp_meta_keys; 
  1021.  
  1022. if ( ! registered_meta_key_exists( $object_type, $meta_key ) ) { 
  1023. return false; 
  1024.  
  1025. $args = $wp_meta_keys[ $object_type ][ $meta_key ]; 
  1026.  
  1027. if ( isset( $args['sanitize_callback'] ) && is_callable( $args['sanitize_callback'] ) ) { 
  1028. remove_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'] ); 
  1029.  
  1030. if ( isset( $args['auth_callback'] ) && is_callable( $args['auth_callback'] ) ) { 
  1031. remove_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'] ); 
  1032.  
  1033. unset( $wp_meta_keys[ $object_type ][ $meta_key ] ); 
  1034.  
  1035. // Do some clean up 
  1036. if ( empty( $wp_meta_keys[ $object_type ] ) ) { 
  1037. unset( $wp_meta_keys[ $object_type ] ); 
  1038.  
  1039. return true; 
  1040.  
  1041. /** 
  1042. * Retrieves a list of registered meta keys for an object type. 
  1043. * 
  1044. * @since 4.6.0 
  1045. * 
  1046. * @param string $object_type The type of object. Post, comment, user, term. 
  1047. * @return array List of registered meta keys. 
  1048. */ 
  1049. function get_registered_meta_keys( $object_type ) { 
  1050. global $wp_meta_keys; 
  1051.  
  1052. if ( ! is_array( $wp_meta_keys ) || ! isset( $wp_meta_keys[ $object_type ] ) ) { 
  1053. return array(); 
  1054.  
  1055. return $wp_meta_keys[ $object_type ]; 
  1056.  
  1057. /** 
  1058. * Retrieves registered metadata for a specified object. 
  1059. * 
  1060. * @since 4.6.0 
  1061. * 
  1062. * @param string $object_type Type of object to request metadata for. (e.g. comment, post, term, user) 
  1063. * @param int $object_id ID of the object the metadata is for. 
  1064. * @param string $meta_key Optional. Registered metadata key. If not specified, retrieve all registered 
  1065. * metadata for the specified object. 
  1066. * @return mixed A single value or array of values for a key if specified. An array of all registered keys 
  1067. * and values for an object ID if not. 
  1068. */ 
  1069. function get_registered_metadata( $object_type, $object_id, $meta_key = '' ) { 
  1070. if ( ! empty( $meta_key ) ) { 
  1071. if ( ! registered_meta_key_exists( $object_type, $meta_key ) ) { 
  1072. return false; 
  1073. $meta_keys = get_registered_meta_keys( $object_type ); 
  1074. $meta_key_data = $meta_keys[ $meta_key ]; 
  1075.  
  1076. $data = get_metadata( $object_type, $object_id, $meta_key, $meta_key_data['single'] ); 
  1077.  
  1078. return $data; 
  1079.  
  1080. $data = get_metadata( $object_type, $object_id ); 
  1081.  
  1082. $meta_keys = get_registered_meta_keys( $object_type ); 
  1083. $registered_data = array(); 
  1084.  
  1085. // Someday, array_filter() 
  1086. foreach ( $meta_keys as $k => $v ) { 
  1087. if ( isset( $data[ $k ] ) ) { 
  1088. $registered_data[ $k ] = $data[ $k ]; 
  1089.  
  1090. return $registered_data; 
  1091.  
  1092. /** 
  1093. * Filter out `register_meta()` args based on a whitelist. 
  1094. * `register_meta()` args may change over time, so requiring the whitelist 
  1095. * to be explicitly turned off is a warranty seal of sorts. 
  1096. * 
  1097. * @access private 
  1098. * @since 4.6.0 
  1099. * 
  1100. * @param array $args Arguments from `register_meta()`. 
  1101. * @param array $default_args Default arguments for `register_meta()`. 
  1102. * 
  1103. * @return array Filtered arguments. 
  1104. */ 
  1105. function _wp_register_meta_args_whitelist( $args, $default_args ) { 
  1106. $whitelist = array_keys( $default_args ); 
  1107.  
  1108. // In an anonymous function world, this would be better as an array_filter() 
  1109. foreach ( $args as $key => $value ) { 
  1110. if ( ! in_array( $key, $whitelist ) ) { 
  1111. unset( $args[ $key ] ); 
  1112.  
  1113. return $args; 
.