Changeset 11888
- Timestamp:
- 03/05/2018 12:57:24 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/bp-notifications/bp-notifications-cache.php
r11851 r11888 45 45 wp_cache_delete( 'all_for_user_' . $user_id, 'bp_notifications' ); 46 46 wp_cache_delete( $user_id, 'bp_notifications_unread_count' ); 47 wp_cache_delete( $user_id, 'bp_notifications_grouped_notifications' ); 47 48 } 48 49 -
trunk/src/bp-notifications/bp-notifications-functions.php
r11851 r11888 164 164 165 165 /** 166 * Get a user's unread notifications, grouped by component and action. 167 * 168 * This function returns a list of notifications collapsed by component + action. 169 * See BP_Notifications_Notification::get_grouped_notifications_for_user() for 170 * more details. 171 * 172 * @since 3.0.0 173 * 174 * @param int $user_id ID of the user whose notifications are being fetched. 175 * @return array $notifications 176 */ 177 function bp_notifications_get_grouped_notifications_for_user( $user_id = 0 ) { 178 if ( empty( $user_id ) ) { 179 $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id(); 180 } 181 182 $notifications = wp_cache_get( $user_id, 'bp_notifications_grouped_notifications' ); 183 if ( false === $notifications ) { 184 $notifications = BP_Notifications_Notification::get_grouped_notifications_for_user( $user_id ); 185 wp_cache_set( $user_id, $notifications, 'bp_notifications_grouped_notifications' ); 186 } 187 188 return $notifications; 189 } 190 191 /** 166 192 * Get notifications for a specific user. 167 193 * … … 174 200 */ 175 201 function bp_notifications_get_notifications_for_user( $user_id, $format = 'string' ) { 176 177 // Setup local variables.178 202 $bp = buddypress(); 179 203 180 // Get notifications (out of the cache, or query if necessary). 181 $notifications = bp_notifications_get_all_notifications_for_user( $user_id ); 182 $grouped_notifications = array(); // Notification groups. 183 $renderable = array(); // Renderable notifications. 184 185 // Group notifications by component and component_action and provide totals. 186 for ( $i = 0, $count = count( $notifications ); $i < $count; ++$i ) { 187 $notification = $notifications[$i]; 188 $grouped_notifications[$notification->component_name][$notification->component_action][] = $notification; 189 } 190 191 // Bail if no notification groups. 192 if ( empty( $grouped_notifications ) ) { 193 return false; 194 } 204 $notifications = bp_notifications_get_grouped_notifications_for_user( $user_id ); 195 205 196 206 // Calculate a renderable output for each notification type. 197 foreach ( $grouped_notifications as $component_name => $action_arrays ) { 198 207 foreach ( $notifications as $notification_item ) { 208 209 $component_name = $notification_item->component_name; 199 210 // We prefer that extended profile component-related notifications use 200 211 // the component_name of 'xprofile'. However, the extended profile child 201 212 // object in the $bp object is keyed as 'profile', which is where we need 202 213 // to look for the registered notification callback. 203 if ( 'xprofile' == $ component_name ) {214 if ( 'xprofile' == $notification_item->component_name ) { 204 215 $component_name = 'profile'; 205 216 } 206 217 207 // Skip if group is empty. 208 if ( empty( $action_arrays ) ) { 209 continue; 210 } 211 212 // Loop through each actionable item and try to map it to a component. 213 foreach ( (array) $action_arrays as $component_action_name => $component_action_items ) { 214 215 // Get the number of actionable items. 216 $action_item_count = count( $component_action_items ); 217 218 // Skip if the count is less than 1. 219 if ( $action_item_count < 1 ) { 220 continue; 218 // Callback function exists. 219 if ( isset( $bp->{$component_name}->notification_callback ) && is_callable( $bp->{$component_name}->notification_callback ) ) { 220 221 // Function should return an object. 222 if ( 'object' === $format ) { 223 224 // Retrieve the content of the notification using the callback. 225 $content = call_user_func( $bp->{$component_name}->notification_callback, $notification_item->component_action, $notification_item->item_id, $notification_item->secondary_item_id, $notification_item->total_count, 'array', $notification_item->id ); 226 227 // Create the object to be returned. 228 $notification_object = $notification_item; 229 230 // Minimal backpat with non-compatible notification 231 // callback functions. 232 if ( is_string( $content ) ) { 233 $notification_object->content = $content; 234 $notification_object->href = bp_loggedin_user_domain(); 235 } else { 236 $notification_object->content = $content['text']; 237 $notification_object->href = $content['link']; 238 } 239 240 $renderable[] = $notification_object; 241 242 // Return an array of content strings. 243 } else { 244 $content = call_user_func( $bp->{$component_name}->notification_callback, $notification_item->component_action, $notification_item->item_id, $notification_item->secondary_item_id, $notification_item->total_count, 'string', $notification_item->id ); 245 $renderable[] = $content; 221 246 } 222 247 223 // Callback function exists. 224 if ( isset( $bp->{$component_name}->notification_callback ) && is_callable( $bp->{$component_name}->notification_callback ) ) { 225 226 // Function should return an object. 227 if ( 'object' === $format ) { 228 229 // Retrieve the content of the notification using the callback. 230 $content = call_user_func( 231 $bp->{$component_name}->notification_callback, 232 $component_action_name, 233 $component_action_items[0]->item_id, 234 $component_action_items[0]->secondary_item_id, 235 $action_item_count, 236 'array', 237 $component_action_items[0]->id 238 ); 239 240 // Create the object to be returned. 241 $notification_object = $component_action_items[0]; 242 243 // Minimal backpat with non-compatible notification 244 // callback functions. 245 if ( is_string( $content ) ) { 246 $notification_object->content = $content; 247 $notification_object->href = bp_loggedin_user_domain(); 248 } else { 249 $notification_object->content = $content['text']; 250 $notification_object->href = $content['link']; 251 } 252 253 $renderable[] = $notification_object; 248 // @deprecated format_notification_function - 1.5 249 } elseif ( isset( $bp->{$component_name}->format_notification_function ) && function_exists( $bp->{$component_name}->format_notification_function ) ) { 250 $renderable[] = call_user_func( $bp->{$component_name}->notification_callback, $notification_item->component_action, $notification_item->item_id, $notification_item->secondary_item_id, $notification_item->total_count ); 251 252 // Allow non BuddyPress components to hook in. 253 } else { 254 255 // The array to reference with apply_filters_ref_array(). 256 $ref_array = array( 257 $notification_item->component_action, 258 $notification_item->item_id, 259 $notification_item->secondary_item_id, 260 $notification_item->total_count, 261 $format, 262 $notification_item->component_action, // Duplicated so plugins can check the canonical action name. 263 $component_name, 264 $notification_item->id, 265 ); 266 267 // Function should return an object. 268 if ( 'object' === $format ) { 269 270 /** 271 * Filters the notification content for notifications created by plugins. 272 * If your plugin extends the {@link BP_Component} class, you should use the 273 * 'notification_callback' parameter in your extended 274 * {@link BP_Component::setup_globals()} method instead. 275 * 276 * @since 1.9.0 277 * @since 2.6.0 Added $component_action_name, $component_name, $id as parameters. 278 * 279 * @param string $content Component action. Deprecated. Do not do checks against this! Use 280 * the 6th parameter instead - $component_action_name. 281 * @param int $item_id Notification item ID. 282 * @param int $secondary_item_id Notification secondary item ID. 283 * @param int $action_item_count Number of notifications with the same action. 284 * @param string $format Format of return. Either 'string' or 'object'. 285 * @param string $component_action_name Canonical notification action. 286 * @param string $component_name Notification component ID. 287 * @param int $id Notification ID. 288 * 289 * @return string|array If $format is 'string', return a string of the notification content. 290 * If $format is 'object', return an array formatted like: 291 * array( 'text' => 'CONTENT', 'link' => 'LINK' ) 292 */ 293 $content = apply_filters_ref_array( 'bp_notifications_get_notifications_for_user', $ref_array ); 294 295 // Create the object to be returned. 296 $notification_object = $notification_item; 297 298 // Minimal backpat with non-compatible notification 299 // callback functions. 300 if ( is_string( $content ) ) { 301 $notification_object->content = $content; 302 $notification_object->href = bp_loggedin_user_domain(); 303 } else { 304 $notification_object->content = $content['text']; 305 $notification_object->href = $content['link']; 306 } 307 308 $renderable[] = $notification_object; 254 309 255 310 // Return an array of content strings. 256 } else {257 $content = call_user_func( $bp->{$component_name}->notification_callback, $component_action_name, $component_action_items[0]->item_id, $component_action_items[0]->secondary_item_id, $action_item_count, 'string', $component_action_items[0]->id );258 $renderable[] = $content;259 }260 261 // @deprecated format_notification_function - 1.5262 } elseif ( isset( $bp->{$component_name}->format_notification_function ) && function_exists( $bp->{$component_name}->format_notification_function ) ) {263 $renderable[] = call_user_func( $bp->{$component_name}->format_notification_function, $component_action_name, $component_action_items[0]->item_id, $component_action_items[0]->secondary_item_id, $action_item_count );264 265 // Allow non BuddyPress components to hook in.266 311 } else { 267 312 268 // The array to reference with apply_filters_ref_array(). 269 $ref_array = array( 270 $component_action_name, 271 $component_action_items[0]->item_id, 272 $component_action_items[0]->secondary_item_id, 273 $action_item_count, 274 $format, 275 $component_action_name, // Duplicated so plugins can check the canonical action name. 276 $component_name, 277 $component_action_items[0]->id 278 ); 279 280 // Function should return an object. 281 if ( 'object' === $format ) { 282 283 /** 284 * Filters the notification content for notifications created by plugins. 285 * 286 * If your plugin extends the {@link BP_Component} class, you should use the 287 * 'notification_callback' parameter in your extended 288 * {@link BP_Component::setup_globals()} method instead. 289 * 290 * @since 1.9.0 291 * @since 2.6.0 Added $component_action_name, $component_name, $id as parameters. 292 * 293 * @param string $content Component action. Deprecated. Do not do checks against this! Use 294 * the 6th parameter instead - $component_action_name. 295 * @param int $item_id Notification item ID. 296 * @param int $secondary_item_id Notification secondary item ID. 297 * @param int $action_item_count Number of notifications with the same action. 298 * @param string $format Format of return. Either 'string' or 'object'. 299 * @param string $component_action_name Canonical notification action. 300 * @param string $component_name Notification component ID. 301 * @param int $id Notification ID. 302 * 303 * @return string|array If $format is 'string', return a string of the notification content. 304 * If $format is 'object', return an array formatted like: 305 * array( 'text' => 'CONTENT', 'link' => 'LINK' ) 306 */ 307 $content = apply_filters_ref_array( 'bp_notifications_get_notifications_for_user', $ref_array ); 308 309 // Create the object to be returned. 310 $notification_object = $component_action_items[0]; 311 312 // Minimal backpat with non-compatible notification 313 // callback functions. 314 if ( is_string( $content ) ) { 315 $notification_object->content = $content; 316 $notification_object->href = bp_loggedin_user_domain(); 317 } else { 318 $notification_object->content = $content['text']; 319 $notification_object->href = $content['link']; 320 } 321 322 $renderable[] = $notification_object; 323 324 // Return an array of content strings. 325 } else { 326 327 /** This filters is documented in bp-notifications/bp-notifications-functions.php */ 328 $renderable[] = apply_filters_ref_array( 'bp_notifications_get_notifications_for_user', $ref_array ); 329 } 313 /** This filters is documented in bp-notifications/bp-notifications-functions.php */ 314 $renderable[] = apply_filters_ref_array( 'bp_notifications_get_notifications_for_user', $ref_array ); 330 315 } 331 316 } -
trunk/src/bp-notifications/classes/class-bp-notifications-notification.php
r11840 r11888 1132 1132 return self::update( $update_args, $where_args ); 1133 1133 } 1134 1135 /** 1136 * Get a user's unread notifications, grouped by component and action. 1137 * 1138 * Multiple notifications of the same type (those that share the same component_name 1139 * and component_action) are collapsed for formatting as "You have 5 pending 1140 * friendship requests", etc. See bp_notifications_get_notifications_for_user(). 1141 * For a full-fidelity list of user notifications, use 1142 * bp_notifications_get_all_notifications_for_user(). 1143 * 1144 * @since 3.0.0 1145 * 1146 * @param int $user_id ID of the user whose notifications are being fetched. 1147 * @return array Notifications items for formatting into a list. 1148 */ 1149 public static function get_grouped_notifications_for_user( $user_id ) { 1150 global $wpdb; 1151 1152 // Load BuddyPress. 1153 $bp = buddypress(); 1154 1155 // SELECT. 1156 $select_sql = "SELECT id, user_id, item_id, secondary_item_id, component_name, component_action, date_notified, is_new, COUNT(id) as total_count "; 1157 1158 // FROM. 1159 $from_sql = "FROM {$bp->notifications->table_name} n "; 1160 1161 // WHERE. 1162 $where_sql = self::get_where_sql( array( 1163 'user_id' => $user_id, 1164 'is_new' => 1, 1165 'component_name' => bp_notifications_get_registered_components(), 1166 ), $select_sql, $from_sql ); 1167 1168 // GROUP 1169 $group_sql = "GROUP BY user_id, component_name, component_action"; 1170 1171 // SORT 1172 $order_sql = "ORDER BY date_notified desc"; 1173 1174 // Concatenate query parts. 1175 $sql = "{$select_sql} {$from_sql} {$where_sql} {$group_sql} {$order_sql}"; 1176 1177 // Return the queried results. 1178 return $wpdb->get_results( $sql ); 1179 } 1134 1180 } -
trunk/tests/phpunit/testcases/notifications/functions.php
r11851 r11888 404 404 $this->n_args = compact( 'action', 'item_id', 'secondary_item_id', 'total_items', 'id', 'format' ); 405 405 } 406 407 /** 408 * @group cache 409 * @ticket BP7130 410 */ 411 public function test_get_grouped_notifications_for_user_cache_invalidation() { 412 $u = self::factory()->user->create(); 413 414 $n1 = self::factory()->notification->create( array( 415 'component_name' => 'activity', 416 'component_action' => 'new_at_mention', 417 'item_id' => 99, 418 'user_id' => $u, 419 ) ); 420 421 // Prime cache. 422 $found = bp_notifications_get_grouped_notifications_for_user( $u ); 423 $this->assertEquals( 1, $found[0]->total_count ); 424 425 $n2 = self::factory()->notification->create( array( 426 'component_name' => 'activity', 427 'component_action' => 'new_at_mention', 428 'item_id' => 100, 429 'user_id' => $u, 430 ) ); 431 432 $found = bp_notifications_get_grouped_notifications_for_user( $u ); 433 $this->assertEquals( 2, $found[0]->total_count ); 434 } 406 435 }
Note: See TracChangeset
for help on using the changeset viewer.