| | 1 | <?php |
| | 2 | /** |
| | 3 | * BuddyPress Metadata API |
| | 4 | * |
| | 5 | * Functions for retrieving and manipulating metadata of various BuddyPress object/component 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 BuddyPress |
| | 10 | * @subpackage Core |
| | 11 | * @since 1.6.2 |
| | 12 | */ |
| | 13 | |
| | 14 | /** |
| | 15 | * Add metadata for the specified object. |
| | 16 | * |
| | 17 | * @since 1.6.2 |
| | 18 | * @uses $wpdb WordPress database object for queries. |
| | 19 | * @uses do_action() Calls 'added_{$meta_type}_meta' with meta_id of added metadata entry, |
| | 20 | * object ID, meta key, and meta value |
| | 21 | * |
| | 22 | * @param string $meta_type Type of object metadata is for (e.g., activity, group etc) |
| | 23 | * @param int $object_id ID of the object metadata is for |
| | 24 | * @param string $meta_key Metadata key |
| | 25 | * @param string $meta_value Metadata value |
| | 26 | * @param bool $unique Optional, default is false. Whether the specified metadata key should be |
| | 27 | * unique for the object. If true, and the object already has a value for the specified |
| | 28 | * metadata key, no change will be made |
| | 29 | * @return bool The meta ID on successful update, false on failure. |
| | 30 | */ |
| | 31 | function bp_add_metadata($meta_type, $object_id, $meta_key, $meta_value, $unique = false) { |
| | 32 | if ( !$meta_type || !$meta_key ) |
| | 33 | return false; |
| | 34 | |
| | 35 | if ( !$object_id = absint($object_id) ) |
| | 36 | return false; |
| | 37 | |
| | 38 | if ( ! $table = _bp_get_meta_table($meta_type) ) |
| | 39 | return false; |
| | 40 | |
| | 41 | global $wpdb; |
| | 42 | |
| | 43 | $column = esc_sql($meta_type . '_id'); |
| | 44 | |
| | 45 | // expected_slashed ($meta_key) |
| | 46 | $meta_key = stripslashes($meta_key); |
| | 47 | $meta_value = stripslashes_deep($meta_value); |
| | 48 | $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type ); |
| | 49 | |
| | 50 | $check = apply_filters( "add_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $unique ); |
| | 51 | if ( null !== $check ) |
| | 52 | return $check; |
| | 53 | |
| | 54 | if ( $unique && $wpdb->get_var( $wpdb->prepare( |
| | 55 | "SELECT COUNT(*) FROM $table WHERE meta_key = %s AND $column = %d", |
| | 56 | $meta_key, $object_id ) ) ) |
| | 57 | return false; |
| | 58 | |
| | 59 | $_meta_value = $meta_value; |
| | 60 | $meta_value = maybe_serialize( $meta_value ); |
| | 61 | |
| | 62 | do_action( "add_{$meta_type}_meta", $object_id, $meta_key, $_meta_value ); |
| | 63 | |
| | 64 | $result = $wpdb->insert( $table, array( |
| | 65 | $column => $object_id, |
| | 66 | 'meta_key' => $meta_key, |
| | 67 | 'meta_value' => $meta_value |
| | 68 | ) ); |
| | 69 | |
| | 70 | if ( ! $result ) |
| | 71 | return false; |
| | 72 | |
| | 73 | $mid = (int) $wpdb->insert_id; |
| | 74 | |
| | 75 | wp_cache_delete($object_id, 'bp_'.$meta_type . '_meta'); |
| | 76 | |
| | 77 | do_action( "added_{$meta_type}_meta", $mid, $object_id, $meta_key, $_meta_value ); |
| | 78 | |
| | 79 | return $mid; |
| | 80 | } |
| | 81 | |
| | 82 | /** |
| | 83 | * Update metadata for the specified object. If no value already exists for the specified object |
| | 84 | * ID and metadata key, the metadata will be added. |
| | 85 | * |
| | 86 | * @since 1.6.2 |
| | 87 | * @uses $wpdb WordPress database object for queries. |
| | 88 | * @uses do_action() Calls 'update_{$meta_type}_meta' before updating metadata with meta_id of |
| | 89 | * metadata entry to update, object ID, meta key, and meta value |
| | 90 | * @uses do_action() Calls 'updated_{$meta_type}_meta' after updating metadata with meta_id of |
| | 91 | * updated metadata entry, object ID, meta key, and meta value |
| | 92 | * |
| | 93 | * @param string $meta_type Type of object metadata is for (e.g., activity, group etc) |
| | 94 | * @param int $object_id ID of the object metadata is for |
| | 95 | * @param string $meta_key Metadata key |
| | 96 | * @param string $meta_value Metadata value |
| | 97 | * @param string $prev_value Optional. If specified, only update existing metadata entries with |
| | 98 | * the specified value. Otherwise, update all entries. |
| | 99 | * @return bool True on successful update, false on failure. |
| | 100 | */ |
| | 101 | function bp_update_metadata($meta_type, $object_id, $meta_key, $meta_value, $prev_value = '') { |
| | 102 | if ( !$meta_type || !$meta_key ) |
| | 103 | return false; |
| | 104 | |
| | 105 | if ( !$object_id = absint($object_id) ) |
| | 106 | return false; |
| | 107 | |
| | 108 | if ( ! $table = _bp_get_meta_table($meta_type) ) |
| | 109 | return false; |
| | 110 | |
| | 111 | global $wpdb; |
| | 112 | |
| | 113 | $column = esc_sql($meta_type . '_id');//eg.g activity_id, group_id |
| | 114 | $id_column = 'id'; |
| | 115 | |
| | 116 | // expected_slashed ($meta_key) |
| | 117 | $meta_key = stripslashes($meta_key); |
| | 118 | $passed_value = $meta_value; |
| | 119 | $meta_value = stripslashes_deep($meta_value); |
| | 120 | $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type ); |
| | 121 | |
| | 122 | $check = apply_filters( "update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value ); |
| | 123 | if ( null !== $check ) |
| | 124 | return (bool) $check; |
| | 125 | |
| | 126 | if ( ! $meta_id = $wpdb->get_var( $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s AND $column = %d", $meta_key, $object_id ) ) ) |
| | 127 | return bp_add_metadata($meta_type, $object_id, $meta_key, $passed_value); |
| | 128 | |
| | 129 | // Compare existing value to new value if no prev value given and the key exists only once. |
| | 130 | if ( empty($prev_value) ) { |
| | 131 | $old_value = bp_get_metadata($meta_type, $object_id, $meta_key); |
| | 132 | if ( count($old_value) == 1 ) { |
| | 133 | if ( $old_value[0] === $meta_value ) |
| | 134 | return false; |
| | 135 | } |
| | 136 | } |
| | 137 | |
| | 138 | $_meta_value = $meta_value; |
| | 139 | $meta_value = maybe_serialize( $meta_value ); |
| | 140 | |
| | 141 | $data = compact( 'meta_value' ); |
| | 142 | $where = array( $column => $object_id, 'meta_key' => $meta_key ); |
| | 143 | |
| | 144 | if ( !empty( $prev_value ) ) { |
| | 145 | $prev_value = maybe_serialize($prev_value); |
| | 146 | $where['meta_value'] = $prev_value; |
| | 147 | } |
| | 148 | |
| | 149 | do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value ); |
| | 150 | |
| | 151 | |
| | 152 | |
| | 153 | $wpdb->update( $table, $data, $where ); |
| | 154 | |
| | 155 | wp_cache_delete($object_id, 'bp_'.$meta_type . '_meta'); |
| | 156 | |
| | 157 | do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value ); |
| | 158 | |
| | 159 | |
| | 160 | |
| | 161 | return true; |
| | 162 | } |
| | 163 | |
| | 164 | /** |
| | 165 | * Delete metadata for the specified object. |
| | 166 | * |
| | 167 | * @since 1.6.2 |
| | 168 | * @uses $wpdb WordPress database object for queries. |
| | 169 | * @uses do_action() Calls 'deleted_{$meta_type}_meta' after deleting with meta_id of |
| | 170 | * deleted metadata entries, object ID, meta key, and meta value |
| | 171 | * |
| | 172 | * @param string $meta_type Type of object metadata is for (e.g., activity, group) |
| | 173 | * @param int $object_id ID of the object metadata is for |
| | 174 | * @param string $meta_key Metadata key |
| | 175 | * @param string $meta_value Optional. Metadata value. If specified, only delete metadata entries |
| | 176 | * with this value. Otherwise, delete all entries with the specified meta_key. |
| | 177 | * @param bool $delete_all Optional, default is false. If true, delete matching metadata entries |
| | 178 | * for all objects, ignoring the specified object_id. Otherwise, only delete matching |
| | 179 | * metadata entries for the specified object_id. |
| | 180 | * @return bool True on successful delete, false on failure. |
| | 181 | */ |
| | 182 | function bp_delete_metadata($meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false) { |
| | 183 | if ( !$meta_type || !$meta_key ) |
| | 184 | return false; |
| | 185 | |
| | 186 | if ( (!$object_id = absint($object_id)) && !$delete_all ) |
| | 187 | return false; |
| | 188 | |
| | 189 | if ( ! $table = _bp_get_meta_table($meta_type) ) |
| | 190 | return false; |
| | 191 | |
| | 192 | global $wpdb; |
| | 193 | |
| | 194 | $type_column = esc_sql($meta_type . '_id'); |
| | 195 | $id_column = 'id'; |
| | 196 | // expected_slashed ($meta_key) |
| | 197 | $meta_key = stripslashes($meta_key); |
| | 198 | $meta_value = stripslashes_deep($meta_value); |
| | 199 | |
| | 200 | $check = apply_filters( "delete_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $delete_all ); |
| | 201 | if ( null !== $check ) |
| | 202 | return (bool) $check; |
| | 203 | |
| | 204 | $_meta_value = $meta_value; |
| | 205 | $meta_value = maybe_serialize( $meta_value ); |
| | 206 | |
| | 207 | $query = $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s", $meta_key ); |
| | 208 | |
| | 209 | if ( !$delete_all ) |
| | 210 | $query .= $wpdb->prepare(" AND $type_column = %d", $object_id ); |
| | 211 | |
| | 212 | if ( $meta_value ) |
| | 213 | $query .= $wpdb->prepare(" AND meta_value = %s", $meta_value ); |
| | 214 | |
| | 215 | $meta_ids = $wpdb->get_col( $query ); |
| | 216 | if ( !count( $meta_ids ) ) |
| | 217 | return false; |
| | 218 | |
| | 219 | if ( $delete_all ) |
| | 220 | $object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $type_column FROM $table WHERE meta_key = %s", $meta_key ) ); |
| | 221 | |
| | 222 | do_action( "delete_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value ); |
| | 223 | |
| | 224 | |
| | 225 | |
| | 226 | $query = "DELETE FROM $table WHERE $id_column IN( " . implode( ',', $meta_ids ) . " )"; |
| | 227 | |
| | 228 | $count = $wpdb->query($query); |
| | 229 | |
| | 230 | if ( !$count ) |
| | 231 | return false; |
| | 232 | |
| | 233 | if ( $delete_all ) { |
| | 234 | foreach ( (array) $object_ids as $o_id ) { |
| | 235 | wp_cache_delete($o_id, 'bp_'.$meta_type . '_meta'); |
| | 236 | } |
| | 237 | } else { |
| | 238 | wp_cache_delete($object_id, 'bp_'.$meta_type . '_meta'); |
| | 239 | } |
| | 240 | |
| | 241 | do_action( "deleted_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value ); |
| | 242 | |
| | 243 | |
| | 244 | |
| | 245 | return true; |
| | 246 | } |
| | 247 | |
| | 248 | /** |
| | 249 | * Retrieve metadata for the specified object. |
| | 250 | * |
| | 251 | * @since 1.6.2 |
| | 252 | * |
| | 253 | * @param string $meta_type Type of object metadata is for (e.g., activity, group) |
| | 254 | * @param int $object_id ID of the object metadata is for |
| | 255 | * @param string $meta_key Optional. Metadata key. If not specified, retrieve all metadata for |
| | 256 | * the specified object. |
| | 257 | * @param bool $single Optional, default is false. If true, return only the first value of the |
| | 258 | * specified meta_key. This parameter has no effect if meta_key is not specified. |
| | 259 | * @return string|array Single metadata value, or array of values |
| | 260 | */ |
| | 261 | function bp_get_metadata($meta_type, $object_id, $meta_key = '', $single = false) { |
| | 262 | if ( !$meta_type ) |
| | 263 | return false; |
| | 264 | |
| | 265 | if ( !$object_id = absint($object_id) ) |
| | 266 | return false; |
| | 267 | |
| | 268 | $check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, $single ); |
| | 269 | if ( null !== $check ) { |
| | 270 | if ( $single && is_array( $check ) ) |
| | 271 | return $check[0]; |
| | 272 | else |
| | 273 | return $check; |
| | 274 | } |
| | 275 | |
| | 276 | $meta_cache = wp_cache_get($object_id, 'bp_'.$meta_type . '_meta'); |
| | 277 | |
| | 278 | if ( !$meta_cache ) { |
| | 279 | $meta_cache = _bp_update_meta_cache( $meta_type, array( $object_id ) ); |
| | 280 | $meta_cache = $meta_cache[$object_id]; |
| | 281 | } |
| | 282 | |
| | 283 | if ( !$meta_key ) |
| | 284 | return $meta_cache; |
| | 285 | |
| | 286 | if ( isset($meta_cache[$meta_key]) ) { |
| | 287 | if ( $single ) |
| | 288 | return maybe_unserialize( $meta_cache[$meta_key][0] ); |
| | 289 | else |
| | 290 | return array_map('maybe_unserialize', $meta_cache[$meta_key]); |
| | 291 | } |
| | 292 | |
| | 293 | if ($single) |
| | 294 | return ''; |
| | 295 | else |
| | 296 | return array(); |
| | 297 | } |
| | 298 | |
| | 299 | /** |
| | 300 | * Determine if a meta key is set for a given object |
| | 301 | * |
| | 302 | * @since 1.6.2 |
| | 303 | * |
| | 304 | * @param string $meta_type Type of object metadata is for (e.g., activity, group) |
| | 305 | * @param int $object_id ID of the object metadata is for |
| | 306 | * @param string $meta_key Metadata key. |
| | 307 | * @return boolean true of the key is set, false if not. |
| | 308 | */ |
| | 309 | function bp_metadata_exists( $meta_type, $object_id, $meta_key ) { |
| | 310 | if ( ! $meta_type ) |
| | 311 | return false; |
| | 312 | |
| | 313 | if ( ! $object_id = absint( $object_id ) ) |
| | 314 | return false; |
| | 315 | |
| | 316 | $check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, true ); |
| | 317 | if ( null !== $check ) |
| | 318 | return true; |
| | 319 | |
| | 320 | $meta_cache = wp_cache_get( $object_id, 'bp_'.$meta_type . '_meta' ); |
| | 321 | |
| | 322 | if ( !$meta_cache ) { |
| | 323 | $meta_cache = _bp_update_meta_cache( $meta_type, array( $object_id ) ); |
| | 324 | $meta_cache = $meta_cache[$object_id]; |
| | 325 | } |
| | 326 | |
| | 327 | if ( isset( $meta_cache[ $meta_key ] ) ) |
| | 328 | return true; |
| | 329 | |
| | 330 | return false; |
| | 331 | } |
| | 332 | |
| | 333 | /** |
| | 334 | * Get meta data by meta ID |
| | 335 | * |
| | 336 | * @since 1.6.2 |
| | 337 | * |
| | 338 | * @param string $meta_type Type of object metadata is for (e.g., activity, group, or message) |
| | 339 | * @param int $meta_id ID for a specific meta row |
| | 340 | * @return object Meta object or false. |
| | 341 | */ |
| | 342 | function bp_get_metadata_by_mid( $meta_type, $meta_id ) { |
| | 343 | global $wpdb; |
| | 344 | |
| | 345 | if ( ! $meta_type ) |
| | 346 | return false; |
| | 347 | |
| | 348 | if ( !$meta_id = absint( $meta_id ) ) |
| | 349 | return false; |
| | 350 | |
| | 351 | if ( ! $table = _bp_get_meta_table($meta_type) ) |
| | 352 | return false; |
| | 353 | |
| | 354 | $id_column = 'id'; |
| | 355 | |
| | 356 | $meta = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table WHERE $id_column = %d", $meta_id ) ); |
| | 357 | |
| | 358 | if ( empty( $meta ) ) |
| | 359 | return false; |
| | 360 | |
| | 361 | if ( isset( $meta->meta_value ) ) |
| | 362 | $meta->meta_value = maybe_unserialize( $meta->meta_value ); |
| | 363 | |
| | 364 | return $meta; |
| | 365 | } |
| | 366 | |
| | 367 | /** |
| | 368 | * Update meta data by meta ID |
| | 369 | * |
| | 370 | * @since 1.6.2 |
| | 371 | * |
| | 372 | * @uses get_metadata_by_mid() Calls get_metadata_by_mid() to fetch the meta key, value |
| | 373 | * and object_id of the given meta_id. |
| | 374 | * |
| | 375 | * @param string $meta_type Type of object metadata is for (e.g., activity, group) |
| | 376 | * @param int $meta_id ID for a specific meta row |
| | 377 | * @param string $meta_value Metadata value |
| | 378 | * @param string $meta_key Optional, you can provide a meta key to update it |
| | 379 | * @return bool True on successful update, false on failure. |
| | 380 | */ |
| | 381 | function bp_update_metadata_by_mid( $meta_type, $meta_id, $meta_value, $meta_key = false ) { |
| | 382 | global $wpdb; |
| | 383 | |
| | 384 | // Make sure everything is valid. |
| | 385 | if ( ! $meta_type ) |
| | 386 | return false; |
| | 387 | |
| | 388 | if ( ! $meta_id = absint( $meta_id ) ) |
| | 389 | return false; |
| | 390 | |
| | 391 | if ( ! $table = _bp_get_meta_table( $meta_type ) ) |
| | 392 | return false; |
| | 393 | |
| | 394 | $column = esc_sql($meta_type . '_id'); |
| | 395 | $id_column = 'id'; |
| | 396 | |
| | 397 | // Fetch the meta and go on if it's found. |
| | 398 | if ( $meta = bp_get_metadata_by_mid( $meta_type, $meta_id ) ) { |
| | 399 | $original_key = $meta->meta_key; |
| | 400 | $original_value = $meta->meta_value; |
| | 401 | $object_id = $meta->{$column}; |
| | 402 | |
| | 403 | // If a new meta_key (last parameter) was specified, change the meta key, |
| | 404 | // otherwise use the original key in the update statement. |
| | 405 | if ( false === $meta_key ) { |
| | 406 | $meta_key = $original_key; |
| | 407 | } elseif ( ! is_string( $meta_key ) ) { |
| | 408 | return false; |
| | 409 | } |
| | 410 | |
| | 411 | // Sanitize the meta |
| | 412 | $_meta_value = $meta_value; |
| | 413 | $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type ); |
| | 414 | $meta_value = maybe_serialize( $meta_value ); |
| | 415 | |
| | 416 | // Format the data query arguments. |
| | 417 | $data = array( |
| | 418 | 'meta_key' => $meta_key, |
| | 419 | 'meta_value' => $meta_value |
| | 420 | ); |
| | 421 | |
| | 422 | // Format the where query arguments. |
| | 423 | $where = array(); |
| | 424 | $where[$id_column] = $meta_id; |
| | 425 | |
| | 426 | do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value ); |
| | 427 | |
| | 428 | |
| | 429 | |
| | 430 | // Run the update query, all fields in $data are %s, $where is a %d. |
| | 431 | $result = (bool) $wpdb->update( $table, $data, $where, '%s', '%d' ); |
| | 432 | |
| | 433 | // Clear the caches. |
| | 434 | wp_cache_delete($object_id, 'bp_'.$meta_type . '_meta'); |
| | 435 | |
| | 436 | do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value ); |
| | 437 | |
| | 438 | |
| | 439 | |
| | 440 | return $result; |
| | 441 | } |
| | 442 | |
| | 443 | // And if the meta was not found. |
| | 444 | return false; |
| | 445 | } |
| | 446 | |
| | 447 | /** |
| | 448 | * Delete meta data by meta ID |
| | 449 | * |
| | 450 | * @since 1.6.2 |
| | 451 | * |
| | 452 | * @uses get_metadata_by_mid() Calls get_metadata_by_mid() to fetch the meta key, value |
| | 453 | * and object_id of the given meta_id. |
| | 454 | * |
| | 455 | * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) |
| | 456 | * @param int $meta_id ID for a specific meta row |
| | 457 | * @return bool True on successful delete, false on failure. |
| | 458 | */ |
| | 459 | function bp_delete_metadata_by_mid( $meta_type, $meta_id ) { |
| | 460 | global $wpdb; |
| | 461 | |
| | 462 | // Make sure everything is valid. |
| | 463 | if ( ! $meta_type ) |
| | 464 | return false; |
| | 465 | |
| | 466 | if ( ! $meta_id = absint( $meta_id ) ) |
| | 467 | return false; |
| | 468 | |
| | 469 | if ( ! $table = _bp_get_meta_table( $meta_type ) ) |
| | 470 | return false; |
| | 471 | |
| | 472 | // object and id columns |
| | 473 | $column = esc_sql($meta_type . '_id'); |
| | 474 | $id_column = 'id'; |
| | 475 | |
| | 476 | // Fetch the meta and go on if it's found. |
| | 477 | if ( $meta = get_metadata_by_mid( $meta_type, $meta_id ) ) { |
| | 478 | $object_id = $meta->{$column}; |
| | 479 | |
| | 480 | do_action( "delete_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value ); |
| | 481 | |
| | 482 | |
| | 483 | // Run the query, will return true if deleted, false otherwise |
| | 484 | $result = (bool) $wpdb->delete( $table, array( $id_column => $meta_id ) ); |
| | 485 | |
| | 486 | // Clear the caches. |
| | 487 | wp_cache_delete($object_id, 'bp_'.$meta_type . '_meta'); |
| | 488 | |
| | 489 | do_action( "deleted_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value ); |
| | 490 | |
| | 491 | |
| | 492 | |
| | 493 | return $result; |
| | 494 | |
| | 495 | } |
| | 496 | |
| | 497 | // Meta id was not found. |
| | 498 | return false; |
| | 499 | } |
| | 500 | |
| | 501 | /** |
| | 502 | * Update the metadata cache for the specified objects. |
| | 503 | * |
| | 504 | * @since 1.6.2 |
| | 505 | * @uses $wpdb WordPress database object for queries. |
| | 506 | * |
| | 507 | * @param string $meta_type Type of object metadata is for (e.g., activity, group) |
| | 508 | * @param int|array $object_ids array or comma delimited list of object IDs to update cache for |
| | 509 | * @return mixed Metadata cache for the specified objects, or false on failure. |
| | 510 | */ |
| | 511 | function _bp_update_meta_cache($meta_type, $object_ids) { |
| | 512 | if ( empty( $meta_type ) || empty( $object_ids ) ) |
| | 513 | return false; |
| | 514 | |
| | 515 | if ( ! $table = _bp_get_meta_table($meta_type) ) |
| | 516 | return false; |
| | 517 | |
| | 518 | $column = esc_sql($meta_type . '_id'); |
| | 519 | |
| | 520 | global $wpdb; |
| | 521 | |
| | 522 | if ( !is_array($object_ids) ) { |
| | 523 | $object_ids = preg_replace('|[^0-9,]|', '', $object_ids); |
| | 524 | $object_ids = explode(',', $object_ids); |
| | 525 | } |
| | 526 | |
| | 527 | $object_ids = array_map('intval', $object_ids); |
| | 528 | |
| | 529 | $cache_key = 'bp_'.$meta_type . '_meta'; |
| | 530 | $ids = array(); |
| | 531 | $cache = array(); |
| | 532 | foreach ( $object_ids as $id ) { |
| | 533 | $cached_object = wp_cache_get( $id, $cache_key ); |
| | 534 | if ( false === $cached_object ) |
| | 535 | $ids[] = $id; |
| | 536 | else |
| | 537 | $cache[$id] = $cached_object; |
| | 538 | } |
| | 539 | |
| | 540 | if ( empty( $ids ) ) |
| | 541 | return $cache; |
| | 542 | |
| | 543 | // Get meta info |
| | 544 | $id_list = join(',', $ids); |
| | 545 | $meta_list = $wpdb->get_results( $wpdb->prepare("SELECT $column, meta_key, meta_value FROM $table WHERE $column IN ($id_list)", |
| | 546 | $meta_type), ARRAY_A ); |
| | 547 | |
| | 548 | if ( !empty($meta_list) ) { |
| | 549 | foreach ( $meta_list as $metarow) { |
| | 550 | $mpid = intval($metarow[$column]); |
| | 551 | $mkey = $metarow['meta_key']; |
| | 552 | $mval = $metarow['meta_value']; |
| | 553 | |
| | 554 | // Force subkeys to be array type: |
| | 555 | if ( !isset($cache[$mpid]) || !is_array($cache[$mpid]) ) |
| | 556 | $cache[$mpid] = array(); |
| | 557 | if ( !isset($cache[$mpid][$mkey]) || !is_array($cache[$mpid][$mkey]) ) |
| | 558 | $cache[$mpid][$mkey] = array(); |
| | 559 | |
| | 560 | // Add a value to the current pid/key: |
| | 561 | $cache[$mpid][$mkey][] = $mval; |
| | 562 | } |
| | 563 | } |
| | 564 | |
| | 565 | foreach ( $ids as $id ) { |
| | 566 | if ( ! isset($cache[$id]) ) |
| | 567 | $cache[$id] = array(); |
| | 568 | wp_cache_add( $id, $cache[$id], $cache_key ); |
| | 569 | } |
| | 570 | |
| | 571 | return $cache; |
| | 572 | } |
| | 573 | |
| | 574 | /** |
| | 575 | * Given a meta query, generates SQL clauses to be appended to a main query |
| | 576 | * |
| | 577 | * @since 1.6.2 |
| | 578 | * |
| | 579 | * @see WP_Meta_Query |
| | 580 | * |
| | 581 | * @param array $meta_query A meta query |
| | 582 | * @param string $type Type of meta |
| | 583 | * @param string $primary_table |
| | 584 | * @param string $primary_id_column |
| | 585 | * @param object $context (optional) The main query object |
| | 586 | * @return array( 'join' => $join_sql, 'where' => $where_sql ) |
| | 587 | */ |
| | 588 | function bp_get_meta_sql( $meta_query, $type, $primary_table, $primary_id_column, $context = null ) { |
| | 589 | $meta_query_obj = new BP_Meta_Query( $meta_query ); |
| | 590 | return $meta_query_obj->get_sql( $type, $primary_table, $primary_id_column, $context ); |
| | 591 | } |
| | 592 | |
| | 593 | /** |
| | 594 | * Container class for a multiple metadata query, built on the op of WP_Meta_query and works exactly as WP_Meta_query |
| | 595 | * |
| | 596 | * @since 1.6.2 |
| | 597 | */ |
| | 598 | class BP_Meta_Query extends WP_Meta_Query { |
| | 599 | /** |
| | 600 | * List of metadata queries. A single query is an associative array: |
| | 601 | * - 'key' string The meta key |
| | 602 | * - 'value' string|array The meta value |
| | 603 | * - 'compare' (optional) string How to compare the key to the value. |
| | 604 | * Possible values: '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'. |
| | 605 | * Default: '=' |
| | 606 | * - 'type' string (optional) The type of the value. |
| | 607 | * Possible values: 'NUMERIC', 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', 'UNSIGNED'. |
| | 608 | * Default: 'CHAR' |
| | 609 | * |
| | 610 | * @since 1.6.2 |
| | 611 | * @access public |
| | 612 | * @var array |
| | 613 | */ |
| | 614 | |
| | 615 | |
| | 616 | |
| | 617 | function __construct( $meta_query = false ) { |
| | 618 | parent::__construct($meta_query); |
| | 619 | } |
| | 620 | |
| | 621 | |
| | 622 | |
| | 623 | /** |
| | 624 | * Generates SQL clauses to be appended to a main query. |
| | 625 | * |
| | 626 | * @since 1.6.2 |
| | 627 | * @access public |
| | 628 | * |
| | 629 | * @param string $type Type of meta |
| | 630 | * @param string $primary_table |
| | 631 | * @param string $primary_id_column |
| | 632 | * @param object $context (optional) The main query object |
| | 633 | * @return array( 'join' => $join_sql, 'where' => $where_sql ) |
| | 634 | */ |
| | 635 | function get_sql( $type, $primary_table, $primary_id_column, $context = null ) { |
| | 636 | global $wpdb; |
| | 637 | |
| | 638 | if ( ! $meta_table = _bp_get_meta_table( $type ) ) |
| | 639 | return false; |
| | 640 | |
| | 641 | $meta_id_column = esc_sql( $type . '_id' ); |
| | 642 | |
| | 643 | $join = array(); |
| | 644 | $where = array(); |
| | 645 | |
| | 646 | foreach ( $this->queries as $k => $q ) { |
| | 647 | $meta_key = isset( $q['key'] ) ? trim( $q['key'] ) : ''; |
| | 648 | $meta_type = isset( $q['type'] ) ? strtoupper( $q['type'] ) : 'CHAR'; |
| | 649 | |
| | 650 | if ( 'NUMERIC' == $meta_type ) |
| | 651 | $meta_type = 'SIGNED'; |
| | 652 | elseif ( ! in_array( $meta_type, array( 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', 'UNSIGNED' ) ) ) |
| | 653 | $meta_type = 'CHAR'; |
| | 654 | |
| | 655 | $i = count( $join ); |
| | 656 | $alias = $i ? 'mt' . $i : $meta_table; |
| | 657 | |
| | 658 | // Set JOIN |
| | 659 | $join[$i] = "INNER JOIN $meta_table"; |
| | 660 | $join[$i] .= $i ? " AS $alias" : ''; |
| | 661 | $join[$i] .= " ON ($primary_table.$primary_id_column = $alias.$meta_id_column)"; |
| | 662 | |
| | 663 | $where[$k] = ''; |
| | 664 | if ( !empty( $meta_key ) ) |
| | 665 | $where[$k] = $wpdb->prepare( "$alias.meta_key = %s", $meta_key ); |
| | 666 | |
| | 667 | if ( !isset( $q['value'] ) ) { |
| | 668 | if ( empty( $where[$k] ) ) |
| | 669 | unset( $join[$i] ); |
| | 670 | continue; |
| | 671 | } |
| | 672 | |
| | 673 | $meta_value = $q['value']; |
| | 674 | |
| | 675 | $meta_compare = is_array( $meta_value ) ? 'IN' : '='; |
| | 676 | if ( isset( $q['compare'] ) ) |
| | 677 | $meta_compare = strtoupper( $q['compare'] ); |
| | 678 | |
| | 679 | if ( ! in_array( $meta_compare, array( '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) ) |
| | 680 | $meta_compare = '='; |
| | 681 | |
| | 682 | if ( in_array( $meta_compare, array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) ) { |
| | 683 | if ( ! is_array( $meta_value ) ) |
| | 684 | $meta_value = preg_split( '/[,\s]+/', $meta_value ); |
| | 685 | |
| | 686 | if ( empty( $meta_value ) ) { |
| | 687 | unset( $join[$i] ); |
| | 688 | continue; |
| | 689 | } |
| | 690 | } else { |
| | 691 | $meta_value = trim( $meta_value ); |
| | 692 | } |
| | 693 | |
| | 694 | if ( 'IN' == substr( $meta_compare, -2) ) { |
| | 695 | $meta_compare_string = '(' . substr( str_repeat( ',%s', count( $meta_value ) ), 1 ) . ')'; |
| | 696 | } elseif ( 'BETWEEN' == substr( $meta_compare, -7) ) { |
| | 697 | $meta_value = array_slice( $meta_value, 0, 2 ); |
| | 698 | $meta_compare_string = '%s AND %s'; |
| | 699 | } elseif ( 'LIKE' == substr( $meta_compare, -4 ) ) { |
| | 700 | $meta_value = '%' . like_escape( $meta_value ) . '%'; |
| | 701 | $meta_compare_string = '%s'; |
| | 702 | } else { |
| | 703 | $meta_compare_string = '%s'; |
| | 704 | } |
| | 705 | |
| | 706 | if ( ! empty( $where[$k] ) ) |
| | 707 | $where[$k] .= ' AND '; |
| | 708 | |
| | 709 | $where[$k] = ' (' . $where[$k] . $wpdb->prepare( "CAST($alias.meta_value AS {$meta_type}) {$meta_compare} {$meta_compare_string})", $meta_value ); |
| | 710 | } |
| | 711 | |
| | 712 | $where = array_filter( $where ); |
| | 713 | |
| | 714 | if ( empty( $where ) ) |
| | 715 | $where = ''; |
| | 716 | else |
| | 717 | $where = ' AND (' . implode( "\n{$this->relation} ", $where ) . ' )'; |
| | 718 | |
| | 719 | $join = implode( "\n", $join ); |
| | 720 | if ( ! empty( $join ) ) |
| | 721 | $join = ' ' . $join; |
| | 722 | |
| | 723 | return apply_filters_ref_array( 'get_meta_sql', array( compact( 'join', 'where' ), $this->queries, $type, $primary_table, $primary_id_column, $context ) ); |
| | 724 | } |
| | 725 | } |
| | 726 | |
| | 727 | /** |
| | 728 | * Retrieve the name of the metadata table for the specified object type. |
| | 729 | * Plugin Develpres can use the filter bp_meta_tables to add their own table |
| | 730 | * |
| | 731 | * @since 1.6.0 |
| | 732 | * @uses $wpdb WordPress database object for queries. |
| | 733 | * |
| | 734 | * @param string $type Type of object to get metadata table for (e.g., comment, post, or user) |
| | 735 | * @return mixed Metadata table name, or false if no metadata table exists |
| | 736 | */ |
| | 737 | function _bp_get_meta_table($type) { |
| | 738 | global $bp; |
| | 739 | |
| | 740 | $table_map=array(); |
| | 741 | if(bp_is_action_variable('blogs')) |
| | 742 | $table_map['activity']=$bp->activity->table_name_meta; |
| | 743 | if(bp_is_active('groups')) |
| | 744 | $table_map['group']=$bp->groups->table_name_groupmeta; |
| | 745 | |
| | 746 | if(bp_is_active('blogs')) |
| | 747 | $table_map['blog']=$bp->blogs->table_name_blogmeta; |
| | 748 | |
| | 749 | $table_map=apply_filters('bp_meta_tables',$table_map);//allow plugins to utilize it |
| | 750 | $table_name = $table_map[$type]; |
| | 751 | |
| | 752 | return $table_name; |
| | 753 | |
| | 754 | } |
| | 755 | |
| | 756 | |
| | 757 | |
| | 758 | |
| | 759 | |