Ticket #3083: 3083.02.patch
| File 3083.02.patch, 21.8 KB (added by , 11 years ago) |
|---|
-
src/bp-core/admin/bp-core-schema.php
304 304 KEY is_active (is_active) 305 305 ) {$charset_collate};"; 306 306 307 $sql[] = "CREATE TABLE {$bp_prefix}bp_messages_meta ( 308 id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY, 309 message_id bigint(20) NOT NULL, 310 meta_key varchar(255) DEFAULT NULL, 311 meta_value longtext DEFAULT NULL, 312 KEY message_id (message_id), 313 KEY meta_key (meta_key) 314 ) {$charset_collate};"; 315 307 316 dbDelta( $sql ); 308 317 } 309 318 -
src/bp-core/bp-core-update.php
241 241 if ( $raw_db_version < 8311 ) { 242 242 bp_update_to_2_0_1(); 243 243 } 244 245 // 2.2 246 if ( $raw_db_version < 9180 ) { 247 bp_update_to_2_2(); 248 } 244 249 } 245 250 246 251 /** All done! *************************************************************/ … … 390 395 } 391 396 392 397 /** 398 * 2.2.0 update routine. 399 * 400 * - Add messages meta table 401 * 402 * @since BuddyPress (2.2.0) 403 */ 404 function bp_update_to_2_2() { 405 if ( bp_is_active( 'messages' ) ) { 406 bp_core_install_private_messaging(); 407 } 408 } 409 410 /** 393 411 * Redirect user to BP's What's New page on first page load after activation. 394 412 * 395 413 * @since BuddyPress (1.7.0) -
src/bp-loader.php
301 301 /** Versions **********************************************************/ 302 302 303 303 $this->version = '2.2-alpha'; 304 $this->db_version = 91 67;304 $this->db_version = 9180; 305 305 306 306 /** Loading ***********************************************************/ 307 307 -
src/bp-messages/bp-messages-cache.php
12 12 // Exit if accessed directly 13 13 if ( !defined( 'ABSPATH' ) ) exit; 14 14 15 /** 16 * Slurp up metadata for a set of messages. 17 * 18 * It grabs all message meta associated with all of the messages passed in 19 * $message_ids and adds it to WP cache. This improves efficiency when using 20 * message meta within a loop context. 21 * 22 * @since BuddyPress (2.2.0) 23 * 24 * @param int|str|array $message_ids Accepts a single message_id, or a 25 * comma-separated list or array of message ids. 26 */ 27 function bp_messages_update_meta_cache( $message_ids = false ) { 28 bp_update_meta_cache( array( 29 'object_ids' => $message_ids, 30 'object_type' => buddypress()->messages->id, 31 'cache_group' => 'message_meta', 32 'object_column' => 'message_id', 33 'meta_table' => buddypress()->messages->table_name_meta, 34 'cache_key_prefix' => 'bp_messages_meta' 35 ) ); 36 } 37 15 38 // List actions to clear super cached pages on, if super cache is installed 16 39 add_action( 'messages_delete_thread', 'bp_core_clear_cache' ); 17 40 add_action( 'messages_send_notice', 'bp_core_clear_cache' ); -
src/bp-messages/bp-messages-classes.php
109 109 * 110 110 * @since BuddyPress (1.0.0) 111 111 * 112 * @param bool|int $thread_id The message thread ID. 113 * @param string $order The order to sort the messages. Either 'ASC' or 'DESC'. 112 * @see BP_Messages_Thread::populate() for full description of parameters 114 113 */ 115 public function __construct( $thread_id = false, $order = 'ASC' ) {114 public function __construct( $thread_id = false, $order = 'ASC', $args = array() ) { 116 115 if ( $thread_id ) { 117 $this->populate( $thread_id, $order );116 $this->populate( $thread_id, $order, $args ); 118 117 } 119 118 } 120 119 … … 127 126 * 128 127 * @param int $thread_id The message thread ID. 129 128 * @param string $order The order to sort the messages. Either 'ASC' or 'DESC'. 129 * @param array $args { 130 * Array of arguments. 131 * @type bool $update_meta_cache Whether to pre-fetch metadata for 132 * queried message items. Default: true. 133 * } 130 134 * @return bool False on failure. 131 135 */ 132 public function populate( $thread_id , $order) {136 public function populate( $thread_id = 0, $order = 'ASC', $args = array() ) { 133 137 global $wpdb, $bp; 134 138 135 139 if( 'ASC' != $order && 'DESC' != $order ) { 136 $order = 'ASC';140 $order = 'ASC'; 137 141 } 138 142 143 // merge $args with our defaults 144 $r = wp_parse_args( $args, array( 145 'update_meta_cache' => true 146 ) ); 147 139 148 $this->messages_order = $order; 140 149 $this->thread_id = $thread_id; 141 150 … … 155 164 $this->unread_count = $this->recipients[bp_loggedin_user_id()]->unread_count; 156 165 } 157 166 167 // Grab all message meta 168 if ( true === (bool) $r['update_meta_cache'] ) { 169 bp_messages_update_meta_cache( wp_list_pluck( $this->messages, 'id' ) ); 170 } 171 158 172 /** 159 173 * Fires after a BP_Messages_Thread object has been populated. 160 174 * … … 218 232 /** Static Functions ******************************************************/ 219 233 220 234 /** 221 * Delete a message thread. 235 * Mark messages in a thread as deleted or delete all messages in a thread. 236 * 237 * Note: All messages in a thread are deleted once every recipient in a thread 238 * has marked the thread as deleted. 222 239 * 223 240 * @since BuddyPress (1.0.0) 224 241 * 225 242 * @param int $thread_id The message thread ID 226 * @return bool 243 * @return bool Always true... sucks. 227 244 */ 228 245 public static function delete( $thread_id ) { 229 246 global $wpdb, $bp; 230 247 231 248 /** 232 * Fires before a message thread is deleted.249 * Fires before a message thread is marked as deleted. 233 250 * 234 251 * @since BuddyPress (2.2.0) 235 252 * 236 253 * @param int $thread_id ID of the thread being deleted. 237 254 */ 238 do_action( 'bp_messages_thread_before_ delete', $thread_id );255 do_action( 'bp_messages_thread_before_mark_delete', $thread_id ); 239 256 240 257 // Mark messages as deleted 258 // 259 // @todo the reliance on bp_loggedin_user_id() sucks for plugins 260 // refactor this method to accept a $user_id parameter 241 261 $wpdb->query( $wpdb->prepare( "UPDATE {$bp->messages->table_name_recipients} SET is_deleted = 1 WHERE thread_id = %d AND user_id = %d", $thread_id, bp_loggedin_user_id() ) ); 242 262 243 // Get the message id in order to pass to the action244 $message_id = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->messages->table_name_messages} WHERE thread_id = %d", $thread_id ) );263 // Get the message ids in order to pass to the action 264 $message_ids = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM {$bp->messages->table_name_messages} WHERE thread_id = %d", $thread_id ) ); 245 265 246 266 // Check to see if any more recipients remain for this message 247 // if not, then delete the message from the database.248 267 $recipients = $wpdb->get_results( $wpdb->prepare( "SELECT id FROM {$bp->messages->table_name_recipients} WHERE thread_id = %d AND is_deleted = 0", $thread_id ) ); 249 268 269 // No more recipients so delete all messages associated with the thread 250 270 if ( empty( $recipients ) ) { 271 /** 272 * Fires before an entire message thread is deleted. 273 * 274 * @since BuddyPress (2.2.0) 275 * 276 * @param int $thread_id ID of the thread being deleted. 277 * @param array $message_ids IDs of messages being deleted 278 */ 279 do_action( 'bp_messages_thread_before_delete', $thread_id, $message_ids ); 280 251 281 // Delete all the messages 252 282 $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->messages->table_name_messages} WHERE thread_id = %d", $thread_id ) ); 253 283 284 // Do something for each message ID 285 foreach ( $message_ids as $message_id ) { 286 // Delete message meta 287 bp_messages_delete_meta( $message_id ); 288 289 /** 290 * Fires after a message is deleted. This hook is poorly named. 291 * 292 * @since BuddyPress (1.0.0) 293 * 294 * @param int $message_id ID of the message 295 */ 296 do_action( 'messages_thread_deleted_thread', $message_id ); 297 } 298 254 299 // Delete all the recipients 255 300 $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->messages->table_name_recipients} WHERE thread_id = %d", $thread_id ) ); 256 301 } 257 302 258 303 /** 259 * Fires after a message thread is deleted.304 * Fires after a message thread is either marked as deleted or deleted 260 305 * 261 306 * @since BuddyPress (2.2.0) 262 307 * 263 308 * @param int $thread_id ID of the thread being deleted. 264 309 */ 265 do_action( 'bp_messages_thread_after_delete', $ message_id);310 do_action( 'bp_messages_thread_after_delete', $thread_id, $message_ids ); 266 311 267 312 return true; 268 313 } … … 325 370 326 371 $threads = false; 327 372 foreach ( (array) $sorted_threads as $thread_id => $date_sent ) { 328 $threads[] = new BP_Messages_Thread( $thread_id ); 373 $threads[] = new BP_Messages_Thread( $thread_id, 'ASC', array( 374 // need some feedback here... 375 // what are the chances a plugin will need the message meta during the inbox? 376 'update_meta_cache' => false 377 ) ); 329 378 } 330 379 331 380 /** -
src/bp-messages/bp-messages-functions.php
335 335 function messages_is_valid_thread( $thread_id ) { 336 336 return BP_Messages_Thread::is_valid( $thread_id ); 337 337 } 338 339 /** Messages Meta *******************************************************/ 340 341 /** 342 * Delete metadata for a message. 343 * 344 * If $meta_key is false, this will delete all meta for the message ID. 345 * 346 * @since BuddyPress (2.2.0) 347 * 348 * @see delete_metadata() for full documentation excluding $meta_type variable. 349 */ 350 function bp_messages_delete_meta( $message_id, $meta_key = false, $meta_value = false, $delete_all = false ) { 351 // Legacy - if no meta_key is passed, delete all for the item 352 if ( empty( $meta_key ) ) { 353 global $wpdb; 354 355 $keys = $wpdb->get_col( $wpdb->prepare( "SELECT meta_key FROM {$wpdb->messagemeta} WHERE message_id = %d", $message_id ) ); 356 357 // With no meta_key, ignore $delete_all 358 $delete_all = false; 359 } else { 360 $keys = array( $meta_key ); 361 } 362 363 // no keys, so stop now! 364 if ( empty( $keys ) ) { 365 return false; 366 } 367 368 add_filter( 'query', 'bp_filter_metaid_column_name' ); 369 370 foreach ( $keys as $key ) { 371 $retval = delete_metadata( 'message', $message_id, $key, $meta_value, $delete_all ); 372 } 373 374 remove_filter( 'query', 'bp_filter_metaid_column_name' ); 375 376 return $retval; 377 } 378 379 /** 380 * Get a piece of message metadata. 381 * 382 * @since BuddyPress (2.2.0) 383 * 384 * @see get_metadata() for full documentation excluding $meta_type variable. 385 */ 386 function bp_messages_get_meta( $message_id, $meta_key = '', $single = true ) { 387 add_filter( 'query', 'bp_filter_metaid_column_name' ); 388 $retval = get_metadata( 'message', $message_id, $meta_key, $single ); 389 remove_filter( 'query', 'bp_filter_metaid_column_name' ); 390 391 return $retval; 392 } 393 394 /** 395 * Update a piece of message metadata. 396 * 397 * @since BuddyPress (2.2.0) 398 * 399 * @see update_metadata() for full documentation excluding $meta_type variable. 400 */ 401 function bp_messages_update_meta( $message_id, $meta_key, $meta_value, $prev_value = '' ) { 402 add_filter( 'query', 'bp_filter_metaid_column_name' ); 403 $retval = update_metadata( 'message', $message_id, $meta_key, $meta_value, $prev_value ); 404 remove_filter( 'query', 'bp_filter_metaid_column_name' ); 405 406 return $retval; 407 } 408 409 /** 410 * Add a piece of message metadata. 411 * 412 * @since BuddyPress (2.2.0) 413 * 414 * @see add_metadata() for full documentation excluding $meta_type variable. 415 */ 416 function bp_message_add_meta( $message_id, $meta_key, $meta_value, $unique = false ) { 417 add_filter( 'query', 'bp_filter_metaid_column_name' ); 418 $retval = add_metadata( 'message', $message_id, $meta_key, $meta_value, $unique ); 419 remove_filter( 'query', 'bp_filter_metaid_column_name' ); 420 421 return $retval; 422 } -
src/bp-messages/bp-messages-loader.php
90 90 $global_tables = array( 91 91 'table_name_notices' => $bp->table_prefix . 'bp_messages_notices', 92 92 'table_name_messages' => $bp->table_prefix . 'bp_messages_messages', 93 'table_name_recipients' => $bp->table_prefix . 'bp_messages_recipients' 93 'table_name_recipients' => $bp->table_prefix . 'bp_messages_recipients', 94 'table_name_meta' => $bp->table_prefix . 'bp_messages_meta', 94 95 ); 95 96 97 // Metadata tables for messaging component 98 $meta_tables = array( 99 'message' => $bp->table_prefix . 'bp_messages_meta', 100 ); 101 102 $this->autocomplete_all = defined( 'BP_MESSAGES_AUTOCOMPLETE_ALL' ); 103 96 104 // All globals for messaging component. 97 105 // Note that global_tables is included in this array. 98 $globals =array(106 parent::setup_globals( array( 99 107 'slug' => BP_MESSAGES_SLUG, 100 108 'has_directory' => false, 101 109 'notification_callback' => 'messages_format_notifications', 102 110 'search_string' => __( 'Search Messages...', 'buddypress' ), 103 'global_tables' => $global_tables 104 ); 105 106 $this->autocomplete_all = defined( 'BP_MESSAGES_AUTOCOMPLETE_ALL' ); 107 108 parent::setup_globals( $globals ); 111 'global_tables' => $global_tables, 112 'meta_tables' => $meta_tables 113 ) ); 109 114 } 110 115 111 116 /** -
src/bp-messages/bp-messages-template.php
1467 1467 /** 1468 1468 * Constructor method. 1469 1469 * 1470 * @param int $thread_id ID of the message thread. 1471 * @param string $order 'ASC' or 'DESC'. 1470 * @see BP_Messages_Thread::populate() for full parameter info 1472 1471 */ 1473 public function __construct( $thread_id, $order ) {1474 $this->thread = new BP_Messages_Thread( $thread_id, $order );1472 public function __construct( $thread_id, $order, $args ) { 1473 $this->thread = new BP_Messages_Thread( $thread_id, $order, $args ); 1475 1474 $this->message_count = count( $this->thread->messages ); 1476 1475 1477 1476 $last_message_index = $this->message_count - 1; … … 1572 1571 * Default: if viewing a thread, the thread ID will be parsed from 1573 1572 * the URL (bp_action_variable( 0 )). 1574 1573 * @type string $order 'ASC' or 'DESC'. Default: 'ASC'. 1574 * @type bool $update_meta_cache Whether to pre-fetch metadata for 1575 * queried message items. Default: true. 1575 1576 * } 1576 1577 * @return bool True if there are messages to display, otherwise false. 1577 1578 */ … … 1579 1580 global $thread_template; 1580 1581 1581 1582 $r = bp_parse_args( $args, array( 1582 'thread_id' => false, 1583 'order' => 'ASC' 1583 'thread_id' => false, 1584 'order' => 'ASC', 1585 'update_meta_cache' => true, 1584 1586 ), 'thread_has_messages' ); 1585 1587 1586 1588 if ( empty( $r['thread_id'] ) && bp_is_messages_component() && bp_is_current_action( 'view' ) ) { 1587 1589 $r['thread_id'] = (int) bp_action_variable( 0 ); 1588 1590 } 1589 1591 1590 $thread_template = new BP_Messages_Thread_Template( $r['thread_id'], $r['order'] ); 1592 // Set up extra args 1593 $extra_args = $r; 1594 unset( $extra_args['thread_id'], $extra_args['order'] ); 1595 1596 $thread_template = new BP_Messages_Thread_Template( $r['thread_id'], $r['order'], $extra_args ); 1591 1597 1592 1598 return $thread_template->has_messages(); 1593 1599 } … … 1992 1998 /** 1993 1999 * Enable oEmbed support for Messages. 1994 2000 * 1995 * There's no caching as BP 1.5 does not have a Messages meta API.1996 *1997 2001 * @since BuddyPress (1.5.0) 1998 2002 * 1999 2003 * @see BP_Embed 2000 *2001 * @todo Add Messages meta?2002 2004 */ 2003 2005 function bp_messages_embed() { 2004 add_filter( 'embed_post_id', 'bp_get_message_thread_id' ); 2006 add_filter( 'embed_post_id', 'bp_get_the_thread_message_id' ); 2007 add_filter( 'bp_embed_get_cache', 'bp_embed_message_cache', 10, 3 ); 2008 add_action( 'bp_embed_update_cache', 'bp_embed_message_save_cache', 10, 3 ); 2009 } 2010 add_action( 'thread_loop_start', 'bp_messages_embed' ); 2011 2012 /** 2013 * Fetch a private message item's cached embeds. 2014 * 2015 * Used during {@link BP_Embed::parse_oembed()} via {@link bp_messages_embed()}. 2016 * 2017 * @since BuddyPress (2.2.0) 2018 * 2019 * @param string $cache An empty string passed by BP_Embed::parse_oembed() for 2020 * functions like this one to filter. 2021 * @param int $id The ID of the message item. 2022 * @param string $cachekey The cache key generated in BP_Embed::parse_oembed(). 2023 * @return mixed The cached embeds for this message item. 2024 */ 2025 function bp_embed_message_cache( $cache, $id, $cachekey ) { 2026 return bp_messages_get_meta( $id, $cachekey ); 2027 } 2028 2029 /** 2030 * Set a private message item's embed cache. 2031 * 2032 * Used during {@link BP_Embed::parse_oembed()} via {@link bp_messages_embed()}. 2033 * 2034 * @since BuddyPress (2.2.0) 2035 * 2036 * @param string $cache An empty string passed by BP_Embed::parse_oembed() for 2037 * functions like this one to filter. 2038 * @param string $cachekey The cache key generated in BP_Embed::parse_oembed(). 2039 * @param int $id The ID of the message item. 2040 * @return bool True on success, false on failure. 2041 */ 2042 function bp_embed_message_save_cache( $cache, $cachekey, $id ) { 2043 bp_messages_update_meta( $id, $cachekey, $cache ); 2005 2044 } 2006 add_action( 'messages_box_loop_start', 'bp_messages_embed' ); -
src/bp-templates/bp-legacy/buddypress-functions.php
1298 1298 1299 1299 bp_thread_has_messages( array( 'thread_id' => (int) $_REQUEST['thread_id'] ) ); 1300 1300 1301 bp_thread_the_message(); 1302 1301 1303 if ( $thread_template->message_count % 2 == 1 ) { 1302 1304 $class = 'odd'; 1303 1305 } else { -
new file tests/phpunit/testcases/messages/cache.php
new file mode 100644
- + 1 <?php 2 3 /** 4 * @group messages 5 * @group cache 6 */ 7 class BP_Tests_Message_Cache extends BP_UnitTestCase { 8 /** 9 * @group bp_messages_update_meta_cache 10 */ 11 public function test_bp_messages_update_meta_cache() { 12 $u1 = $this->factory->user->create(); 13 $u2 = $this->factory->user->create(); 14 15 // create the thread 16 $t1 = $this->factory->message->create( array( 17 'sender_id' => $u1, 18 'recipients' => array( $u2 ), 19 'subject' => 'This is a knive', 20 ) ); 21 22 // create a reply 23 $this->factory->message->create( array( 24 'thread_id' => $t1, 25 'sender_id' => $u2, 26 'recipients' => array( $u1 ), 27 'content' => "That's a spoon", 28 ) ); 29 30 // grab the message ids as individual variables 31 list( $m1, $m2 ) = $this->get_message_ids( $t1 ); 32 33 // add cache for each message 34 bp_messages_update_meta( $m1, 'utensil', 'knive' ); 35 bp_messages_update_meta( $m1, 'is_knive', 'yes' ); 36 37 bp_messages_update_meta( $m2, 'utensil', 'spoon' ); 38 bp_messages_update_meta( $m2, 'is_knive', 'no' ); 39 bp_messages_update_meta( $m2, 'is_spoon', 'yes' ); 40 41 // prime cache 42 bp_messages_get_meta( $m1, 'utensil' ); 43 44 // Ensure an empty cache for second message 45 wp_cache_delete( $m2, 'message_meta' ); 46 47 // update message meta cache 48 bp_messages_update_meta_cache( array( $m1, $m2 ) ); 49 50 $expected = array( 51 $m1 => array( 52 'utensil' => array( 53 'knive', 54 ), 55 'is_knive' => array( 56 'yes', 57 ), 58 ), 59 $m2 => array( 60 'utensil' => array( 61 'spoon', 62 ), 63 'is_knive' => array( 64 'no', 65 ), 66 'is_spoon' => array( 67 'yes', 68 ), 69 ), 70 ); 71 72 $found = array( 73 $m1 => wp_cache_get( $m1, 'message_meta' ), 74 $m2 => wp_cache_get( $m2, 'message_meta' ), 75 ); 76 77 $this->assertEquals( $expected, $found ); 78 } 79 80 /** 81 * @group bp_messages_update_meta_cache 82 * @group bp_thread_has_messages 83 */ 84 public function test_bp_messages_metadata_cache_in_message_loop() { 85 $u1 = $this->factory->user->create(); 86 $u2 = $this->factory->user->create(); 87 88 // create the thread 89 $t1 = $this->factory->message->create( array( 90 'sender_id' => $u1, 91 'recipients' => array( $u2 ), 92 'subject' => 'Oy', 93 ) ); 94 95 // add message cache 96 list( $m1 ) = $this->get_message_ids( $t1 ); 97 bp_messages_update_meta( $m1, 'yolo', 'gah' ); 98 99 // prime meta cache in message loop 100 bp_thread_has_messages( array( 101 'thread_id' => $t1, 102 'update_meta_cache' => true 103 ) ); 104 105 $this->assertNotEmpty( wp_cache_get( $m1, 'message_meta' ) ); 106 } 107 108 /** 109 * @group bp_messages_delete_meta 110 * @group messages_delete_thread 111 */ 112 public function test_bp_messages_delete_metadata_cache_on_thread_delete() { 113 $this->old_current_user = get_current_user_id(); 114 115 $u1 = $this->factory->user->create(); 116 $u2 = $this->factory->user->create(); 117 118 // create the thread 119 $t1 = $this->factory->message->create( array( 120 'sender_id' => $u1, 121 'recipients' => array( $u2 ), 122 'subject' => 'Oy', 123 ) ); 124 125 // create a reply 126 $this->factory->message->create( array( 127 'thread_id' => $t1, 128 'sender_id' => $u2, 129 'recipients' => array( $u1 ), 130 'content' => 'Yo', 131 ) ); 132 133 // add message meta 134 list( $m1, $m2 ) = $this->get_message_ids( $t1 ); 135 bp_messages_update_meta( $m1, 'yolo', 'gah' ); 136 bp_messages_update_meta( $m2, 'yolo', 'bah' ); 137 138 // prime message meta cache 139 bp_messages_get_meta( $m1, 'yolo' ); 140 bp_messages_get_meta( $m2, 'yolo' ); 141 142 // delete thread 143 // to outright delete a thread, both recipients must delete it 144 $this->set_current_user( $u1 ); 145 messages_delete_thread( $t1 ); 146 $this->set_current_user( $u2 ); 147 messages_delete_thread( $t1 ); 148 149 // assert empty meta cache 150 $this->assertEmpty( wp_cache_get( $m1, 'message_meta' ) ); 151 $this->assertEmpty( wp_cache_get( $m2, 'message_meta' ) ); 152 153 // cleanup 154 $this->set_current_user( $this->old_current_user ); 155 } 156 157 /** 158 * Helper method to grab the message IDs from a message thread. 159 * 160 * @param int $thread_id The message thread ID 161 * @return array 162 */ 163 protected function get_message_ids( $thread_id = 0 ) { 164 $thread = new BP_Messages_Thread( $thread_id ); 165 return wp_list_pluck( $thread->messages, 'id' ); 166 } 167 }