Ticket #5148: 5148.02b.patch
File 5148.02b.patch, 93.8 KB (added by , 11 years ago) |
---|
-
bp-core/admin/bp-core-components.php
function bp_core_admin_components_options() { 58 58 'xprofile' => array( 59 59 'title' => __( 'Extended Profiles', 'buddypress' ), 60 60 'description' => __( 'Customize your community with fully editable profile fields that allow your users to describe themselves.', 'buddypress' ) 61 ) 61 ), 62 'settings' => array( 63 'title' => __( 'Account Settings', 'buddypress' ), 64 'description' => __( 'Allow your users to modify their account and notification settings directly from within their profiles.', 'buddypress' ) 65 ), 66 'notifications' => array( 67 'title' => __( 'Notifications', 'buddypress' ), 68 'description' => __( 'Notify members of relevant activity with a toolbar bubble and/or via email, and allow them to customize their notification settings.', 'buddypress' ) 69 ), 62 70 ); 63 71 64 72 $optional_components = bp_core_admin_get_components( 'optional' ); 65 73 $required_components = bp_core_admin_get_components( 'required' ); 66 $retired_components = bp_core_admin_get_components( 'retired');74 $retired_components = bp_core_admin_get_components( 'retired' ); 67 75 68 76 // Don't show Forums component in optional components if it's disabled 69 77 if ( ! bp_is_active( 'forums' ) ) { … … function bp_core_admin_get_components( $type = 'all' ) { 371 379 'title' => __( 'Activity Streams', 'buddypress' ), 372 380 'description' => __( 'Global, personal, and group activity streams with threaded commenting, direct posting, favoriting and @mentions, all with full RSS feed and email notification support.', 'buddypress' ) 373 381 ), 382 'notifications' => array( 383 'title' => __( 'Notifications', 'buddypress' ), 384 'description' => __( 'Notify members of relevant activity with a toolbar bubble and/or via email, and allow them to customize their notification settings.', 'buddypress' ) 385 ), 374 386 'groups' => array( 375 387 'title' => __( 'User Groups', 'buddypress' ), 376 388 'description' => __( 'Groups allow your users to organize themselves into specific public, private or hidden sections with separate activity streams and member listings.', 'buddypress' ) -
bp-core/admin/bp-core-schema.php
function bp_core_install( $active_components = false ) { 23 23 if ( empty( $active_components ) ) 24 24 $active_components = apply_filters( 'bp_active_components', bp_get_option( 'bp-active-components' ) ); 25 25 26 // Core DB Tables 27 bp_core_install_notifications(); 26 // Notifications 27 if ( !empty( $active_components['notifications'] ) ) 28 bp_core_install_notifications(); 28 29 29 30 // Activity Streams 30 31 if ( !empty( $active_components['activity'] ) ) -
bp-core/bp-core-classes.php
class BP_Core_User { 1291 1291 1292 1292 1293 1293 /** 1294 * BP_Core_Notification class can be used by any component. 1295 * It will handle the fetching, saving and deleting of a user notification. 1294 * BP_Core_Notification is deprecated. 1295 * 1296 * Use BP_Notifications_Notification instead. 1296 1297 * 1297 1298 * @package BuddyPress Core 1299 * @deprecated since BuddyPress (1.9) 1298 1300 */ 1299 1300 1301 class BP_Core_Notification { 1301 1302 1302 1303 /** -
bp-core/bp-core-loader.php
class BP_Core extends BP_Component { 54 54 /** Components ********************************************************/ 55 55 56 56 // Set the included and optional components. 57 $bp->optional_components = apply_filters( 'bp_optional_components', array( 'activity', 'blogs', 'forums', 'friends', 'groups', 'messages', ' settings', 'xprofile' ) );57 $bp->optional_components = apply_filters( 'bp_optional_components', array( 'activity', 'blogs', 'forums', 'friends', 'groups', 'messages', 'notifications', 'settings', 'xprofile' ) ); 58 58 59 59 // Set the required components 60 60 $bp->required_components = apply_filters( 'bp_required_components', array( 'members' ) ); … … class BP_Core extends BP_Component { 177 177 $bp->grav_default->group = apply_filters( 'bp_group_gravatar_default', $bp->grav_default->user ); 178 178 $bp->grav_default->blog = apply_filters( 'bp_blog_gravatar_default', $bp->grav_default->user ); 179 179 180 // Notifications Table 180 // Notifications table. Included here for legacy purposes. Use 181 // bp-notifications instead. 181 182 $bp->core->table_name_notifications = $bp->table_prefix . 'bp_notifications'; 182 183 183 184 /** -
bp-core/bp-core-template.php
function bp_is_forums_component() { 1436 1436 } 1437 1437 1438 1438 /** 1439 * Check whether the current page is part of the Notifications component. 1440 * 1441 * @since BuddyPress (1.9.0) 1442 * 1443 * @return bool True if the current page is part of the Notifications component. 1444 */ 1445 function bp_is_notifications_component() { 1446 if ( bp_is_current_component( 'notifications' ) ) { 1447 return true; 1448 } 1449 1450 return false; 1451 } 1452 1453 /** 1439 1454 * Check whether the current page is part of the Settings component. 1440 1455 * 1441 1456 * @return bool True if the current page is part of the Settings component. … … function bp_is_user_friend_requests() { 1750 1765 } 1751 1766 1752 1767 /** 1768 * Is this a user's notifications page? 1769 * 1770 * Eg http://example.com/members/joe/notifications/ (or a subpage thereof). 1771 * 1772 * @since BuddyPress (1.9.0) 1773 * 1774 * @return bool True if the current page is a user's Notifications page. 1775 */ 1776 function bp_is_user_notifications() { 1777 if ( bp_is_user() && bp_is_notifications_component() ) { 1778 return true; 1779 } 1780 1781 return false; 1782 } 1783 1784 /** 1753 1785 * Is this a user's settings page? 1754 1786 * 1755 1787 * Eg http://example.com/members/joe/settings/ (or a subpage thereof). -
bp-core/bp-core-update.php
function bp_version_updater() { 187 187 $raw_db_version = (int) bp_get_db_version_raw(); 188 188 189 189 $default_components = apply_filters( 'bp_new_install_default_components', array( 190 'activity' => 1, 191 'members' => 1, 192 'settings' => 1, 193 'xprofile' => 1, 190 'activity' => 1, 191 'members' => 1, 192 'settings' => 1, 193 'xprofile' => 1, 194 'notifications' => 1, 194 195 ) ); 195 196 196 197 require_once( BP_PLUGIN_DIR . '/bp-core/admin/bp-core-schema.php' ); -
bp-friends/bp-friends-classes.php
class BP_Friends_Friendship { 363 363 // Delete all friendships related to $user_id 364 364 $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->friends->table_name} WHERE friend_user_id = %d OR initiator_user_id = %d", $user_id, $user_id ) ); 365 365 366 // Delete friend request notifications for members who have a notification from this user. 367 $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->core->table_name_notifications} WHERE component_name = 'friends' AND ( component_action = 'friendship_request' OR component_action = 'friendship_accepted' ) AND item_id = %d", $user_id ) ); 366 // Delete friend request notifications for members who have a 367 // notification from this user. 368 if ( bp_is_active( 'notifications' ) ) { 369 $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->notifications->table_name} WHERE component_name = 'friends' AND ( component_action = 'friendship_request' OR component_action = 'friendship_accepted' ) AND item_id = %d", $user_id ) ); 370 } 368 371 369 372 // Loop through friend_ids and update their counts 370 373 foreach ( (array) $friend_ids as $friend_id ) { -
bp-members/bp-members-adminbar.php
add_action( 'admin_bar_menu', 'bp_members_admin_bar_user_admin_menu', 99 ); 139 139 * @since BuddyPress (1.5) 140 140 */ 141 141 function bp_members_admin_bar_notifications_menu() { 142 global $wp_admin_bar;143 142 144 if ( !is_user_logged_in() ) 143 // Bail if notifications is not active 144 if ( ! bp_is_active( 'notifications' ) ) { 145 145 return false; 146 147 $notifications = bp_core_get_notifications_for_user( bp_loggedin_user_id(), 'object' );148 $count = !empty( $notifications ) ? count( $notifications ) : 0;149 $alert_class = (int) $count > 0 ? 'pending-count alert' : 'count no-alert';150 $menu_title = '<span id="ab-pending-notifications" class="' . $alert_class . '">' . $count . '</span>';151 152 // Add the top-level Notifications button153 $wp_admin_bar->add_menu( array(154 'parent' => 'top-secondary',155 'id' => 'bp-notifications',156 'title' => $menu_title,157 'href' => bp_loggedin_user_domain(),158 ) );159 160 if ( !empty( $notifications ) ) {161 foreach ( (array) $notifications as $notification ) {162 $wp_admin_bar->add_menu( array(163 'parent' => 'bp-notifications',164 'id' => 'notification-' . $notification->id,165 'title' => $notification->content,166 'href' => $notification->href167 ) );168 }169 } else {170 $wp_admin_bar->add_menu( array(171 'parent' => 'bp-notifications',172 'id' => 'no-notifications',173 'title' => __( 'No new notifications', 'buddypress' ),174 'href' => bp_loggedin_user_domain()175 ) );176 146 } 177 147 178 return;148 bp_notifications_toolbar_menu(); 179 149 } 180 150 add_action( 'admin_bar_menu', 'bp_members_admin_bar_notifications_menu', 90 ); 181 151 -
bp-members/bp-members-buddybar.php
if ( !defined( 'ABSPATH' ) ) exit; 17 17 */ 18 18 function bp_adminbar_notifications_menu() { 19 19 20 if ( !is_user_logged_in() ) 20 // Bail if notifications is not active 21 if ( ! bp_is_active( 'notifications' ) ) { 21 22 return false; 22 23 echo '<li id="bp-adminbar-notifications-menu"><a href="' . bp_loggedin_user_domain() . '">';24 _e( 'Notifications', 'buddypress' );25 26 if ( $notifications = bp_core_get_notifications_for_user( bp_loggedin_user_id() ) ) { ?>27 <span><?php echo count( $notifications ) ?></span>28 <?php29 }30 31 echo '</a>';32 echo '<ul>';33 34 if ( $notifications ) {35 $counter = 0;36 for ( $i = 0, $count = count( $notifications ); $i < $count; ++$i ) {37 $alt = ( 0 == $counter % 2 ) ? ' class="alt"' : ''; ?>38 39 <li<?php echo $alt ?>><?php echo $notifications[$i] ?></li>40 41 <?php $counter++;42 }43 } else { ?>44 45 <li><a href="<?php echo bp_loggedin_user_domain() ?>"><?php _e( 'No new notifications.', 'buddypress' ); ?></a></li>46 47 <?php48 23 } 49 24 50 echo '</ul>'; 51 echo '</li>'; 25 bp_notifications_buddybar_menu(); 52 26 } 53 27 add_action( 'bp_adminbar_menus', 'bp_adminbar_notifications_menu', 8 ); 54 28 -
bp-members/bp-members-notifications.php
3 3 /** 4 4 * BuddyPress Member Notifications 5 5 * 6 * Functions and filters used for member notification 6 * Backwards compatibility functions and filters used for member notifications. 7 * Use bp-notifications instead. 7 8 * 8 9 * @package BuddyPress 9 10 * @subpackage MembersNotifications … … if ( !defined( 'ABSPATH' ) ) exit; 26 27 */ 27 28 function bp_core_add_notification( $item_id, $user_id, $component_name, $component_action, $secondary_item_id = 0, $date_notified = false ) { 28 29 29 if ( empty( $date_notified ) ) 30 $date_notified = bp_core_current_time(); 31 32 $notification = new BP_Core_Notification; 33 $notification->item_id = $item_id; 34 $notification->user_id = $user_id; 35 $notification->component_name = $component_name; 36 $notification->component_action = $component_action; 37 $notification->date_notified = $date_notified; 38 $notification->is_new = 1; 39 40 if ( !empty( $secondary_item_id ) ) 41 $notification->secondary_item_id = $secondary_item_id; 30 // Bail if notifications is not active 31 if ( ! bp_is_active( 'notifications' ) ) { 32 return false; 33 } 42 34 43 if ( $notification->save() ) 44 return true; 35 $args = array( 36 'item_id' => $item_id, 37 'user_id' => $user_id, 38 'component_name' => $component_name, 39 'component_action' => $component_action, 40 'secondary_item_id' => $secondary_item_id, 41 'date_notified' => $date_notified 42 ); 45 43 46 return false;44 return bp_notifications_add_notification( $args ); 47 45 } 48 46 49 47 /** … … function bp_core_add_notification( $item_id, $user_id, $component_name, $compone 54 52 * @return boolean True on success, false on fail 55 53 */ 56 54 function bp_core_delete_notification( $id ) { 57 if ( !bp_core_check_notification_access( bp_loggedin_user_id(), $id ) ) 55 56 // Bail if notifications is not active 57 if ( ! bp_is_active( 'notifications' ) ) { 58 58 return false; 59 } 59 60 60 return BP_ Core_Notification::delete( $id );61 return BP_Notifications_Notification::delete_by_id( $id ); 61 62 } 62 63 63 64 /** … … function bp_core_delete_notification( $id ) { 68 69 * @return BP_Core_Notification 69 70 */ 70 71 function bp_core_get_notification( $id ) { 71 return new BP_Core_Notification( $id ); 72 73 // Bail if notifications is not active 74 if ( ! bp_is_active( 'notifications' ) ) { 75 return false; 76 } 77 78 return bp_notifications_get_notification( $id ); 72 79 } 73 80 74 81 /** … … function bp_core_get_notification( $id ) { 81 88 * @return boolean Object or array on success, false on fail 82 89 */ 83 90 function bp_core_get_notifications_for_user( $user_id, $format = 'simple' ) { 84 global $bp;85 86 $notifications = BP_Core_Notification::get_all_for_user( $user_id );87 $grouped_notifications = array(); // Notification groups88 $renderable = array(); // Renderable notifications89 90 // Group notifications by component and component_action and provide totals91 for ( $i = 0, $count = count( $notifications ); $i < $count; ++$i ) {92 $notification = $notifications[$i];93 $grouped_notifications[$notification->component_name][$notification->component_action][] = $notification;94 }95 91 96 // Bail if no notification groups97 if ( empty( $grouped_notifications ) )92 // Bail if notifications is not active 93 if ( ! bp_is_active( 'notifications' ) ) { 98 94 return false; 99 100 // Calculate a renderable output for each notification type101 foreach ( $grouped_notifications as $component_name => $action_arrays ) {102 103 // Skip if group is empty104 if ( empty( $action_arrays ) )105 continue;106 107 // Skip inactive components108 if ( !bp_is_active( $component_name ) )109 continue;110 111 // Loop through each actionable item and try to map it to a component112 foreach ( (array) $action_arrays as $component_action_name => $component_action_items ) {113 114 // Get the number of actionable items115 $action_item_count = count( $component_action_items );116 117 // Skip if the count is less than 1118 if ( $action_item_count < 1 )119 continue;120 121 // Callback function exists122 if ( isset( $bp->{$component_name}->notification_callback ) && is_callable( $bp->{$component_name}->notification_callback ) ) {123 124 // Function should return an object125 if ( 'object' == $format ) {126 127 // Retrieve the content of the notification using the callback128 $content = call_user_func(129 $bp->{$component_name}->notification_callback,130 $component_action_name,131 $component_action_items[0]->item_id,132 $component_action_items[0]->secondary_item_id,133 $action_item_count,134 'array'135 );136 137 // Create the object to be returned138 $notification_object = new stdClass;139 140 // Minimal backpat with non-compatible notification141 // callback functions142 if ( is_string( $content ) ) {143 $notification_object->content = $content;144 $notification_object->href = bp_loggedin_user_domain();145 } else {146 $notification_object->content = $content['text'];147 $notification_object->href = $content['link'];148 }149 150 $notification_object->id = $component_action_items[0]->id;151 $renderable[] = $notification_object;152 153 // Return an array of content strings154 } else {155 $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 );156 $renderable[] = $content;157 }158 159 // @deprecated format_notification_function - 1.5160 } elseif ( isset( $bp->{$component_name}->format_notification_function ) && function_exists( $bp->{$component_name}->format_notification_function ) ) {161 $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 );162 }163 }164 95 } 165 96 166 // If renderable is empty array, set to false 167 if ( empty( $renderable ) ) 168 $renderable = false; 97 $renderable = bp_notifications_get_notifications_for_user( $user_id, $format ); 169 98 170 // Filter and return171 99 return apply_filters( 'bp_core_get_notifications_for_user', $renderable, $user_id, $format ); 172 100 } 173 101 … … function bp_core_get_notifications_for_user( $user_id, $format = 'simple' ) { 184 112 * @return boolean True on success, false on fail 185 113 */ 186 114 function bp_core_delete_notifications_by_type( $user_id, $component_name, $component_action ) { 187 return BP_Core_Notification::delete_for_user_by_type( $user_id, $component_name, $component_action ); 115 116 // Bail if notifications is not active 117 if ( ! bp_is_active( 'notifications' ) ) { 118 return false; 119 } 120 121 return bp_notifications_delete_notifications_by_type( $user_id, $component_name, $component_action ); 188 122 } 189 123 190 124 /** … … function bp_core_delete_notifications_by_type( $user_id, $component_name, $compo 200 134 * @return boolean True on success, false on fail 201 135 */ 202 136 function bp_core_delete_notifications_by_item_id( $user_id, $item_id, $component_name, $component_action, $secondary_item_id = false ) { 203 return BP_Core_Notification::delete_for_user_by_item_id( $user_id, $item_id, $component_name, $component_action, $secondary_item_id ); 137 138 // Bail if notifications is not active 139 if ( ! bp_is_active( 'notifications' ) ) { 140 return false; 141 } 142 143 return bp_notifications_delete_notifications_by_item_id( $user_id, $item_id, $component_name, $component_action, $secondary_item_id ); 204 144 } 205 145 206 146 /** … … function bp_core_delete_notifications_by_item_id( $user_id, $item_id, $component 215 155 * @return boolean True on success, false on fail 216 156 */ 217 157 function bp_core_delete_all_notifications_by_type( $item_id, $component_name, $component_action = false, $secondary_item_id = false ) { 218 return BP_Core_Notification::delete_all_by_type( $item_id, $component_name, $component_action, $secondary_item_id ); 158 159 // Bail if notifications is not active 160 if ( ! bp_is_active( 'notifications' ) ) { 161 return false; 162 } 163 164 bp_notifications_delete_all_notifications_by_type( $item_id, $component_name, $component_action, $secondary_item_id ); 219 165 } 220 166 221 167 /** … … function bp_core_delete_all_notifications_by_type( $item_id, $component_name, $c 230 176 * @return boolean True on success, false on fail 231 177 */ 232 178 function bp_core_delete_notifications_from_user( $user_id, $component_name, $component_action ) { 233 return BP_Core_Notification::delete_from_user_by_type( $user_id, $component_name, $component_action ); 179 180 // Bail if notifications is not active 181 if ( ! bp_is_active( 'notifications' ) ) { 182 return false; 183 } 184 185 return bp_notifications_delete_notifications_from_user( $user_id, $component_name, $component_action ); 234 186 } 235 187 236 188 /** … … function bp_core_delete_notifications_from_user( $user_id, $component_name, $com 244 196 * @return boolean True on success, false on fail 245 197 */ 246 198 function bp_core_check_notification_access( $user_id, $notification_id ) { 247 if ( !BP_Core_Notification::check_access( $user_id, $notification_id ) ) 199 200 // Bail if notifications is not active 201 if ( ! bp_is_active( 'notifications' ) ) { 248 202 return false; 203 } 249 204 250 return true;205 return bp_notifications_check_notification_access( $user_id, $notification_id ); 251 206 } -
bp-notifications/bp-notifications-adminbar.php
new file mode 100644
1 <?php 2 3 /** 4 * BuddyPress Notifications Admin Bar functions. 5 * 6 * Admin Bar functions for the Notifications component. 7 * 8 * @package BuddyPress 9 * @subpackage NotificationsToolbar 10 */ 11 12 // Exit if accessed directly 13 if ( !defined( 'ABSPATH' ) ) exit; 14 15 /** 16 * Build the "Notifications" dropdown. 17 * 18 * @since BuddyPress (1.9.0) 19 */ 20 function bp_notifications_toolbar_menu() { 21 global $wp_admin_bar; 22 23 if ( ! is_user_logged_in() ) { 24 return false; 25 } 26 27 $notifications = bp_core_get_notifications_for_user( bp_loggedin_user_id(), 'object' ); 28 $count = ! empty( $notifications ) ? count( $notifications ) : 0; 29 $alert_class = (int) $count > 0 ? 'pending-count alert' : 'count no-alert'; 30 $menu_title = '<span id="ab-pending-notifications" class="' . $alert_class . '">' . $count . '</span>'; 31 32 // Add the top-level Notifications button 33 $wp_admin_bar->add_menu( array( 34 'parent' => 'top-secondary', 35 'id' => 'bp-notifications', 36 'title' => $menu_title, 37 'href' => bp_loggedin_user_domain(), 38 ) ); 39 40 if ( ! empty( $notifications ) ) { 41 foreach ( (array) $notifications as $notification ) { 42 $wp_admin_bar->add_menu( array( 43 'parent' => 'bp-notifications', 44 'id' => 'notification-' . $notification->id, 45 'title' => $notification->content, 46 'href' => $notification->href, 47 ) ); 48 } 49 } else { 50 $wp_admin_bar->add_menu( array( 51 'parent' => 'bp-notifications', 52 'id' => 'no-notifications', 53 'title' => __( 'No new notifications', 'buddypress' ), 54 'href' => bp_loggedin_user_domain(), 55 ) ); 56 } 57 58 return; 59 } 60 add_action( 'admin_bar_menu', 'bp_members_admin_bar_notifications_menu', 90 ); -
bp-notifications/bp-notifications-buddybar.php
new file mode 100644
1 <?php 2 3 /** 4 * BuddyPress Notifications Navigational Functions. 5 * 6 * Sets up navigation elements, including BuddyBar functionality, for the 7 * Notifications component. 8 * 9 * @package BuddyPress 10 * @subpackage NotificationsBuddyBar 11 */ 12 13 // Exit if accessed directly 14 if ( !defined( 'ABSPATH' ) ) exit; 15 16 /** 17 * Create the Notifications menu for the BuddyBar. 18 * 19 * @since BuddyPress (1.9.0) 20 */ 21 function bp_notifications_buddybar_menu() { 22 23 if ( ! is_user_logged_in() ) { 24 return false; 25 } 26 27 echo '<li id="bp-adminbar-notifications-menu"><a href="' . bp_loggedin_user_domain() . '">'; 28 _e( 'Notifications', 'buddypress' ); 29 30 if ( $notifications = bp_core_get_notifications_for_user( bp_loggedin_user_id() ) ) : ?> 31 <span><?php echo count( $notifications ) ?></span> 32 <?php 33 endif; 34 35 echo '</a>'; 36 echo '<ul>'; 37 38 if ( $notifications ) { 39 $counter = 0; 40 for ( $i = 0, $count = count( $notifications ); $i < $count; ++$i ) { 41 $alt = ( 0 == $counter % 2 ) ? ' class="alt"' : ''; ?> 42 43 <li<?php echo $alt ?>><?php echo $notifications[$i] ?></li> 44 45 <?php $counter++; 46 } 47 } else { ?> 48 49 <li><a href="<?php echo bp_loggedin_user_domain() ?>"><?php _e( 'No new notifications.', 'buddypress' ); ?></a></li> 50 51 <?php 52 } 53 54 echo '</ul>'; 55 echo '</li>'; 56 } 57 add_action( 'bp_adminbar_menus', 'bp_adminbar_notifications_menu', 8 ); -
bp-notifications/bp-notifications-classes.php
new file mode 100644
1 <?php 2 3 /** 4 * BuddyPress Notifications Classes 5 * 6 * Classes used for the Notifications component. 7 * 8 * @package BuddyPress 9 * @subpackage NotificationsClasses 10 * 11 * @since BuddyPress (1.9.0) 12 */ 13 14 // Exit if accessed directly 15 if ( !defined( 'ABSPATH' ) ) exit; 16 17 /** 18 * BuddyPress Notification items. 19 * 20 * Use this class to create, access, edit, or delete BuddyPress Notifications. 21 * 22 * @since BuddyPress (1.9.0) 23 */ 24 class BP_Notifications_Notification { 25 26 /** 27 * The notification ID. 28 * 29 * @var int 30 */ 31 public $id; 32 33 /** 34 * The ID of the item associated with the notification. 35 * 36 * @var int 37 */ 38 public $item_id; 39 40 /** 41 * The ID of the secondary item associated with the notification. 42 * 43 * @var int 44 */ 45 public $secondary_item_id = null; 46 47 /** 48 * The ID of the user the notification is associated with. 49 * 50 * @var int 51 */ 52 public $user_id; 53 54 /** 55 * The name of the component that the notification is for. 56 * 57 * @var string 58 */ 59 public $component_name; 60 61 /** 62 * The component action which the notification is related to. 63 * 64 * @var string 65 */ 66 public $component_action; 67 68 /** 69 * The date the notification was created. 70 * 71 * @var string 72 */ 73 public $date_notified; 74 75 /** 76 * Is the notification new, or has it already been read. 77 * 78 * @var bool 79 */ 80 public $is_new; 81 82 /** Public Methods ****************************************************/ 83 84 /** 85 * Constructor method. 86 * 87 * @since BuddyPress (1.9.0) 88 * 89 * @param int $id Optional. Provide an ID to access an existing 90 * notification item. 91 */ 92 public function __construct( $id = 0 ) { 93 if ( ! empty( $id ) ) { 94 $this->id = $id; 95 $this->populate(); 96 } 97 } 98 99 /** 100 * Update or insert notification details into the database. 101 * 102 * @since BuddyPress (1.9.0) 103 * 104 * @global wpdb $wpdb WordPress database object. 105 * 106 * @return bool True on success, false on failure. 107 */ 108 public function save() { 109 110 // Return value 111 $retval = false; 112 113 // Default data and format 114 $data = array( 115 'user_id' => $this->user_id, 116 'item_id' => $this->item_id, 117 'secondary_item_id' => $this->secondary_item_id, 118 'component_name' => $this->component_name, 119 'component_action' => $this->component_action, 120 'date_notified' => $this->date_notified, 121 'is_new' => $this->is_new, 122 ); 123 $data_format = array( '%d', '%d', '%d', '%s', '%s', '%s', '%d' ); 124 125 // Update 126 if ( ! empty( $this->id ) ) { 127 $result = self::_update( $data, array( 'ID' => $this->id ), $data_format, array( '%d' ) ); 128 129 // Insert 130 } else { 131 $result = self::_insert( $data, $data_format ); 132 } 133 134 // Set the notification ID if successful 135 if ( ! empty( $result ) && ! is_wp_error( $result ) ) { 136 global $wpdb; 137 138 $this->id = $wpdb->insert_id; 139 $retval = $wpdb->insert_id; 140 } 141 142 // Return the result 143 return $retval; 144 } 145 146 /** 147 * Fetch data for an existing notification from the database. 148 * 149 * @since BuddyPress (1.9.0) 150 * 151 * @global BuddyPress $bp The one true BuddyPress instance. 152 * @global wpdb $wpdb WordPress database object. 153 */ 154 public function populate() { 155 global $wpdb; 156 157 $bp = buddypress(); 158 159 // Look for a notification 160 $notification = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->notifications->table_name} WHERE id = %d", $this->id ) ); 161 162 // Setup the notification data 163 if ( ! empty( $notification ) && ! is_wp_error( $notification ) ) { 164 $this->item_id = $notification->item_id; 165 $this->secondary_item_id = $notification->secondary_item_id; 166 $this->user_id = $notification->user_id; 167 $this->component_name = $notification->component_name; 168 $this->component_action = $notification->component_action; 169 $this->date_notified = $notification->date_notified; 170 $this->is_new = $notification->is_new; 171 } 172 } 173 174 /** Protected Static Methods ******************************************/ 175 176 /** 177 * Create a notification entry. 178 * 179 * @since BuddyPress (1.9.0) 180 * 181 * @param array $data { 182 * Array of notification data, passed to {@link wpdb::insert()}. 183 * @type int $user_id ID of the associated user. 184 * @type int $item_id ID of the associated item. 185 * @type int $secondary_item_id ID of the secondary associated item. 186 * @type string $component_name Name of the associated component. 187 * @type string $component_action Name of the associated component 188 * action. 189 * @type string $date_notified Timestamp of the notification. 190 * @type bool $is_new True if the notification is unread, otherwise 191 * false. 192 * } 193 * @param array $data_format See {@link wpdb::insert()}. 194 * @return int|false The number of rows inserted, or false on error. 195 */ 196 protected static function _insert( $data = array(), $data_format = array() ) { 197 global $wpdb; 198 return $wpdb->insert( buddypress()->notifications->table_name, $data, $data_format ); 199 } 200 201 /** 202 * Update notifications. 203 * 204 * @since BuddyPress (1.9.0) 205 * 206 * @see wpdb::update() for further description of paramater formats. 207 * 208 * @param array $data Array of notification data to update, passed to 209 * {@link wpdb::update()}. Accepts any property of a 210 * BP_Notification_Notification object. 211 * @param array $where The WHERE params as passed to wpdb::update(). 212 * Typically consists of array( 'ID' => $id ) to specify the ID 213 * of the item being updated. See {@link wpdb::update()}. 214 * @param array $data_format See {@link wpdb::insert()}. 215 * @param array $where_format See {@link wpdb::insert()}. 216 * @return int|false The number of rows updated, or false on error. 217 */ 218 protected static function _update( $data = array(), $where = array(), $data_format = array(), $where_format = array() ) { 219 global $wpdb; 220 return $wpdb->update( buddypress()->notifications->table_name, $data, $where, $data_format, $where_format ); 221 } 222 223 /** 224 * Delete notifications. 225 * 226 * @since BuddyPress (1.9.0) 227 * 228 * @see wpdb::update() for further description of paramater formats. 229 * 230 * @param array $where Array of WHERE clauses to filter by, passed to 231 * {@link wpdb::delete()}. Accepts any property of a 232 * BP_Notification_Notification object. 233 * @param array $where_format See {@link wpdb::insert()}. 234 * @return int|false The number of rows updated, or false on error. 235 */ 236 protected static function _delete( $where = array(), $where_format = array() ) { 237 global $wpdb; 238 return $wpdb->delete( buddypress()->notifications->table_name, $where, $where_format ); 239 } 240 241 /** 242 * Assemble the WHERE clause of a get() SQL statement. 243 * 244 * Used by BP_Notifications_Notification::get() to create its WHERE 245 * clause. 246 * 247 * @since BuddyPress (1.9.0) 248 * 249 * @param array $args See {@link BP_Notifications_Notification::get()} 250 * for more details. 251 * @return string WHERE clause. 252 */ 253 protected static function get_where_sql( $args = array() ) { 254 global $wpdb; 255 256 $where_conditions = array(); 257 258 // id 259 if ( ! empty( $args['id'] ) ) { 260 $id_in = implode( ',', wp_parse_id_list( $args['id'] ) ); 261 $where_conditions['id'] = "id IN ({$id_in})"; 262 } 263 264 // user_id 265 if ( ! empty( $args['user_id'] ) ) { 266 $user_id_in = implode( ',', wp_parse_id_list( $args['user_id'] ) ); 267 $where_conditions['user_id'] = "user_id IN ({$user_id_in})"; 268 } 269 270 // item_id 271 if ( ! empty( $args['item_id'] ) ) { 272 $item_id_in = implode( ',', wp_parse_id_list( $args['item_id'] ) ); 273 $where_conditions['item_id'] = "item_id IN ({$item_id_in})"; 274 } 275 276 // secondary_item_id 277 if ( ! empty( $args['secondary_item_id'] ) ) { 278 $secondary_item_id_in = implode( ',', wp_parse_id_list( $args['secondary_item_id'] ) ); 279 $where_conditions['secondary_item_id'] = "secondary_item_id IN ({$secondary_item_id_in})"; 280 } 281 282 // component_name 283 if ( ! empty( $args['component_name'] ) ) { 284 if ( ! is_array( $args['component_name'] ) ) { 285 $component_names = explode( ',', $args['component_name'] ); 286 } else { 287 $component_names = $args['component_name']; 288 } 289 290 $cn_clean = array(); 291 foreach ( $component_names as $cn ) { 292 $cn_clean[] = $wpdb->prepare( '%s', $cn ); 293 } 294 295 $cn_in = implode( ',', $cn_clean ); 296 $where_conditions['component_name'] = "component_name IN ({$cn_in})"; 297 } 298 299 // component_action 300 if ( ! empty( $args['component_action'] ) ) { 301 if ( ! is_array( $args['component_action'] ) ) { 302 $component_actions = explode( ',', $args['component_action'] ); 303 } else { 304 $component_actions = $args['component_action']; 305 } 306 307 $ca_clean = array(); 308 foreach ( $component_actions as $ca ) { 309 $ca_clean[] = $wpdb->prepare( '%s', $ca ); 310 } 311 312 $ca_in = implode( ',', $ca_clean ); 313 $where_conditions['component_action'] = "component_action IN ({$ca_in})"; 314 } 315 316 // is_new 317 if ( ! empty( $args['is_new'] ) ) { 318 $where_conditions['is_new'] = "is_new = 1"; 319 } 320 321 // search_terms 322 if ( ! empty( $args['search_terms'] ) ) { 323 $search_terms = like_escape( esc_sql( $args['search_terms'] ) ); 324 $where_conditions['search_terms'] = "( component_name LIKE '%%$search_terms%%' OR component_action LIKE '%%$search_terms%%' )"; 325 } 326 327 if ( ! empty( $where_conditions ) ) { 328 $where = 'WHERE ' . implode( ' AND ', $where_conditions ); 329 } else { 330 $where = ''; 331 } 332 333 return $where; 334 } 335 336 /** 337 * Assemble query clauses, based on arrguments, to pass to $wpdb methods. 338 * 339 * The insert(), update(), and delete() methods of {@link wpdb} expect 340 * arguments of the following forms: 341 * 342 * - associative arrays whose key/value pairs are column => value, to 343 * be used in WHERE, SET, or VALUES clauses 344 * - arrays of "formats", which tell $wpdb->prepare() which type of 345 * value to expect when sanitizing (eg, array( '%s', '%d' )) 346 * 347 * This utility method can be used to assemble both kinds of params, 348 * out of a single set of associative array arguments, such as: 349 * 350 * $args = array( 351 * 'user_id' => 4, 352 * 'component_name' => 'groups', 353 * ); 354 * 355 * This will be converted to: 356 * 357 * array( 358 * 'data' => array( 359 * 'user_id' => 4, 360 * 'component_name' => 'groups', 361 * ), 362 * 'format' => array( 363 * '%d', 364 * '%s', 365 * ), 366 * ) 367 * 368 * which can easily be passed as arguments to the $wpdb methods. 369 * 370 * @since BuddyPress (1.9.0) 371 * 372 * @param $args Associative array of filter arguments. 373 * See {@BP_Notifications_Notification::get()} for a breakdown. 374 * @return array Associative array of 'data' and 'format' args. 375 */ 376 protected static function get_query_clauses( $args = array() ) { 377 $where_clauses = array( 378 'data' => array(), 379 'format' => array(), 380 ); 381 382 // id 383 if ( ! empty( $args['id'] ) ) { 384 $where_clauses['data']['id'] = absint( $args['id'] ); 385 $where_clauses['format'][] = '%d'; 386 } 387 388 // user_id 389 if ( ! empty( $args['user_id'] ) ) { 390 $where_clauses['data']['user_id'] = absint( $args['user_id'] ); 391 $where_clauses['format'][] = '%d'; 392 } 393 394 // item_id 395 if ( ! empty( $args['item_id'] ) ) { 396 $where_clauses['data']['item_id'] = absint( $args['item_id'] ); 397 $where_clauses['format'][] = '%d'; 398 } 399 400 // secondary_item_id 401 if ( ! empty( $args['secondary_item_id'] ) ) { 402 $where_clauses['data']['secondary_item_id'] = absint( $args['secondary_item_id'] ); 403 $where_clauses['format'][] = '%d'; 404 } 405 406 // component_name 407 if ( ! empty( $args['component_name'] ) ) { 408 $where_clauses['data']['component_name'] = $args['component_name']; 409 $where_clauses['format'][] = '%s'; 410 } 411 412 // component_action 413 if ( ! empty( $args['component_action'] ) ) { 414 $where_clauses['data']['component_action'] = $args['component_action']; 415 $where_clauses['format'][] = '%s'; 416 } 417 418 // is_new 419 if ( isset( $args['is_new'] ) ) { 420 $where_clauses['data']['is_new'] = ! empty( $args['is_new'] ) ? 1 : 0; 421 $where_clauses['format'][] = '%d'; 422 } 423 424 return $where_clauses; 425 } 426 427 /** Public Static Methods *********************************************/ 428 429 /** 430 * Check that a specific notification is for a specific user. 431 * 432 * @since BuddyPress (1.9.0) 433 * 434 * @param int $user_id ID of the user being checked. 435 * @param int $notification_id ID of the notification being checked. 436 * @return bool True if the notification belongs to the user, otherwise 437 * false. 438 */ 439 public static function check_access( $user_id, $notification_id ) { 440 global $wpdb; 441 442 $bp = buddypress(); 443 444 return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$bp->core->table_name_notifications} WHERE id = %d AND user_id = %d", $notification_id, $user_id ) ); 445 } 446 447 /** 448 * Get notifications, based on provided filter parameters. 449 * 450 * @since BuddyPress (1.9.0) 451 * 452 * @param array $args { 453 * Associative array of arguments. All arguments but $page and 454 * $per_page can be treated as filter values for get_where_sql() 455 * and get_query_clauses(). All items are optional. 456 * @type int|array $id ID of notification being updated. Can be an 457 * array of IDs. 458 * @type int|array $user_id ID of user being queried. Can be an 459 * array of user IDs. 460 * @type int|array $item_id ID of associated item. Can be an array 461 * of multiple item IDs. 462 * @type int|array $secondary_item_id ID of secondary associated 463 * item. Can be an array of multiple IDs. 464 * @type string|array $component_name Name of the component to 465 * filter by. Can be an array of component names. 466 * @type string|array $component_action Name of the action to 467 * filter by. Can be an array of actions. 468 * @type bool $is_new Whether to limit the query to is_new (unread) 469 * notifications. Default: true. 470 * @type string $search_terms Term to match against component_name 471 * or component_action fields. 472 * @type int $page Number of the current page of results. Default: 473 * false (no pagination - all items). 474 * @type int $per_page Number of items to show per page. Default: 475 * false (no pagination - all items). 476 * } 477 * @return array Located notifications. 478 */ 479 public static function get( $args = array() ) { 480 global $wpdb; 481 482 $r = wp_parse_args( $args, array( 483 'id' => false, 484 'user_id' => false, 485 'item_id' => false, 486 'secondary_item_id' => false, 487 'component_name' => false, 488 'component_action' => false, 489 'is_new' => true, 490 'search_terms' => '', 491 'page' => false, 492 'per_page' => false, 493 ) ); 494 495 $bp = buddypress(); 496 497 $select_sql = "SELECT *"; 498 $from_sql = "FROM {$bp->notifications->table_name}"; 499 500 $where_args = array( 501 'id' => $r['id'], 502 'user_id' => $r['user_id'], 503 'item_id' => $r['item_id'], 504 'secondary_item_id' => $r['secondary_item_id'], 505 'component_name' => $r['component_name'], 506 'component_action' => $r['component_action'], 507 'is_new' => $r['is_new'], 508 'search_terms' => $r['search_terms'], 509 ); 510 511 $where_sql = self::get_where_sql( $where_args ); 512 513 $pag_sql = ''; 514 if ( ! empty( $r['page'] ) && ! empty( $r['per_page'] ) ) { 515 $page = absint( $r['page'] ); 516 $per_page = absint( $r['per_page'] ); 517 $offset = $per_page * ( $page - 1 ); 518 $pag_sql = $wpdb->prepare( "LIMIT %d, %d", $offset, $per_page ); 519 } 520 521 $sql = "{$select_sql} {$from_sql} {$where_sql} {$pag_sql}"; 522 523 return $wpdb->get_results( $sql ); 524 } 525 526 /** 527 * Get a count of total notifications matching a set of arguments. 528 * 529 * @since BuddyPress (1.9.0) 530 * 531 * @see BP_Notifications_Notification::get() for a description of 532 * arguments. 533 * 534 * @param array $args See {@link BP_Notifications_Notification::get()}. 535 * @return int Count of located items. 536 */ 537 public static function get_total_count( $args ) { 538 global $wpdb; 539 540 $bp = buddypress(); 541 542 $select_sql = "SELECT COUNT(*)"; 543 $from_sql = "FROM {$bp->notifications->table_name}"; 544 $where_sql = self::get_where_sql( $args ); 545 546 $sql = "{$select_sql} {$from_sql} {$where_sql}"; 547 548 return $wpdb->get_var( $sql ); 549 } 550 551 /** 552 * Update notifications. 553 * 554 * @since BuddyPress (1.9.0) 555 * 556 * @see BP_Notifications_Notification::get() for a description of 557 * accepted update/where arguments. 558 * 559 * @param array $update_args Associative array of fields to update, 560 * and the values to update them to. Of the format 561 * array( 'user_id' => 4, 'component_name' => 'groups', ) 562 * @param array $where_args Associative array of columns/values, to 563 * determine which rows should be updated. Of the format 564 * array( 'item_id' => 7, 'component_action' => 'members', ) 565 * @return int|bool Number of rows updated on success, false on failure. 566 */ 567 public static function update( $update_args = array(), $where_args = array() ) { 568 $update = self::get_query_clauses( $update_args ); 569 $where = self::get_query_clauses( $where_args ); 570 571 return self::_update( $update['data'], $where['data'], $update['format'], $where['format'] ); 572 } 573 574 /** 575 * Delete notifications. 576 * 577 * @since BuddyPress (1.9.0) 578 * 579 * @see BP_Notifications_Notification::get() for a description of 580 * accepted update/where arguments. 581 * 582 * @param array $args Associative array of columns/values, to determine 583 * which rows should be deleted. Of the format 584 * array( 'item_id' => 7, 'component_action' => 'members', ) 585 * @return int|bool Number of rows deleted on success, false on failure. 586 */ 587 public static function delete( $args = array() ) { 588 $where = self::get_query_clauses( $args ); 589 590 return self::_delete( $where['data'], $where['format'] ); 591 } 592 593 594 /** Convenience methods **********************************************/ 595 596 /** 597 * Delete a single notification by ID. 598 * 599 * @since BuddyPress (1.9.0) 600 * 601 * @see BP_Notifications_Notification::delete() for explanation of 602 * return value. 603 * 604 * @param int $id ID of the notification item to be deleted. 605 * @return bool True on success, false on failure. 606 */ 607 public static function delete_by_id( $id ) { 608 return self::delete( array( 609 'id' => $id, 610 ) ); 611 } 612 613 /** 614 * Fetch all the notifications in the database for a specific user. 615 * 616 * @since BuddyPress (1.9.0) 617 * 618 * @param int $user_id ID of the user whose notifications are being 619 * fetched. 620 * @param string $status Optional. Status of notifications to fetch. 621 * 'is_new' to get only unread items, 'all' to get all. 622 * @return array Associative array of notification items. 623 */ 624 public static function get_all_for_user( $user_id, $status = 'is_new' ) { 625 $args = array( 626 'user_id' => $user_id, 627 'is_new' => 'is_new' === $status, 628 ); 629 return self::get( $args ); 630 } 631 632 /** 633 * Fetch all the unread notifications in the database for a specific user. 634 * 635 * @since BuddyPress (1.9.0) 636 * 637 * @param int $user_id ID of the user whose notifications are being 638 * fetched. 639 * @return array Associative array of unread notification items. 640 */ 641 public static function get_unread_for_user( $user_id = 0 ) { 642 $args = array( 643 'user_id' => $user_id, 644 'is_new' => true, 645 ); 646 return self::get( $args ); 647 } 648 649 /** 650 * Fetch all the read notifications in the database for a specific user. 651 * 652 * @since BuddyPress (1.9.0) 653 * 654 * @param int $user_id ID of the user whose notifications are being 655 * fetched. 656 * @return array Associative array of unread notification items. 657 */ 658 public static function get_read_for_user( $user_id = 0 ) { 659 $args = array( 660 'user_id' => $user_id, 661 'is_new' => false, 662 ); 663 return self::get( $args ); 664 } 665 666 /** 667 * Get unread notifications for a user, in a pagination-friendly format. 668 * 669 * @since BuddyPress (1.9.0) 670 * 671 * @param array $args { 672 * Array of arguments. 673 * @type int $user_id ID of the user for whom the notifications are 674 * being fetched. Default: logged-in user ID. 675 * @type bool $is_new Whether to limit the query to unread 676 * notifications. Default: true. 677 * @type int $page Number of the page to return. Default: 1. 678 * @type int $per_page Number of results to display per page. 679 * Default: 10. 680 * @type string $search_terms Optional. A term to search against in 681 * the 'component_name' and 'component_action' columns. 682 * } 683 * @return array { 684 * @type array $notifications Array of notification results. 685 * @type int $total Count of all located notifications matching 686 * the query params. 687 * } 688 */ 689 public static function get_current_notifications_for_user( $args = array() ) { 690 $r = wp_parse_args( $args, array( 691 'user_id' => bp_loggedin_user_id(), 692 'is_new' => true, 693 'page' => 1, 694 'per_page' => 10, 695 'search_terms' => '', 696 ) ); 697 698 $notifications = self::get( $r ); 699 700 // Bail if no notifications 701 if ( empty( $notifications ) ) { 702 return false; 703 } 704 705 $total_count = self::get_total_count( $r ); 706 707 return array( 'notifications' => &$notifications, 'total' => $total_count ); 708 } 709 710 /** Mark Read *************************************************************/ 711 712 /** 713 * Mark all user notifications as read. 714 * 715 * @since BuddyPress (1.9.0) 716 * 717 * @param int $user_id The ID of the user who the notifications 718 * are for. 719 * @param int $is_new Mark as read (1) or unread (0). 720 */ 721 public static function mark_all_for_user( $user_id, $is_new = 0, $item_id = 0, $component_name = '', $component_action = '', $secondary_item_id = 0 ) { 722 723 // Values to be updated 724 $update_args = array( 725 'is_new' => $is_new, 726 ); 727 728 // WHERE clauses 729 $where_args = array( 730 'user_id' => $user_id, 731 ); 732 733 if ( $component_name ) { 734 $where_args['component_name'] = $component_name; 735 } 736 737 if ( $component_action ) { 738 $where_args['component_action'] = $component_action; 739 } 740 741 if ( $secondary_item_id ) { 742 $where_args['secondary_item_id'] = $secondary_item_id; 743 } 744 745 return self::update( $update_args, $where_args ); 746 } 747 748 /** 749 * Mark all notifications from a user as read. 750 * 751 * @since BuddyPress (1.9.0) 752 * 753 * @param int $user_id The ID of the user who the notifications are from. 754 * @param int $is_new Mark as read (1) or unread (0). 755 */ 756 public static function mark_all_from_user( $user_id, $is_new = 0, $component_name = '', $component_action = '', $secondary_item_id = 0 ) { 757 758 // Values to be updated 759 $update_args = array( 760 'is_new' => $is_new, 761 ); 762 763 // WHERE clauses 764 $where_args = array( 765 'item_id' => $user_id, 766 ); 767 768 if ( $component_name ) { 769 $where_args['component_name'] = $component_name; 770 } 771 772 if ( $component_action ) { 773 $where_args['component_action'] = $component_action; 774 } 775 776 if ( $secondary_item_id ) { 777 $where_args['secondary_item_id'] = $secondary_item_id; 778 } 779 780 return self::update( $update_args, $where_args ); 781 } 782 783 /** 784 * Mark all notifications for all users as read by item id, and optional 785 * secondary item id, and component name and action. 786 * 787 * @since BuddyPress (1.9.0) 788 * 789 * @param int $item_id The ID of the item associated with the 790 * notifications. 791 * @param string $component_name The component that the notifications 792 * are associated with. 793 * @param string $component_action The action that the notifications 794 * are associated with. 795 * @param string $secondary_item_id Optional. ID of the secondary 796 * associated item. 797 */ 798 public static function mark_all_by_type( $item_id, $is_new = 0, $component_name = '', $component_action = '', $secondary_item_id = 0 ) { 799 800 // Values to be updated 801 $update_args = array( 802 'is_new' => $is_new, 803 ); 804 805 // WHERE clauses 806 $where_args = array( 807 'item_id' => $item_id, 808 ); 809 810 if ( $component_name ) { 811 $where_args['component_name'] = $component_name; 812 } 813 814 if ( $component_action ) { 815 $where_args['component_action'] = $component_action; 816 } 817 818 if ( $secondary_item_id ) { 819 $where_args['secondary_item_id'] = $secondary_item_id; 820 } 821 822 return self::update( $update_args, $where_args ); 823 } 824 } -
bp-notifications/bp-notifications-functions.php
new file mode 100644
1 <?php 2 3 /** 4 * BuddyPress Member Notifications Functions. 5 * 6 * Functions and filters used in the Notifications component. 7 * 8 * @package BuddyPress 9 * @subpackage NotificationsFunctions 10 */ 11 12 // Exit if accessed directly 13 if ( !defined( 'ABSPATH' ) ) exit; 14 15 /** 16 * Add a notification for a specific user, from a specific component. 17 * 18 * @since BuddyPress (1.9.0) 19 * 20 * @param array $args { 21 * Array of arguments describing the notification. All are optional. 22 * @type int $user_id ID of the user to associate the notificiton with. 23 * @type int $item_id ID of the item to associate the notification with. 24 * @type int $secondary_item_id ID of the secondary item to associate the 25 * notification with. 26 * @type string $component_name Name of the component to associate the 27 * notification with. 28 * @type string $component_action Name of the action to associate the 29 * notification with. 30 * @type string $date_notified Timestamp for the notification. 31 * } 32 * @return int|bool ID of the newly created notification on success, false 33 * on failure. 34 */ 35 function bp_notifications_add_notification( $args = array() ) { 36 37 $r = wp_parse_args( $args, array( 38 'user_id' => 0, 39 'item_id' => 0, 40 'secondary_item_id' => 0, 41 'component_name' => '', 42 'component_action' => '', 43 'date_notified' => bp_core_current_time(), 44 ) ); 45 46 // Setup the new notification 47 $notification = new BP_Notifications_Notification; 48 $notification->user_id = $r['user_id']; 49 $notification->item_id = $r['item_id']; 50 $notification->secondary_item_id = $r['secondary_item_id']; 51 $notification->component_name = $r['component_name']; 52 $notification->component_action = $r['component_action']; 53 $notification->date_notified = $r['date_notified']; 54 $notification->is_new = 1; 55 56 // Save the new notification 57 return $notification->save(); 58 } 59 60 /** 61 * Get a specific notification by its ID. 62 * 63 * @since BuddyPress (1.9.0) 64 * 65 * @param int $id ID of the notification. 66 * @return BP_Notifications_Notification 67 */ 68 function bp_notifications_get_notification( $id ) { 69 return new BP_Notifications_Notification( $id ); 70 } 71 72 /** 73 * Delete a specific notification by its ID. 74 * 75 * @since BuddyPress (1.9.0) 76 * 77 * @param int $id ID of the notification to delete. 78 * @return bool True on success, false on failure. 79 */ 80 function bp_notifications_delete_notification( $id ) { 81 if ( ! bp_notifications_check_notification_access( bp_loggedin_user_id(), $id ) ) { 82 return false; 83 } 84 85 return BP_Notifications_Notification::delete( $id ); 86 } 87 88 /** 89 * Get notifications for a specific user. 90 * 91 * @since BuddyPress (1.9.0) 92 * 93 * @param int $user_id ID of the user whose notification are being fetched. 94 * @param string $format Format of the returned values. 'simple' returns HTML, 95 * while 'object' returns a structured object for parsing. 96 * @return mixed Object or array on success, false on failure. 97 */ 98 function bp_notifications_get_notifications_for_user( $user_id, $format = 'simple' ) { 99 100 // Setup local variables 101 $bp = buddypress(); 102 $notifications = BP_Notifications_Notification::get( array( 103 'user_id' => $user_id, 104 ) ); 105 $grouped_notifications = array(); // Notification groups 106 $renderable = array(); // Renderable notifications 107 108 // Group notifications by component and component_action and provide totals 109 for ( $i = 0, $count = count( $notifications ); $i < $count; ++$i ) { 110 $notification = $notifications[$i]; 111 $grouped_notifications[$notification->component_name][$notification->component_action][] = $notification; 112 } 113 114 // Bail if no notification groups 115 if ( empty( $grouped_notifications ) ) { 116 return false; 117 } 118 119 // Calculate a renderable output for each notification type 120 foreach ( $grouped_notifications as $component_name => $action_arrays ) { 121 122 // Skip if group is empty 123 if ( empty( $action_arrays ) ) { 124 continue; 125 } 126 127 // Skip inactive components 128 if ( ! bp_is_active( $component_name ) ) { 129 continue; 130 } 131 132 // Loop through each actionable item and try to map it to a component 133 foreach ( (array) $action_arrays as $component_action_name => $component_action_items ) { 134 135 // Get the number of actionable items 136 $action_item_count = count( $component_action_items ); 137 138 // Skip if the count is less than 1 139 if ( $action_item_count < 1 ) { 140 continue; 141 } 142 143 // Callback function exists 144 if ( isset( $bp->{$component_name}->notification_callback ) && is_callable( $bp->{$component_name}->notification_callback ) ) { 145 146 // Function should return an object 147 if ( 'object' == $format ) { 148 149 // Retrieve the content of the notification using the callback 150 $content = call_user_func( 151 $bp->{$component_name}->notification_callback, 152 $component_action_name, 153 $component_action_items[0]->item_id, 154 $component_action_items[0]->secondary_item_id, 155 $action_item_count, 156 'array' 157 ); 158 159 // Create the object to be returned 160 $notification_object = new stdClass; 161 162 // Minimal backpat with non-compatible notification 163 // callback functions 164 if ( is_string( $content ) ) { 165 $notification_object->content = $content; 166 $notification_object->href = bp_loggedin_user_domain(); 167 } else { 168 $notification_object->content = $content['text']; 169 $notification_object->href = $content['link']; 170 } 171 172 $notification_object->id = $component_action_items[0]->id; 173 $renderable[] = $notification_object; 174 175 // Return an array of content strings 176 } else { 177 $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 ); 178 $renderable[] = $content; 179 } 180 181 // @deprecated format_notification_function - 1.5 182 } elseif ( isset( $bp->{$component_name}->format_notification_function ) && function_exists( $bp->{$component_name}->format_notification_function ) ) { 183 $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 ); 184 } 185 } 186 } 187 188 // If renderable is empty array, set to false 189 if ( empty( $renderable ) ) { 190 $renderable = false; 191 } 192 193 // Filter and return 194 return apply_filters( 'bp_core_get_notifications_for_user', $renderable, $user_id, $format ); 195 } 196 197 /** 198 * Delete notifications for a user by type. 199 * 200 * Used when clearing out notifications for a specific component when the user 201 * has visited that component. 202 * 203 * @since BuddyPress (1.9.0) 204 * 205 * @param int $user_id ID of the user whose notifications are being deleted. 206 * @param string $component_name Name of the associated component. 207 * @param string $component_action Name of the associated action. 208 * @return bool True on success, false on failure. 209 */ 210 function bp_notifications_delete_notifications_by_type( $user_id, $component_name, $component_action ) { 211 return BP_Notifications_Notification::delete( array( 212 'user_id' => $user_id, 213 'component_name' => $component_name, 214 'component_action' => $component_action, 215 ) ); 216 } 217 218 /** 219 * Delete notifications for an item ID. 220 * 221 * Used when clearing out notifications for a specific component when the user 222 * has visited that component. 223 * 224 * @since BuddyPress (1.9.0) 225 * 226 * @param int $user_id ID of the user whose notifications are being deleted. 227 * @param int $item_id ID of the associated item. 228 * @param string $component_name Name of the associated component. 229 * @param string $component_action Name of the associated action. 230 * @param int $secondary_item_id ID of the secondary associated item. 231 * @return bool True on success, false on failure. 232 */ 233 function bp_notifications_delete_notifications_by_item_id( $user_id, $item_id, $component_name, $component_action, $secondary_item_id = false ) { 234 return BP_Notifications_Notification::delete( array( 235 'user_id' => $user_id, 236 'item_id' => $item_id, 237 'secondary_item_id' => $secondary_item_id, 238 'component_name' => $component_name, 239 'component_action' => $component_action, 240 ) ); 241 } 242 243 /** 244 * Delete all notifications by type. 245 * 246 * Used when clearing out notifications for an entire component. 247 * 248 * @since BuddyPress (1.9.0) 249 * 250 * @param int $user_id ID of the user whose notifications are being deleted. 251 * @param string $component_name Name of the associated component. 252 * @param string $component_action Optional. Name of the associated action. 253 * @param int $secondary_item_id Optional. ID of the secondary associated item. 254 * @return bool True on success, false on failure. 255 */ 256 function bp_notifications_delete_all_notifications_by_type( $item_id, $component_name, $component_action = false, $secondary_item_id = false ) { 257 return BP_Notifications_Notification::delete( array( 258 'item_id' => $item_id, 259 'secondary_item_id' => $secondary_item_id, 260 'component_name' => $component_name, 261 'component_action' => $component_action, 262 ) ); 263 } 264 265 /** 266 * Delete all notifications from a user. 267 * 268 * Used when clearing out all notifications for a user, when deleted or spammed. 269 * 270 * @todo This function assumes that items with the user_id in the item_id slot 271 * are associated with that user. However, this will only be true with 272 * certain components (such as Friends). Use with caution! 273 * 274 * @since BuddyPress (1.9.0) 275 * 276 * @param int $user_id ID of the user whose associated items are beind deleted. 277 * @param string $component_name Name of the associated component. 278 * @param string $component_action Name of the associated action. 279 * @return bool True on success, false on failure. 280 */ 281 function bp_notifications_delete_notifications_from_user( $user_id, $component_name, $component_action ) { 282 return BP_Notifications_Notification::delete( array( 283 'item_id' => $user_id, 284 'component_name' => $component_name, 285 'component_action' => $component_action, 286 ) ); 287 } 288 289 /** 290 * Check if a user has access to a specific notification. 291 * 292 * Used before deleting a notification for a user. 293 * 294 * @since BuddyPress (1.9.0) 295 * 296 * @param int $user_id ID of the user being checked. 297 * @param int $notification_id ID of the notification being checked. 298 * @return bool True if the notification belongs to the user, otherwise false. 299 */ 300 function bp_notifications_check_notification_access( $user_id, $notification_id ) { 301 return (bool) BP_Notifications_Notification::check_access( $user_id, $notification_id ); 302 } 303 304 /** 305 * Get a count of unread notification items for a user. 306 * 307 * @since BuddyPress (1.9.0) 308 * 309 * @param int $user_id ID of the user whose unread notifications are being 310 * counted. 311 * @return int Unread notification count. 312 */ 313 function bp_notifications_get_unread_notification_count( $user_id = 0 ) { 314 315 // Default to displayed user if no ID is passed 316 if ( empty( $user_id ) ) { 317 $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id(); 318 } 319 320 // Get the notifications, and count them 321 $notifications = BP_Notifications_Notification::get( array( 322 'user_id' => $user_id, 323 ) ); 324 325 $count = ! empty( $notifications ) ? count( $notifications ) : 0; 326 327 return apply_filters( 'bp_notifications_get_total_notification_count', $count ); 328 } -
bp-notifications/bp-notifications-loader.php
new file mode 100644
1 <?php 2 3 /** 4 * BuddyPress Member Notifications Loader. 5 * 6 * Initializes the Notifications component. 7 * 8 * @package BuddyPress 9 * @subpackage NotificationsLoader 10 * @since BuddyPress (1.9.0) 11 */ 12 13 // Exit if accessed directly 14 if ( !defined( 'ABSPATH' ) ) exit; 15 16 class BP_Notifications_Component extends BP_Component { 17 18 /** 19 * Start the notifications component creation process. 20 * 21 * @since BuddyPress (1.9.0) 22 */ 23 function __construct() { 24 parent::start( 25 'notifications', 26 __( 'Notifications', 'buddypress' ), 27 BP_PLUGIN_DIR, 28 array( 29 'adminbar_myaccount_order' => 100 30 ) 31 ); 32 } 33 34 /** 35 * Include notifications component files. 36 * 37 * @since BuddyPress (1.9.0) 38 * 39 * @see BP_Component::includes() for a description of arguments. 40 * 41 * @param array $includes See BP_Component::includes() for a description. 42 */ 43 public function includes( $includes = array() ) { 44 $includes = array( 45 'classes', 46 'screens', 47 'adminbar', 48 'buddybar', 49 'template', 50 'functions', 51 ); 52 53 parent::includes( $includes ); 54 } 55 56 /** 57 * Setup globals 58 * 59 * The BP_FRIENDS_SLUG constant is deprecated, and only used here for 60 * backwards compatibility. 61 * 62 * @since BuddyPress (1.9.0) 63 * 64 * @see BP_Component::setup_globals() for a description of arguments. 65 * 66 * @param array $args See BP_Component::setup_globals() for a description. 67 */ 68 public function setup_globals( $args = array() ) { 69 // Define a slug, if necessary 70 if ( !defined( 'BP_NOTIFICATIONS_SLUG' ) ) { 71 define( 'BP_NOTIFICATIONS_SLUG', $this->id ); 72 } 73 74 // Global tables for the notifications component 75 $global_tables = array( 76 'table_name' => bp_core_get_table_prefix() . 'bp_notifications' 77 ); 78 79 // All globals for the notifications component. 80 // Note that global_tables is included in this array. 81 $args = array( 82 'slug' => BP_NOTIFICATIONS_SLUG, 83 'has_directory' => false, 84 'search_string' => __( 'Search Notifications...', 'buddypress' ), 85 'global_tables' => $global_tables, 86 ); 87 88 parent::setup_globals( $args ); 89 } 90 91 /** 92 * Set up component navigation. 93 * 94 * @since BuddyPress (1.9.0) 95 * 96 * @see BP_Component::setup_nav() for a description of arguments. 97 * 98 * @param array $main_nav Optional. See BP_Component::setup_nav() for 99 * description. 100 * @param array $sub_nav Optional. See BP_Component::setup_nav() for 101 * description. 102 */ 103 public function setup_nav( $main_nav = array(), $sub_nav = array() ) { 104 105 // Add 'Notifications' to the main navigation 106 $count = bp_notifications_get_unread_notification_count( bp_loggedin_user_id() ); 107 $main_nav = array( 108 'name' => sprintf( __( 'Notifications <span>%d</span>', 'buddypress' ), number_format_i18n( $count ) ), 109 'slug' => $this->slug, 110 'position' => 60, 111 'screen_function' => 'bp_notifications_screen_unread', 112 'default_subnav_slug' => 'unread', 113 'item_css_id' => $this->id, 114 ); 115 116 // Determine user to use 117 if ( bp_displayed_user_domain() ) { 118 $user_domain = bp_displayed_user_domain(); 119 } elseif ( bp_loggedin_user_domain() ) { 120 $user_domain = bp_loggedin_user_domain(); 121 } else { 122 return; 123 } 124 125 $notifications_link = trailingslashit( $user_domain . bp_get_notifications_slug() ); 126 127 // Add the subnav items to the notifications nav item 128 $sub_nav[] = array( 129 'name' => __( 'Unread', 'buddypress' ), 130 'slug' => 'unread', 131 'parent_url' => $notifications_link, 132 'parent_slug' => bp_get_notifications_slug(), 133 'screen_function' => 'bp_notifications_screen_unread', 134 'position' => 10, 135 'item_css_id' => 'notifications-my-notifications', 136 ); 137 138 $sub_nav[] = array( 139 'name' => __( 'Read', 'buddypress' ), 140 'slug' => 'read', 141 'parent_url' => $notifications_link, 142 'parent_slug' => bp_get_notifications_slug(), 143 'screen_function' => 'bp_notifications_screen_read', 144 'position' => 20, 145 'user_has_access' => bp_core_can_edit_settings(), 146 ); 147 148 parent::setup_nav( $main_nav, $sub_nav ); 149 } 150 151 /** 152 * Set up the component entries in the WordPress Admin Bar. 153 * 154 * @since BuddyPress (1.9.0) 155 * 156 * @see BP_Component::setup_nav() for a description of the $wp_admin_nav 157 * parameter array. 158 * 159 * @param array $wp_admin_nav See BP_Component::setup_admin_bar() for a 160 * description. 161 */ 162 public function setup_admin_bar( $wp_admin_nav = array() ) { 163 164 // Menus for logged in user 165 if ( is_user_logged_in() ) { 166 167 // Setup the logged in user variables 168 $notifications_link = trailingslashit( bp_loggedin_user_domain() . $this->slug ); 169 170 // Pending notification requests 171 $count = bp_notifications_get_unread_notification_count( bp_loggedin_user_id() ); 172 if ( ! empty( $count ) ) { 173 $unread = sprintf( __( 'Notifications <span class="count">%s</span>', 'buddypress' ), number_format_i18n( $count ) ); 174 } else { 175 $unread = __( 'Notifications', 'buddypress' ); 176 } 177 178 // Add the "My Account" sub menus 179 $wp_admin_nav[] = array( 180 'parent' => buddypress()->my_account_menu_id, 181 'id' => 'my-account-' . $this->id, 182 'title' => $unread, 183 'href' => trailingslashit( $notifications_link ), 184 ); 185 186 // Unread 187 $wp_admin_nav[] = array( 188 'parent' => 'my-account-' . $this->id, 189 'id' => 'my-account-' . $this->id . '-unread', 190 'title' => __( 'Unread', 'buddypress' ), 191 'href' => trailingslashit( $notifications_link ), 192 ); 193 194 // Read 195 $wp_admin_nav[] = array( 196 'parent' => 'my-account-' . $this->id, 197 'id' => 'my-account-' . $this->id . '-read', 198 'title' => __( 'Read', 'buddypress' ), 199 'href' => trailingslashit( $notifications_link . 'read' ), 200 ); 201 } 202 203 parent::setup_admin_bar( $wp_admin_nav ); 204 } 205 206 /** 207 * Set up the title for pages and <title>. 208 * 209 * @since BuddyPress (1.9.0) 210 */ 211 function setup_title() { 212 $bp = buddypress(); 213 214 // Adjust title 215 if ( bp_is_notifications_component() ) { 216 if ( bp_is_my_profile() ) { 217 $bp->bp_options_title = __( 'Notifications', 'buddypress' ); 218 } else { 219 $bp->bp_options_avatar = bp_core_fetch_avatar( array( 220 'item_id' => bp_displayed_user_id(), 221 'type' => 'thumb', 222 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_displayed_user_fullname() ) 223 ) ); 224 $bp->bp_options_title = bp_get_displayed_user_fullname(); 225 } 226 } 227 228 parent::setup_title(); 229 } 230 } 231 232 /** 233 * Bootstrap the Notifications component. 234 * 235 * @since BuddyPress (1.9.0) 236 */ 237 function bp_setup_notifications() { 238 buddypress()->notifications = new BP_Notifications_Component(); 239 } 240 add_action( 'bp_setup_components', 'bp_setup_notifications', 6 ); -
bp-notifications/bp-notifications-screens.php
new file mode 100644
1 <?php 2 3 /** 4 * BuddyPress Notifications Screen Functions. 5 * 6 * Screen functions are the controllers of BuddyPress. They will execute when 7 * their specific URL is caught. They will first save or manipulate data using 8 * business functions, then pass on the user to a template file. 9 * 10 * @package BuddyPress 11 * @subpackage NotificationsScreens 12 */ 13 14 // Exit if accessed directly 15 if ( ! defined( 'ABSPATH' ) ) exit; 16 17 /** 18 * Catch and route the 'unread' notifications screen. 19 * 20 * @since BuddyPress (1.9.0) 21 */ 22 function bp_notifications_screen_unread() { 23 do_action( 'bp_notifications_screen_unread' ); 24 25 bp_core_load_template( apply_filters( 'bp_notifications_template_unread', 'members/single/home' ) ); 26 } 27 28 /** 29 * Catch and route the 'read' notifications screen. 30 * 31 * @since BuddyPress (1.9.0) 32 */ 33 function bp_notifications_screen_read() { 34 do_action( 'bp_notifications_screen_read' ); 35 36 bp_core_load_template( apply_filters( 'bp_notifications_template_read', 'members/single/home' ) ); 37 } 38 39 /** 40 * Catch and route the 'settings' notifications screen. 41 * 42 * @since BuddyPress (1.9.0) 43 */ 44 function bp_notifications_screen_settings() { 45 46 } -
bp-notifications/bp-notifications-template.php
new file mode 100644
1 <?php 2 3 /** 4 * BuddyPress Notifications Template Functions 5 * 6 * @package BuddyPress 7 * @subpackage TonificationsTemplate 8 */ 9 10 // Exit if accessed directly 11 if ( !defined( 'ABSPATH' ) ) exit; 12 13 /** 14 * Output the notifications component slug. 15 * 16 * @since BuddyPress (1.9.0) 17 */ 18 function bp_notifications_slug() { 19 echo bp_get_notifications_slug(); 20 } 21 /** 22 * Return the notifications component slug. 23 * 24 * @since BuddyPress (1.9.0) 25 * 26 * @return string Slug of the Notifications component. 27 */ 28 function bp_get_notifications_slug() { 29 return apply_filters( 'bp_get_notifications_slug', buddypress()->notifications->slug ); 30 } 31 32 /** Main Loop *****************************************************************/ 33 34 /** 35 * The main notifications template loop class. 36 * 37 * Responsible for loading a group of notifications into a loop for display. 38 * 39 * @since BuddyPress (1.9.0) 40 */ 41 class BP_Notifications_Template { 42 /** 43 * The loop iterator. 44 * 45 * @since BuddyPress (1.9.0) 46 * @access public 47 * @var int 48 */ 49 var $current_notification = -1; 50 51 /** 52 * The number of notifications returned by the paged query. 53 * 54 * @since BuddyPress (1.9.0) 55 * @access public 56 * @var int 57 */ 58 var $current_notification_count; 59 60 /** 61 * Total number of notifications matching the query. 62 * 63 * @since BuddyPress (1.9.0) 64 * @access public 65 * @var int 66 */ 67 var $total_notification_count; 68 69 /** 70 * Array of notifications located by the query. 71 * 72 * @since BuddyPress (1.9.0) 73 * @access public 74 * @var array 75 */ 76 var $notifications; 77 78 /** 79 * The notification object currently being iterated on. 80 * 81 * @since BuddyPress (1.9.0) 82 * @access public 83 * @var object 84 */ 85 var $notification; 86 87 /** 88 * A flag for whether the loop is currently being iterated. 89 * 90 * @since BuddyPress (1.9.0) 91 * @access public 92 * @var bool 93 */ 94 var $in_the_loop; 95 96 /** 97 * The ID of the user to whom the displayed notifications belong. 98 * 99 * @since BuddyPress (1.9.0) 100 * @access public 101 * @var int 102 */ 103 var $user_id; 104 105 /** 106 * The page number being requested. 107 * 108 * @since BuddyPress (1.9.0) 109 * @access public 110 * @var int 111 */ 112 var $pag_page; 113 114 /** 115 * The number of items to display per page of results. 116 * 117 * @since BuddyPress (1.9.0) 118 * @access public 119 * @var int 120 */ 121 var $pag_num; 122 123 /** 124 * An HTML string containing pagination links. 125 * 126 * @since BuddyPress (1.9.0) 127 * @access public 128 * @var string 129 */ 130 var $pag_links; 131 132 /** 133 * A string to match against. 134 * 135 * @since BuddyPress (1.9.0) 136 * @access public 137 * @var string 138 */ 139 var $search_terms; 140 141 /** 142 * Constructor method. 143 * 144 * @since BuddyPress (1.9.0) 145 * 146 * @param array $args { 147 * @type int $user_id ID of the user to whom the displayed 148 * notifications belong. 149 * @type bool $is_new Whether to limit the query to unread 150 * notifications. Default: true. 151 * @type int $page Number of the page of results to return. 152 * Will be overridden by URL parameter. Default: 1. 153 * @type int $per_page Number of results to return per page. 154 * Will be overridden by URL parameter. Default: 25. 155 * @type int $max Optional. Max results to display. 156 * @type string $search_terms Optional. Term to match against 157 * component_name and component_action. 158 * @type string $page_arg URL argument to use for pagination. 159 * Default: 'npage'. 160 * } 161 */ 162 public function __construct( $args = array() ) { 163 164 $r = wp_parse_args( $args, array( 165 'user_id' => 0, 166 'is_new' => true, 167 'page' => 1, 168 'per_page' => 25, 169 'max' => null, 170 'search_terms' => '', 171 'page_arg' => 'npage', 172 ) ); 173 174 // Setup variables 175 $this->pag_page = isset( $_GET[ $r['page_arg'] ] ) ? intval( $_GET[ $r['page_arg'] ] ) : $r['page']; 176 $this->pag_num = isset( $_GET['num'] ) ? intval( $_GET['num'] ) : $r['per_page']; 177 $this->user_id = $r['user_id']; 178 $this->is_new = $r['is_new']; 179 $this->search_terms = $r['search_terms']; 180 $this->page_arg = $r['page_arg']; 181 182 // Get the notifications 183 $notifications = BP_Notifications_Notification::get_current_notifications_for_user( array( 184 'user_id' => $this->user_id, 185 'is_new' => $this->is_new, 186 'page' => $this->pag_page, 187 'per_page' => $this->pag_num, 188 'search_terms' => $this->search_terms 189 ) ); 190 191 // Setup the notifications to loop through 192 $this->notifications = $notifications['notifications']; 193 $this->total_notification_count = $notifications['total']; 194 195 if ( empty( $this->notifications ) ) { 196 $this->notification_count = 0; 197 $this->total_notification_count = 0; 198 199 } else { 200 if ( ! empty( $max ) ) { 201 if ( $max >= count( $this->notifications ) ) { 202 $this->notification_count = count( $this->notifications ); 203 } else { 204 $this->notification_count = (int) $max; 205 } 206 } else { 207 $this->notification_count = count( $this->notifications ); 208 } 209 } 210 211 if ( (int) $this->total_notification_count && (int) $this->pag_num ) { 212 $this->pag_links = paginate_links( array( 213 'base' => add_query_arg( $this->page_arg, '%#%' ), 214 'format' => '', 215 'total' => ceil( (int) $this->total_notification_count / (int) $this->pag_num ), 216 'current' => $this->pag_page, 217 'prev_text' => _x( '←', 'Notifications pagination previous text', 'buddypress' ), 218 'next_text' => _x( '→', 'Notifications pagination next text', 'buddypress' ), 219 'mid_size' => 1 220 ) ); 221 } 222 } 223 224 /** 225 * Whether there are notifications available in the loop. 226 * 227 * @since BuddyPress (1.9.0) 228 * 229 * @see bp_has_notifications() 230 * 231 * @return bool True if there are items in the loop, otherwise false. 232 */ 233 public function has_notifications() { 234 if ( $this->notification_count ) { 235 return true; 236 } 237 238 return false; 239 } 240 241 /** 242 * Set up the next notification and iterate index. 243 * 244 * @since BuddyPress (1.9.0) 245 * 246 * @return object The next notification to iterate over. 247 */ 248 public function next_notification() { 249 250 $this->current_notification++; 251 252 $this->notification = $this->notifications[ $this->current_notification ]; 253 254 return $this->notification; 255 } 256 257 /** 258 * Rewind the blogs and reset blog index. 259 * 260 * @since BuddyPress (1.9.0) 261 */ 262 public function rewind_notifications() { 263 264 $this->current_notification = -1; 265 266 if ( $this->notification_count > 0 ) { 267 $this->notification = $this->notifications[0]; 268 } 269 } 270 271 /** 272 * Whether there are notifications left in the loop to iterate over. 273 * 274 * This method is used by {@link bp_notifications()} as part of the 275 * while loop that controls iteration inside the notifications loop, eg: 276 * while ( bp_notifications() ) { ... 277 * 278 * @since BuddyPress (1.9.0) 279 * 280 * @see bp_notifications() 281 * 282 * @return bool True if there are more notifications to show, 283 * otherwise false. 284 */ 285 public function notifications() { 286 287 if ( $this->current_notification + 1 < $this->notification_count ) { 288 return true; 289 290 } elseif ( $this->current_notification + 1 == $this->notification_count ) { 291 do_action( 'notifications_loop_end'); 292 293 $this->rewind_notifications(); 294 } 295 296 $this->in_the_loop = false; 297 return false; 298 } 299 300 /** 301 * Set up the current notification inside the loop. 302 * 303 * Used by {@link bp_the_notification()} to set up the current 304 * notification data while looping, so that template tags used during 305 * that iteration make reference to the current notification. 306 * 307 * @since BuddyPress (1.9.0) 308 * 309 * @see bp_the_notification() 310 */ 311 public function the_notification() { 312 $this->in_the_loop = true; 313 $this->notification = $this->next_notification(); 314 315 // loop has just started 316 if ( 0 === $this->current_notification ) { 317 do_action( 'notifications_loop_start' ); 318 } 319 } 320 } 321 322 /** 323 * Initialize the notifications loop. 324 * 325 * Based on the $args passed, bp_has_notifications() populates 326 * buddypress()->notifications->query_loop global, enabling the use of BP 327 * templates and template functions to display a list of notifications. 328 * 329 * @since BuddyPress (1.9.0) 330 * 331 * @param array $args { 332 * Arguments for limiting the contents of the notifications loop. Can be 333 * passed as an associative array, or as a URL query string. 334 * @type int $user_id ID of the user to whom notifications belong. Default: 335 * ID of the logged-in user. 336 * @type bool $is_new Whether to limit query to unread notifications. 337 * Default: when viewing the 'unread' tab, defaults to true; when 338 * viewing the 'read' tab, defaults to false. 339 * @type int $page The page of notifications being fetched. Default: 1. 340 * @type int $per_page Number of items to display on a page. Default: 25. 341 * @type int $max Optional. Max items to display. Default: false. 342 * @type string $search_terms Optional. Term to match against 343 * component_name and component_action. 344 * @type string $page_arg URL argument to use for pagination. 345 * Default: 'npage'. 346 * } 347 */ 348 function bp_has_notifications( $args = '' ) { 349 350 // Get the default is_new argument 351 if ( bp_is_current_action( 'unread' ) ) { 352 $is_new = 1; 353 } elseif ( bp_is_current_action( 'read' ) ) { 354 $is_new = 0; 355 } 356 357 // Parse the args 358 $r = wp_parse_args( $args, array( 359 'user_id' => bp_loggedin_user_id(), 360 'is_new' => $is_new, 361 'page' => 1, 362 'per_page' => 25, 363 'max' => false, 364 'search_terms' => isset( $_REQUEST['s'] ) ? stripslashes( $_REQUEST['s'] ) : '', 365 'page_arg' => 'npage' 366 ) ); 367 368 // Get the notifications 369 $query_loop = new BP_Notifications_Template( $r ); 370 371 // Setup the global query loop 372 buddypress()->notifications->query_loop = $query_loop; 373 374 return apply_filters( 'bp_has_notificationss', $query_loop->has_notifications(), $query_loop ); 375 } 376 377 /** 378 * Get the notifications returned by the template loop. 379 * 380 * @since BuddyPress (1.9.0) 381 * 382 * @return array List of notifications. 383 */ 384 function bp_the_notifications() { 385 return buddypress()->notifications->query_loop->notifications(); 386 } 387 388 /** 389 * Get the current notification object in the loop. 390 * 391 * @since BuddyPress (1.9.0) 392 * 393 * @return object The current notification within the loop. 394 */ 395 function bp_the_notification() { 396 return buddypress()->notifications->query_loop->the_notification(); 397 } 398 399 /** 400 * Output the ID of the notification currently being iterated on. 401 * 402 * @since BuddyPress (1.9.0) 403 */ 404 function bp_the_notification_id() { 405 echo bp_get_the_notification_id(); 406 } 407 /** 408 * Return the ID of the notification currently being iterated on. 409 * 410 * @since BuddyPress (1.9.0) 411 * 412 * @return int ID of the current notification. 413 */ 414 function bp_get_the_notification_id() { 415 return apply_filters( 'bp_get_the_notification_id', buddypress()->notifications->query_loop->notification->id ); 416 } 417 418 /** 419 * Output the associated item ID of the notification currently being iterated on. 420 * 421 * @since BuddyPress (1.9.0) 422 */ 423 function bp_the_notification_item_id() { 424 echo bp_get_the_notification_item_id(); 425 } 426 /** 427 * Return the associated item ID of the notification currently being iterated on. 428 * 429 * @since BuddyPress (1.9.0) 430 * 431 * @return int ID of the item associated with the current notification. 432 */ 433 function bp_get_the_notification_item_id() { 434 return apply_filters( 'bp_get_the_notification_item_id', stripslashes_deep( buddypress()->notifications->query_loop->notification->item_id ) ); 435 } 436 437 /** 438 * Output the secondary associated item ID of the notification currently being iterated on. 439 * 440 * @since BuddyPress (1.9.0) 441 */ 442 function bp_the_notification_secondary_item_id() { 443 echo bp_get_the_notification_secondary_item_id(); 444 } 445 /** 446 * Return the secondary associated item ID of the notification currently being iterated on. 447 * 448 * @since BuddyPress (1.9.0) 449 * 450 * @return int ID of the secondary item associated with the current notification. 451 */ 452 function bp_get_the_notification_secondary_item_id() { 453 return apply_filters( 'bp_get_the_notification_secondary_item_id', stripslashes_deep( buddypress()->notifications->query_loop->notification->secondary_item_id ) ); 454 } 455 456 /** 457 * Output the name of the component associated with the notification currently being iterated on. 458 * 459 * @since BuddyPress (1.9.0) 460 */ 461 function bp_the_notification_component_name() { 462 echo bp_get_the_notification_component_name(); 463 } 464 /** 465 * Return the name of the component associated with the notification currently being iterated on. 466 * 467 * @since BuddyPress (1.9.0) 468 * 469 * @return int Name of the component associated with the current notification. 470 */ 471 function bp_get_the_notification_component_name() { 472 return apply_filters( 'bp_get_the_notification_component_name', stripslashes_deep( buddypress()->notifications->query_loop->notification->component_name ) ); 473 } 474 475 /** 476 * Output the name of the action associated with the notification currently being iterated on. 477 * 478 * @since BuddyPress (1.9.0) 479 */ 480 function bp_the_notification_component_action() { 481 echo bp_get_the_notification_component_action(); 482 } 483 /** 484 * Return the name of the action associated with the notification currently being iterated on. 485 * 486 * @since BuddyPress (1.9.0) 487 * 488 * @return int Name of the action associated with the current notification. 489 */ 490 function bp_get_the_notification_component_action() { 491 return apply_filters( 'bp_get_the_notification_component_action', stripslashes_deep( buddypress()->notifications->query_loop->notification->component_action ) ); 492 } 493 494 /** 495 * Output the timestamp of the current notification. 496 * 497 * @since BuddyPress (1.9.0) 498 */ 499 function bp_the_notification_date_notified() { 500 echo bp_get_the_notification_date_notified(); 501 } 502 /** 503 * Return the timestamp of the current notification. 504 * 505 * @since BuddyPress (1.9.0) 506 * 507 * @return string Timestamp of the current notification. 508 */ 509 function bp_get_the_notification_date_notified() { 510 return apply_filters( 'bp_get_the_notification_date_notified', stripslashes_deep( buddypress()->notifications->query_loop->notification->date_notified ) ); 511 } 512 513 /** 514 * Output the pagination for the current notification loop. 515 * 516 * @since BuddyPress (1.9.0) 517 */ 518 function bp_notifications_pagination_links() { 519 echo bp_get_notifications_pagination_links(); 520 } 521 /** 522 * Return the pagination for the current notification loop. 523 * 524 * @since BuddyPress (1.9.0) 525 * 526 * @return string HTML for the pagination. 527 */ 528 function bp_get_notifications_pagination_links() { 529 return apply_filters( 'bp_get_notifications_pagination_links', buddypress()->notifications->query_loop->pag_links ); 530 } -
bp-templates/bp-legacy/buddypress/members/single/home.php
45 45 elseif ( bp_is_user_forums() ) : 46 46 bp_get_template_part( 'members/single/forums' ); 47 47 48 elseif ( bp_is_user_notifications() ) : 49 bp_get_template_part( 'members/single/notifications' ); 50 48 51 elseif ( bp_is_user_settings() ) : 49 52 bp_get_template_part( 'members/single/settings' ); 50 53 -
bp-templates/bp-legacy/buddypress/members/single/notifications.php
new file mode 100644
1 <?php 2 3 /** 4 * BuddyPress - Users Notifications 5 * 6 * @package BuddyPress 7 * @subpackage bp-legacy 8 */ 9 10 ?> 11 12 <div class="item-list-tabs no-ajax" id="subnav" role="navigation"> 13 <ul> 14 <?php if ( bp_is_my_profile() ) bp_get_options_nav(); ?> 15 16 <li id="members-order-select" class="last filter"> 17 18 <label for="members-friends"><?php _e( 'Order By:', 'buddypress' ); ?></label> 19 <select id="members-friends"> 20 <option value="newest"><?php _e( 'Newest First', 'buddypress' ); ?></option> 21 <option value="oldest"><?php _e( 'Oldest First', 'buddypress' ); ?></option> 22 </select> 23 </li> 24 </ul> 25 </div> 26 27 <?php 28 switch ( bp_current_action() ) : 29 30 // Unread 31 case 'unread' : 32 bp_get_template_part( 'members/single/notifications/unread' ); 33 break; 34 35 // Read 36 case 'read' : 37 bp_get_template_part( 'members/single/notifications/read' ); 38 break; 39 40 // Any other 41 default : 42 bp_get_template_part( 'members/single/plugins' ); 43 break; 44 endswitch; -
bp-templates/bp-legacy/buddypress/members/single/notifications/notifications-loop.php
new file mode 100644
1 <div class="notification-pagination"> 2 <?php bp_notifications_pagination_links() ?> 3 </div> 4 5 <?php while ( bp_the_notifications() ) : bp_the_notification(); ?> 6 7 <tr> 8 <td></td> 9 <td><?php bp_the_notification_component_action(); ?></td> 10 <td><?php echo bp_core_get_userlink( bp_get_the_notification_item_id() ); ?></td> 11 <td><?php echo bp_core_time_since( bp_get_the_notification_date_notified() ); ?></td> 12 </tr> 13 14 <?php endwhile; -
bp-templates/bp-legacy/buddypress/members/single/notifications/read.php
new file mode 100644
1 <?php if ( bp_has_notifications() ) : ?> 2 3 <table class="notification-settings"> 4 <thead> 5 <tr> 6 <th class="icon"></th> 7 <th class="title"><?php _e( 'Notification', 'buddypress' ) ?></th> 8 <th class="title"><?php _e( 'Member', 'buddypress' ) ?></th> 9 <th class="date"><?php _e( 'Date Received', 'buddypress' ) ?></th> 10 </tr> 11 </thead> 12 13 <tbody> 14 <?php bp_get_template_part( 'members/single/notifications/notifications-loop' ); ?> 15 </tbody> 16 </table> 17 18 <?php else : ?> 19 20 <div id="message" class="info"> 21 <p><?php _e( 'You have no notifications.', 'buddypress' ); ?></p> 22 </div> 23 24 <?php endif; 25 No newline at end of file -
bp-templates/bp-legacy/buddypress/members/single/notifications/unread.php
new file mode 100644
1 <?php if ( bp_has_notifications() ) : ?> 2 3 <table class="notification-settings"> 4 <thead> 5 <tr> 6 <th class="icon"></th> 7 <th class="title"><?php _e( 'Notification', 'buddypress' ) ?></th> 8 <th class="title"><?php _e( 'Member', 'buddypress' ) ?></th> 9 <th class="date"><?php _e( 'Date Received', 'buddypress' ) ?></th> 10 </tr> 11 </thead> 12 13 <tbody> 14 <?php bp_get_template_part( 'members/single/notifications/notifications-loop' ); ?> 15 </tbody> 16 </table> 17 18 <?php else : ?> 19 20 <div id="message" class="info"> 21 <p><?php _e( 'You have no new notifications.', 'buddypress' ); ?></p> 22 </div> 23 24 <?php endif; 25 No newline at end of file -
tests/includes/factory.php
class BP_UnitTest_Factory extends WP_UnitTest_Factory { 9 9 $this->group = new BP_UnitTest_Factory_For_Group( $this ); 10 10 $this->xprofile_group = new BP_UnitTest_Factory_For_XProfileGroup( $this ); 11 11 $this->xprofile_field = new BP_UnitTest_Factory_For_XProfileField( $this ); 12 $this->notification = new BP_UnitTest_Factory_For_Notification( $this ); 12 13 } 13 14 } 14 15 … … class BP_UnitTest_Factory_For_XProfileField extends WP_UnitTest_Factory_For_Thin 146 147 return new BP_XProfile_Field( $field_id ); 147 148 } 148 149 } 150 151 class BP_UnitTest_Factory_For_Notification extends WP_UnitTest_Factory_For_Thing { 152 public function __construct( $factory = null ) { 153 parent::__construct( $factory ); 154 } 155 156 public function create_object( $args ) { 157 return bp_notifications_add_notification( $args ); 158 } 159 160 public function update_object( $id, $fields ) {} 161 162 public function get_object_by_id( $id ) { 163 return new BP_Notifications_Notification( $id ); 164 } 165 } -
tests/includes/install.php
define( 'BP_ROOT_BLOG', 1 ); 26 26 tests_add_filter( 'show_admin_bar', '__return_true' ); 27 27 28 28 function wp_test_bp_install( $value ) { 29 return array( 'activity' => 1, 'blogs' => 1, 'friends' => 1, 'groups' => 1, 'members' => 1, 'messages' => 1, ' settings' => 1, 'xprofile' => 1, );29 return array( 'activity' => 1, 'blogs' => 1, 'friends' => 1, 'groups' => 1, 'members' => 1, 'messages' => 1, 'notifications' => 1, 'settings' => 1, 'xprofile' => 1, ); 30 30 } 31 31 tests_add_filter( 'bp_new_install_default_components', 'wp_test_bp_install' ); 32 32 -
tests/testcases/notifications/class-bp-core-notification.php
new file mode 100644
1 <?php 2 /** 3 * @group notifications 4 */ 5 class BP_Tests_BP_Core_Notification_TestCases extends BP_UnitTestCase { 6 public function setUp() { 7 if ( ! method_exists( 'BP_Core_Notification', 'get') ) { 8 $this->markTestSkipped( 9 'BP_Core_Notification::get() is only available in BP 1.9.' 10 ); 11 12 } 13 14 parent::setUp(); 15 16 add_filter( 'bp_notifications_delete_sql', array( $this, 'save_sql' ), 0 ); 17 add_filter( 'bp_notifications_get_sql', array( $this, 'save_sql' ), 0 ); 18 } 19 20 public function tearDown() { 21 parent::tearDown(); 22 unset( $this->where_sql ); 23 } 24 25 /** TESTS ****************************************************************/ 26 27 /** 28 * Tests the WHERE sql statement generated by {@link BP_Core_Notification::get_all_for_user()}. 29 */ 30 public function test_get_all_for_user_is_new_sql() { 31 $expected = 'WHERE user_id = 1 AND is_new = 1'; 32 33 BP_Core_Notification::get_all_for_user( 1 ); 34 35 $this->assertEquals( 36 $expected, 37 $this->where_sql 38 ); 39 } 40 41 /** 42 * Tests the WHERE sql statement generated by {@link BP_Core_Notification::get_all_for_user()}. 43 */ 44 public function test_get_all_for_user_sql() { 45 $expected = 'WHERE user_id = 1'; 46 47 BP_Core_Notification::get_all_for_user( 1, 'all' ); 48 49 $this->assertEquals( 50 $expected, 51 $this->where_sql 52 ); 53 } 54 55 /** 56 * Tests the WHERE sql statement generated by {@link bp_core_delete_notifications_by_type()}. 57 */ 58 public function test_delete_for_user_by_type_sql() { 59 $expected = "WHERE user_id = 1 AND component_name = 'activity' AND component_action = 'new_at_mention'"; 60 61 // emulates call in bp_activity_remove_screen_notifications() 62 bp_core_delete_notifications_by_type( 1, 'activity', 'new_at_mention' ); 63 64 $this->assertEquals( 65 $expected, 66 $this->where_sql 67 ); 68 } 69 70 /** 71 * Tests the WHERE sql statement generated by {@link bp_core_delete_notifications_by_item_id()}. 72 */ 73 public function test_delete_for_user_by_item_id_sql() { 74 $expected = "WHERE user_id = 1 AND item_id = 1 AND component_name = 'groups' AND component_action = 'group_invite'"; 75 76 // emulates call in groups_accept_invite() 77 bp_core_delete_notifications_by_item_id( 1, 1, 'groups', 'group_invite' ); 78 79 $this->assertEquals( 80 $expected, 81 $this->where_sql 82 ); 83 } 84 85 /** 86 * Tests the WHERE sql statement generated by {@link bp_core_delete_notifications_from_user()}. 87 */ 88 public function test_delete_from_user_by_type_sql() { 89 $expected = "WHERE user_id = 1 AND component_name = 'groups' AND component_action = 'new_membership_request'"; 90 91 // emulates call in groups_remove_data_for_user() 92 bp_core_delete_notifications_from_user( 1, 'groups', 'new_membership_request' ); 93 94 $this->assertEquals( 95 $expected, 96 $this->where_sql 97 ); 98 } 99 100 /** 101 * Tests the WHERE sql statement generated by {@link bp_core_delete_all_notifications_by_type()}. 102 */ 103 public function test_delete_all_by_type_sql() { 104 $expected = "WHERE item_id = 1 AND component_name = 'groups'"; 105 106 // emulates call in groups_delete_group() 107 bp_core_delete_all_notifications_by_type( 1, 'groups' ); 108 109 $this->assertEquals( 110 $expected, 111 $this->where_sql 112 ); 113 } 114 115 /** UTILITY **************************************************************/ 116 117 /** 118 * Utility method to save the SQL statement before the actual query is run. 119 */ 120 public function save_sql( $retval ) { 121 // only get the WHERE sql portion of the statement 122 $this->where_sql = $this->get_where_sql( $retval ); 123 124 return $retval; 125 } 126 127 /** 128 * Utility method to return the WHERE sql statement from a given SQL statement. 129 */ 130 protected function get_where_sql( $sql ) { 131 $leading_sql = strpos( $sql, 'WHERE' ); 132 return substr( $sql, $leading_sql ); 133 } 134 }